Lely core libraries 1.9.2
sock.c
Go to the documentation of this file.
1
24#include "handle.h"
25#include "io.h"
26#include <lely/io/addr.h>
27#include <lely/io/sock.h>
28#include <lely/util/errnum.h>
29
30#include <assert.h>
31#include <string.h>
32
33#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
34
36struct sock {
43 int domain;
45 int type;
46};
47
48static void sock_fini(struct io_handle *handle);
49static int sock_flags(struct io_handle *handle, int flags);
50static ssize_t sock_read(struct io_handle *handle, void *buf, size_t nbytes);
51static ssize_t sock_write(
52 struct io_handle *handle, const void *buf, size_t nbytes);
53static ssize_t sock_recv(struct io_handle *handle, void *buf, size_t nbytes,
54 io_addr_t *addr, int flags);
55static ssize_t sock_send(struct io_handle *handle, const void *buf,
56 size_t nbytes, const io_addr_t *addr, int flags);
57static struct io_handle *sock_accept(struct io_handle *handle, io_addr_t *addr);
58static int sock_connect(struct io_handle *handle, const io_addr_t *addr);
59
60static const struct io_handle_vtab sock_vtab = { .type = IO_TYPE_SOCK,
61 .size = sizeof(struct sock),
62 .fini = &sock_fini,
63 .flags = &sock_flags,
64 .read = &sock_read,
65 .write = &sock_write,
66 .recv = &sock_recv,
67 .send = &sock_send,
68 .accept = &sock_accept,
69 .connect = &sock_connect };
70
71static int _socketpair(int af, int type, int protocol, SOCKET sv[2]);
72
75{
76 int errc = 0;
77
78 int flags = 0;
79#if defined(__CYGWIN__) || defined(__linux__)
80 flags |= SOCK_CLOEXEC;
81#endif
82
83 SOCKET s;
84 switch (domain) {
85#ifdef _WIN32
86 case IO_SOCK_BTH:
87 switch (type) {
88 case IO_SOCK_STREAM:
89 s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
90 break;
91 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
92 }
93 break;
94#elif defined(__linux__) && defined(HAVE_BLUETOOTH_BLUETOOTH_H) \
95 && defined(HAVE_BLUETOOTH_RFCOMM_H)
96 case IO_SOCK_BTH:
97 switch (type) {
98 case IO_SOCK_STREAM:
99 s = socket(AF_BLUETOOTH, SOCK_STREAM | flags,
100 BTPROTO_RFCOMM);
101 break;
102 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
103 }
104 break;
105#endif
106 case IO_SOCK_IPV4:
107 switch (type) {
108 case IO_SOCK_STREAM:
109 s = socket(AF_INET, SOCK_STREAM | flags, 0);
110 break;
111 case IO_SOCK_DGRAM:
112 s = socket(AF_INET, SOCK_DGRAM | flags, 0);
113 break;
114 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
115 }
116 break;
117 case IO_SOCK_IPV6:
118 switch (type) {
119 case IO_SOCK_STREAM:
120 s = socket(AF_INET6, SOCK_STREAM | flags, 0);
121 break;
122 case IO_SOCK_DGRAM:
123 s = socket(AF_INET6, SOCK_DGRAM | flags, 0);
124 break;
125 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
126 }
127 break;
128#if _POSIX_C_SOURCE >= 200112L
129 case IO_SOCK_UNIX:
130 switch (type) {
131 case IO_SOCK_STREAM:
132 s = socket(AF_UNIX, SOCK_STREAM | flags, 0);
133 break;
134 case IO_SOCK_DGRAM:
135 s = socket(AF_UNIX, SOCK_DGRAM | flags, 0);
136 break;
137 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
138 }
139 break;
140#endif
141 default: errc = errnum2c(ERRNUM_AFNOSUPPORT); goto error_domain;
142 }
143
144 if (__unlikely(s == INVALID_SOCKET)) {
145 errc = get_errc();
146 goto error_socket;
147 }
148
149#if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
150 if (__unlikely(fcntl(s, F_SETFD, FD_CLOEXEC) == -1)) {
151 errc = get_errc();
152 goto error_fcntl;
153 }
154#endif
155
156 struct io_handle *handle = io_handle_alloc(&sock_vtab);
157 if (__unlikely(!handle)) {
158 errc = get_errc();
159 goto error_alloc_handle;
160 }
161
162 handle->fd = (HANDLE)s;
163 ((struct sock *)handle)->domain = domain;
164 ((struct sock *)handle)->type = type;
165
166 return io_handle_acquire(handle);
167
168error_alloc_handle:
169#if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
170error_fcntl:
171#endif
172 closesocket(s);
173error_socket:
174error_type:
175error_domain:
176 set_errc(errc);
177 return IO_HANDLE_ERROR;
178}
179
180int
181io_open_socketpair(int domain, int type, io_handle_t handle_vector[2])
182{
183 assert(handle_vector);
184 handle_vector[0] = handle_vector[1] = IO_HANDLE_ERROR;
185
186 int errc = 0;
187
188 int flags = 0;
189#if defined(__CYGWIN__) || defined(__linux__)
190 flags |= SOCK_CLOEXEC;
191#endif
192
193 int result;
194 SOCKET socket_vector[2];
195 switch (domain) {
196 case IO_SOCK_IPV4:
197 switch (type) {
198 case IO_SOCK_STREAM:
199 result = _socketpair(AF_INET, SOCK_STREAM | flags, 0,
200 socket_vector);
201 break;
202 case IO_SOCK_DGRAM:
203 result = _socketpair(AF_INET, SOCK_DGRAM | flags, 0,
204 socket_vector);
205 break;
206 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
207 }
208 break;
209 case IO_SOCK_IPV6:
210 switch (type) {
211 case IO_SOCK_STREAM:
212 result = _socketpair(AF_INET6, SOCK_STREAM | flags, 0,
213 socket_vector);
214 break;
215 case IO_SOCK_DGRAM:
216 result = _socketpair(AF_INET6, SOCK_DGRAM | flags, 0,
217 socket_vector);
218 break;
219 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
220 }
221 break;
222#if _POSIX_C_SOURCE >= 200112L
223 case IO_SOCK_UNIX:
224 switch (type) {
225 case IO_SOCK_STREAM:
226 result = _socketpair(AF_UNIX, SOCK_STREAM | flags, 0,
227 socket_vector);
228 break;
229 case IO_SOCK_DGRAM:
230 result = _socketpair(AF_UNIX, SOCK_DGRAM | flags, 0,
231 socket_vector);
232 break;
233 default: errc = errnum2c(ERRNUM_PROTOTYPE); goto error_type;
234 }
235 break;
236#endif
237 default: errc = errnum2c(ERRNUM_AFNOSUPPORT); goto error_domain;
238 }
239
240 if (__unlikely(result == SOCKET_ERROR)) {
241 errc = get_errc();
242 goto error_socketpair;
243 }
244
245#if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
246 if (__unlikely(fcntl(socket_vector[0], F_SETFD, FD_CLOEXEC) == -1)) {
247 errc = get_errc();
248 goto error_fcntl;
249 }
250 if (__unlikely(fcntl(socket_vector[1], F_SETFD, FD_CLOEXEC) == -1)) {
251 errc = get_errc();
252 goto error_fcntl;
253 }
254#endif
255
256 handle_vector[0] = io_handle_alloc(&sock_vtab);
257 if (__unlikely(!handle_vector[0])) {
258 errc = get_errc();
259 goto error_alloc_handle_vector_0;
260 }
261
262 handle_vector[0]->fd = (HANDLE)socket_vector[0];
263 ((struct sock *)handle_vector[0])->domain = domain;
264 ((struct sock *)handle_vector[0])->type = type;
265
266 handle_vector[1] = io_handle_alloc(&sock_vtab);
267 if (__unlikely(!handle_vector[1])) {
268 errc = get_errc();
269 goto error_alloc_handle_vector_1;
270 }
271
272 handle_vector[1]->fd = (HANDLE)socket_vector[1];
273 ((struct sock *)handle_vector[1])->domain = domain;
274 ((struct sock *)handle_vector[1])->type = type;
275
276 io_handle_acquire(handle_vector[0]);
277 io_handle_acquire(handle_vector[1]);
278
279 return 0;
280
281error_alloc_handle_vector_1:
282 handle_vector[1] = IO_HANDLE_ERROR;
283 io_handle_free(handle_vector[0]);
284error_alloc_handle_vector_0:
285 handle_vector[0] = IO_HANDLE_ERROR;
286#if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
287error_fcntl:
288#endif
289 closesocket(socket_vector[1]);
290 closesocket(socket_vector[0]);
291error_socketpair:
292error_type:
293error_domain:
294 set_errc(errc);
295 return -1;
296}
297
298#endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
299
301io_recv(io_handle_t handle, void *buf, size_t nbytes, io_addr_t *addr,
302 int flags)
303{
304 if (__unlikely(handle == IO_HANDLE_ERROR)) {
306 return -1;
307 }
308
309 assert(handle->vtab);
310 if (__unlikely(!handle->vtab->recv)) {
312 return -1;
313 }
314
315 return handle->vtab->recv(handle, buf, nbytes, addr, flags);
316}
317
319io_send(io_handle_t handle, const void *buf, size_t nbytes,
320 const io_addr_t *addr, int flags)
321{
322 if (__unlikely(handle == IO_HANDLE_ERROR)) {
324 return -1;
325 }
326
327 assert(handle->vtab);
328 if (__unlikely(!handle->vtab->send)) {
330 return -1;
331 }
332
333 return handle->vtab->send(handle, buf, nbytes, addr, flags);
334}
335
338{
339 if (__unlikely(handle == IO_HANDLE_ERROR)) {
341 return IO_HANDLE_ERROR;
342 }
343
344 assert(handle->vtab);
345 if (__unlikely(!handle->vtab->accept)) {
347 return IO_HANDLE_ERROR;
348 }
349
350 return handle->vtab->accept(handle, addr);
351}
352
353int
354io_connect(io_handle_t handle, const io_addr_t *addr)
355{
356 if (__unlikely(handle == IO_HANDLE_ERROR)) {
358 return -1;
359 }
360
361 assert(handle->vtab);
362 if (__unlikely(!handle->vtab->connect)) {
364 return -1;
365 }
366
367 return handle->vtab->connect(handle, addr);
368}
369
370#if defined(_WIN32) || _POSIX_C_SOURCE >= 200112L
371
372int
374{
375 if (__unlikely(handle == IO_HANDLE_ERROR)) {
377 return -1;
378 }
379
380 if (__unlikely(handle->vtab != &sock_vtab)) {
382 return -1;
383 }
384
385 return ((struct sock *)handle)->domain;
386}
387
388int
390{
391 if (__unlikely(handle == IO_HANDLE_ERROR)) {
393 return -1;
394 }
395
396 if (__unlikely(handle->vtab != &sock_vtab)) {
398 return -1;
399 }
400
401 return ((struct sock *)handle)->type;
402}
403
404int
406{
407 assert(addr);
408
409 if (__unlikely(handle == IO_HANDLE_ERROR)) {
411 return -1;
412 }
413
414 return bind((SOCKET)handle->fd, (const struct sockaddr *)&addr->addr,
415 addr->addrlen);
416}
417
418int
419io_sock_listen(io_handle_t handle, int backlog)
420{
421 if (__unlikely(handle == IO_HANDLE_ERROR)) {
423 return -1;
424 }
425
426 return listen((SOCKET)handle->fd, backlog) ? -1 : 0;
427}
428
429int
431{
432 if (__unlikely(handle == IO_HANDLE_ERROR)) {
434 return -1;
435 }
436
437 switch (how) {
438 case IO_SHUT_RD:
439#ifdef _WIN32
440 how = SD_RECEIVE;
441#else
442 how = SHUT_RD;
443#endif
444 break;
445 case IO_SHUT_WR:
446#ifdef _WIN32
447 how = SD_SEND;
448#else
449 how = SHUT_WR;
450#endif
451 break;
452 case IO_SHUT_RDWR:
453#ifdef _WIN32
454 how = SD_BOTH;
455#else
456 how = SHUT_RDWR;
457#endif
458 break;
459 default: set_errnum(ERRNUM_INVAL); return -1;
460 }
461
462 return shutdown((SOCKET)handle->fd, how) ? -1 : 0;
463}
464
465int
467{
468 assert(addr);
469
470 if (__unlikely(handle == IO_HANDLE_ERROR)) {
472 return -1;
473 }
474
475 addr->addrlen = sizeof(addr->addr);
476#ifdef _WIN32
477 // clang-format off
478 return getsockname((SOCKET)handle->fd, (struct sockaddr *)&addr->addr,
479 (socklen_t *)&addr->addrlen) ? -1 : 0;
480 // clang-format on
481#else
482 int errsv = errno;
483 int result = getsockname(handle->fd, (struct sockaddr *)&addr->addr,
484 (socklen_t *)&addr->addrlen);
485 // getsockname() may return an error if the address length is too large.
486 if (!result || errno != EINVAL
487 || addr->addrlen > (int)sizeof(addr->addr))
488 return result;
489 errno = errsv;
490 return getsockname(handle->fd, (struct sockaddr *)&addr->addr,
491 (socklen_t *)&addr->addrlen);
492#endif
493}
494
495int
497{
498 assert(addr);
499
500 if (__unlikely(handle == IO_HANDLE_ERROR)) {
502 return -1;
503 }
504
505 addr->addrlen = sizeof(addr->addr);
506#ifdef _WIN32
507 // clang-format off
508 return getpeername((SOCKET)handle->fd, (struct sockaddr *)&addr->addr,
509 (socklen_t *)&addr->addrlen) ? -1 : 0;
510 // clang-format on
511#else
512 int errsv = errno;
513 int result = getpeername(handle->fd, (struct sockaddr *)&addr->addr,
514 (socklen_t *)&addr->addrlen);
515 // getpeername() may return an error if the address length is too large.
516 if (!result || errno != EINVAL
517 || addr->addrlen > (int)sizeof(addr->addr))
518 return result;
519 errno = errsv;
520 return getpeername(handle->fd, (struct sockaddr *)&addr->addr,
521 (socklen_t *)&addr->addrlen);
522#endif
523}
524
525int
527{
528 return SOMAXCONN;
529}
530
531int
533{
534 if (__unlikely(handle == IO_HANDLE_ERROR)) {
536 return -1;
537 }
538
539#ifdef _WIN32
540 BOOL optval;
541#else
542 int optval;
543#endif
544 // clang-format off
545 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_ACCEPTCONN,
546 (char *)&optval, &(socklen_t){ sizeof(optval) })))
547 // clang-format on
548 return -1;
549 return !!optval;
550}
551
552int
554{
555 if (__unlikely(handle == IO_HANDLE_ERROR)) {
557 return -1;
558 }
559
560#ifdef _WIN32
561 BOOL optval;
562#else
563 int optval;
564#endif
565 // clang-format off
566 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_BROADCAST,
567 (char *)&optval, &(socklen_t){ sizeof(optval) })))
568 // clang-format on
569 return -1;
570 return !!optval;
571}
572
573int
574io_sock_set_broadcast(io_handle_t handle, int broadcast)
575{
576 if (__unlikely(handle == IO_HANDLE_ERROR)) {
578 return -1;
579 }
580
581#ifdef _WIN32
582 BOOL optval = !!broadcast;
583#else
584 int optval = !!broadcast;
585#endif
586 // clang-format off
587 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_BROADCAST,
588 (const char *)&optval, sizeof(optval)) ? -1 : 0;
589 // clang-format on
590}
591
592int
594{
595 if (__unlikely(handle == IO_HANDLE_ERROR)) {
597 return -1;
598 }
599
600#ifdef _WIN32
601 BOOL optval;
602#else
603 int optval;
604#endif
605 // clang-format off
606 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_DEBUG,
607 (char *)&optval, &(socklen_t){ sizeof(optval) })))
608 // clang-format on
609 return -1;
610 return !!optval;
611}
612
613int
615{
616 if (__unlikely(handle == IO_HANDLE_ERROR)) {
618 return -1;
619 }
620
621#ifdef _WIN32
622 BOOL optval = !!debug;
623#else
624 int optval = !!debug;
625#endif
626 // clang-format off
627 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_DEBUG,
628 (const char *)&optval, sizeof(optval)) ? -1 : 0;
629 // clang-format on
630}
631
632int
634{
635 if (__unlikely(handle == IO_HANDLE_ERROR)) {
637 return -1;
638 }
639
640#ifdef _WIN32
641 BOOL optval;
642#else
643 int optval;
644#endif
645 // clang-format off
646 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_DONTROUTE,
647 (char *)&optval, &(socklen_t){ sizeof(optval) })))
648 // clang-format on
649 return -1;
650 return !!optval;
651}
652
653int
654io_sock_set_dontroute(io_handle_t handle, int dontroute)
655{
656 if (__unlikely(handle == IO_HANDLE_ERROR)) {
658 return -1;
659 }
660
661#ifdef _WIN32
662 BOOL optval = !!dontroute;
663#else
664 int optval = !!dontroute;
665#endif
666 // clang-format off
667 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_DONTROUTE,
668 (const char *)&optval, sizeof(optval)) ? -1 : 0;
669 // clang-format on
670}
671
672int
673io_sock_get_error(io_handle_t handle, int *perror)
674{
675 if (__unlikely(handle == IO_HANDLE_ERROR)) {
677 return -1;
678 }
679
680 // clang-format off
681 return getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_ERROR,
682 (char *)perror, &(socklen_t){ sizeof(*perror) })
683 ? -1 : 0;
684 // clang-format on
685}
686
687int
689{
690 if (__unlikely(handle == IO_HANDLE_ERROR)) {
692 return -1;
693 }
694
695#ifdef _WIN32
696 BOOL optval;
697#else
698 int optval;
699#endif
700 // clang-format off
701 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_KEEPALIVE,
702 (char *)&optval, &(socklen_t){ sizeof(optval) })))
703 // clang-format on
704 return -1;
705 return !!optval;
706}
707
708int
709io_sock_set_keepalive(io_handle_t handle, int keepalive, int time, int interval)
710{
711 if (__unlikely(handle == IO_HANDLE_ERROR)) {
713 return -1;
714 }
715
716#ifdef _WIN32
717 struct tcp_keepalive kaInBuffer = { .onoff = keepalive,
718 // The timeout is specified in milliseconds.
719 .keepalivetime = time * 1000,
720 // The interval is specified in milliseconds.
721 .keepaliveinterval = interval * 1000 };
722 DWORD dwBytesReturned;
723 // clang-format off
724 return WSAIoctl((SOCKET)handle->fd, SIO_KEEPALIVE_VALS, &kaInBuffer,
725 sizeof(kaInBuffer), NULL, 0, &dwBytesReturned, NULL,
726 NULL) ? -1 : 0;
727// clang-format on
728#else
729 // clang-format off
730 if (__unlikely(setsockopt(handle->fd, SOL_SOCKET, SO_KEEPALIVE,
731 &keepalive, sizeof(keepalive)) == -1))
732 // clang-format on
733 return -1;
734#ifdef __linux__
735 if (keepalive) {
736 // clang-format off
737 if (__unlikely(setsockopt(handle->fd, SOL_TCP, TCP_KEEPIDLE,
738 &time, sizeof(time)) == -1))
739 // clang-format on
740 return -1;
741 // clang-format off
742 if (__unlikely(setsockopt(handle->fd, SOL_TCP, TCP_KEEPINTVL,
743 &interval, sizeof(interval)) == -1))
744 // clang-format on
745 return -1;
746 }
747#else
748 (void)time;
749 (void)interval;
750#endif
751 return 0;
752#endif
753}
754
755int
757{
758 if (__unlikely(handle == IO_HANDLE_ERROR)) {
760 return -1;
761 }
762
763 struct linger optval;
764 // clang-format off
765 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_LINGER,
766 (char *)&optval, &(socklen_t){ sizeof(optval) })))
767 // clang-format on
768 return -1;
769 return optval.l_onoff ? optval.l_linger : 0;
770}
771
772int
774{
775 if (__unlikely(handle == IO_HANDLE_ERROR)) {
777 return -1;
778 }
779
780 if (__unlikely(time < 0)) {
782 return -1;
783 }
784
785 struct linger optval = { !!time, time };
786 // clang-format off
787 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_LINGER,
788 (const char *)&optval, sizeof(optval)) ? -1 : 0;
789 // clang-format on
790}
791
792int
794{
795 if (__unlikely(handle == IO_HANDLE_ERROR)) {
797 return -1;
798 }
799
800#ifdef _WIN32
801 BOOL optval;
802#else
803 int optval;
804#endif
805 // clang-format off
806 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_OOBINLINE,
807 (char *)&optval, &(socklen_t){ sizeof(optval) })))
808 // clang-format on
809 return -1;
810 return !!optval;
811}
812
813int
814io_sock_set_oobinline(io_handle_t handle, int oobinline)
815{
816 if (__unlikely(handle == IO_HANDLE_ERROR)) {
818 return -1;
819 }
820
821#ifdef _WIN32
822 BOOL optval = !!oobinline;
823#else
824 int optval = !!oobinline;
825#endif
826 // clang-format off
827 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_OOBINLINE,
828 (const char *)&optval, sizeof(optval)) ? -1 : 0;
829 // clang-format on
830}
831
832int
834{
835 if (__unlikely(handle == IO_HANDLE_ERROR)) {
837 return -1;
838 }
839
840 int optval;
841 // clang-format off
842 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_RCVBUF,
843 (char *)&optval, &(socklen_t){ sizeof(optval) })))
844 // clang-format on
845 return -1;
846 return !!optval;
847}
848
849int
851{
852 if (__unlikely(handle == IO_HANDLE_ERROR)) {
854 return -1;
855 }
856
857 // clang-format off
858 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_RCVBUF,
859 (const char *)&size, sizeof(size)) ? -1 : 0;
860 // clang-format on
861}
862
863int
865{
866 if (__unlikely(handle == IO_HANDLE_ERROR)) {
868 return -1;
869 }
870
871#ifdef _WIN32
872 DWORD optval = timeout;
873#else
874 struct timeval optval = { .tv_sec = timeout / 1000,
875 .tv_usec = (timeout % 1000) * 1000 };
876#endif
877 // clang-format off
878 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_RCVTIMEO,
879 (const char *)&optval, sizeof(optval)) ? -1 : 0;
880 // clang-format on
881}
882
883int
885{
886 if (__unlikely(handle == IO_HANDLE_ERROR)) {
888 return -1;
889 }
890
891#ifdef _WIN32
892 BOOL optval;
893#else
894 int optval;
895#endif
896 // clang-format off
897 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_REUSEADDR,
898 (char *)&optval, &(socklen_t){ sizeof(optval) })))
899 // clang-format on
900 return -1;
901 return !!optval;
902}
903
904int
905io_sock_set_reuseaddr(io_handle_t handle, int reuseaddr)
906{
907 if (__unlikely(handle == IO_HANDLE_ERROR)) {
909 return -1;
910 }
911
912#ifdef _WIN32
913 BOOL optval = !!reuseaddr;
914#else
915 int optval = !!reuseaddr;
916#endif
917 // clang-format off
918 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_REUSEADDR,
919 (const char *)&optval, sizeof(optval)) ? -1 : 0;
920 // clang-format on
921}
922
923int
925{
926 if (__unlikely(handle == IO_HANDLE_ERROR)) {
928 return -1;
929 }
930
931 int optval;
932 // clang-format off
933 if (__unlikely(getsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_SNDBUF,
934 (char *)&optval, &(socklen_t){ sizeof(optval) })))
935 // clang-format on
936 return -1;
937 return !!optval;
938}
939
940int
942{
943 if (__unlikely(handle == IO_HANDLE_ERROR)) {
945 return -1;
946 }
947
948 // clang-format off
949 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_SNDBUF,
950 (const char *)&size, sizeof(size)) ? -1 : 0;
951 // clang-format on
952}
953
954int
956{
957 if (__unlikely(handle == IO_HANDLE_ERROR)) {
959 return -1;
960 }
961
962#ifdef _WIN32
963 DWORD optval = timeout;
964#else
965 struct timeval optval = { .tv_sec = timeout / 1000,
966 .tv_usec = (timeout % 1000) * 1000 };
967#endif
968 // clang-format off
969 return setsockopt((SOCKET)handle->fd, SOL_SOCKET, SO_SNDTIMEO,
970 (const char *)&optval, sizeof(optval)) ? -1 : 0;
971 // clang-format on
972}
973
974int
976{
977 if (__unlikely(handle == IO_HANDLE_ERROR)) {
979 return -1;
980 }
981
982#ifdef _WIN32
983 BOOL optval;
984#else
985 int optval;
986#endif
987 // clang-format off
988 if (__unlikely(getsockopt((SOCKET)handle->fd, IPPROTO_TCP, TCP_NODELAY,
989 (char *)&optval, &(socklen_t){ sizeof(optval) })))
990 // clang-format on
991 return -1;
992 return !!optval;
993}
994
995int
997{
998 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1000 return -1;
1001 }
1002
1003#ifdef _WIN32
1004 BOOL optval = !!nodelay;
1005#else
1006 int optval = !!nodelay;
1007#endif
1008 // clang-format off
1009 return setsockopt((SOCKET)handle->fd, IPPROTO_TCP, TCP_NODELAY,
1010 (const char *)&optval, sizeof(optval)) ? -1 : 0;
1011 // clang-format on
1012}
1013
1014#if defined(_WIN32) || defined(HAVE_SYS_IOCTL_H)
1015ssize_t
1017{
1018 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1020 return -1;
1021 }
1022
1023#ifdef _WIN32
1024 u_long optval;
1025 if (__unlikely(ioctlsocket((SOCKET)handle->fd, FIONREAD, &optval)))
1026 return -1;
1027 return optval;
1028#else
1029 int optval;
1030 int result;
1031 int errsv = errno;
1032 do {
1033 errno = errsv;
1034 result = ioctl(handle->fd, FIONREAD, &optval);
1035 } while (__unlikely(result == -1 && errno == EINTR));
1036 if (__unlikely(result == -1))
1037 return -1;
1038 return optval;
1039#endif
1040}
1041#endif
1042
1043#if defined(_WIN32) || defined(__CYGWIN__) || defined(__linux__)
1044
1045int
1047{
1048 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1050 return -1;
1051 }
1052
1053 if (__unlikely(handle->vtab != &sock_vtab)) {
1055 return -1;
1056 }
1057
1058#ifdef _WIN32
1059 DWORD optval;
1060#else
1061 int optval;
1062#endif
1063 switch (((struct sock *)handle)->domain) {
1064 case IO_SOCK_IPV4:
1065 // clang-format off
1066 if (__unlikely(getsockopt((SOCKET)handle->fd, IPPROTO_IP,
1067 IP_MULTICAST_LOOP, (char *)&optval,
1068 &(socklen_t){ sizeof(optval) })))
1069 // clang-format on
1070 return -1;
1071 break;
1072 case IO_SOCK_IPV6:
1073 // clang-format off
1074 if (__unlikely(getsockopt((SOCKET)handle->fd, IPPROTO_IPV6,
1075 IPV6_MULTICAST_LOOP, (char *)&optval,
1076 &(socklen_t){ sizeof(optval) })))
1077 // clang-format on
1078 return -1;
1079 break;
1080 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
1081 }
1082 return !!optval;
1083}
1084
1085int
1087{
1088 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1090 return -1;
1091 }
1092
1093 if (__unlikely(handle->vtab != &sock_vtab)) {
1095 return -1;
1096 }
1097
1098#ifdef _WIN32
1099 DWORD optval = !!loop;
1100#else
1101 int optval = !!loop;
1102#endif
1103 switch (((struct sock *)handle)->domain) {
1104 case IO_SOCK_IPV4:
1105 // clang-format off
1106 return setsockopt((SOCKET)handle->fd, IPPROTO_IP,
1107 IP_MULTICAST_LOOP, (const char *)&optval,
1108 sizeof(optval)) ? -1 : 0;
1109 // clang-format on
1110 case IO_SOCK_IPV6:
1111 // clang-format off
1112 return setsockopt((SOCKET)handle->fd, IPPROTO_IPV6,
1113 IPV6_MULTICAST_LOOP, (const char *)&optval,
1114 sizeof(optval)) ? -1 : 0;
1115 // clang-format on
1116 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
1117 }
1118}
1119
1120int
1122{
1123 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1125 return -1;
1126 }
1127
1128 if (__unlikely(handle->vtab != &sock_vtab)) {
1130 return -1;
1131 }
1132
1133#ifdef _WIN32
1134 DWORD optval;
1135#else
1136 int optval;
1137#endif
1138 switch (((struct sock *)handle)->domain) {
1139 case IO_SOCK_IPV4:
1140 // clang-format off
1141 if (__unlikely(getsockopt((SOCKET)handle->fd, IPPROTO_IP,
1142 IP_MULTICAST_TTL, (char *)&optval,
1143 &(socklen_t){ sizeof(optval) })))
1144 // clang-format on
1145 return -1;
1146 break;
1147 case IO_SOCK_IPV6:
1148 // clang-format off
1149 if (__unlikely(getsockopt((SOCKET)handle->fd, IPPROTO_IPV6,
1150 IPV6_MULTICAST_HOPS, (char *)&optval,
1151 &(socklen_t){ sizeof(optval) })))
1152 // clang-format on
1153 return -1;
1154 break;
1155 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
1156 }
1157 return optval;
1158}
1159
1160int
1162{
1163 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1165 return -1;
1166 }
1167
1168 if (__unlikely(handle->vtab != &sock_vtab)) {
1170 return -1;
1171 }
1172
1173#ifdef _WIN32
1174 DWORD optval = ttl;
1175#else
1176 int optval = ttl;
1177#endif
1178 switch (((struct sock *)handle)->domain) {
1179 case IO_SOCK_IPV4:
1180 // clang-format off
1181 return setsockopt((SOCKET)handle->fd, IPPROTO_IP,
1182 IP_MULTICAST_TTL, (const char *)&optval,
1183 sizeof(optval)) ? -1 : 0;
1184 // clang-format on
1185 case IO_SOCK_IPV6:
1186 // clang-format off
1187 return setsockopt((SOCKET)handle->fd, IPPROTO_IPV6,
1188 IPV6_MULTICAST_HOPS, (const char *)&optval,
1189 sizeof(optval)) ? -1 :0;
1190 // clang-format on
1191 default: set_errnum(ERRNUM_AFNOSUPPORT); return -1;
1192 }
1193}
1194
1195int
1197 io_handle_t handle, unsigned int index, const io_addr_t *group)
1198{
1199 assert(group);
1200
1201 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1203 return -1;
1204 }
1205
1206 if (__unlikely(handle->vtab != &sock_vtab)) {
1208 return -1;
1209 }
1210
1211 struct group_req greq;
1212 memset(&greq, 0, sizeof(greq));
1213 greq.gr_interface = index;
1214 memcpy(&greq.gr_group, &group->addr, sizeof(greq.gr_group));
1215
1216 int level = ((struct sock *)handle)->domain == IO_SOCK_IPV6
1217 ? IPPROTO_IPV6
1218 : IPPROTO_IP;
1219 // clang-format off
1220 return setsockopt((SOCKET)handle->fd, level, MCAST_JOIN_GROUP,
1221 (const char *)&greq, sizeof(greq)) ? 0 : -1;
1222 // clang-format on
1223}
1224
1225int
1226io_sock_mcast_block_source(io_handle_t handle, unsigned int index,
1227 const io_addr_t *group, const io_addr_t *source)
1228{
1229 assert(group);
1230 assert(source);
1231
1232 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1234 return -1;
1235 }
1236
1237 if (__unlikely(handle->vtab != &sock_vtab)) {
1239 return -1;
1240 }
1241
1242 struct group_source_req greq;
1243 memset(&greq, 0, sizeof(greq));
1244 greq.gsr_interface = index;
1245 memcpy(&greq.gsr_group, &group->addr, sizeof(greq.gsr_group));
1246 memcpy(&greq.gsr_source, &source->addr, sizeof(greq.gsr_source));
1247
1248 int level = ((struct sock *)handle)->domain == IO_SOCK_IPV6
1249 ? IPPROTO_IPV6
1250 : IPPROTO_IP;
1251 // clang-format off
1252 return setsockopt((SOCKET)handle->fd, level, MCAST_BLOCK_SOURCE,
1253 (const char *)&greq, sizeof(greq)) ? -1 : 0;
1254 // clang-format on
1255}
1256
1257int
1259 const io_addr_t *group, const io_addr_t *source)
1260{
1261 assert(group);
1262 assert(source);
1263
1264 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1266 return -1;
1267 }
1268
1269 if (__unlikely(handle->vtab != &sock_vtab)) {
1271 return -1;
1272 }
1273
1274 struct group_source_req greq;
1275 memset(&greq, 0, sizeof(greq));
1276 greq.gsr_interface = index;
1277 memcpy(&greq.gsr_group, &group->addr, sizeof(greq.gsr_group));
1278 memcpy(&greq.gsr_source, &source->addr, sizeof(greq.gsr_source));
1279
1280 int level = ((struct sock *)handle)->domain == IO_SOCK_IPV6
1281 ? IPPROTO_IPV6
1282 : IPPROTO_IP;
1283 // clang-format off
1284 return setsockopt((SOCKET)handle->fd, level, MCAST_UNBLOCK_SOURCE,
1285 (const char *)&greq, sizeof(greq)) ? -1 : 0;
1286 // clang-format on
1287}
1288
1289int
1291 io_handle_t handle, unsigned int index, const io_addr_t *group)
1292{
1293 assert(group);
1294
1295 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1297 return -1;
1298 }
1299
1300 if (__unlikely(handle->vtab != &sock_vtab)) {
1302 return -1;
1303 }
1304
1305 struct group_req greq;
1306 memset(&greq, 0, sizeof(greq));
1307 greq.gr_interface = index;
1308 memcpy(&greq.gr_group, &group->addr, sizeof(greq.gr_group));
1309
1310 int level = ((struct sock *)handle)->domain == IO_SOCK_IPV6
1311 ? IPPROTO_IPV6
1312 : IPPROTO_IP;
1313 // clang-format off
1314 return setsockopt((SOCKET)handle->fd, level, MCAST_LEAVE_GROUP,
1315 (const char *)&greq, sizeof(greq)) ? -1 : 0;
1316 // clang-format on
1317}
1318
1319int
1321 const io_addr_t *group, const io_addr_t *source)
1322{
1323 assert(group);
1324 assert(source);
1325
1326 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1328 return -1;
1329 }
1330
1331 if (__unlikely(handle->vtab != &sock_vtab)) {
1333 return -1;
1334 }
1335
1336 struct group_source_req greq;
1337 memset(&greq, 0, sizeof(greq));
1338 greq.gsr_interface = index;
1339 memcpy(&greq.gsr_group, &group->addr, sizeof(greq.gsr_group));
1340 memcpy(&greq.gsr_source, &source->addr, sizeof(greq.gsr_source));
1341
1342 int level = ((struct sock *)handle)->domain == IO_SOCK_IPV6
1343 ? IPPROTO_IPV6
1344 : IPPROTO_IP;
1345 // clang-format off
1346 return setsockopt((SOCKET)handle->fd, level, MCAST_JOIN_SOURCE_GROUP,
1347 (const char *)&greq, sizeof(greq)) ? -1 : 0;
1348 // clang-format on
1349}
1350
1351int
1353 const io_addr_t *group, const io_addr_t *source)
1354{
1355 if (__unlikely(handle == IO_HANDLE_ERROR)) {
1357 return -1;
1358 }
1359
1360 if (__unlikely(handle->vtab != &sock_vtab)) {
1362 return -1;
1363 }
1364
1365 struct group_source_req greq;
1366 memset(&greq, 0, sizeof(greq));
1367 greq.gsr_interface = index;
1368 memcpy(&greq.gsr_group, &group->addr, sizeof(greq.gsr_group));
1369 memcpy(&greq.gsr_source, &source->addr, sizeof(greq.gsr_source));
1370
1371 int level = ((struct sock *)handle)->domain == IO_SOCK_IPV6
1372 ? IPPROTO_IPV6
1373 : IPPROTO_IP;
1374 // clang-format off
1375 return setsockopt((SOCKET)handle->fd, level, MCAST_LEAVE_SOURCE_GROUP,
1376 (const char *)&greq, sizeof(greq)) ? -1 : 0;
1377 // clang-format on
1378}
1379
1380#endif // _WIN32 || __CYGWIN__ || __linux__
1381
1382static void
1383sock_fini(struct io_handle *handle)
1384{
1385 if (!(handle->flags & IO_FLAG_NO_CLOSE))
1386 closesocket((SOCKET)handle->fd);
1387}
1388
1389static int
1390sock_flags(struct io_handle *handle, int flags)
1391{
1392 assert(handle);
1393
1394#ifdef _WIN32
1395 u_long iMode = !!(flags & IO_FLAG_NONBLOCK);
1396 return ioctlsocket((SOCKET)handle->fd, FIONBIO, &iMode) ? -1 : 0;
1397#else
1398 int arg = fcntl(handle->fd, F_GETFL, 0);
1399 if (__unlikely(arg == -1))
1400 return -1;
1401
1402 if ((flags & IO_FLAG_NONBLOCK) && !(arg & O_NONBLOCK))
1403 return fcntl(handle->fd, F_SETFL, arg | O_NONBLOCK);
1404 else if (!(flags & IO_FLAG_NONBLOCK) && (arg & O_NONBLOCK))
1405 return fcntl(handle->fd, F_SETFL, arg & ~O_NONBLOCK);
1406 return 0;
1407#endif
1408}
1409
1410static ssize_t
1411sock_read(struct io_handle *handle, void *buf, size_t nbytes)
1412{
1413 return sock_recv(handle, buf, nbytes, NULL, 0);
1414}
1415
1416static ssize_t
1417sock_write(struct io_handle *handle, const void *buf, size_t nbytes)
1418{
1419 return sock_send(handle, buf, nbytes, NULL, 0);
1420}
1421
1422static ssize_t
1423sock_recv(struct io_handle *handle, void *buf, size_t nbytes, io_addr_t *addr,
1424 int flags)
1425{
1426 assert(handle);
1427
1428 int _flags = 0;
1429 if (flags & IO_MSG_PEEK)
1430 _flags |= MSG_PEEK;
1431 if (flags & IO_MSG_OOB)
1432 _flags |= MSG_OOB;
1433 if (flags & IO_MSG_WAITALL)
1434 _flags |= MSG_WAITALL;
1435
1436 ssize_t result;
1437 if (addr) {
1438 addr->addrlen = sizeof(addr->addr);
1439#ifdef _WIN32
1440 result = recvfrom((SOCKET)handle->fd, buf, nbytes, _flags,
1441 (struct sockaddr *)&addr->addr, &addr->addrlen);
1442#else
1443 int errsv = errno;
1444 do {
1445 errno = errsv;
1446 result = recvfrom(handle->fd, buf, nbytes, _flags,
1447 (struct sockaddr *)&addr->addr,
1448 (socklen_t *)&addr->addrlen);
1449 } while (__unlikely(result == -1 && errno == EINTR));
1450#endif
1451 } else {
1452#ifdef _WIN32
1453 result = recv((SOCKET)handle->fd, buf, nbytes, _flags);
1454#else
1455 int errsv = errno;
1456 do {
1457 errno = errsv;
1458 result = recv(handle->fd, buf, nbytes, _flags);
1459 } while (__unlikely(result == -1 && errno == EINTR));
1460#endif
1461 }
1462 return result == SOCKET_ERROR ? -1 : result;
1463}
1464
1465static ssize_t
1466sock_send(struct io_handle *handle, const void *buf, size_t nbytes,
1467 const io_addr_t *addr, int flags)
1468{
1469 assert(handle);
1470
1471 int _flags = 0;
1472 if (flags & IO_MSG_OOB)
1473 _flags |= MSG_OOB;
1474#ifndef _WIN32
1475 _flags |= MSG_NOSIGNAL;
1476#endif
1477
1478 ssize_t result;
1479#ifdef _WIN32
1480 // clang-format off
1481 result = addr
1482 ? sendto((SOCKET)handle->fd, buf, nbytes, _flags,
1483 (const struct sockaddr *)&addr->addr, addr->addrlen)
1484 : send((SOCKET)handle->fd, buf, nbytes, _flags);
1485 // clang-format on
1486#else
1487 int errsv = errno;
1488 do {
1489 errno = errsv;
1490 // clang-format off
1491 result = addr
1492 ? sendto(handle->fd, buf, nbytes, _flags,
1493 (const struct sockaddr *)&addr->addr,
1494 addr->addrlen)
1495 : send(handle->fd, buf, nbytes, _flags);
1496 // clang-format on
1497 } while (__unlikely(result == -1 && errno == EINTR));
1498#endif
1499 return result == SOCKET_ERROR ? -1 : result;
1500}
1501
1502static struct io_handle *
1503sock_accept(struct io_handle *handle, io_addr_t *addr)
1504{
1505 struct sock *sock = (struct sock *)handle;
1506 assert(sock);
1507
1508 int errc = 0;
1509
1510 SOCKET s;
1511 if (addr) {
1512 addr->addrlen = sizeof(addr->addr);
1513#ifdef _WIN32
1514 s = accept((SOCKET)handle->fd, (struct sockaddr *)&addr->addr,
1515 &addr->addrlen);
1516#else
1517 int errsv = errno;
1518 do {
1519 errno = errsv;
1520#ifdef _GNU_SOURCE
1521 s = accept4(handle->fd, (struct sockaddr *)&addr->addr,
1522 (socklen_t *)&addr->addrlen,
1523 SOCK_CLOEXEC);
1524#else
1525 s = accept(handle->fd, (struct sockaddr *)&addr->addr,
1526 (socklen_t *)&addr->addrlen);
1527#endif
1528 } while (__unlikely(s == -1 && errno == EINTR));
1529#endif
1530 } else {
1531#ifdef _WIN32
1532 s = accept((SOCKET)handle->fd, NULL, NULL);
1533#else
1534 int errsv = errno;
1535 do {
1536 errno = errsv;
1537#ifdef _GNU_SOURCE
1538 s = accept4(handle->fd, NULL, NULL, SOCK_CLOEXEC);
1539#else
1540 s = accept(handle->fd, NULL, NULL);
1541#endif
1542 } while (__unlikely(s == -1 && errno == EINTR));
1543#endif
1544 }
1545
1546 if (__unlikely(s == INVALID_SOCKET)) {
1547 errc = get_errc();
1548 goto error_accept;
1549 }
1550
1551#if _POSIX_C_SOURCE >= 200112L && !defined(_GNU_SOURCE)
1552 if (__unlikely(fcntl(s, F_SETFD, FD_CLOEXEC) == -1)) {
1553 errc = get_errc();
1554 goto error_fcntl;
1555 }
1556#endif
1557
1558 handle = io_handle_alloc(&sock_vtab);
1559 if (__unlikely(!handle)) {
1560 errc = get_errc();
1561 goto error_alloc_handle;
1562 }
1563
1564 handle->fd = (HANDLE)s;
1565 ((struct sock *)handle)->domain = sock->domain;
1566 ((struct sock *)handle)->type = sock->type;
1567
1568 return io_handle_acquire(handle);
1569
1570error_alloc_handle:
1571#if _POSIX_C_SOURCE >= 200112L && !defined(_GNU_SOURCE)
1572error_fcntl:
1573#endif
1574#ifdef _WIN32
1575 closesocket(s);
1576#else
1577 close(s);
1578#endif
1579error_accept:
1580 set_errc(errc);
1581 return IO_HANDLE_ERROR;
1582}
1583
1584static int
1585sock_connect(struct io_handle *handle, const io_addr_t *addr)
1586{
1587 assert(handle);
1588
1589#ifdef _WIN32
1590 // clang-format off
1591 return connect((SOCKET)handle->fd, (const struct sockaddr *)&addr->addr,
1592 addr->addrlen) ? -1 : 0;
1593 // clang-format on
1594#else
1595 int result;
1596 int errsv = errno;
1597 do {
1598 errno = errsv;
1599 result = connect(handle->fd,
1600 (const struct sockaddr *)&addr->addr,
1601 addr->addrlen);
1602 } while (__unlikely(result == -1 && errno == EINTR));
1603 return result;
1604#endif
1605}
1606
1607static int
1608_socketpair(int af, int type, int protocol, SOCKET sv[2])
1609{
1610 assert(sv);
1611 sv[0] = sv[1] = INVALID_SOCKET;
1612
1613#if _POSIX_C_SOURCE >= 200112L
1614 if (af == AF_UNIX)
1615 return socketpair(af, type, protocol, sv);
1616#endif
1617
1618 int errc = 0;
1619
1620 if (__unlikely(af != AF_INET && af != AF_INET6)) {
1622 goto error_param;
1623 }
1624
1625 int flags = 0;
1626#if defined(__CYGWIN__) || defined(__linux__)
1627 flags = type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
1628 type &= ~flags;
1629#endif
1630
1631 if (__unlikely(type != SOCK_STREAM && type != SOCK_DGRAM)) {
1632 errc = errnum2c(ERRNUM_PROTOTYPE);
1633 goto error_param;
1634 }
1635
1636 sv[0] = socket(af, type | flags, protocol);
1637 if (__unlikely(sv[0] == INVALID_SOCKET)) {
1638 errc = get_errc();
1639 goto error_socket_0;
1640 }
1641
1642 sv[1] = socket(af, type | flags, protocol);
1643 if (__unlikely(sv[1] == INVALID_SOCKET)) {
1644 errc = get_errc();
1645 goto error_socket_1;
1646 }
1647
1648 struct sockaddr_storage name[2];
1649 struct sockaddr *name_0 = (struct sockaddr *)&name[0];
1650 struct sockaddr_in *name_in_0 = (struct sockaddr_in *)name_0;
1651 struct sockaddr_in6 *name_in6_0 = (struct sockaddr_in6 *)name_0;
1652 struct sockaddr *name_1 = (struct sockaddr *)&name[1];
1653 struct sockaddr_in *name_in_1 = (struct sockaddr_in *)name_1;
1654 struct sockaddr_in6 *name_in6_1 = (struct sockaddr_in6 *)name_1;
1655 socklen_t namelen_0, namelen_1;
1656
1657 if (af == AF_INET) {
1658 name_in_1->sin_family = AF_INET;
1659 name_in_1->sin_port = 0;
1660 name_in_1->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1661 namelen_1 = sizeof(*name_in_1);
1662 } else {
1663 name_in6_1->sin6_family = AF_INET6;
1664 name_in6_1->sin6_port = 0;
1665 name_in6_1->sin6_addr = in6addr_loopback;
1666 namelen_1 = sizeof(*name_in6_1);
1667 }
1668
1669 if (__unlikely(bind(sv[1], name_1, namelen_1) == SOCKET_ERROR)) {
1670 errc = get_errc();
1671 goto error_bind_1;
1672 }
1673 // clang-format off
1674 if (__unlikely(getsockname(sv[1], name_1, &namelen_1)
1675 == SOCKET_ERROR)) {
1676 // clang-format on
1677 errc = get_errc();
1678 goto error_getsockname_1;
1679 }
1680
1681 if (type == SOCK_STREAM) {
1682 if (__unlikely(listen(sv[1], 1) == SOCKET_ERROR)) {
1683 errc = get_errc();
1684 goto error_listen;
1685 }
1686 } else {
1687 if (af == AF_INET) {
1688 name_in_0->sin_family = AF_INET;
1689 name_in_0->sin_port = 0;
1690 name_in_0->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1691 namelen_0 = sizeof(*name_in_0);
1692 } else {
1693 name_in6_0->sin6_family = AF_INET6;
1694 name_in6_0->sin6_port = 0;
1695 name_in6_0->sin6_addr = in6addr_loopback;
1696 namelen_0 = sizeof(*name_in6_0);
1697 }
1698
1699 // clang-format off
1700 if (__unlikely(bind(sv[0], name_0, namelen_0)
1701 == SOCKET_ERROR)) {
1702 // clang-format on
1703 errc = get_errc();
1704 goto error_bind_0;
1705 }
1706 // clang-format off
1707 if (__unlikely(getsockname(sv[0], name_0, &namelen_0)
1708 == SOCKET_ERROR)) {
1709 // clang-format on
1710 errc = get_errc();
1711 goto error_getsockname_0;
1712 }
1713 }
1714
1715 if (af == AF_INET)
1716 name_in_1->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1717 else
1718 name_in6_1->sin6_addr = in6addr_loopback;
1719 if (__unlikely(connect(sv[0], name_1, namelen_1) == SOCKET_ERROR)) {
1720 errc = get_errc();
1721 goto error_connect_0;
1722 }
1723
1724 if (type == SOCK_STREAM) {
1725 SOCKET s = accept(sv[1], NULL, NULL);
1726 if (__unlikely(s == INVALID_SOCKET)) {
1727 errc = get_errc();
1728 goto error_accept;
1729 }
1730 closesocket(sv[1]);
1731 sv[1] = s;
1732 } else {
1733 if (af == AF_INET)
1734 name_in_0->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1735 else
1736 name_in6_0->sin6_addr = in6addr_loopback;
1737 // clang-format off
1738 if (__unlikely(connect(sv[1], name_0, namelen_0)
1739 == SOCKET_ERROR)) {
1740 // clang-format on
1741 errc = get_errc();
1742 goto error_connect_1;
1743 }
1744 }
1745
1746 return 0;
1747
1748error_connect_1:
1749error_accept:
1750error_connect_0:
1751error_getsockname_0:
1752error_bind_0:
1753error_listen:
1754error_getsockname_1:
1755error_bind_1:
1756 closesocket(sv[1]);
1757 sv[1] = INVALID_SOCKET;
1758error_socket_1:
1759 closesocket(sv[0]);
1760 sv[0] = INVALID_SOCKET;
1761error_socket_0:
1762error_param:
1763 set_errc(errc);
1764 return -1;
1765}
1766
1767#endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
This header file is part of the I/O library; it contains the network address declarations.
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
@ ERRNUM_AFNOSUPPORT
Address family not supported.
Definition: errnum.h:84
@ ERRNUM_BADF
Bad file descriptor.
Definition: errnum.h:90
@ ERRNUM_NOTSOCK
Not a socket.
Definition: errnum.h:191
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:129
@ ERRNUM_PROTOTYPE
Protocol wrong type for socket.
Definition: errnum.h:213
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:375
#define __unlikely(x)
Indicates to the compiler that the expression is most-likely false.
Definition: features.h:286
void io_handle_free(struct io_handle *handle)
Frees an I/O device handle.
Definition: handle.c:116
struct io_handle * io_handle_alloc(const struct io_handle_vtab *vtab)
Allocates a new I/O device handle from a virtual table.
Definition: handle.c:77
This is the internal header file of the I/O handle declarations.
@ IO_TYPE_SOCK
A network socket.
Definition: io.h:55
io_handle_t io_handle_acquire(io_handle_t handle)
Increments the reference count of an I/O device handle.
Definition: handle.c:32
#define IO_HANDLE_ERROR
The value of an invalid I/O device handle.
Definition: io.h:34
@ IO_FLAG_NONBLOCK
Perform I/O operations in non-blocking mode.
Definition: io.h:62
@ IO_FLAG_NO_CLOSE
Do not close the native file descriptor when closing an I/O device.
Definition: io.h:60
int io_sock_mcast_unblock_source(io_handle_t handle, unsigned int index, const io_addr_t *group, const io_addr_t *source)
Unblocks data from a given source to a given multicast group.
Definition: sock.c:1258
int io_sock_shutdown(io_handle_t handle, int how)
Causes all or part of a full-duplex connection on a socket to be shut down.
Definition: sock.c:430
int io_sock_get_oobinline(io_handle_t handle)
Checks if out-of-band data is received in the normal data stream of a socket.
Definition: sock.c:793
int io_sock_set_sndtimeo(io_handle_t handle, int timeout)
Sets the timeout (in milliseconds) of a send operation on a socket.
Definition: sock.c:955
int io_sock_get_mcast_loop(io_handle_t handle)
Checks if the loopback of outgoing multicast datagrams is enabled for a socket.
Definition: sock.c:1046
int io_sock_mcast_join_source_group(io_handle_t handle, unsigned int index, const io_addr_t *group, const io_addr_t *source)
Joins a source-specific multicast group.
Definition: sock.c:1320
int io_sock_get_tcp_nodelay(io_handle_t handle)
Checks if Nagle's algorithm for send coalescing is enabled for a socket.
Definition: sock.c:975
int io_open_socketpair(int domain, int type, io_handle_t handle_vector[2])
Opens a pair of connected sockets.
Definition: sock.c:181
int io_sock_set_reuseaddr(io_handle_t handle, int reuseaddr)
Enables a socket to be bound to an address that is already in use if reuseaddr is non-zero,...
Definition: sock.c:905
int io_sock_set_broadcast(io_handle_t handle, int broadcast)
Enables a socket to send broadcast messages if broadcast is non-zero, and disables this option otherw...
Definition: sock.c:574
int io_sock_set_mcast_ttl(io_handle_t handle, int ttl)
Sets the TTL (time to live) value for IP multicast traffic on a socket (the default is 1).
Definition: sock.c:1161
int io_sock_mcast_leave_group(io_handle_t handle, unsigned int index, const io_addr_t *group)
Leaves an any-source multicast group.
Definition: sock.c:1290
ssize_t io_recv(io_handle_t handle, void *buf, size_t nbytes, io_addr_t *addr, int flags)
Performs a receive operation on a network socket.
Definition: sock.c:301
int io_sock_get_error(io_handle_t handle, int *perror)
Obtains and clears the current error number of a socket, and stores the value in *perror.
Definition: sock.c:673
int io_sock_get_sockname(io_handle_t handle, io_addr_t *addr)
Obtains the locally-bound name of a socket and stores the resulting address in *addr.
Definition: sock.c:466
int io_sock_set_sndbuf(io_handle_t handle, int size)
Sets the size (in bytes) of the send buffer of a socket.
Definition: sock.c:941
int io_sock_get_peername(io_handle_t handle, io_addr_t *addr)
Obtains the peer address of a socket and stores the result in *addr.
Definition: sock.c:496
int io_sock_get_rcvbuf(io_handle_t handle)
Obtains the size (in bytes) of the receive buffer of a socket.
Definition: sock.c:833
int io_sock_get_broadcast(io_handle_t handle)
Checks if a socket is allowed to send broadcast messages.
Definition: sock.c:553
int io_sock_get_type(io_handle_t handle)
Obtains the type of a network socket (the second parameter in a call to io_open_socket() or io_open_s...
Definition: sock.c:389
int io_sock_get_maxconn(void)
Returns the maximum queue length for pending connections.
Definition: sock.c:526
int io_sock_mcast_leave_source_group(io_handle_t handle, unsigned int index, const io_addr_t *group, const io_addr_t *source)
Leaves a source-specific multicast group.
Definition: sock.c:1352
int io_sock_get_keepalive(io_handle_t handle)
Checks if the TCP keep-alive option is enabled for a socket.
Definition: sock.c:688
int io_sock_listen(io_handle_t handle, int backlog)
Marks a connection-mode socket (IO_SOCK_STREAM) as accepting connections.
Definition: sock.c:419
int io_sock_get_acceptconn(io_handle_t handle)
Checks if a socket is currently listening for incoming connections.
Definition: sock.c:532
ssize_t io_send(io_handle_t handle, const void *buf, size_t nbytes, const io_addr_t *addr, int flags)
Performs a send operation on a network socket.
Definition: sock.c:319
int io_sock_get_mcast_ttl(io_handle_t handle)
Obtains the TTL (time to live) value for IP multicast traffic on a socket.
Definition: sock.c:1121
int io_sock_get_dontroute(io_handle_t handle)
Checks if routing is disabled for a socket.
Definition: sock.c:633
int io_sock_get_domain(io_handle_t handle)
Obtains the domain of a socket (the first parameter in a call to io_open_socket() or io_open_socketpa...
Definition: sock.c:373
int io_sock_mcast_block_source(io_handle_t handle, unsigned int index, const io_addr_t *group, const io_addr_t *source)
Blocks data from a given source to a given multicast group.
Definition: sock.c:1226
int io_sock_set_rcvtimeo(io_handle_t handle, int timeout)
Sets the timeout (in milliseconds) of a receive operation on a socket.
Definition: sock.c:864
int io_sock_bind(io_handle_t handle, const io_addr_t *addr)
Binds a local network address to a socket.
Definition: sock.c:405
io_handle_t io_accept(io_handle_t handle, io_addr_t *addr)
Accepts an incoming connection on a listening socket.
Definition: sock.c:337
io_handle_t io_open_socket(int domain, int type)
Opens a network socket.
Definition: sock.c:74
ssize_t io_sock_get_nread(io_handle_t handle)
Obtains the amount of data (in bytes) in the input buffer of a socket.
Definition: sock.c:1016
int io_sock_set_linger(io_handle_t handle, int time)
Sets the time (in seconds) io_close() will wait for unsent messages to be sent.
Definition: sock.c:773
int io_sock_set_oobinline(io_handle_t handle, int oobinline)
Requests that out-of-band data is placed into the normal data stream of socket if oobinline is non-ze...
Definition: sock.c:814
int io_sock_set_mcast_loop(io_handle_t handle, int loop)
Enables the loopback of outgoing multicast datagrams for a socket if loop is non-zero,...
Definition: sock.c:1086
int io_sock_get_sndbuf(io_handle_t handle)
Obtains the size (in bytes) of the send buffer of a socket.
Definition: sock.c:924
int io_sock_set_rcvbuf(io_handle_t handle, int size)
Sets the size (in bytes) of the receive buffer of a socket.
Definition: sock.c:850
int io_sock_set_keepalive(io_handle_t handle, int keepalive, int time, int interval)
Enables or disables the TCP keep-alive option for a socket (disabled by default).
Definition: sock.c:709
int io_sock_mcast_join_group(io_handle_t handle, unsigned int index, const io_addr_t *group)
Joins an any-source multicast group.
Definition: sock.c:1196
int io_sock_set_dontroute(io_handle_t handle, int dontroute)
Bypasses normal routing for a socket if dontroute is non-zero, and disables this option otherwise (di...
Definition: sock.c:654
int io_sock_get_reuseaddr(io_handle_t handle)
Checks if a socket is allowed to be bound to an address that is already in use.
Definition: sock.c:884
int io_sock_get_debug(io_handle_t handle)
Checks if debugging is enabled for a socket.
Definition: sock.c:593
int io_sock_set_tcp_nodelay(io_handle_t handle, int nodelay)
Disables Nagle's algorithm for send coalescing if nodelay is non-zero, and enables it otherwise.
Definition: sock.c:996
int io_sock_get_linger(io_handle_t handle)
Obtains the linger time (in seconds) of a socket.
Definition: sock.c:756
int io_sock_set_debug(io_handle_t handle, int debug)
Enables (platform dependent) debugging output for a socket if debug is non-zero, and disables this op...
Definition: sock.c:614
int io_connect(io_handle_t handle, const io_addr_t *addr)
Connects a socket to a network address.
Definition: sock.c:354
This header file is part of the I/O library; it contains the network socket declarations.
@ IO_SOCK_DGRAM
A datagram-oriented, typically connectionless-mode, socket type.
Definition: sock.h:48
@ IO_SOCK_STREAM
A stream-oriented connection-mode socket type.
Definition: sock.h:43
@ IO_MSG_OOB
Requests out-of-band data.
Definition: sock.h:55
@ IO_MSG_PEEK
Peeks at incoming data.
Definition: sock.h:53
@ IO_MSG_WAITALL
On stream-oriented sockets, block until the full amount of data can be returned.
Definition: sock.h:60
@ IO_SHUT_RD
Disables further receive operations.
Definition: sock.h:65
@ IO_SHUT_RDWR
Disables further send and receive operations.
Definition: sock.h:69
@ IO_SHUT_WR
Disables further send operations.
Definition: sock.h:67
@ IO_SOCK_IPV4
An IPv4 socket.
Definition: sock.h:31
@ IO_SOCK_UNIX
A UNIX domain socket (only supported on POSIX platforms).
Definition: sock.h:35
@ IO_SOCK_IPV6
An IPv6 socket.
Definition: sock.h:33
@ IO_SOCK_BTH
A Bluetooth socket.
Definition: sock.h:29
This is the internal header file of the I/O library.
This header file is part of the C11 and POSIX compatibility library; it includes <string....
An opaque network address type.
Definition: addr.h:30
int addrlen
The size (in bytes) of addr.
Definition: addr.h:32
union __io_addr::@2 addr
The network address.
The virtual table of an I/O device handle.
Definition: handle.h:74
struct io_handle *(* accept)(struct io_handle *handle, io_addr_t *addr)
A pointer to the accept method.
Definition: handle.h:110
ssize_t(* send)(struct io_handle *handle, const void *buf, size_t nbytes, const io_addr_t *addr, int flags)
A pointer to the send method.
Definition: handle.h:107
int type
The type of the device (one of IO_TYPE_CAN, IO_TYPE_FILE, IO_TYPE_PIPE, IO_TYPE_SERIAL or IO_TYPE_SOC...
Definition: handle.h:79
int(* connect)(struct io_handle *handle, const io_addr_t *addr)
A pointer to the connect method.
Definition: handle.h:112
ssize_t(* recv)(struct io_handle *handle, void *buf, size_t nbytes, io_addr_t *addr, int flags)
A pointer to the recv method.
Definition: handle.h:104
An I/O device handle.
Definition: handle.h:41
int fd
The native file descriptor.
Definition: handle.h:56
int flags
The I/O device flags (any combination of IO_FLAG_NO_CLOSE and IO_FLAG_NONBLOCK).
Definition: handle.h:62
const struct io_handle_vtab * vtab
A pointer to the virtual table.
Definition: handle.h:43
A network socket.
Definition: sock.c:36
int type
The type of the socket (IO_SOCK_STREAM or IO_SOCK_DGRAM).
Definition: sock.c:45
struct io_handle base
The I/O device base handle.
Definition: sock.c:38
int domain
The domain of the socket (one of IO_SOCK_BTH, IO_SOCK_IPV4, IO_SOCK_IPV6 or IO_SOCK_UNIX).
Definition: sock.c:43
ptrdiff_t ssize_t
Used for a count of bytes or an error indication.
Definition: types.h:43