maph 1.0.0 High-Performance Memory-Mapped Key-Value Database with O(1) Lookups

Loading...
Searching...
No Matches
bsd.c
Go to the documentation of this file.
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/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 // ipv6 or ipv4
148 if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
149 struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg);
150 memcpy(ip, &pi->ipi_addr, 4);
151 return 4;
152 }
153
154 if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
155 struct in6_pktinfo *pi6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
156 memcpy(ip, &pi6->ipi6_addr, 16);
157 return 16;
158 }
159 }
160
161 return 0; // no length
162
163#endif
164}
165
166 char *bsd_udp_packet_buffer_peer(void *msgvec, int index) {
167#if defined(_WIN32) || defined(__APPLE__)
168 struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
169 return (char *)&packet_buffer->addr[index];
170#else
171 return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_name;
172#endif
173}
174
175 char *bsd_udp_packet_buffer_payload(void *msgvec, int index) {
176#if defined(_WIN32) || defined(__APPLE__)
177 struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
178 return packet_buffer->buf[index];
179#else
180 return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_iov[0].iov_base;
181#endif
182}
183
184 int bsd_udp_packet_buffer_payload_length(void *msgvec, int index) {
185#if defined(_WIN32) || defined(__APPLE__)
186 struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) msgvec;
187 return packet_buffer->len[index];
188#else
189 return ((struct mmsghdr *) msgvec)[index].msg_len;
190#endif
191}
192
193 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) {
194#if defined(_WIN32) || defined(__APPLE__)
195 struct us_internal_udp_packet_buffer *packet_buffer = (struct us_internal_udp_packet_buffer *) send_buf;
196
197 memcpy(packet_buffer->buf[index], payload, length);
198 memcpy(&packet_buffer->addr[index], peer_addr, sizeof(struct sockaddr_storage));
199
200 packet_buffer->len[index] = length;
201#else
202 //printf("length: %d, offset: %d\n", length, offset);
203
204 struct mmsghdr *ss = (struct mmsghdr *) send_buf;
205
206 // copy the peer address
207 memcpy(ss[index].msg_hdr.msg_name, peer_addr, /*ss[index].msg_hdr.msg_namelen*/ sizeof(struct sockaddr_in));
208
209 // set control length to 0
210 ss[index].msg_hdr.msg_controllen = 0;
211
212 // copy the payload
213
214 ss[index].msg_hdr.msg_iov->iov_len = length + offset;
215
216
217 memcpy(((char *) ss[index].msg_hdr.msg_iov->iov_base) + offset, payload, length);
218#endif
219}
220
221/* The maximum UDP payload size is 64kb, but in IPV6 you can have jumbopackets larger than so.
222 * We do not support those jumbo packets currently, but will safely ignore them.
223 * Any sane sender would assume we don't support them if we consistently drop them.
224 * Therefore a udp_packet_buffer_t will be 64 MB in size (64kb * 1024). */
225 void *bsd_create_udp_packet_buffer() {
226#if defined(_WIN32) || defined(__APPLE__)
227 struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
228
229 for (int i = 0; i < LIBUS_UDP_MAX_NUM; i++) {
230 b->buf[i] = ((char *) b) + sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * i;
231 }
232
233 return (struct us_udp_packet_buffer_t *) b;
234#else
235 /* Allocate 64kb times 1024 */
236 struct us_internal_udp_packet_buffer *b = malloc(sizeof(struct us_internal_udp_packet_buffer) + LIBUS_UDP_MAX_SIZE * LIBUS_UDP_MAX_NUM);
237
238 for (int n = 0; n < LIBUS_UDP_MAX_NUM; ++n) {
239
240 b->iov[n].iov_base = &((char *) (b + 1))[n * LIBUS_UDP_MAX_SIZE];
241 b->iov[n].iov_len = LIBUS_UDP_MAX_SIZE;
242
243 b->msgvec[n].msg_hdr = (struct msghdr) {
244 .msg_name = &b->addr,
245 .msg_namelen = sizeof (struct sockaddr_storage),
246
247 .msg_iov = &b->iov[n],
248 .msg_iovlen = 1,
249
250 .msg_control = b->control[n],
251 .msg_controllen = 256,
252 };
253 }
254
255 return (struct us_udp_packet_buffer_t *) b;
256#endif
257}
258
259 LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) {
260#ifdef __APPLE__
261 if (fd != LIBUS_SOCKET_ERROR) {
262 int no_sigpipe = 1;
263 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &no_sigpipe, sizeof(int));
264 }
265#endif
266 return fd;
267}
268
269 LIBUS_SOCKET_DESCRIPTOR bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd) {
270#ifdef _WIN32
271 /* Libuv will set windows sockets as non-blocking */
272#else
273 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
274#endif
275 return fd;
276}
277
278 void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) {
279 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled));
280}
281
282 void bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd) {
283 // Linux TCP_CORK has the same underlying corking mechanism as with MSG_MORE
284#ifdef TCP_CORK
285 int enabled = 0;
286 setsockopt(fd, IPPROTO_TCP, TCP_CORK, (void *) &enabled, sizeof(int));
287#endif
288}
289
290 LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) {
291 // returns INVALID_SOCKET on error
292 int flags = 0;
293#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
294 flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
295#endif
296
297 LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol);
298
299 return bsd_set_nonblocking(apple_no_sigpipe(created_fd));
300}
301
302 void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
303#ifdef _WIN32
304 closesocket(fd);
305#else
306 close(fd);
307#endif
308}
309
310 void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
311#ifdef _WIN32
312 shutdown(fd, SD_SEND);
313#else
314 shutdown(fd, SHUT_WR);
315#endif
316}
317
318 void bsd_shutdown_socket_read(LIBUS_SOCKET_DESCRIPTOR fd) {
319#ifdef _WIN32
320 shutdown(fd, SD_RECEIVE);
321#else
322 shutdown(fd, SHUT_RD);
323#endif
324}
325
326 void internal_finalize_bsd_addr(struct bsd_addr_t *addr) {
327 // parse, so to speak, the address
328 if (addr->mem.ss_family == AF_INET6) {
329 addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr;
330 addr->ip_length = sizeof(struct in6_addr);
331 addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
332 } else if (addr->mem.ss_family == AF_INET) {
333 addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr;
334 addr->ip_length = sizeof(struct in_addr);
335 addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port);
336 } else {
337 addr->ip_length = 0;
338 addr->port = -1;
339 }
340}
341
342 int bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
343 addr->len = sizeof(addr->mem);
344 if (getsockname(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
345 return -1;
346 }
347 internal_finalize_bsd_addr(addr);
348 return 0;
349}
350
351 int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
352 addr->len = sizeof(addr->mem);
353 if (getpeername(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
354 return -1;
355 }
356 internal_finalize_bsd_addr(addr);
357 return 0;
358}
359
360 char *bsd_addr_get_ip(struct bsd_addr_t *addr) {
361 return addr->ip;
362}
363
364 int bsd_addr_get_ip_length(struct bsd_addr_t *addr) {
365 return addr->ip_length;
366}
367
368 int bsd_addr_get_port(struct bsd_addr_t *addr) {
369 return addr->port;
370}
371
372// called by dispatch_ready_poll
373 LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
374 LIBUS_SOCKET_DESCRIPTOR accepted_fd;
375 addr->len = sizeof(addr->mem);
376
377#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
378 // Linux, FreeBSD
379 accepted_fd = accept4(fd, (struct sockaddr *) addr, &addr->len, SOCK_CLOEXEC | SOCK_NONBLOCK);
380#else
381 // Windows, OS X
382 accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len);
383
384#endif
385
386 /* We cannot rely on addr since it is not initialized if failed */
387 if (accepted_fd == LIBUS_SOCKET_ERROR) {
388 return LIBUS_SOCKET_ERROR;
389 }
390
391 internal_finalize_bsd_addr(addr);
392
393 return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd));
394}
395
396 int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) {
397 return recv(fd, buf, length, flags);
398}
399
400 int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) {
401
402 // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD)
403
404#ifndef MSG_NOSIGNAL
405#define MSG_NOSIGNAL 0
406#endif
407
408#ifdef MSG_MORE
409
410 // for Linux we do not want signals
411 return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL);
412
413#else
414
415 // use TCP_NOPUSH
416
417 return send(fd, buf, length, MSG_NOSIGNAL);
418
419#endif
420}
421
422 int bsd_would_block() {
423#ifdef _WIN32
424 return WSAGetLastError() == WSAEWOULDBLOCK;
425#else
426 return errno == EWOULDBLOCK;// || errno == EAGAIN;
427#endif
428}
429
430// return LIBUS_SOCKET_ERROR or the fd that represents listen socket
431// listen both on ipv6 and ipv4
432 LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) {
433 struct addrinfo hints, *result;
434 memset(&hints, 0, sizeof(struct addrinfo));
435
436 hints.ai_flags = AI_PASSIVE;
437 hints.ai_family = AF_UNSPEC;
438 hints.ai_socktype = SOCK_STREAM;
439
440 char port_string[16];
441 snprintf(port_string, 16, "%d", port);
442
443 if (getaddrinfo(host, port_string, &hints, &result)) {
444 return LIBUS_SOCKET_ERROR;
445 }
446
447 LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
448 struct addrinfo *listenAddr;
449 for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
450 if (a->ai_family == AF_INET6) {
451 listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
452 listenAddr = a;
453 }
454 }
455
456 for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
457 if (a->ai_family == AF_INET) {
458 listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
459 listenAddr = a;
460 }
461 }
462
463 if (listenFd == LIBUS_SOCKET_ERROR) {
464 freeaddrinfo(result);
465 return LIBUS_SOCKET_ERROR;
466 }
467
468 if (port != 0) {
469 /* Otherwise, always enable SO_REUSEPORT and SO_REUSEADDR _unless_ options specify otherwise */
470#ifdef _WIN32
471 if (options & LIBUS_LISTEN_EXCLUSIVE_PORT) {
472 int optval2 = 1;
473 setsockopt(listenFd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &optval2, sizeof(optval2));
474 } else {
475 int optval3 = 1;
476 setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval3, sizeof(optval3));
477 }
478#else
479 #if /*defined(__linux) &&*/ defined(SO_REUSEPORT)
480 if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) {
481 int optval = 1;
482 setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval));
483 }
484 #endif
485 int enabled = 1;
486 setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
487#endif
488
489 }
490
491#ifdef IPV6_V6ONLY
492 int disabled = 0;
493 setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
494#endif
495
496 if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) {
497 bsd_close_socket(listenFd);
498 freeaddrinfo(result);
499 return LIBUS_SOCKET_ERROR;
500 }
501
502 freeaddrinfo(result);
503 return listenFd;
504}
505
506#ifndef _WIN32
507#include <sys/un.h>
508#else
509#include <afunix.h>
510#include <io.h>
511#endif
512#include <sys/stat.h>
513#include <stddef.h>
514 LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, int options) {
515
516 LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
517
518 listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0);
519
520 if (listenFd == LIBUS_SOCKET_ERROR) {
521 return LIBUS_SOCKET_ERROR;
522 }
523
524#ifndef _WIN32
525 // 700 permission by default
526 fchmod(listenFd, S_IRWXU);
527#else
528 _chmod(path, S_IREAD | S_IWRITE | S_IEXEC);
529#endif
530
531 struct sockaddr_un server_address;
532 memset(&server_address, 0, sizeof(server_address));
533 server_address.sun_family = AF_UNIX;
534 strcpy(server_address.sun_path, path);
535 int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path);
536#ifdef _WIN32
537 _unlink(path);
538#else
539 unlink(path);
540#endif
541
542 if (bind(listenFd, (struct sockaddr *)&server_address, size) || listen(listenFd, 512)) {
543 bsd_close_socket(listenFd);
544 return LIBUS_SOCKET_ERROR;
545 }
546
547 return listenFd;
548}
549
550 LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) {
551 struct addrinfo hints, *result;
552 memset(&hints, 0, sizeof(struct addrinfo));
553
554 hints.ai_flags = AI_PASSIVE;
555 hints.ai_family = AF_UNSPEC;
556 hints.ai_socktype = SOCK_DGRAM;
557
558 char port_string[16];
559 snprintf(port_string, 16, "%d", port);
560
561 if (getaddrinfo(host, port_string, &hints, &result)) {
562 return LIBUS_SOCKET_ERROR;
563 }
564
565 LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
566 struct addrinfo *listenAddr;
567 for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
568 if (a->ai_family == AF_INET6) {
569 listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
570 listenAddr = a;
571 }
572 }
573
574 for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
575 if (a->ai_family == AF_INET) {
576 listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
577 listenAddr = a;
578 }
579 }
580
581 if (listenFd == LIBUS_SOCKET_ERROR) {
582 freeaddrinfo(result);
583 return LIBUS_SOCKET_ERROR;
584 }
585
586 if (port != 0) {
587 /* Should this also go for UDP? */
588 int enabled = 1;
589 setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled));
590 }
591
592#ifdef IPV6_V6ONLY
593 int disabled = 0;
594 setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled));
595#endif
596
597 /* We need destination address for udp packets in both ipv6 and ipv4 */
598
599/* On FreeBSD this option seems to be called like so */
600#ifndef IPV6_RECVPKTINFO
601#define IPV6_RECVPKTINFO IPV6_PKTINFO
602#endif
603
604 int enabled = 1;
605 if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &enabled, sizeof(enabled)) == -1) {
606 if (errno == 92) {
607 if (setsockopt(listenFd, IPPROTO_IP, IP_PKTINFO, (void *) &enabled, sizeof(enabled)) != 0) {
608 printf("Error setting IPv4 pktinfo!\n");
609 }
610 } else {
611 printf("Error setting IPv6 pktinfo!\n");
612 }
613 }
614
615 /* These are used for getting the ECN */
616 if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVTCLASS, (void *) &enabled, sizeof(enabled)) == -1) {
617 if (errno == 92) {
618 if (setsockopt(listenFd, IPPROTO_IP, IP_RECVTOS, (void *) &enabled, sizeof(enabled)) != 0) {
619 printf("Error setting IPv4 ECN!\n");
620 }
621 } else {
622 printf("Error setting IPv6 ECN!\n");
623 }
624 }
625
626 /* We bind here as well */
627 if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen)) {
628 bsd_close_socket(listenFd);
629 freeaddrinfo(result);
630 return LIBUS_SOCKET_ERROR;
631 }
632
633 freeaddrinfo(result);
634 return listenFd;
635}
636
637 int bsd_udp_packet_buffer_ecn(void *msgvec, int index) {
638
639#if defined(_WIN32) || defined(__APPLE__)
640 printf("ECN not supported!\n");
641#else
642 // we should iterate all control messages once, after recvmmsg and then only fetch them with these functions
643 struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr;
644 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) {
645 // do we need to get TOS from ipv6 also?
646 if (cmsg->cmsg_level == IPPROTO_IP) {
647 if (cmsg->cmsg_type == IP_TOS) {
648 uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
649 return tos & 3;
650 }
651 }
652
653 if (cmsg->cmsg_level == IPPROTO_IPV6) {
654 if (cmsg->cmsg_type == IPV6_TCLASS) {
655 // is this correct?
656 uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg);
657 return tos & 3;
658 }
659 }
660 }
661#endif
662
663 printf("We got no ECN!\n");
664
665 return 0; // no ecn defaults to 0
666}
667
668 LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, const char *source_host, int options) {
669 struct addrinfo hints, *result;
670 memset(&hints, 0, sizeof(struct addrinfo));
671 hints.ai_family = AF_UNSPEC;
672 hints.ai_socktype = SOCK_STREAM;
673
674 char port_string[16];
675 snprintf(port_string, 16, "%d", port);
676
677 if (getaddrinfo(host, port_string, &hints, &result) != 0) {
678 return LIBUS_SOCKET_ERROR;
679 }
680
681 LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(result->ai_family, result->ai_socktype, result->ai_protocol);
682 if (fd == LIBUS_SOCKET_ERROR) {
683 freeaddrinfo(result);
684 return LIBUS_SOCKET_ERROR;
685 }
686
687 if (source_host) {
688 struct addrinfo *interface_result;
689 if (!getaddrinfo(source_host, NULL, NULL, &interface_result)) {
690 int ret = bind(fd, interface_result->ai_addr, (socklen_t) interface_result->ai_addrlen);
691 freeaddrinfo(interface_result);
692 if (ret == LIBUS_SOCKET_ERROR) {
693 bsd_close_socket(fd);
694 freeaddrinfo(result);
695 return LIBUS_SOCKET_ERROR;
696 }
697 }
698 }
699
700 connect(fd, result->ai_addr, (socklen_t) result->ai_addrlen);
701 freeaddrinfo(result);
702
703 return fd;
704}
705
706 LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket_unix(const char *server_path, int options) {
707
708 struct sockaddr_un server_address;
709 memset(&server_address, 0, sizeof(server_address));
710 server_address.sun_family = AF_UNIX;
711 strcpy(server_address.sun_path, server_path);
712 int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path);
713
714 LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0);
715
716 if (fd == LIBUS_SOCKET_ERROR) {
717 return LIBUS_SOCKET_ERROR;
718 }
719
720 connect(fd, (struct sockaddr *)&server_address, size);
721
722 return fd;
723}
bsd_recv
int bsd_recv(int fd, void *buf, int length, int flags)
Definition bsd.c:396
bsd_set_nonblocking
int bsd_set_nonblocking(int fd)
Definition bsd.c:269
bsd_create_connect_socket_unix
int bsd_create_connect_socket_unix(const char *server_path, int options)
Definition bsd.c:706
apple_no_sigpipe
int apple_no_sigpipe(int fd)
Definition bsd.c:259
bsd_create_socket
int bsd_create_socket(int domain, int type, int protocol)
Definition bsd.c:290
us_internal_udp_packet_buffer::addr
struct sockaddr_storage addr[LIBUS_UDP_MAX_NUM]
Definition bsd.c:50
bsd_shutdown_socket_read
void bsd_shutdown_socket_read(int fd)
Definition bsd.c:318
bsd_create_listen_socket
int bsd_create_listen_socket(const char *host, int port, int options)
Definition bsd.c:432
bsd_addr_get_ip
char * bsd_addr_get_ip(struct bsd_addr_t *addr)
Definition bsd.c:360
bsd_create_udp_socket
int bsd_create_udp_socket(const char *host, int port)
Definition bsd.c:550
IPV6_RECVPKTINFO
#define IPV6_RECVPKTINFO
bsd_close_socket
void bsd_close_socket(int fd)
Definition bsd.c:302
internal_finalize_bsd_addr
void internal_finalize_bsd_addr(struct bsd_addr_t *addr)
Definition bsd.c:326
bsd_udp_packet_buffer_peer
char * bsd_udp_packet_buffer_peer(void *msgvec, int index)
Definition bsd.c:166
bsd_socket_flush
void bsd_socket_flush(int fd)
Definition bsd.c:282
bsd_addr_get_ip_length
int bsd_addr_get_ip_length(struct bsd_addr_t *addr)
Definition bsd.c:364
bsd_udp_packet_buffer_payload
char * bsd_udp_packet_buffer_payload(void *msgvec, int index)
Definition bsd.c:175
bsd_remote_addr
int bsd_remote_addr(int fd, struct bsd_addr_t *addr)
Definition bsd.c:351
bsd_addr_get_port
int bsd_addr_get_port(struct bsd_addr_t *addr)
Definition bsd.c:368
bsd_send
int bsd_send(int fd, const char *buf, int length, int msg_more)
Definition bsd.c:400
MSG_NOSIGNAL
#define MSG_NOSIGNAL
bsd_udp_packet_buffer_ecn
int bsd_udp_packet_buffer_ecn(void *msgvec, int index)
Definition bsd.c:637
bsd_udp_packet_buffer_payload_length
int bsd_udp_packet_buffer_payload_length(void *msgvec, int index)
Definition bsd.c:184
bsd_create_connect_socket
int bsd_create_connect_socket(const char *host, int port, const char *source_host, int options)
Definition bsd.c:668
bsd_udp_packet_buffer_local_ip
int bsd_udp_packet_buffer_local_ip(void *msgvec, int index, char *ip)
Definition bsd.c:141
bsd_sendmmsg
int bsd_sendmmsg(int fd, void *msgvec, unsigned int vlen, int flags)
Definition bsd.c:56
bsd_create_listen_socket_unix
int bsd_create_listen_socket_unix(const char *path, int options)
Definition bsd.c:514
bsd_shutdown_socket
void bsd_shutdown_socket(int fd)
Definition bsd.c:310
us_internal_udp_packet_buffer::iov
struct iovec iov[LIBUS_UDP_MAX_NUM]
Definition bsd.c:49
bsd_recvmmsg
int bsd_recvmmsg(int fd, void *msgvec, unsigned int vlen, int flags, void *timeout)
Definition bsd.c:111
bsd_socket_nodelay
void bsd_socket_nodelay(int fd, int enabled)
Definition bsd.c:278
bsd_create_udp_packet_buffer
void * bsd_create_udp_packet_buffer()
Definition bsd.c:225
bsd_udp_buffer_set_packet_payload
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)
Definition bsd.c:193
us_internal_udp_packet_buffer::control
char control[LIBUS_UDP_MAX_NUM][256]
Definition bsd.c:51
bsd_local_addr
int bsd_local_addr(int fd, struct bsd_addr_t *addr)
Definition bsd.c:342
us_internal_udp_packet_buffer::msgvec
struct mmsghdr msgvec[LIBUS_UDP_MAX_NUM]
Definition bsd.c:48
bsd_accept_socket
int bsd_accept_socket(int fd, struct bsd_addr_t *addr)
Definition bsd.c:373
bsd_would_block
int bsd_would_block()
Definition bsd.c:422
us_internal_udp_packet_buffer
Definition bsd.c:42
bsd_addr_t::port
int port
Definition bsd.h:55
LIBUS_UDP_MAX_NUM
#define LIBUS_UDP_MAX_NUM
Definition bsd.h:48
bsd_addr_t::len
socklen_t len
Definition bsd.h:52
LIBUS_SOCKET_ERROR
#define LIBUS_SOCKET_ERROR
Definition bsd.h:44
bsd_addr_t::ip_length
int ip_length
Definition bsd.h:54
LIBUS_UDP_MAX_SIZE
#define LIBUS_UDP_MAX_SIZE
Definition bsd.h:47
bsd_addr_t::mem
struct sockaddr_storage mem
Definition bsd.h:51
bsd_addr_t::ip
char * ip
Definition bsd.h:53
bsd_addr_t
Definition bsd.h:50
internal.h
libusockets.h
LIBUS_SOCKET_DESCRIPTOR
#define LIBUS_SOCKET_DESCRIPTOR
Definition libusockets.h:38
LIBUS_LISTEN_EXCLUSIVE_PORT
@ LIBUS_LISTEN_EXCLUSIVE_PORT
Definition libusockets.h:49