-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.hpp
338 lines (282 loc) · 8.96 KB
/
util.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/**
* Utility functions and definitions for cppdtp.
*/
#pragma once
#ifndef CPPDTP_UTIL_HPP
#define CPPDTP_UTIL_HPP
#include <string>
#include <vector>
#include <type_traits>
#include <utility>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "../include/SimpleBinStream.h"
#pragma GCC diagnostic pop
#ifdef _WIN32
# include <WinSock2.h>
# include <Windows.h>
# include <WS2tcpip.h>
#else
# include <unistd.h>
# include <sys/socket.h>
# include <fcntl.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <errno.h>
# include <time.h>
# include <limits.h>
#endif
// CPPDTP error codes
#define CPPDTP_SUCCESS 0
#define CPPDTP_WINSOCK_INIT_FAILED 1
#define CPPDTP_SERVER_SOCK_INIT_FAILED 2
#define CPPDTP_SERVER_SETSOCKOPT_FAILED 3
#define CPPDTP_SERVER_CANNOT_RESTART 4
#define CPPDTP_SERVER_NOT_SERVING 5
#define CPPDTP_SERVER_ALREADY_SERVING 6
#define CPPDTP_SERVER_ADDRESS_FAILED 7
#define CPPDTP_SERVER_BIND_FAILED 8
#define CPPDTP_SERVER_LISTEN_FAILED 9
#define CPPDTP_SERVER_STOP_FAILED 10
#define CPPDTP_SERVE_THREAD_NOT_CLOSING 11
#define CPPDTP_CLIENT_DOES_NOT_EXIST 12
#define CPPDTP_CLIENT_REMOVE_FAILED 13
#define CPPDTP_SERVER_SEND_FAILED 14
#define CPPDTP_EVENT_THREAD_START_FAILED 15
#define CPPDTP_SERVE_THREAD_START_FAILED 16
#define CPPDTP_HANDLE_THREAD_START_FAILED 17
#define CPPDTP_SELECT_FAILED 18
#define CPPDTP_SOCKET_ACCEPT_FAILED 19
#define CPPDTP_SERVER_RECV_FAILED 20
#define CPPDTP_STATUS_SEND_FAILED 21
#define CPPDTP_SERVER_FULL 22
#define CPPDTP_CLIENT_SOCK_INIT_FAILED 23
#define CPPDTP_CLIENT_CANNOT_RECONNECT 24
#define CPPDTP_CLIENT_ALREADY_CONNECTED 25
#define CPPDTP_CLIENT_ADDRESS_FAILED 26
#define CPPDTP_CLIENT_CONNECT_FAILED 27
#define CPPDTP_CLIENT_DISCONNECT_FAILED 28
#define CPPDTP_HANDLE_THREAD_NOT_CLOSING 29
#define CPPDTP_CLIENT_NOT_CONNECTED 30
#define CPPDTP_CLIENT_SEND_FAILED 31
#define CPPDTP_CLIENT_RECV_FAILED 32
#define CPPDTP_OPENSSL_ERROR 33
#define CPPDTP_SERVER_KEY_EXCHANGE_FAILED 34
#define CPPDTP_CLIENT_KEY_EXCHANGE_FAILED 35
// Global address family to use
#ifndef CPPDTP_ADDRESS_FAMILY
# define CPPDTP_ADDRESS_FAMILY AF_INET
#endif
// INET and INET6 address string length
#define CPPDTP_INET_ADDRSTRLEN INET_ADDRSTRLEN
#define CPPDTP_INET6_ADDRSTRLEN INET6_ADDRSTRLEN
// Global address string length
#if (CPPDTP_ADDRESS_FAMILY == AF_INET)
# define CPPDTP_ADDRSTRLEN CPPDTP_INET_ADDRSTRLEN
#elif (CPPDTP_ADDRESS_FAMILY == AF_INET6)
# define CPPDTP_ADDRSTRLEN CPPDTP_INET6_ADDRSTRLEN
#endif
// Default CPPDTP server host address
#define CPPDTP_SERVER_HOST "0.0.0.0"
// Default CPPDTP client host address
#define CPPDTP_CLIENT_HOST "127.0.0.1"
// Default CPPDTP port
#ifndef CPPDTP_PORT
# define CPPDTP_PORT 29275
#endif
// Default CPPDTP server listen backlog
#ifndef CPPDTP_SERVER_LISTEN_BACKLOG
# define CPPDTP_SERVER_LISTEN_BACKLOG 8
#endif
// Length of the size portion of each message
#define CPPDTP_LENSIZE 5
// Amount of time to sleep between socket reads
#define CPPDTP_SLEEP_TIME 0.001
// Determine if a blocking error has occurred
// This is necessary because -Wlogical-op causes a compile-time error on machines where EAGAIN and EWOULDBLOCK are equal
#ifndef _WIN32
# if EAGAIN == EWOULDBLOCK
# define CPPDTP_EAGAIN_OR_WOULDBLOCK(e) (e == EAGAIN)
# else
# define CPPDTP_EAGAIN_OR_WOULDBLOCK(e) (e == EAGAIN || e == EWOULDBLOCK)
# endif
#endif
namespace cppdtp {
using mem_ostream = simple::mem_ostream<std::true_type>;
using mem_istream = simple::mem_istream<std::true_type>;
static bool _cppdtp_init_status = false;
static bool _cppdtp_exit_status = false;
/**
* Called on exit.
*/
void _cppdtp_exit() {
if (!_cppdtp_exit_status) {
_cppdtp_exit_status = true;
#ifdef _WIN32
WSACleanup();
#endif
}
}
/**
* Called on library initialization.
*
* @return The initialization return status.
*/
int _cppdtp_init() {
if (!_cppdtp_init_status) {
_cppdtp_init_status = true;
std::atexit(_cppdtp_exit);
#ifdef _WIN32
WSADATA wsa;
return WSAStartup(MAKEWORD(2, 2), &wsa);
#else
return 0;
#endif
}
return 0;
}
/**
* Serialize an object to bytes.
*
* @tparam T The type of object. This must override the streaming operators to be serialized.
* @param object The object to serialize.
* @return A string representing the binary representation of the object.
*/
template<typename T>
const std::vector<char> _serialize(const T &object) {
mem_ostream out;
out << object;
return out.get_internal_vec();
}
/**
* Deserialize an object from bytes.
*
* @tparam T The type of object.
* @param object The object to deserialize into.
* @param bytes The byte representation of the object.
*/
template<typename T>
void _deserialize(T &object, const std::vector<char> &bytes) {
mem_istream in(bytes);
in >> object;
}
/**
* Encode the size portion of a message.
*
* @param size The message size.
* @return The message size encoded in bytes.
*/
const std::vector<char> _encode_message_size(size_t size) {
std::vector<char> encoded_size;
for (int i = CPPDTP_LENSIZE - 1; i >= 0; i--) {
encoded_size.insert(encoded_size.begin(), size % 256);
size = size >> 8;
}
return encoded_size;
}
/**
* Decode the size portion of a message.
*
* @param encoded_size The message size encoded in bytes.
* @return The size of the message.
*/
size_t _decode_message_size(const std::vector<char> &encoded_size) {
size_t size = 0;
for (int i = 0; i < CPPDTP_LENSIZE; i++) {
size = size << 8;
size += (unsigned char) (encoded_size[i]);
}
return size;
}
/**
* Construct a message.
*
* @param data The message data.
* @return The constructed message.
*/
const std::vector<char> _encode_message(const std::vector<char> &data) {
const std::vector<char> size = _encode_message_size(data.size());
std::vector<char> message;
message.reserve(size.size() + data.size());
message.insert(message.end(), size.begin(), size.end());
message.insert(message.end(), data.begin(), data.end());
return message;
}
/**
* Deconstruct a message.
*
* @param message The message to be deconstructed.
* @return The deconstructed message.
*/
std::vector<char> _decode_message(const std::vector<char> &message) {
std::vector<char> data(message.begin() + CPPDTP_LENSIZE, message.end());
return data;
}
/**
* Sleep for a number of seconds.
*
* @param seconds The number of seconds to sleep.
*/
void sleep(double seconds) {
#ifdef _WIN32
Sleep(seconds * 1000);
#else
struct timespec ts;
ts.tv_sec = seconds;
ts.tv_nsec = ((int) (seconds * 1000) % 1000) * 1000000;
nanosleep(&ts, NULL);
#endif
}
#ifdef _WIN32
/**
* Convert a C-style string to a wide character type.
*
* @param cstr The C-style string.
* @return The wide character string.
*/
wchar_t *cstr_to_wchar(const char *cstr) {
size_t newsize = strlen(cstr) + 1;
wchar_t *wchar = new wchar_t[newsize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wchar, newsize, cstr, _TRUNCATE);
return wchar;
}
/**
* Convert a wide character string to a C-string.
*
* @param wchar The wide character string.
* @return The C-style string.
*/
char *wchar_to_cstr(const wchar_t *wchar) {
size_t wcharsize = wcslen(wchar) + 1;
size_t convertedChars = 0;
const size_t newsize = wcharsize * 2;
char* cstr = new char[newsize];
wcstombs_s(&convertedChars, cstr, newsize, wchar, _TRUNCATE);
return cstr;
}
#endif
} // namespace cppdtp
template<typename T>
cppdtp::mem_ostream &operator<<(cppdtp::mem_ostream &out, const std::vector <T> &vec) {
static_assert(std::is_default_constructible<T>::value, "T must be default constructible");
size_t size = vec.size();
out << size;
for (size_t i = 0; i < vec.size(); i++) {
out << vec[i];
}
return out;
}
template<typename T>
cppdtp::mem_istream &operator>>(cppdtp::mem_istream &in, std::vector <T> &vec) {
static_assert(std::is_default_constructible<T>::value, "T must be default constructible");
size_t size = 0;
in >> size;
for (size_t i = 0; i < size; i++) {
T val; // This is why `T` must be default constructible
in >> val;
vec.push_back(val);
}
return in;
}
#endif // CPPDTP_UTIL_HPP