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