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