opal-up 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +209 -0
  3. data/README.md +81 -28
  4. data/bin/up_ruby +4 -0
  5. data/bin/up_ruby_cluster +4 -0
  6. data/ext/up_ext/App.h +606 -0
  7. data/ext/up_ext/AsyncSocket.h +355 -0
  8. data/ext/up_ext/AsyncSocketData.h +87 -0
  9. data/ext/up_ext/BloomFilter.h +83 -0
  10. data/ext/up_ext/ChunkedEncoding.h +236 -0
  11. data/ext/up_ext/ClientApp.h +36 -0
  12. data/ext/up_ext/HttpContext.h +502 -0
  13. data/ext/up_ext/HttpContextData.h +56 -0
  14. data/ext/up_ext/HttpErrors.h +53 -0
  15. data/ext/up_ext/HttpParser.h +680 -0
  16. data/ext/up_ext/HttpResponse.h +578 -0
  17. data/ext/up_ext/HttpResponseData.h +95 -0
  18. data/ext/up_ext/HttpRouter.h +380 -0
  19. data/ext/up_ext/Loop.h +204 -0
  20. data/ext/up_ext/LoopData.h +112 -0
  21. data/ext/up_ext/MoveOnlyFunction.h +377 -0
  22. data/ext/up_ext/PerMessageDeflate.h +315 -0
  23. data/ext/up_ext/ProxyParser.h +163 -0
  24. data/ext/up_ext/QueryParser.h +120 -0
  25. data/ext/up_ext/TopicTree.h +363 -0
  26. data/ext/up_ext/Utilities.h +66 -0
  27. data/ext/up_ext/WebSocket.h +381 -0
  28. data/ext/up_ext/WebSocketContext.h +434 -0
  29. data/ext/up_ext/WebSocketContextData.h +109 -0
  30. data/ext/up_ext/WebSocketData.h +86 -0
  31. data/ext/up_ext/WebSocketExtensions.h +256 -0
  32. data/ext/up_ext/WebSocketHandshake.h +145 -0
  33. data/ext/up_ext/WebSocketProtocol.h +506 -0
  34. data/ext/up_ext/bsd.c +767 -0
  35. data/ext/up_ext/bsd.h +109 -0
  36. data/ext/up_ext/context.c +524 -0
  37. data/ext/up_ext/epoll_kqueue.c +458 -0
  38. data/ext/up_ext/epoll_kqueue.h +67 -0
  39. data/ext/up_ext/extconf.rb +5 -0
  40. data/ext/up_ext/internal.h +224 -0
  41. data/ext/up_ext/libusockets.h +350 -0
  42. data/ext/up_ext/libuwebsockets.cpp +1374 -0
  43. data/ext/up_ext/libuwebsockets.h +260 -0
  44. data/ext/up_ext/loop.c +386 -0
  45. data/ext/up_ext/loop_data.h +38 -0
  46. data/ext/up_ext/socket.c +231 -0
  47. data/ext/up_ext/up_ext.c +278 -0
  48. data/lib/up/node/rack_env.rb +2 -2
  49. data/lib/up/ruby/cluster_cli.rb +10 -0
  50. data/lib/up/ruby/rack_cluster.rb +26 -0
  51. data/lib/up/ruby/rack_env.rb +97 -0
  52. data/lib/up/ruby/rack_server.rb +26 -0
  53. data/lib/up/ruby/server_cli.rb +10 -0
  54. data/lib/up/u_web_socket/rack_env.rb +1 -1
  55. data/lib/up/version.rb +1 -1
  56. metadata +71 -18
  57. data/.gitignore +0 -5
  58. data/Gemfile +0 -2
  59. data/example_rack_app/Gemfile +0 -3
  60. data/example_rack_app/config.ru +0 -6
  61. data/example_rack_app/rack_app.rb +0 -5
  62. data/example_roda_app/Gemfile +0 -6
  63. data/example_roda_app/config.ru +0 -6
  64. data/example_roda_app/roda_app.rb +0 -37
  65. data/example_sinatra_app/Gemfile +0 -6
  66. data/example_sinatra_app/config.ru +0 -6
  67. data/example_sinatra_app/sinatra_app.rb +0 -7
  68. data/opal-up.gemspec +0 -27
  69. data/up_logo.svg +0 -256
