opal-up 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }