/src/uWebSockets/uSockets/src/bsd.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | 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 | 0 | return sendmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags | MSG_NOSIGNAL); |
108 | 0 | #endif |
109 | 0 | } |
110 | | |
111 | 0 | 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 | 0 | for (int i = 0; i < vlen; i++) { |
131 | 0 | ((struct mmsghdr *)msgvec)[i].msg_hdr.msg_controllen = 256; |
132 | 0 | } |
133 | |
|
134 | 0 | return recvmmsg(fd, (struct mmsghdr *)msgvec, vlen, flags, 0); |
135 | 0 | #endif |
136 | 0 | } |
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 | 0 | 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 | 0 | struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr; |
146 | 0 | for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(mh); cmsg != NULL; cmsg = CMSG_NXTHDR(mh, cmsg)) { |
147 | | // Linux ipv4 |
148 | 0 | #ifdef IP_PKTINFO |
149 | 0 | if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { |
150 | 0 | struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg); |
151 | 0 | memcpy(ip, &pi->ipi_addr, 4); |
152 | 0 | return 4; |
153 | 0 | } |
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 | 0 | if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { |
165 | 0 | struct in6_pktinfo *pi6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); |
166 | 0 | memcpy(ip, &pi6->ipi6_addr, 16); |
167 | 0 | return 16; |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | 0 | return 0; // no length |
172 | |
|
173 | 0 | #endif |
174 | 0 | } |
175 | | |
176 | 0 | 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 | 0 | return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_name; |
182 | 0 | #endif |
183 | 0 | } |
184 | | |
185 | 0 | 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 | 0 | return ((struct mmsghdr *) msgvec)[index].msg_hdr.msg_iov[0].iov_base; |
191 | 0 | #endif |
192 | 0 | } |
193 | | |
194 | 0 | 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 | 0 | return ((struct mmsghdr *) msgvec)[index].msg_len; |
200 | 0 | #endif |
201 | 0 | } |
202 | | |
203 | 0 | 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 | 0 | struct mmsghdr *ss = (struct mmsghdr *) send_buf; |
215 | | |
216 | | // copy the peer address |
217 | 0 | 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 | 0 | ss[index].msg_hdr.msg_controllen = 0; |
221 | | |
222 | | // copy the payload |
223 | | |
224 | 0 | ss[index].msg_hdr.msg_iov->iov_len = length + offset; |
225 | | |
226 | |
|
227 | 0 | memcpy(((char *) ss[index].msg_hdr.msg_iov->iov_base) + offset, payload, length); |
228 | 0 | #endif |
229 | 0 | } |
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 | 0 | 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 | 0 | 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 | 0 | for (int n = 0; n < LIBUS_UDP_MAX_NUM; ++n) { |
249 | |
|
250 | 0 | b->iov[n].iov_base = &((char *) (b + 1))[n * LIBUS_UDP_MAX_SIZE]; |
251 | 0 | b->iov[n].iov_len = LIBUS_UDP_MAX_SIZE; |
252 | |
|
253 | 0 | b->msgvec[n].msg_hdr = (struct msghdr) { |
254 | 0 | .msg_name = &b->addr, |
255 | 0 | .msg_namelen = sizeof (struct sockaddr_storage), |
256 | |
|
257 | 0 | .msg_iov = &b->iov[n], |
258 | 0 | .msg_iovlen = 1, |
259 | |
|
260 | 0 | .msg_control = b->control[n], |
261 | 0 | .msg_controllen = 256, |
262 | 0 | }; |
263 | 0 | } |
264 | |
|
265 | 0 | return (struct us_udp_packet_buffer_t *) b; |
266 | 0 | #endif |
267 | 0 | } |
268 | | |
269 | 6.06M | 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 | 6.06M | return fd; |
277 | 6.06M | } |
278 | | |
279 | 6.06M | 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 | 6.06M | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); |
284 | 6.06M | #endif |
285 | 6.06M | return fd; |
286 | 6.06M | } |
287 | | |
288 | 6.03M | void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) { |
289 | 6.03M | setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled)); |
290 | 6.03M | } |
291 | | |
292 | 255 | void bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd) { |
293 | | // Linux TCP_CORK has the same underlying corking mechanism as with MSG_MORE |
294 | 255 | #ifdef TCP_CORK |
295 | 255 | int enabled = 0; |
296 | 255 | setsockopt(fd, IPPROTO_TCP, TCP_CORK, (void *) &enabled, sizeof(int)); |
297 | 255 | #endif |
298 | 255 | } |
299 | | |
300 | 26.1k | LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) { |
301 | | // returns INVALID_SOCKET on error |
302 | 26.1k | int flags = 0; |
303 | 26.1k | #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) |
304 | 26.1k | flags = SOCK_CLOEXEC | SOCK_NONBLOCK; |
305 | 26.1k | #endif |
306 | | |
307 | 26.1k | LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol); |
308 | | |
309 | 26.1k | return bsd_set_nonblocking(apple_no_sigpipe(created_fd)); |
310 | 26.1k | } |
311 | | |
312 | 6.05M | void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) { |
313 | | #ifdef _WIN32 |
314 | | closesocket(fd); |
315 | | #else |
316 | 6.05M | close(fd); |
317 | 6.05M | #endif |
318 | 6.05M | } |
319 | | |
320 | 1.77M | void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) { |
321 | | #ifdef _WIN32 |
322 | | shutdown(fd, SD_SEND); |
323 | | #else |
324 | 1.77M | shutdown(fd, SHUT_WR); |
325 | 1.77M | #endif |
326 | 1.77M | } |
327 | | |
328 | 852 | void bsd_shutdown_socket_read(LIBUS_SOCKET_DESCRIPTOR fd) { |
329 | | #ifdef _WIN32 |
330 | | shutdown(fd, SD_RECEIVE); |
331 | | #else |
332 | 852 | shutdown(fd, SHUT_RD); |
333 | 852 | #endif |
334 | 852 | } |
335 | | |
336 | 6.07M | void internal_finalize_bsd_addr(struct bsd_addr_t *addr) { |
337 | | // parse, so to speak, the address |
338 | 6.07M | if (addr->mem.ss_family == AF_INET6) { |
339 | 1.97M | addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr; |
340 | 1.97M | addr->ip_length = sizeof(struct in6_addr); |
341 | 1.97M | addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); |
342 | 4.09M | } else if (addr->mem.ss_family == AF_INET) { |
343 | 4.09M | addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr; |
344 | 4.09M | addr->ip_length = sizeof(struct in_addr); |
345 | 4.09M | addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port); |
346 | 4.09M | } else { |
347 | 0 | addr->ip_length = 0; |
348 | 0 | addr->port = -1; |
349 | 0 | } |
350 | 6.07M | } |
351 | | |
352 | 2.32k | int bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) { |
353 | 2.32k | addr->len = sizeof(addr->mem); |
354 | 2.32k | if (getsockname(fd, (struct sockaddr *) &addr->mem, &addr->len)) { |
355 | 2.32k | return -1; |
356 | 2.32k | } |
357 | 0 | internal_finalize_bsd_addr(addr); |
358 | 0 | return 0; |
359 | 2.32k | } |
360 | | |
361 | 39.0k | int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) { |
362 | 39.0k | addr->len = sizeof(addr->mem); |
363 | 39.0k | if (getpeername(fd, (struct sockaddr *) &addr->mem, &addr->len)) { |
364 | 0 | return -1; |
365 | 0 | } |
366 | 39.0k | internal_finalize_bsd_addr(addr); |
367 | 39.0k | return 0; |
368 | 39.0k | } |
369 | | |
370 | 6.07M | char *bsd_addr_get_ip(struct bsd_addr_t *addr) { |
371 | 6.07M | return addr->ip; |
372 | 6.07M | } |
373 | | |
374 | 6.11M | int bsd_addr_get_ip_length(struct bsd_addr_t *addr) { |
375 | 6.11M | return addr->ip_length; |
376 | 6.11M | } |
377 | | |
378 | 0 | int bsd_addr_get_port(struct bsd_addr_t *addr) { |
379 | 0 | return addr->port; |
380 | 0 | } |
381 | | |
382 | | // called by dispatch_ready_poll |
383 | 11.6M | LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) { |
384 | 11.6M | LIBUS_SOCKET_DESCRIPTOR accepted_fd; |
385 | 11.6M | addr->len = sizeof(addr->mem); |
386 | | |
387 | 11.6M | #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) |
388 | | // Linux, FreeBSD |
389 | 11.6M | 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 | 11.6M | if (accepted_fd == LIBUS_SOCKET_ERROR) { |
398 | 5.61M | return LIBUS_SOCKET_ERROR; |
399 | 5.61M | } |
400 | | |
401 | 6.03M | internal_finalize_bsd_addr(addr); |
402 | | |
403 | 6.03M | return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd)); |
404 | 11.6M | } |
405 | | |
406 | 2.69M | int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) { |
407 | 2.69M | return recv(fd, buf, length, flags); |
408 | 2.69M | } |
409 | | |
410 | | #if !defined(_WIN32) |
411 | | #include <sys/uio.h> |
412 | | |
413 | 0 | int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) { |
414 | 0 | struct iovec chunks[2]; |
415 | | |
416 | 0 | chunks[0].iov_base = (char *)header; |
417 | 0 | chunks[0].iov_len = header_length; |
418 | 0 | chunks[1].iov_base = (char *)payload; |
419 | 0 | chunks[1].iov_len = payload_length; |
420 | | |
421 | 0 | return writev(fd, chunks, 2); |
422 | 0 | } |
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 | 2.51M | 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 | 2.51M | #ifdef MSG_MORE |
445 | | |
446 | | // for Linux we do not want signals |
447 | 2.51M | 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 | 2.51M | } |
457 | | |
458 | 27.1k | int bsd_would_block() { |
459 | | #ifdef _WIN32 |
460 | | return WSAGetLastError() == WSAEWOULDBLOCK; |
461 | | #else |
462 | 27.1k | return errno == EWOULDBLOCK;// || errno == EAGAIN; |
463 | 27.1k | #endif |
464 | 27.1k | } |
465 | | |
466 | | // return LIBUS_SOCKET_ERROR or the fd that represents listen socket |
467 | | // listen both on ipv6 and ipv4 |
468 | 19.9k | LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) { |
469 | 19.9k | struct addrinfo hints, *result; |
470 | 19.9k | memset(&hints, 0, sizeof(struct addrinfo)); |
471 | | |
472 | 19.9k | hints.ai_flags = AI_PASSIVE; |
473 | 19.9k | hints.ai_family = AF_UNSPEC; |
474 | 19.9k | hints.ai_socktype = SOCK_STREAM; |
475 | | |
476 | 19.9k | char port_string[16]; |
477 | 19.9k | snprintf(port_string, 16, "%d", port); |
478 | | |
479 | 19.9k | if (getaddrinfo(host, port_string, &hints, &result)) { |
480 | 6 | return LIBUS_SOCKET_ERROR; |
481 | 6 | } |
482 | | |
483 | 19.9k | LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; |
484 | 19.9k | struct addrinfo *listenAddr; |
485 | 39.8k | for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { |
486 | 19.9k | if (a->ai_family == AF_INET6) { |
487 | 13.4k | listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); |
488 | 13.4k | listenAddr = a; |
489 | 13.4k | } |
490 | 19.9k | } |
491 | | |
492 | 26.3k | for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { |
493 | 6.44k | if (a->ai_family == AF_INET) { |
494 | 6.29k | listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); |
495 | 6.29k | listenAddr = a; |
496 | 6.29k | } |
497 | 6.44k | } |
498 | | |
499 | 19.9k | if (listenFd == LIBUS_SOCKET_ERROR) { |
500 | 147 | freeaddrinfo(result); |
501 | 147 | return LIBUS_SOCKET_ERROR; |
502 | 147 | } |
503 | | |
504 | 19.7k | 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 | 19.7k | #if /*defined(__linux) &&*/ defined(SO_REUSEPORT) |
516 | 19.7k | if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) { |
517 | 19.7k | int optval = 1; |
518 | 19.7k | setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval)); |
519 | 19.7k | } |
520 | 19.7k | #endif |
521 | 19.7k | int enabled = 1; |
522 | 19.7k | setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled)); |
523 | 19.7k | #endif |
524 | | |
525 | 19.7k | } |
526 | | |
527 | 19.7k | #ifdef IPV6_V6ONLY |
528 | 19.7k | int disabled = 0; |
529 | 19.7k | setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled)); |
530 | 19.7k | #endif |
531 | | |
532 | 19.7k | if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) { |
533 | 44 | bsd_close_socket(listenFd); |
534 | 44 | freeaddrinfo(result); |
535 | 44 | return LIBUS_SOCKET_ERROR; |
536 | 44 | } |
537 | | |
538 | 19.7k | freeaddrinfo(result); |
539 | 19.7k | return listenFd; |
540 | 19.7k | } |
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 | 0 | LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket_unix(const char *path, int options) { |
551 | |
|
552 | 0 | LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; |
553 | |
|
554 | 0 | listenFd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0); |
555 | |
|
556 | 0 | if (listenFd == LIBUS_SOCKET_ERROR) { |
557 | 0 | return LIBUS_SOCKET_ERROR; |
558 | 0 | } |
559 | | |
560 | 0 | #ifndef _WIN32 |
561 | | // 700 permission by default |
562 | 0 | fchmod(listenFd, S_IRWXU); |
563 | | #else |
564 | | _chmod(path, S_IREAD | S_IWRITE | S_IEXEC); |
565 | | #endif |
566 | |
|
567 | 0 | struct sockaddr_un server_address; |
568 | 0 | memset(&server_address, 0, sizeof(server_address)); |
569 | 0 | server_address.sun_family = AF_UNIX; |
570 | 0 | strcpy(server_address.sun_path, path); |
571 | 0 | int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path); |
572 | | #ifdef _WIN32 |
573 | | _unlink(path); |
574 | | #else |
575 | 0 | unlink(path); |
576 | 0 | #endif |
577 | |
|
578 | 0 | if (bind(listenFd, (struct sockaddr *)&server_address, size) || listen(listenFd, 512)) { |
579 | 0 | bsd_close_socket(listenFd); |
580 | 0 | return LIBUS_SOCKET_ERROR; |
581 | 0 | } |
582 | | |
583 | 0 | return listenFd; |
584 | 0 | } |
585 | | |
586 | 0 | LIBUS_SOCKET_DESCRIPTOR bsd_create_udp_socket(const char *host, int port) { |
587 | 0 | struct addrinfo hints, *result; |
588 | 0 | memset(&hints, 0, sizeof(struct addrinfo)); |
589 | |
|
590 | 0 | hints.ai_flags = AI_PASSIVE; |
591 | 0 | hints.ai_family = AF_UNSPEC; |
592 | 0 | hints.ai_socktype = SOCK_DGRAM; |
593 | |
|
594 | 0 | char port_string[16]; |
595 | 0 | snprintf(port_string, 16, "%d", port); |
596 | |
|
597 | 0 | if (getaddrinfo(host, port_string, &hints, &result)) { |
598 | 0 | return LIBUS_SOCKET_ERROR; |
599 | 0 | } |
600 | | |
601 | 0 | LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; |
602 | 0 | struct addrinfo *listenAddr; |
603 | 0 | for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { |
604 | 0 | if (a->ai_family == AF_INET6) { |
605 | 0 | listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); |
606 | 0 | listenAddr = a; |
607 | 0 | } |
608 | 0 | } |
609 | |
|
610 | 0 | for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { |
611 | 0 | if (a->ai_family == AF_INET) { |
612 | 0 | listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); |
613 | 0 | listenAddr = a; |
614 | 0 | } |
615 | 0 | } |
616 | |
|
617 | 0 | if (listenFd == LIBUS_SOCKET_ERROR) { |
618 | 0 | freeaddrinfo(result); |
619 | 0 | return LIBUS_SOCKET_ERROR; |
620 | 0 | } |
621 | | |
622 | 0 | if (port != 0) { |
623 | | /* Should this also go for UDP? */ |
624 | 0 | int enabled = 1; |
625 | 0 | setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled)); |
626 | 0 | } |
627 | | |
628 | 0 | #ifdef IPV6_V6ONLY |
629 | 0 | int disabled = 0; |
630 | 0 | setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled)); |
631 | 0 | #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 | 0 | int enabled = 1; |
641 | 0 | if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (void *) &enabled, sizeof(enabled)) == -1) { |
642 | 0 | if (errno == 92) { |
643 | | // Linux ipv4 |
644 | 0 | #ifdef IP_PKTINFO |
645 | 0 | if (setsockopt(listenFd, IPPROTO_IP, IP_PKTINFO, (void *) &enabled, sizeof(enabled)) != 0) { |
646 | 0 | printf("Error setting IPv4 pktinfo!\n"); |
647 | 0 | } |
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 | 0 | } else { |
655 | 0 | printf("Error setting IPv6 pktinfo!\n"); |
656 | 0 | } |
657 | 0 | } |
658 | | |
659 | | /* These are used for getting the ECN */ |
660 | 0 | if (setsockopt(listenFd, IPPROTO_IPV6, IPV6_RECVTCLASS, (void *) &enabled, sizeof(enabled)) == -1) { |
661 | 0 | if (errno == 92) { |
662 | 0 | if (setsockopt(listenFd, IPPROTO_IP, IP_RECVTOS, (void *) &enabled, sizeof(enabled)) != 0) { |
663 | 0 | printf("Error setting IPv4 ECN!\n"); |
664 | 0 | } |
665 | 0 | } else { |
666 | 0 | printf("Error setting IPv6 ECN!\n"); |
667 | 0 | } |
668 | 0 | } |
669 | | |
670 | | /* We bind here as well */ |
671 | 0 | if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen)) { |
672 | 0 | bsd_close_socket(listenFd); |
673 | 0 | freeaddrinfo(result); |
674 | 0 | return LIBUS_SOCKET_ERROR; |
675 | 0 | } |
676 | | |
677 | 0 | freeaddrinfo(result); |
678 | 0 | return listenFd; |
679 | 0 | } |
680 | | |
681 | 0 | 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 | 0 | struct msghdr *mh = &((struct mmsghdr *) msgvec)[index].msg_hdr; |
688 | 0 | 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 | 0 | if (cmsg->cmsg_level == IPPROTO_IP) { |
691 | 0 | if (cmsg->cmsg_type == IP_TOS) { |
692 | 0 | uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg); |
693 | 0 | return tos & 3; |
694 | 0 | } |
695 | 0 | } |
696 | | |
697 | 0 | if (cmsg->cmsg_level == IPPROTO_IPV6) { |
698 | 0 | if (cmsg->cmsg_type == IPV6_TCLASS) { |
699 | | // is this correct? |
700 | 0 | uint8_t tos = *(uint8_t *)CMSG_DATA(cmsg); |
701 | 0 | return tos & 3; |
702 | 0 | } |
703 | 0 | } |
704 | 0 | } |
705 | 0 | #endif |
706 | | |
707 | 0 | printf("We got no ECN!\n"); |
708 | |
|
709 | 0 | return 0; // no ecn defaults to 0 |
710 | 0 | } |
711 | | |
712 | 6.41k | LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, const char *source_host, int options) { |
713 | 6.41k | struct addrinfo hints, *result; |
714 | 6.41k | memset(&hints, 0, sizeof(struct addrinfo)); |
715 | 6.41k | hints.ai_family = AF_UNSPEC; |
716 | 6.41k | hints.ai_socktype = SOCK_STREAM; |
717 | | |
718 | 6.41k | char port_string[16]; |
719 | 6.41k | snprintf(port_string, 16, "%d", port); |
720 | | |
721 | 6.41k | if (getaddrinfo(host, port_string, &hints, &result) != 0) { |
722 | 21 | return LIBUS_SOCKET_ERROR; |
723 | 21 | } |
724 | | |
725 | 6.39k | LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(result->ai_family, result->ai_socktype, result->ai_protocol); |
726 | 6.39k | if (fd == LIBUS_SOCKET_ERROR) { |
727 | 4.06k | freeaddrinfo(result); |
728 | 4.06k | return LIBUS_SOCKET_ERROR; |
729 | 4.06k | } |
730 | | |
731 | 2.32k | if (source_host) { |
732 | 2.32k | struct addrinfo *interface_result; |
733 | 2.32k | if (!getaddrinfo(source_host, NULL, NULL, &interface_result)) { |
734 | 2.32k | int ret = bind(fd, interface_result->ai_addr, (socklen_t) interface_result->ai_addrlen); |
735 | 2.32k | freeaddrinfo(interface_result); |
736 | 2.32k | if (ret == LIBUS_SOCKET_ERROR) { |
737 | 0 | bsd_close_socket(fd); |
738 | 0 | freeaddrinfo(result); |
739 | 0 | return LIBUS_SOCKET_ERROR; |
740 | 0 | } |
741 | 2.32k | } |
742 | 2.32k | } |
743 | | |
744 | 2.32k | connect(fd, result->ai_addr, (socklen_t) result->ai_addrlen); |
745 | 2.32k | freeaddrinfo(result); |
746 | | |
747 | 2.32k | return fd; |
748 | 2.32k | } |
749 | | |
750 | 0 | LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket_unix(const char *server_path, int options) { |
751 | |
|
752 | 0 | struct sockaddr_un server_address; |
753 | 0 | memset(&server_address, 0, sizeof(server_address)); |
754 | 0 | server_address.sun_family = AF_UNIX; |
755 | 0 | strcpy(server_address.sun_path, server_path); |
756 | 0 | int size = offsetof(struct sockaddr_un, sun_path) + strlen(server_address.sun_path); |
757 | |
|
758 | 0 | LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(AF_UNIX, SOCK_STREAM, 0); |
759 | |
|
760 | 0 | if (fd == LIBUS_SOCKET_ERROR) { |
761 | 0 | return LIBUS_SOCKET_ERROR; |
762 | 0 | } |
763 | | |
764 | 0 | connect(fd, (struct sockaddr *)&server_address, size); |
765 | |
|
766 | 0 | return fd; |
767 | 0 | } |