data/ext/up_ext/bsd.c ADDED
@@ -0,0 +1,767 @@
1
+ /*
2
+ * Authored by Alex Hultman, 2018-2021.
3
+ * Intellectual property of third-party.
4
+
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /* Todo: this file should lie in networking/bsd.c */
19
+
20
+ #define __APPLE_USE_RFC_3542
21
+
22
+ #include "libusockets.h"
23
+ #include "internal.h"
24
+
25
+ #include <stdio.h>
26
+ #include <stdlib.h>
27
+
28
+ #ifndef _WIN32
29
+ //#define _GNU_SOURCE
30
+ #include <sys/types.h>
31
+ #include <sys/socket.h>
32
+ #include <netinet/in.h>
33
+ #include <netinet/tcp.h>
34
+ #include <netdb.h>
35
+ #include <string.h>
36
+ #include <unistd.h>
37
+ #include <fcntl.h>
38
+ #include <errno.h>
39
+ #endif
40
+
41
+ /* Internal structure of packet buffer */
42
+ struct us_internal_udp_packet_buffer {
43
+ #if defined(_WIN32) || defined(__APPLE__)
44
+ char *buf[LIBUS_UDP_MAX_NUM];
45
+ size_t len[LIBUS_UDP_MAX_NUM];
46
+ struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM];
47
+ #else
48
+ struct mmsghdr msgvec[LIBUS_UDP_MAX_NUM];
49
+ struct iovec iov[LIBUS_UDP_MAX_NUM];
50
+ struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM];
51
+ char control[LIBUS_UDP_MAX_NUM][256];
52
+ #endif
53
+ };
54
+
55
+ /* We need to emulate sendmmsg, recvmmsg on platform who don't have it */
56
+ int bsd_sendmmsg(LIBUS_SOCKET_DESCRIPTOR fd, void *msgvec, unsigned int vlen, int flags) {
57
+ #if defined(__APPLE__)
58
+
59
+ struct mmsghdr {
60
+ struct msghdr msg_hdr; /* Message header */
61
+ unsigned int msg_len; /* Number of bytes transmitted */
62
+ };
63
+
64
+ struct mmsghdr *hdrs = (struct mmsghdr *) msgvec;
65
+
66
+ for (int i = 0; i < vlen; i++) {
67
+ int ret = sendmsg(fd, &hdrs[i].msg_hdr, flags);
68
+ if (ret == -1) {
69
+ if (i) {
70
+ return i;
71
+ } else {
72
+ return -1;
73
+ }
74
+ } else {
75
+ hdrs[i].msg_len = ret;
76
+ }
77
+ }
78
+
79
+ return vlen;
80
+
81
+ #elif defined(_WIN32)
82
+
83
+ struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
84
+
85
+ /* Let's just use sendto here */
86
+ /* Winsock does not have sendmsg, while macOS has, however, we simply use sendto since both macOS and Winsock has it.
87
+ * Besides, you should use Linux either way to get best performance with the sendmmsg */
88
+
89
+
90
+ // while we do not get error, send next
91
+
92
+ for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
93
+ // need to support ipv6 addresses also!
94
+ int ret = sendto(fd, packet_buffer->buf[i], packet_buffer->len[i], flags, (struct sockaddr *)&packet_buffer->addr[i], sizeof(struct sockaddr_in));
95
+
96
+ if (ret == -1) {
97
+ // if we fail then we need to buffer up, no that's not our problem
98
+ // we do need to register poll out though and have a callback for it
99
+ return i;
100
+ }
101
+
102
+ //printf("sendto: %d\n", ret);
103
+ }
104
+
105
+ return LIBUS_UDP_MAX_NUM; // one message
106
+ #else
107
+ return sendmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags | MSG_NOSIGNAL);
108
+ #endif
109
+ }
110
+
111
+ int bsd_recvmmsg(LIBUS_SOCKET_DESCRIPTOR fd, void *msgvec, unsigned int vlen, int flags, void *timeout) {
112
+ #if defined(_WIN32) || defined(__APPLE__)
113
+ struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
114
+
115
+
116
+ for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
117
+ socklen_t addr_len = sizeof(struct sockaddr_storage);
118
+ int ret = recvfrom(fd, packet_buffer->buf[i], LIBUS_UDP_MAX_SIZE, flags, (struct sockaddr *)&packet_buffer->addr[i], &addr_len);
119
+
120
+ if (ret == -1) {
121
+ return i;
122
+ }
123
+
124
+ packet_buffer->len[i] = ret;
125
+ }
126
+
127
+ return LIBUS_UDP_MAX_NUM;
128
+ #else
129
+ // we need to set controllen for ip packet
130
+ for (int i = 0; i < vlen; i++) {
131
+ ((struct mmsghdr *)msgvec)[i].msg_hdr.msg_controllen = 256;
132
+ }
133
+
134
+ return recvmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags, 0);
135
+ #endif
136
+ }
137
+
138
+ // this one is needed for knowing the destination addr of udp packet
139
+ // an udp socket can only bind to one port, and that port never changes
140
+ // this function returns ONLY the IP address, not any port
141
+ int bsd_udp_packet_buffer_local_ip(void *msgvec, int index, char *ip) {
142
+ #if defined(_WIN32) || defined(__APPLE__)
143
+ return 0; // not supported
144
+ #else
145
+ struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
146
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
147
+ // Linux ipv4
148
+ #ifdef IP_PKTINFO
149
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
150
+ struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg);
151
+ memcpy(ip, &pi->ipi_addr, 4);
152
+ return 4;
153
+ }
154
+ // FreeBSD ipv4
155
+ #elif IP_RECVDSTADDR
156
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
157
+ struct in_addr *addr = (struct in_addr *) CMSG_DATA(cmsg);
158
+ memcpy(ip, addr, 4);
159
+ return 4;
160
+ }
161
+ #endif
162
+
163
+ // Linux, FreeBSD ipv6
164
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
165
+ struct in6_pktinfo *pi6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
166
+ memcpy(ip, &pi6->ipi6_addr, 16);
167
+ return 16;
168
+ }
169
+ }
170
+
171
+ return 0; // no length
172
+
173
+ #endif
174
+ }
175
+
176
+ char *bsd_udp_packet_buffer_peer(void *msgvec, int index) {
177
+ #if defined(_WIN32) || defined(__APPLE__)
178
+ struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
179
+ return (char *)&packet_buffer->addr[index];
180
+ #else
181
+ return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_name;
182
+ #endif
183
+ }
184
+
185
+ char *bsd_udp_packet_buffer_payload(void *msgvec, int index) {
186
+ #if defined(_WIN32) || defined(__APPLE__)
187
+ struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
188
+ return packet_buffer->buf[index];
189
+ #else
190
+ return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_iov[0].iov_base;
191
+ #endif
192
+ }
193
+
194
+ int bsd_udp_packet_buffer_payload_length(void *msgvec, int index) {
195
+ #if defined(_WIN32) || defined(__APPLE__)
196
+ struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
197
+ return packet_buffer->len[index];
198
+ #else
199
+ return ((struct mmsghdr *) msgvec)[index].msg_len;
200
+ #endif
201
+ }
202
+
203
+ void bsd_udp_buffer_set_packet_payload(struct us_udp_packet_buffer_t *send_buf, int index, int offset, void *payload, int length, void *peer_addr) {
204
+ #if defined(_WIN32) || defined(__APPLE__)
205
+ struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) send_buf;
206
+
207
+ memcpy(packet_buffer->buf[index], payload, length);
208
+ memcpy(&packet_buffer->addr[index], peer_addr, sizeof(struct sockaddr_storage));
209
+
210
+ packet_buffer->len[index] = length;
211
+ #else
212
+ //printf("length: %d, offset: %d\n", length, offset);
213
+
214
+ struct mmsghdr *ss = (struct mmsghdr *) send_buf;
215
+
216
+ // copy the peer address
217
+ memcpy(ss[index].msg_hdr.msg_name, peer_addr, /*ss[index].msg_hdr.msg_namelen*/ sizeof(struct sockaddr_in));
218
+
219
+ // set control length to 0
220
+ ss[index].msg_hdr.msg_controllen = 0;
221
+
222
+ // copy the payload
223
+
224
+ ss[index].msg_hdr.msg_iov->iov_len = length + offset;
225
+
226
+
227
+ memcpy(((char *) ss[index].msg_hdr.msg_iov->iov_base) + offset, payload, length);
228
+ #endif
229
+ }
230
+
231
+ /* The maximum UDP payload size is 64kb, but in IPV6 you can have jumbopackets larger than so.
232
+ * We do not support those jumbo packets currently, but will safely ignore them.
233
+ * Any sane sender would assume we don't support them if we consistently drop them.
234
+ * Therefore a udp_packet_buffer_t will be 64 MB in size (64kb * 1024). */
235
+ void *bsd_create_udp_packet_buffer() {
236
+ #if defined(_WIN32) || defined(__APPLE__)
237
+ struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
238
+
239
+ for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
240
+ b->buf[i] = ((char *) b) + sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * i;
241
+ }
242
+
243
+ return (struct us_udp_packet_buffer_t *) b;
244
+ #else
245
+ /* Allocate 64kb times 1024 */
246
+ struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
247
+
248
+ for (int n = 0; n < LIBUS_UDP_MAX_NUM; ++n) {
249
+
250
+ b->iov[n].iov_base = &((char *) (b + 1))[n * LIBUS_UDP_MAX_SIZE];
251
+ b->iov[n].iov_len = LIBUS_UDP_MAX_SIZE;
252
+
253
+ b->msgvec[n].msg_hdr = (struct msghdr) {
254
+ .msg_name = &b->addr,
255
+ .msg_namelen = sizeof (struct sockaddr_storage),
256
+
257
+ .msg_iov = &b->iov[n],
258
+ .msg_iovlen = 1,
259
+
260
+ .msg_control = b->control[n],
261
+ .msg_controllen = 256,
262
+ };
263
+ }
264
+
265
+ return (struct us_udp_packet_buffer_t *) b;
266
+ #endif
267
+ }
268
+
269
+ LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) {
270
+ #ifdef __APPLE__
271
+ if (fd != LIBUS_SOCKET_ERROR) {
272
+ int no_sigpipe = 1;
273
+ setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &no_sigpipe, sizeof(int));
274
+ }
275
+ #endif
276
+ return fd;
277
+ }
278
+
279
+ LIBUS_SOCKET_DESCRIPTOR bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd) {
280
+ #ifdef _WIN32
281
+ /* Libuv will set windows sockets as non-blocking */
282
+ #else
283
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
284
+ #endif
285
+ return fd;
286
+ }
287
+
288
+ void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) {
289
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled));
290
+ }
291
+
292
+ void bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd) {
293
+ // Linux TCP_CORK has the same underlying corking mechanism as with MSG_MORE
294
+ #ifdef TCP_CORK
295
+ int enabled = 0;
296
+ setsockopt(fd, IPPROTO_TCP, TCP_CORK, (void *) &enabled, sizeof(int));
297
+ #endif
298
+ }
299
+
300
+ LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) {
301
+ // returns INVALID_SOCKET on error
302
+ int flags = 0;
303
+ #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
304
+ flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
305
+ #endif
306
+
307
+ LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol);
308
+
309
+ return bsd_set_nonblocking(apple_no_sigpipe(created_fd));
310
+ }
311
+
312
+ void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
313
+ #ifdef _WIN32
314
+ closesocket(fd);
315
+ #else
316
+ close(fd);
317
+ #endif
318
+ }
319
+
320
+ void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
321
+ #ifdef _WIN32
322
+ shutdown(fd, SD_SEND);
323
+ #else
324
+ shutdown(fd, SHUT_WR);
325
+ #endif
326
+ }
327
+
328
+ void bsd_shutdown_socket_read(LIBUS_SOCKET_DESCRIPTOR fd) {
329
+ #ifdef _WIN32
330
+ shutdown(fd, SD_RECEIVE);
331
+ #else
332
+ shutdown(fd, SHUT_RD);
333
+ #endif
334
+ }
335
+
336
+ void internal_finalize_bsd_addr(struct bsd_addr_t *addr) {
337
+ // parse, so to speak, the address
338
+ if (addr->mem.ss_family == AF_INET6) {
339
+ addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr;
340
+ addr->ip_length = sizeof(struct in6_addr);
341
+ addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
342
+ } else if (addr->mem.ss_family == AF_INET) {
343
+ addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr;
344
+ addr->ip_length = sizeof(struct in_addr);
345
+ addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port);
346
+ } else {
347
+ addr->ip_length = 0;
348
+ addr->port = -1;
349
+ }
350
+ }
351
+
352
+ int bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
353
+ addr->len = sizeof(addr->mem);
354
+ if (getsockname(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
355
+ return -1;
356
+ }
357
+ internal_finalize_bsd_addr(addr);
358
+ return 0;
359
+ }
360
+
361
+ int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
362
+ addr->len = sizeof(addr->mem);
363
+ if (getpeername(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
364
+ return -1;
365
+ }
366
+ internal_finalize_bsd_addr(addr);
367
+ return 0;
368
+ }
369
+
370
+ char *bsd_addr_get_ip(struct bsd_addr_t *addr) {
371
+ return addr->ip;
372
+ }
373
+
374
+ int bsd_addr_get_ip_length(struct bsd_addr_t *addr) {
375
+ return addr->ip_length;
376
+ }
377
+
378
+ int bsd_addr_get_port(struct bsd_addr_t *addr) {
379
+ return addr->port;
380
+ }
381
+
382
+ // called by dispatch_ready_poll
383
+ LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
384
+ LIBUS_SOCKET_DESCRIPTOR accepted_fd;
385
+ addr->len = sizeof(addr->mem);
386
+
387
+ #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
388
+ // Linux, FreeBSD
389
+ accepted_fd = accept4(fd, (struct sockaddr *) addr, &addr->len, SOCK_CLOEXEC | SOCK_NONBLOCK);
390
+ #else
391
+ // Windows, OS X
392
+ accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len);
393
+
394
+ #endif
395
+
396
+ /* We cannot rely on addr since it is not initialized if failed */
397
+ if (accepted_fd == LIBUS_SOCKET_ERROR) {
398
+ return LIBUS_SOCKET_ERROR;
399
+ }
400
+
401
+ internal_finalize_bsd_addr(addr);
402
+
403
+ return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd));
404
+ }
405
+
406
+ int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) {
407
+ return recv(fd, buf, length, flags);
408
+ }
409
+
410
+ #if !defined(_WIN32)
411
+ #include <sys/uio.h>
412
+
413
+ int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) {
414
+ struct iovec chunks[2];
415
+
416
+ chunks[0].iov_base = (char *)header;
417
+ chunks[0].iov_len = header_length;
418
+ chunks[1].iov_base = (char *)payload;
419
+ chunks[1].iov_len = payload_length;
420
+
421
+ return writev(fd, chunks, 2);
422
+ }
423
+ #else
424
+ int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) {
425
+ int written = bsd_send(fd, header, header_length, 0);
426
+ if (written == header_length) {
427
+ int second_write = bsd_send(fd, payload, payload_length, 0);
428
+ if (second_write > 0) {
429
+ written += second_write;
430
+ }
431
+ }
432
+ return written;
433
+ }
434
+ #endif
435
+
436
+ int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) {
437
+
438
+ // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD)
439
+
440
+ #ifndef MSG_NOSIGNAL
441
+ #define MSG_NOSIGNAL 0
442
+ #endif
443
+
444
+ #ifdef MSG_MORE
445
+
446
+ // for Linux we do not want signals
447
+ return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL);
448
+
449
+ #else
450
+
451
+ // use TCP_NOPUSH
452
+
453
+ return send(fd, buf, length, MSG_NOSIGNAL);
454
+
455
+ #endif
456
+ }
457
+
458
+ int bsd_would_block() {
459
+ #ifdef _WIN32
460
+ return WSAGetLastError() == WSAEWOULDBLOCK;
461
+ #else
462
+ return errno == EWOULDBLOCK;// || errno == EAGAIN;
463
+ #endif
464
+ }
465
+
466
+ // return LIBUS_SOCKET_ERROR or the fd that represents listen socket
467
+ // listen both on ipv6 and ipv4
468
+ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) {
469
+ struct addrinfo hints, *result;
470
+ memset(&hints, 0, sizeof(struct addrinfo));
471
+
472
+ hints.ai_flags = AI_PASSIVE;
473
+ hints.ai_family = AF_UNSPEC;
474
+ hints.ai_socktype = SOCK_STREAM;
475
+
476
+ char port_string[16];
477
+ snprintf(port_string, 16, "%d", port);
478
+
479
+ if (getaddrinfo(host, port_string, &hints, &result)) {
480
+ return LIBUS_SOCKET_ERROR;
481
+ }
482
+
483
+ LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
484
+ struct addrinfo *listenAddr;
485
+ for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
486
+ if (a->ai_family == AF_INET6) {
487
+ listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
488
+ listenAddr = a;
489
+ }
490
+ }
491
+
492
+ for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
493
+ if (a->ai_family == AF_INET) {
494
+ listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
495
+ listenAddr = a;
496
+ }
497
+ }
498
+
499
+ if (listenFd == LIBUS_SOCKET_ERROR) {
500
+ freeaddrinfo(result);
501
+ return LIBUS_SOCKET_ERROR;
502
+ }
503
+
504
+ if (port != 0) {
505
+ /* Otherwise, always enable SO_REUSEPORT and SO_REUSEADDR _unless_ options specify otherwise */
506
+ #ifdef _WIN32
507
+ if (options & LIBUS_LISTEN_EXCLUSIVE_PORT) {
508
+ int optval2 = 1;
509
+ setsockopt(listenFd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &optval2, sizeof(optval2));
510
+ } else {
511
+ int optval3 = 1;
512
+ setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval3, sizeof(optval3));
513
+ }
514
+ #else
515
+ #if /*defined(__linux) &&*/ defined(SO_REUSEPORT)
516
+ if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) {
517
+ int optval = 1;
518
+ setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval));
519
+ }
520
+ #endif
521
+ int enabled = 1;
522
+ setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
523
+ #endif
524
+
525
+ }
526
+
527
+ #ifdef IPV6_V6ONLY
528
+ int disabled = 0;
529
+ setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
530
+ #endif
531
+
532
+ if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) {
533
+ bsd_close_socket(listenFd);
534
+ freeaddrinfo(result);
535
+ return LIBUS_SOCKET_ERROR;
536
+ }
537
+
538
+ freeaddrinfo(result);
539
+ return listenFd;
540
+ }
541
+
542
+ #ifndef _WIN32
543
+ #include <sys/un.h>
544
+ #else
545
+ #include <afunix.h>
546
+ #include <io.h>
547
+ #endif
548
+ #include <sys/stat.h>
549
+ #include <stddef.h>
550
+ LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, int options) {
551
+
552
+ LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
553
+
554
+ listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0);
555
+
556
+ if (listenFd == LIBUS_SOCKET_ERROR) {
557
+ return LIBUS_SOCKET_ERROR;
558
+ }
559
+
560
+ #ifndef _WIN32
561
+ // 700 permission by default
562
+ fchmod(listenFd, S_IRWXU);
563
+ #else
564
+ _chmod(path, S_IREAD | S_IWRITE | S_IEXEC);
565
+ #endif
566
+
567
+ struct sockaddr_un server_address;
568
+ memset(&server_address, 0, sizeof(server_address));
569
+ server_address.sun_family = AF_UNIX;
570
+ strcpy(server_address.sun_path, path);
571
+ int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path);
572
+ #ifdef _WIN32
573
+ _unlink(path);
574
+ #else
575
+ unlink(path);
576
+ #endif
577
+
578
+ if (bind(listenFd, (struct sockaddr *)&server_address, size) || listen(listenFd, 512)) {
579
+ bsd_close_socket(listenFd);
580
+ return LIBUS_SOCKET_ERROR;
581
+ }
582
+
583
+ return listenFd;
584
+ }
585
+
586
+ LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) {
587
+ struct addrinfo hints, *result;
588
+ memset(&hints, 0, sizeof(struct addrinfo));
589
+
590
+ hints.ai_flags = AI_PASSIVE;
591
+ hints.ai_family = AF_UNSPEC;
592
+ hints.ai_socktype = SOCK_DGRAM;
593
+
594
+ char port_string[16];
595
+ snprintf(port_string, 16, "%d", port);
596
+
597
+ if (getaddrinfo(host, port_string, &hints, &result)) {
598
+ return LIBUS_SOCKET_ERROR;
599
+ }
600
+
601
+ LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
602
+ struct addrinfo *listenAddr;
603
+ for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
604
+ if (a->ai_family == AF_INET6) {
605
+ listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
606
+ listenAddr = a;
607
+ }
608
+ }
609
+
610
+ for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
611
+ if (a->ai_family == AF_INET) {
612
+ listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
613
+ listenAddr = a;
614
+ }
615
+ }
616
+
617
+ if (listenFd == LIBUS_SOCKET_ERROR) {
618
+ freeaddrinfo(result);
619
+ return LIBUS_SOCKET_ERROR;
620
+ }
621
+
622
+ if (port != 0) {
623
+ /* Should this also go for UDP? */
624
+ int enabled = 1;
625
+ setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
626
+ }
627
+
628
+ #ifdef IPV6_V6ONLY
629
+ int disabled = 0;
630
+ setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
631
+ #endif
632
+
633
+ /* We need destination address for udp packets in both ipv6 and ipv4 */
634
+
635
+ /* On FreeBSD this option seems to be called like so */
636
+ #ifndef IPV6_RECVPKTINFO
637
+ #define IPV6_RECVPKTINFO IPV6_PKTINFO
638
+ #endif
639
+
640
+ int enabled = 1;
641
+ if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &enabled, sizeof(enabled)) == -1) {
642
+ if (errno == 92) {
643
+ // Linux ipv4
644
+ #ifdef IP_PKTINFO
645
+ if (setsockopt(listenFd, IPPROTO_IP, IP_PKTINFO, (void *) &enabled, sizeof(enabled)) != 0) {
646
+ printf("Error setting IPv4 pktinfo!\n");
647
+ }
648
+ // FreeBSD ipv4
649
+ #elif IP_RECVDSTADDR
650
+ if (setsockopt(listenFd, IPPROTO_IP, IP_RECVDSTADDR, (void *) &enabled, sizeof(enabled)) != 0) {
651
+ printf("Error setting IPv4 pktinfo!\n");
652
+ }
653
+ #endif
654
+ } else {
655
+ printf("Error setting IPv6 pktinfo!\n");
656
+ }
657
+ }
658
+
659
+ /* These are used for getting the ECN */
660
+ if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVTCLASS, (void *) &enabled, sizeof(enabled)) == -1) {
661
+ if (errno == 92) {
662
+ if (setsockopt(listenFd, IPPROTO_IP, IP_RECVTOS, (void *) &enabled, sizeof(enabled)) != 0) {
663
+ printf("Error setting IPv4 ECN!\n");
664
+ }
665
+ } else {
666
+ printf("Error setting IPv6 ECN!\n");
667
+ }
668
+ }
669
+
670
+ /* We bind here as well */
671
+ if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen)) {
672
+ bsd_close_socket(listenFd);
673
+ freeaddrinfo(result);
674
+ return LIBUS_SOCKET_ERROR;
675
+ }
676
+
677
+ freeaddrinfo(result);
678
+ return listenFd;
679
+ }
680
+
681
+ int bsd_udp_packet_buffer_ecn(void *msgvec, int index) {
682
+
683
+ #if defined(_WIN32) || defined(__APPLE__)
684
+ printf("ECN not supported!\n");
685
+ #else
686
+ // we should iterate all control messages once, after recvmmsg and then only fetch them with these functions
687
+ struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
688
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
689
+ // do we need to get TOS from ipv6 also?
690
+ if (cmsg->cmsg_level == IPPROTO_IP) {
691
+ if (cmsg->cmsg_type == IP_TOS) {
692
+ uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
693
+ return tos & 3;
694
+ }
695
+ }
696
+
697
+ if (cmsg->cmsg_level == IPPROTO_IPV6) {
698
+ if (cmsg->cmsg_type == IPV6_TCLASS) {
699
+ // is this correct?
700
+ uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
701
+ return tos & 3;
702
+ }
703
+ }
704
+ }
705
+ #endif
706
+
707
+ printf("We got no ECN!\n");
708
+
709
+ return 0; // no ecn defaults to 0
710
+ }
711
+
712
+ LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, const char *source_host, int options) {
713
+ struct addrinfo hints, *result;
714
+ memset(&hints, 0, sizeof(struct addrinfo));
715
+ hints.ai_family = AF_UNSPEC;
716
+ hints.ai_socktype = SOCK_STREAM;
717
+
718
+ char port_string[16];
719
+ snprintf(port_string, 16, "%d", port);
720
+
721
+ if (getaddrinfo(host, port_string, &hints, &result) != 0) {
722
+ return LIBUS_SOCKET_ERROR;
723
+ }
724
+
725
+ LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(result->ai_family, result->ai_socktype, result->ai_protocol);
726
+ if (fd == LIBUS_SOCKET_ERROR) {
727
+ freeaddrinfo(result);
728
+ return LIBUS_SOCKET_ERROR;
729
+ }
730
+
731
+ if (source_host) {
732
+ struct addrinfo *interface_result;
733
+ if (!getaddrinfo(source_host, NULL, NULL, &interface_result)) {
734
+ int ret = bind(fd, interface_result->ai_addr, (socklen_t) interface_result->ai_addrlen);
735
+ freeaddrinfo(interface_result);
736
+ if (ret == LIBUS_SOCKET_ERROR) {
737
+ bsd_close_socket(fd);
738
+ freeaddrinfo(result);
739
+ return LIBUS_SOCKET_ERROR;
740
+ }
741
+ }
742
+ }
743
+
744
+ connect(fd, result->ai_addr, (socklen_t) result->ai_addrlen);
745
+ freeaddrinfo(result);
746
+
747
+ return fd;
748
+ }
749
+
750
+ LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket_unix(const char *server_path, int options) {
751
+
752
+ struct sockaddr_un server_address;
753
+ memset(&server_address, 0, sizeof(server_address));
754
+ server_address.sun_family = AF_UNIX;
755
+ strcpy(server_address.sun_path, server_path);
756
+ int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path);
757
+
758
+ LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0);
759
+
760
+ if (fd == LIBUS_SOCKET_ERROR) {
761
+ return LIBUS_SOCKET_ERROR;
762
+ }
763
+
764
+ connect(fd, (struct sockaddr *)&server_address, size);
765
+
766
+ return fd;
767
+ }