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