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 
40 struct sock {
42  struct io_handle base;
47  int domain;
49  int type;
50 };
51 
52 static void sock_fini(struct io_handle *handle);
53 static int sock_flags(struct io_handle *handle, int flags);
54 static ssize_t sock_read(struct io_handle *handle, void *buf, size_t nbytes);
55 static ssize_t sock_write(
56  struct io_handle *handle, const void *buf, size_t nbytes);
57 static ssize_t sock_recv(struct io_handle *handle, void *buf, size_t nbytes,
58  io_addr_t *addr, int flags);
59 static ssize_t sock_send(struct io_handle *handle, const void *buf,
60  size_t nbytes, const io_addr_t *addr, int flags);
61 static struct io_handle *sock_accept(struct io_handle *handle, io_addr_t *addr);
62 static int sock_connect(struct io_handle *handle, const io_addr_t *addr);
63 
64 static 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 
75 static 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 
172 error_alloc_handle:
173 #if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
174 error_fcntl:
175 #endif
176  closesocket(s);
177 error_socket:
178 error_type:
179 error_domain:
180  set_errc(errc);
181  return IO_HANDLE_ERROR;
182 }
183 
184 int
185 io_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 
285 error_alloc_handle_vector_1:
286  handle_vector[1] = IO_HANDLE_ERROR;
287  io_handle_free(handle_vector[0]);
288 error_alloc_handle_vector_0:
289  handle_vector[0] = IO_HANDLE_ERROR;
290 #if _POSIX_C_SOURCE >= 200112L && !defined(__CYGINW__) && !defined(__linux__)
291 error_fcntl:
292 #endif
293  closesocket(socket_vector[1]);
294  closesocket(socket_vector[0]);
295 error_socketpair:
296 error_type:
297 error_domain:
298  set_errc(errc);
299  return -1;
300 }
301 
302 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
303 
304 ssize_t
305 io_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 
322 ssize_t
323 io_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 
357 int
358 io_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 
376 int
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 
392 int
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 
408 int
409 io_sock_bind(io_handle_t handle, const io_addr_t *addr)
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 
422 int
423 io_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 
433 int
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 
469 int
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 
499 int
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 
529 int
531 {
532  return SOMAXCONN;
533 }
534 
535 int
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 
556 int
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 
577 int
578 io_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 
596 int
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 
617 int
618 io_sock_set_debug(io_handle_t handle, int debug)
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 
636 int
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 
657 int
658 io_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 
676 int
677 io_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 
691 int
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 
712 int
713 io_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 
759 int
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 
776 int
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 
796 int
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 
817 int
818 io_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 
836 int
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 
853 int
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 
867 int
868 io_sock_set_rcvtimeo(io_handle_t handle, int timeout)
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 
887 int
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 
908 int
909 io_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 
927 int
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 
944 int
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 
958 int
959 io_sock_set_sndtimeo(io_handle_t handle, int timeout)
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 
978 int
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 
999 int
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)
1019 ssize_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 
1049 int
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 
1089 int
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 
1124 int
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 
1164 int
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 
1199 int
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 
1229 int
1230 io_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 
1261 int
1262 io_sock_mcast_unblock_source(io_handle_t handle, unsigned int index,
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 
1293 int
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 
1323 int
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 
1355 int
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 
1386 static void
1387 sock_fini(struct io_handle *handle)
1388 {
1389  if (!(handle->flags & IO_FLAG_NO_CLOSE))
1390  closesocket((SOCKET)handle->fd);
1391 }
1392 
1393 static int
1394 sock_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 
1414 static ssize_t
1415 sock_read(struct io_handle *handle, void *buf, size_t nbytes)
1416 {
1417  return sock_recv(handle, buf, nbytes, NULL, 0);
1418 }
1419 
1420 static ssize_t
1421 sock_write(struct io_handle *handle, const void *buf, size_t nbytes)
1422 {
1423  return sock_send(handle, buf, nbytes, NULL, 0);
1424 }
1425 
1426 static ssize_t
1427 sock_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 
1469 static ssize_t
1470 sock_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 
1506 static struct io_handle *
1507 sock_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 
1574 error_alloc_handle:
1575 #if _POSIX_C_SOURCE >= 200112L && !defined(_GNU_SOURCE)
1576 error_fcntl:
1577 #endif
1578 #if _WIN32
1579  closesocket(s);
1580 #else
1581  close(s);
1582 #endif
1583 error_accept:
1584  set_errc(errc);
1585  return IO_HANDLE_ERROR;
1586 }
1587 
1588 static int
1589 sock_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 
1611 static 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) {
1625  errc = errnum2c(ERRNUM_AFNOSUPPORT);
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 
1740 error_connect_1:
1741 error_accept:
1742 error_connect_0:
1743 error_getsockname_0:
1744 error_bind_0:
1745 error_listen:
1746 error_getsockname_1:
1747 error_bind_1:
1748  closesocket(sv[1]);
1749  sv[1] = INVALID_SOCKET;
1750 error_socket_1:
1751  closesocket(sv[0]);
1752  sv[0] = INVALID_SOCKET;
1753 error_socket_0:
1754 error_param:
1755  set_errc(errc);
1756  return -1;
1757 }
1758 
1759 #endif // _WIN32 || _POSIX_C_SOURCE >= 200112L
1760 
1761 #endif // !LELY_NO_STDIO
io_sock_set_debug
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
IO_FLAG_NONBLOCK
@ IO_FLAG_NONBLOCK
Perform I/O operations in non-blocking mode.
Definition: io.h:62
io_sock_get_sockname
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
io_sock_mcast_block_source
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
io_sock_get_dontroute
int io_sock_get_dontroute(io_handle_t handle)
Checks if routing is disabled for a socket.
Definition: sock.c:637
ERRNUM_NOTSOCK
@ ERRNUM_NOTSOCK
Not a socket.
Definition: errnum.h:194
io_open_socket
io_handle_t io_open_socket(int domain, int type)
Opens a network socket.
Definition: sock.c:78
io_sock_get_keepalive
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
sock::base
struct io_handle base
The I/O device base handle.
Definition: sock.c:42
io_sock_get_type
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
string.h
IO_SOCK_UNIX
@ IO_SOCK_UNIX
A UNIX domain socket (only supported on POSIX platforms).
Definition: sock.h:35
sock::domain
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
io_sock_get_error
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
io_accept
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_SHUT_WR
@ IO_SHUT_WR
Disables further send operations.
Definition: sock.h:67
__io_addr
An opaque network address type.
Definition: addr.h:30
io_sock_get_sndbuf
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
sock
A network socket.
Definition: sock.c:40
io_sock_set_tcp_nodelay
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
io_handle_vtab::type
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
io_sock_set_reuseaddr
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
io_sock_get_oobinline
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
io_handle_vtab::recv
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
get_errc
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:932
ERRNUM_AFNOSUPPORT
@ ERRNUM_AFNOSUPPORT
Address family not supported.
Definition: errnum.h:87
io_connect
int io_connect(io_handle_t handle, const io_addr_t *addr)
Connects a socket to a network address.
Definition: sock.c:358
io_handle
An I/O device handle.
Definition: handle.h:33
io_send
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
io_sock_set_oobinline
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
ERRNUM_PROTOTYPE
@ ERRNUM_PROTOTYPE
Protocol wrong type for socket.
Definition: errnum.h:216
io_handle_acquire
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_SOCK_BTH
@ IO_SOCK_BTH
A Bluetooth socket.
Definition: sock.h:29
io_sock_get_linger
int io_sock_get_linger(io_handle_t handle)
Obtains the linger time (in seconds) of a socket.
Definition: sock.c:760
ERRNUM_BADF
@ ERRNUM_BADF
Bad file descriptor.
Definition: errnum.h:93
io_sock_get_maxconn
int io_sock_get_maxconn(void)
Returns the maximum queue length for pending connections.
Definition: sock.c:530
io_sock_set_broadcast
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
IO_TYPE_SOCK
@ IO_TYPE_SOCK
A network socket.
Definition: io.h:55
io_handle_vtab::accept
struct io_handle *(* accept)(struct io_handle *handle, io_addr_t *addr)
A pointer to the accept method.
Definition: handle.h:102
io_sock_mcast_leave_source_group
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
io_handle_alloc
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
io_sock_set_linger
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
set_errnum
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
Definition: errnum.h:424
set_errc
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:944
handle.h
io_handle_vtab::connect
int(* connect)(struct io_handle *handle, const io_addr_t *addr)
A pointer to the connect method.
Definition: handle.h:104
io_sock_get_tcp_nodelay
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
io_sock_set_sndbuf
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
io.h
io_sock_bind
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
errnum2c
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:810
io_sock_get_acceptconn
int io_sock_get_acceptconn(io_handle_t handle)
Checks if a socket is currently listening for incoming connections.
Definition: sock.c:536
io_handle_vtab::send
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
sock::type
int type
The type of the socket (IO_SOCK_STREAM or IO_SOCK_DGRAM).
Definition: sock.c:49
io_sock_mcast_leave_group
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
io_sock_get_reuseaddr
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
addr.h
errnum.h
IO_SHUT_RDWR
@ IO_SHUT_RDWR
Disables further send and receive operations.
Definition: sock.h:69
IO_HANDLE_ERROR
#define IO_HANDLE_ERROR
The value of an invalid I/O device handle.
Definition: io.h:34
io_handle::vtab
const struct io_handle_vtab * vtab
A pointer to the virtual table.
Definition: handle.h:35
io_sock_get_nread
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
ERRNUM_INVAL
@ ERRNUM_INVAL
Invalid argument.
Definition: errnum.h:132
io_sock_get_debug
int io_sock_get_debug(io_handle_t handle)
Checks if debugging is enabled for a socket.
Definition: sock.c:597
IO_FLAG_NO_CLOSE
@ IO_FLAG_NO_CLOSE
Do not close the native file descriptor when closing an I/O device.
Definition: io.h:60
__io_addr::addr
union __io_addr::@5 addr
The network address.
io_handle::flags
int flags
The I/O device flags (any combination of IO_FLAG_NO_CLOSE and IO_FLAG_NONBLOCK).
Definition: handle.h:54
io_sock_set_mcast_loop
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
io_open_socketpair
int io_open_socketpair(int domain, int type, io_handle_t handle_vector[2])
Opens a pair of connected sockets.
Definition: sock.c:185
io_sock_shutdown
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
io_sock_get_mcast_ttl
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
io_sock_set_sndtimeo
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
io_sock_set_keepalive
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
io_handle_vtab
The virtual table of an I/O device handle.
Definition: handle.h:66
io_handle::fd
int fd
The native file descriptor.
Definition: handle.h:48
io_sock_mcast_unblock_source
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
__io_addr::addrlen
int addrlen
The size (in bytes) of addr.
Definition: addr.h:32
IO_SHUT_RD
@ IO_SHUT_RD
Disables further receive operations.
Definition: sock.h:65
io_sock_mcast_join_source_group
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
io_sock_set_dontroute
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
io_sock_set_rcvtimeo
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
io_sock_get_mcast_loop
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
io_sock_get_broadcast
int io_sock_get_broadcast(io_handle_t handle)
Checks if a socket is allowed to send broadcast messages.
Definition: sock.c:557
io_sock_listen
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
IO_MSG_WAITALL
@ IO_MSG_WAITALL
On stream-oriented sockets, block until the full amount of data can be returned.
Definition: sock.h:60
IO_SOCK_DGRAM
@ IO_SOCK_DGRAM
A datagram-oriented, typically connectionless-mode, socket type.
Definition: sock.h:48
io_sock_mcast_join_group
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
io_sock_set_rcvbuf
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
IO_MSG_PEEK
@ IO_MSG_PEEK
Peeks at incoming data.
Definition: sock.h:53
IO_SOCK_IPV6
@ IO_SOCK_IPV6
An IPv6 socket.
Definition: sock.h:33
io_sock_get_domain
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
IO_SOCK_IPV4
@ IO_SOCK_IPV4
An IPv4 socket.
Definition: sock.h:31
io_sock_get_rcvbuf
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
io_sock_set_mcast_ttl
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
sock.h
IO_SOCK_STREAM
@ IO_SOCK_STREAM
A stream-oriented connection-mode socket type.
Definition: sock.h:43
IO_MSG_OOB
@ IO_MSG_OOB
Requests out-of-band data.
Definition: sock.h:55
io_recv
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
io_handle_free
void io_handle_free(struct io_handle *handle)
Frees an I/O device handle.
Definition: handle.c:120
io_sock_get_peername
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