• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib/socket.c

  1 /*
  2  * Copyright (C) 2024 Jo-Philipp Wich <jo@mein.io>
  3  *
  4  * Permission to use, copy, modify, and/or distribute this software for any
  5  * purpose with or without fee is hereby granted, provided that the above
  6  * copyright notice and this permission notice appear in all copies.
  7  *
  8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15  */
 16 
 17 /**
 18  * # Socket Module
 19  *
 20  * The `socket` module provides functions for interacting with sockets.
 21  *
 22  * Functions can be individually imported and directly accessed using the
 23  * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#named_import named import}
 24  * syntax:
 25  *
 26  *   ```javascript
 27  *   import { AF_INET, SOCK_STREAM, create as socket } from 'socket';
 28  *
 29  *   let sock = socket(AF_INET, SOCK_STREAM, 0);
 30  *   sock.connect('192.168.1.1', 80);
 31  *   sock.send(…);
 32  *   sock.recv(…);
 33  *   sock.close();
 34  *   ```
 35  *
 36  * Alternatively, the module namespace can be imported
 37  * using a wildcard import statement:
 38  *
 39  *   ```javascript
 40  *   import * as socket from 'socket';
 41  *
 42  *   let sock = socket.create(socket.AF_INET, socket.SOCK_STREAM, 0);
 43  *   sock.connect('192.168.1.1', 80);
 44  *   sock.send(…);
 45  *   sock.recv(…);
 46  *   sock.close();
 47  *   ```
 48  *
 49  * Additionally, the socket module namespace may also be imported by invoking
 50  * the `ucode` interpreter with the `-lsocket` switch.
 51  *
 52  * @module socket
 53  */
 54 
 55 #include <errno.h>
 56 #include <ctype.h>
 57 #include <sys/stat.h>
 58 #include <sys/un.h>
 59 #include <netinet/tcp.h>
 60 #include <netinet/udp.h>
 61 #include <arpa/inet.h>
 62 #include <unistd.h>
 63 #include <fcntl.h>
 64 #include <net/if.h>
 65 #include <netdb.h>
 66 #include <poll.h>
 67 #include <limits.h>
 68 #include <dirent.h>
 69 
 70 #include "ucode/module.h"
 71 
 72 #if defined(__linux__)
 73 # include <linux/in6.h>
 74 # include <linux/if_packet.h>
 75 # include <linux/filter.h>
 76 # include <linux/can.h>
 77 # include <linux/can/raw.h>
 78 
 79 # ifndef SO_TIMESTAMP_OLD
 80 #  define SO_TIMESTAMP_OLD SO_TIMESTAMP
 81 # endif
 82 
 83 # ifndef SO_TIMESTAMPNS_OLD
 84 #  define SO_TIMESTAMPNS_OLD SO_TIMESTAMP
 85 # endif
 86 #endif
 87 
 88 #if defined(__APPLE__)
 89 # include <sys/ucred.h>
 90 
 91 # define SOCK_NONBLOCK (1 << 16)
 92 # define SOCK_CLOEXEC  (1 << 17)
 93 #endif
 94 
 95 #ifndef NI_IDN
 96 # define NI_IDN 0
 97 #endif
 98 
 99 #ifndef AI_IDN
100 # define AI_IDN 0
101 #endif
102 
103 #ifndef AI_CANONIDN
104 # define AI_CANONIDN 0
105 #endif
106 
107 #ifndef IPV6_FLOWINFO
108 # define IPV6_FLOWINFO 11
109 #endif
110 
111 #ifndef IPV6_FLOWLABEL_MGR
112 # define IPV6_FLOWLABEL_MGR 32
113 #endif
114 
115 #ifndef IPV6_FLOWINFO_SEND
116 # define IPV6_FLOWINFO_SEND 33
117 #endif
118 
119 #define ok_return(expr) do { set_error(0, NULL); return (expr); } while(0)
120 #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0)
121 
122 static struct {
123         int code;
124         char *msg;
125 } last_error;
126 
127 __attribute__((format(printf, 2, 3))) static void
128 set_error(int errcode, const char *fmt, ...)
129 {
130         va_list ap;
131 
132         free(last_error.msg);
133 
134         last_error.code = errcode;
135         last_error.msg = NULL;
136 
137         if (fmt) {
138                 va_start(ap, fmt);
139                 xvasprintf(&last_error.msg, fmt, ap);
140                 va_end(ap);
141         }
142 }
143 
144 static char *
145 arg_type_(uc_type_t type)
146 {
147         switch (type) {
148         case UC_INTEGER:  return "an integer value";
149         case UC_BOOLEAN:  return "a boolean value";
150         case UC_STRING:   return "a string value";
151         case UC_DOUBLE:   return "a double value";
152         case UC_ARRAY:    return "an array";
153         case UC_OBJECT:   return "an object";
154         case UC_REGEXP:   return "a regular expression";
155         case UC_CLOSURE:  return "a function";
156         case UC_RESOURCE: return "a resource value";
157         default:          return "the expected type";
158         }
159 }
160 
161 static bool
162 args_get_(uc_vm_t *vm, size_t nargs, int *fdptr, ...)
163 {
164         const char *name, *rtype = NULL;
165         uc_value_t **ptr, *arg;
166         uc_type_t type, t;
167         size_t index = 0;
168         int *sockfd;
169         va_list ap;
170         bool opt;
171 
172         if (fdptr) {
173                 sockfd = uc_fn_this("socket");
174 
175                 if (!sockfd || *sockfd == -1)
176                         err_return(EBADF, "Invalid socket context");
177 
178                 *fdptr = *sockfd;
179         }
180 
181         va_start(ap, fdptr);
182 
183         while (true) {
184                 name = va_arg(ap, const char *);
185 
186                 if (!name)
187                         break;
188 
189                 arg = uc_fn_arg(index++);
190 
191                 type = va_arg(ap, uc_type_t);
192                 opt = va_arg(ap, int);
193                 ptr = va_arg(ap, uc_value_t **);
194 
195                 if (type == UC_RESOURCE) {
196                         rtype = name;
197                         name = strrchr(rtype, '.');
198                         name = name ? name + 1 : rtype;
199 
200                         if (arg && !ucv_resource_dataptr(arg, rtype))
201                                 err_return(EINVAL,
202                                         "Argument %s is not a %s resource", name, rtype);
203                 }
204 
205                 if (!opt && !arg)
206                         err_return(EINVAL,
207                                 "Argument %s is required", name);
208 
209                 t = ucv_type(arg);
210 
211                 if (t == UC_CFUNCTION)
212                         t = UC_CLOSURE;
213 
214                 if (arg && type != UC_NULL && t != type)
215                         err_return(EINVAL,
216                                 "Argument %s is not %s", name, arg_type_(type));
217 
218                 *ptr = arg;
219         }
220 
221         va_end(ap);
222 
223         ok_return(true);
224 }
225 
226 #define args_get(vm, nargs, fdptr, ...) do { \
227         if (!args_get_(vm, nargs, fdptr, ##__VA_ARGS__, NULL)) \
228                 return NULL; \
229 } while(0)
230 
231 static void
232 strbuf_free(uc_stringbuf_t *sb)
233 {
234         printbuf_free(sb);
235 }
236 
237 static bool
238 strbuf_grow(uc_stringbuf_t *sb, size_t size)
239 {
240         if (size > 0) {
241                 if (printbuf_memset(sb, sizeof(uc_string_t) + size - 1, '\0', 1))
242                         err_return(ENOMEM, "Out of memory");
243         }
244 
245         return true;
246 }
247 
248 static char *
249 strbuf_data(uc_stringbuf_t *sb)
250 {
251         return sb->buf + sizeof(uc_string_t);
252 }
253 
254 static size_t
255 strbuf_size(uc_stringbuf_t *sb)
256 {
257         return (size_t)sb->bpos - sizeof(uc_string_t);
258 }
259 
260 static uc_value_t *
261 strbuf_finish(uc_stringbuf_t **sb, size_t final_size)
262 {
263         size_t buffer_size;
264         uc_string_t *us;
265 
266         if (!sb || !*sb)
267                 return NULL;
268 
269         buffer_size = strbuf_size(*sb);
270         us = (uc_string_t *)(*sb)->buf;
271 
272         if (final_size > buffer_size)
273                 final_size = buffer_size;
274 
275         free(*sb);
276         *sb = NULL;
277 
278         us = xrealloc(us, sizeof(uc_string_t) + final_size + 1);
279         us->length = final_size;
280         us->str[us->length] = 0;
281 
282         return &us->header;
283 }
284 
285 static uc_stringbuf_t *
286 strbuf_alloc(size_t size)
287 {
288         uc_stringbuf_t *sb = ucv_stringbuf_new();
289 
290         if (!strbuf_grow(sb, size)) {
291                 printbuf_free(sb);
292 
293                 return NULL;
294         }
295 
296         return sb;
297 }
298 
299 #if defined(__linux__)
300 static uc_value_t *
301 hwaddr_to_uv(uint8_t *addr, size_t alen)
302 {
303         char buf[sizeof("FF:FF:FF:FF:FF:FF:FF:FF")], *p = buf;
304         const char *hex = "0123456789ABCDEF";
305 
306         if (alen > 8)
307                 alen = 8;
308 
309         for (size_t i = 0; i < alen; i++) {
310                 if (i) *p++ = ':';
311                 *p++ = hex[addr[i] / 16];
312                 *p++ = hex[addr[i] % 16];
313         }
314 
315         return ucv_string_new_length(buf, p - buf);
316 }
317 
318 static bool
319 uv_to_hwaddr(uc_value_t *addr, uint8_t *out, size_t *outlen)
320 {
321         const char *p;
322         size_t len;
323 
324         memset(out, 0, 8);
325         *outlen = 0;
326 
327         if (ucv_type(addr) != UC_STRING)
328                 goto err;
329 
330         len = ucv_string_length(addr);
331         p = ucv_string_get(addr);
332 
333         while (len > 0 && isxdigit(*p) && *outlen < 8) {
334                 uint8_t n = (*p > '9') ? 10 + (*p|32) - 'a' : *p - '';
335                 p++, len--;
336 
337                 if (len > 0 && isxdigit(*p)) {
338                         n = n * 16 + ((*p > '9') ? 10 + (*p|32) - 'a' : *p - '');
339                         p++, len--;
340                 }
341 
342                 if (len > 0 && (*p == ':' || *p == '-' || *p == '.'))
343                         p++, len--;
344 
345                 out[(*outlen)++] = n;
346         }
347 
348         if (len == 0 || *p == 0)
349                 return true;
350 
351 err:
352         err_return(EINVAL, "Invalid hardware address");
353 }
354 #endif
355 
356 static bool
357 sockaddr_to_uv(struct sockaddr_storage *ss, uc_value_t *addrobj)
358 {
359         char *ifname, addrstr[INET6_ADDRSTRLEN];
360         struct sockaddr_in6 *s6;
361         struct sockaddr_in *s4;
362         struct sockaddr_un *su;
363 #if defined(__linux__)
364         struct sockaddr_ll *sl;
365         struct sockaddr_can *sc;
366 #endif
367 
368         ucv_object_add(addrobj, "family", ucv_uint64_new(ss->ss_family));
369 
370         switch (ss->ss_family) {
371         case AF_INET6:
372                 s6 = (struct sockaddr_in6 *)ss;
373 
374                 inet_ntop(AF_INET6, &s6->sin6_addr, addrstr, sizeof(addrstr));
375                 ucv_object_add(addrobj, "address",
376                         ucv_string_new(addrstr));
377 
378                 ucv_object_add(addrobj, "port",
379                         ucv_uint64_new(ntohs(s6->sin6_port)));
380 
381                 ucv_object_add(addrobj, "flowinfo",
382                         ucv_uint64_new(ntohl(s6->sin6_flowinfo)));
383 
384                 if (s6->sin6_scope_id) {
385                         ifname = if_indextoname(s6->sin6_scope_id, addrstr);
386 
387                         if (ifname)
388                                 ucv_object_add(addrobj, "interface",
389                                         ucv_string_new(ifname));
390                         else
391                                 ucv_object_add(addrobj, "interface",
392                                         ucv_uint64_new(s6->sin6_scope_id));
393                 }
394 
395                 return true;
396 
397         case AF_INET:
398                 s4 = (struct sockaddr_in *)ss;
399 
400                 inet_ntop(AF_INET, &s4->sin_addr, addrstr, sizeof(addrstr));
401                 ucv_object_add(addrobj, "address",
402                         ucv_string_new(addrstr));
403 
404                 ucv_object_add(addrobj, "port",
405                         ucv_uint64_new(ntohs(s4->sin_port)));
406 
407                 return true;
408 
409         case AF_UNIX:
410                 su = (struct sockaddr_un *)ss;
411 
412                 ucv_object_add(addrobj, "path",
413                         ucv_string_new(su->sun_path));
414 
415                 return true;
416 
417 #if defined(__linux__)
418         case AF_PACKET:
419                 sl = (struct sockaddr_ll *)ss;
420 
421                 ucv_object_add(addrobj, "protocol",
422                         ucv_uint64_new(ntohs(sl->sll_protocol)));
423 
424                 ifname = (sl->sll_ifindex > 0)
425                         ? if_indextoname(sl->sll_ifindex, addrstr) : NULL;
426 
427                 if (ifname)
428                         ucv_object_add(addrobj, "interface",
429                                 ucv_string_new(ifname));
430                 else if (sl->sll_ifindex != 0)
431                         ucv_object_add(addrobj, "interface",
432                                 ucv_int64_new(sl->sll_ifindex));
433 
434                 ucv_object_add(addrobj, "hardware_type",
435                         ucv_uint64_new(sl->sll_hatype));
436 
437                 ucv_object_add(addrobj, "packet_type",
438                         ucv_uint64_new(sl->sll_pkttype));
439 
440                 ucv_object_add(addrobj, "address",
441                         hwaddr_to_uv(sl->sll_addr, sl->sll_halen));
442 
443                 return true;
444 
445         case AF_CAN:
446                 sc = (struct sockaddr_can *)ss;
447 
448                 ifname = (sc->can_ifindex > 0)
449                         ? if_indextoname(sc->can_ifindex, addrstr) : NULL;
450 
451                 if (ifname)
452                         ucv_object_add(addrobj, "interface",
453                                 ucv_string_new(ifname));
454                 else if (sc->can_ifindex != 0)
455                         ucv_object_add(addrobj, "interface",
456                                 ucv_int64_new(sc->can_ifindex));
457 
458                 return true;
459 #endif
460         }
461 
462         return false;
463 }
464 
465 static int64_t
466 parse_integer(char *s, size_t len)
467 {
468         union { int8_t i8; int16_t i16; int32_t i32; int64_t i64; } v;
469 
470         memcpy(&v, s, len < sizeof(v) ? len : sizeof(v));
471 
472         switch (len) {
473         case 1:  return v.i8;
474         case 2:  return v.i16;
475         case 4:  return v.i32;
476         case 8:  return v.i64;
477         default: return 0;
478         }
479 }
480 
481 static uint64_t
482 parse_unsigned(char *s, size_t len)
483 {
484         union { uint8_t u8; uint16_t u16; uint32_t u32; uint64_t u64; } v;
485 
486         memcpy(&v, s, len < sizeof(v) ? len : sizeof(v));
487 
488         switch (len) {
489         case 1:  return v.u8;
490         case 2:  return v.u16;
491         case 4:  return v.u32;
492         case 8:  return v.u64;
493         default: return 0;
494         }
495 }
496 
497 static bool
498 parse_addr(char *addr, struct sockaddr_storage *ss)
499 {
500         bool v6 = (ss->ss_family == 0 || ss->ss_family == AF_INET6);
501         bool v4 = (ss->ss_family == 0 || ss->ss_family == AF_INET);
502         struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ss;
503         struct sockaddr_in *s4 = (struct sockaddr_in *)ss;
504         unsigned long n;
505         char *scope, *e;
506 
507         if (v6 && (scope = strchr(addr, '%')) != NULL) {
508                 *scope++ = 0;
509                 n = strtoul(scope, &e, 10);
510 
511                 if (e == scope || *e != 0) {
512                         n = if_nametoindex(scope);
513 
514                         if (n == 0)
515                                 err_return(errno, "Unable to resolve interface %s", scope);
516                 }
517 
518                 if (inet_pton(AF_INET6, addr, &s6->sin6_addr) != 1)
519                         err_return(errno, "Invalid IPv6 address");
520 
521                 s6->sin6_family = AF_INET6;
522                 s6->sin6_scope_id = n;
523 
524                 return true;
525         }
526         else if (v6 && inet_pton(AF_INET6, addr, &s6->sin6_addr) == 1) {
527                 s6->sin6_family = AF_INET6;
528 
529                 return true;
530         }
531         else if (v4 && inet_pton(AF_INET, addr, &s4->sin_addr) == 1) {
532                 s4->sin_family = AF_INET;
533 
534                 return true;
535         }
536 
537         err_return(EINVAL, "Unable to parse IP address");
538 }
539 
540 static bool
541 uv_to_sockaddr(uc_value_t *addr, struct sockaddr_storage *ss, socklen_t *slen)
542 {
543         char *s, *p, addrstr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255%interface012345")];
544         struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ss;
545         struct sockaddr_in *s4 = (struct sockaddr_in *)ss;
546         struct sockaddr_un *su = (struct sockaddr_un *)ss;
547 #if defined(__linux__)
548         struct sockaddr_ll *sl = (struct sockaddr_ll *)ss;
549         struct sockaddr_can *sc = (struct sockaddr_can *)ss;
550 #endif
551         uc_value_t *item;
552         unsigned long n;
553         size_t len;
554 
555         memset(ss, 0, sizeof(*ss));
556 
557         if (ucv_type(addr) == UC_STRING) {
558                 s = ucv_string_get(addr);
559                 len = ucv_string_length(addr);
560 
561                 if (memchr(s, '/', len) != NULL) {
562                         if (len >= sizeof(su->sun_path))
563                                 len = sizeof(su->sun_path) - 1;
564 
565                         memcpy(su->sun_path, s, len);
566                         su->sun_path[len++] = 0;
567                         su->sun_family = AF_UNIX;
568                         *slen = sizeof(*su);
569 
570                         ok_return(true);
571                 }
572 
573                 if (len == 0)
574                         err_return(EINVAL, "Invalid IP address");
575 
576                 if (*s == '[') {
577                         p = memchr(++s, ']', --len);
578 
579                         if (!p || (size_t)(p - s) >= sizeof(addrstr))
580                                 err_return(EINVAL, "Invalid IPv6 address");
581 
582                         memcpy(addrstr, s, p - s);
583                         addrstr[p - s] = 0;
584 
585                         ss->ss_family = AF_INET6;
586                         len -= ((p - s) + 1);
587                         s = p + 1;
588                 }
589                 else if ((p = memchr(s, ':', len)) != NULL &&
590                          memchr(p + 1, ':', len - ((p - s) + 1)) == NULL) {
591                         if ((size_t)(p - s) >= sizeof(addrstr))
592                                 err_return(EINVAL, "Invalid IP address");
593 
594                         memcpy(addrstr, s, p - s);
595                         addrstr[p - s] = 0;
596 
597                         ss->ss_family = AF_INET;
598                         len -= (p - s);
599                         s = p;
600                 }
601                 else {
602                         if (len >= sizeof(addrstr))
603                                 err_return(EINVAL, "Invalid IP address");
604 
605                         memcpy(addrstr, s, len);
606                         addrstr[len] = 0;
607 
608                         ss->ss_family = 0;
609                         len = 0;
610                         s = NULL;
611                 }
612 
613                 if (!parse_addr(addrstr, ss))
614                         return NULL;
615 
616                 if (s && *s == ':') {
617                         if (len <= 1)
618                                 err_return(EINVAL, "Invalid port number");
619 
620                         for (s++, len--, n = 0; len > 0; len--, s++) {
621                                 if (*s < '' || *s > '9')
622                                         err_return(EINVAL, "Invalid port number");
623 
624                                 n = n * 10 + (*s - '');
625                         }
626 
627                         if (n > 65535)
628                                 err_return(EINVAL, "Invalid port number");
629 
630                         s6->sin6_port = htons(n);
631                 }
632 
633                 *slen = (ss->ss_family == AF_INET6) ? sizeof(*s6) : sizeof(*s4);
634 
635                 ok_return(true);
636         }
637         else if (ucv_type(addr) == UC_ARRAY) {
638                 if (ucv_array_length(addr) == 16) {
639                         uint8_t *u8 = (uint8_t *)&s6->sin6_addr;
640 
641                         for (size_t i = 0; i < 16; i++) {
642                                 item = ucv_array_get(addr, i);
643                                 n = ucv_uint64_get(item);
644 
645                                 if (ucv_type(item) != UC_INTEGER || errno != 0 || n > 255)
646                                         err_return(EINVAL, "Invalid IP address array");
647 
648                                 u8[i] = n;
649                         }
650 
651                         s6->sin6_family = AF_INET6;
652                         *slen = sizeof(*s6);
653 
654                         ok_return(true);
655                 }
656                 else if (ucv_array_length(addr) == 4) {
657                         s4->sin_addr.s_addr = 0;
658 
659                         for (size_t i = 0; i < 4; i++) {
660                                 item = ucv_array_get(addr, i);
661                                 n = ucv_uint64_get(item);
662 
663                                 if (ucv_type(item) != UC_INTEGER || errno != 0 || n > 255)
664                                         err_return(EINVAL, "Invalid IP address array");
665 
666                                 s4->sin_addr.s_addr = s4->sin_addr.s_addr * 256 + n;
667                         }
668 
669                         s4->sin_addr.s_addr = htonl(s4->sin_addr.s_addr);
670                         s4->sin_family = AF_INET;
671                         *slen = sizeof(*s4);
672 
673                         ok_return(true);
674                 }
675 
676                 err_return(EINVAL, "Invalid IP address array");
677         }
678         else if (ucv_type(addr) == UC_OBJECT) {
679                 n = ucv_to_unsigned(ucv_object_get(addr, "family", NULL));
680 
681                 if (n == 0) {
682                         if (ucv_type(ucv_object_get(addr, "path", NULL)) == UC_STRING) {
683                                 n = AF_UNIX;
684                         }
685                         else {
686                                 item = ucv_object_get(addr, "address", NULL);
687                                 len = ucv_string_length(item);
688                                 s = ucv_string_get(item);
689                                 n = (s && memchr(s, ':', len) != NULL) ? AF_INET6 : AF_INET;
690                         }
691 
692                         if (n == 0)
693                                 err_return(EINVAL, "Invalid address object");
694                 }
695 
696                 switch (n) {
697                 case AF_INET6:
698                         item = ucv_object_get(addr, "flowinfo", NULL);
699                         s6->sin6_flowinfo = htonl(ucv_to_unsigned(item));
700 
701                         item = ucv_object_get(addr, "interface", NULL);
702 
703                         if (ucv_type(item) == UC_STRING) {
704                                 s6->sin6_scope_id = if_nametoindex(ucv_string_get(item));
705 
706                                 if (s6->sin6_scope_id == 0)
707                                         err_return(errno, "Unable to resolve interface %s",
708                                                 ucv_string_get(item));
709                         }
710                         else if (item != NULL) {
711                                 s6->sin6_scope_id = ucv_to_unsigned(item);
712 
713                                 if (errno != 0)
714                                         err_return(errno, "Invalid scope ID");
715                         }
716 
717                         /* fall through */
718 
719                 case AF_INET:
720                         ss->ss_family = n;
721                         *slen = (n == AF_INET6) ? sizeof(*s6) : sizeof(*s4);
722 
723                         item = ucv_object_get(addr, "port", NULL);
724                         n = ucv_to_unsigned(item);
725 
726                         if (errno != 0 || n > 65535)
727                                 err_return(EINVAL, "Invalid port number");
728 
729                         s6->sin6_port = htons(n);
730 
731                         item = ucv_object_get(addr, "address", NULL);
732                         len = ucv_string_length(item);
733                         s = ucv_string_get(item);
734 
735                         if (len >= sizeof(addrstr))
736                                 err_return(EINVAL, "Invalid IP address");
737 
738                         if (len > 0) {
739                                 memcpy(addrstr, s, len);
740                                 addrstr[len] = 0;
741 
742                                 if (!parse_addr(addrstr, ss))
743                                         return NULL;
744                         }
745 
746                         ok_return(true);
747 
748                 case AF_UNIX:
749                         item = ucv_object_get(addr, "path", NULL);
750                         len = ucv_string_length(item);
751 
752                         if (len == 0 || len >= sizeof(su->sun_path))
753                                 err_return(EINVAL, "Invalid path value");
754 
755                         memcpy(su->sun_path, ucv_string_get(item), len);
756                         su->sun_path[len++] = 0;
757                         su->sun_family = AF_UNIX;
758                         *slen = sizeof(*su);
759 
760                         ok_return(true);
761 
762 #if defined(__linux__)
763                 case AF_PACKET:
764                         item = ucv_object_get(addr, "protocol", NULL);
765 
766                         if (item) {
767                                 n = ucv_to_unsigned(item);
768 
769                                 if (errno != 0 || n > 65535)
770                                         err_return(EINVAL, "Invalid protocol number");
771 
772                                 sl->sll_protocol = htons(n);
773                         }
774 
775                         item = ucv_object_get(addr, "address", NULL);
776 
777                         if (uv_to_hwaddr(item, sl->sll_addr, &len))
778                                 sl->sll_halen = len;
779                         else
780                                 return false;
781 
782                         item = ucv_object_get(addr, "interface", NULL);
783 
784                         if (ucv_type(item) == UC_STRING) {
785                                 sl->sll_ifindex = if_nametoindex(ucv_string_get(item));
786 
787                                 if (sl->sll_ifindex == 0)
788                                         err_return(errno, "Unable to resolve interface %s",
789                                                 ucv_string_get(item));
790                         }
791                         else if (item != NULL) {
792                                 sl->sll_ifindex = ucv_to_integer(item);
793 
794                                 if (errno)
795                                         err_return(errno, "Unable to convert interface to integer");
796                         }
797 
798                         item = ucv_object_get(addr, "hardware_type", NULL);
799 
800                         if (item) {
801                                 n = ucv_to_unsigned(item);
802 
803                                 if (errno != 0 || n > 65535)
804                                         err_return(EINVAL, "Invalid hardware type");
805 
806                                 sl->sll_hatype = n;
807                         }
808 
809                         item = ucv_object_get(addr, "packet_type", NULL);
810 
811                         if (item) {
812                                 n = ucv_to_unsigned(item);
813 
814                                 if (errno != 0 || n > 255)
815                                         err_return(EINVAL, "Invalid packet type");
816 
817                                 sl->sll_pkttype = n;
818                         }
819 
820                         sl->sll_family = AF_PACKET;
821                         *slen = sizeof(*sl);
822 
823                         ok_return(true);
824 
825                 case AF_CAN:
826                         item = ucv_object_get(addr, "interface", NULL);
827 
828                         if (ucv_type(item) == UC_STRING) {
829                                 sc->can_ifindex = if_nametoindex(ucv_string_get(item));
830 
831                                 if (sc->can_ifindex == 0)
832                                         err_return(errno, "Unable to resolve interface %s",
833                                                 ucv_string_get(item));
834                         }
835                         else if (item != NULL) {
836                                 sc->can_ifindex = ucv_to_integer(item);
837 
838                                 if (errno)
839                                         err_return(errno, "Unable to convert interface to integer");
840                         }
841 
842                         sc->can_family = AF_CAN;
843                         *slen = sizeof(*sc);
844 
845                         ok_return(true);
846 #endif
847                 }
848         }
849 
850         err_return(EINVAL, "Invalid address value");
851 }
852 
853 static bool
854 uv_to_fileno(uc_vm_t *vm, uc_value_t *val, int *fileno)
855 {
856         uc_value_t *fn;
857         int *fdptr;
858 
859         fdptr = (int *)ucv_resource_dataptr(val, "socket");
860 
861         if (fdptr) {
862                 if (*fdptr < 0)
863                         err_return(EBADF, "Socket is closed");
864 
865                 *fileno = *fdptr;
866 
867                 return true;
868         }
869 
870         fn = ucv_property_get(val, "fileno");
871 
872         if (ucv_is_callable(fn)) {
873                 uc_vm_stack_push(vm, ucv_get(val));
874                 uc_vm_stack_push(vm, ucv_get(fn));
875 
876                 if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE)
877                         return false;
878 
879                 val = uc_vm_stack_pop(vm);
880         }
881         else {
882                 ucv_get(val);
883         }
884 
885         *fileno = ucv_int64_get(val);
886 
887         ucv_put(val);
888 
889         if (errno != 0 || *fileno < 0)
890                 err_return(EBADF, "Invalid file descriptor number");
891 
892         return true;
893 }
894 
895 static uc_value_t *
896 uv_to_pollfd(uc_vm_t *vm, uc_value_t *val, struct pollfd *pfd)
897 {
898         uc_value_t *rv;
899         int64_t flags;
900 
901         if (ucv_type(val) == UC_ARRAY) {
902                 if (!uv_to_fileno(vm, ucv_array_get(val, 0), &pfd->fd))
903                         return NULL;
904 
905                 flags = ucv_to_integer(ucv_array_get(val, 1));
906 
907                 if (errno != 0 || flags < -32768 || flags > 32767)
908                         err_return(ERANGE, "Flags value out of range");
909 
910                 pfd->events = flags;
911                 pfd->revents = 0;
912 
913                 return ucv_get(val);
914         }
915 
916         if (!uv_to_fileno(vm, val, &pfd->fd))
917                 return NULL;
918 
919         pfd->events = POLLIN | POLLERR | POLLHUP;
920         pfd->revents = 0;
921 
922         rv = ucv_array_new_length(vm, 2);
923 
924         ucv_array_set(rv, 0, ucv_get(val));
925         ucv_array_set(rv, 1, ucv_uint64_new(pfd->events));
926 
927         return rv;
928 }
929 
930 static uc_value_t *
931 ucv_socket_new(uc_vm_t *vm, int fd)
932 {
933         return ucv_resource_new(
934                 ucv_resource_type_lookup(vm, "socket"),
935                 (void *)(intptr_t)fd
936         );
937 }
938 
939 static bool
940 xclose(int *fdptr)
941 {
942         bool rv = true;
943 
944         if (fdptr) {
945                 if (*fdptr >= 0)
946                         rv = (close(*fdptr) == 0);
947 
948                 *fdptr = -1;
949         }
950 
951         return rv;
952 }
953 
954 
955 typedef struct {
956     const char *name;
957     enum { DT_SIGNED, DT_UNSIGNED, DT_IPV4ADDR, DT_IPV6ADDR, DT_CALLBACK } type;
958         union {
959         size_t offset;
960                 bool (*to_c)(void *, uc_value_t *);
961         } u1;
962         union {
963                 size_t size;
964                 uc_value_t *(*to_uv)(void *);
965         } u2;
966 } member_t;
967 
968 typedef struct {
969         size_t size;
970         member_t *members;
971 } struct_t;
972 
973 typedef struct {
974         int level;
975         int option;
976         struct_t *ctype;
977 } sockopt_t;
978 
979 typedef struct {
980         int level;
981         int type;
982         struct_t *ctype;
983 } cmsgtype_t;
984 
985 #define STRUCT_MEMBER_NP(struct_name, member_name, data_type)   \
986         { #member_name, data_type,                                                                      \
987           { .offset = offsetof(struct struct_name, member_name) },      \
988           { .size = sizeof(((struct struct_name *)NULL)->member_name) } }
989 
990 #define STRUCT_MEMBER_CB(member_name, to_c_fn, to_uv_fn)                \
991         { #member_name, DT_CALLBACK, { .to_c = to_c_fn }, { .to_uv = to_uv_fn } }
992 
993 #define STRUCT_MEMBER(struct_name, member_prefix, member_name, data_type)                       \
994         { #member_name, data_type,                                                                                                              \
995           { .offset = offsetof(struct struct_name, member_prefix##_##member_name) },    \
996           { .size = sizeof(((struct struct_name *)NULL)->member_prefix##_##member_name) } }
997 
998 static struct_t st_timeval = {
999         .size = sizeof(struct timeval),
1000         .members = (member_t []){
1001                 STRUCT_MEMBER(timeval, tv, sec, DT_SIGNED),
1002                 STRUCT_MEMBER(timeval, tv, usec, DT_SIGNED),
1003                 { 0 }
1004         }
1005 };
1006 
1007 #if defined(__linux__)
1008 static bool
1009 filter_to_c(void *st, uc_value_t *uv)
1010 {
1011         struct sock_fprog **fpp = st;
1012         struct sock_fprog *fp = *fpp;
1013         size_t i, len;
1014 
1015         if (ucv_type(uv) == UC_STRING) {
1016                 size_t len = ucv_string_length(uv);
1017 
1018                 if (len == 0 || (len % sizeof(struct sock_filter)) != 0)
1019                         err_return(EINVAL, "Filter program length not a multiple of %zu",
1020                                 sizeof(struct sock_filter));
1021 
1022                 fp = *fpp = xrealloc(fp, sizeof(struct sock_fprog) + len);
1023                 fp->filter = memcpy((char *)fp + sizeof(struct sock_fprog), ucv_string_get(uv), len);
1024 
1025                 if (fp->len == 0)
1026                         fp->len = len / sizeof(struct sock_filter);
1027         }
1028         else if (ucv_type(uv) == UC_ARRAY) {
1029                 /* Opcode array of array. Each sub-array is a 4 element tuple */
1030                 if (ucv_type(ucv_array_get(uv, 0)) == UC_ARRAY) {
1031                         len = ucv_array_length(uv);
1032 
1033                         fp = *fpp = xrealloc(fp, sizeof(struct sock_fprog)
1034                                 + (len * sizeof(struct sock_filter)));
1035 
1036                         fp->filter = (struct sock_filter *)((char *)fp + sizeof(struct sock_fprog));
1037 
1038                         for (i = 0; i < len; i++) {
1039                                 uc_value_t *op = ucv_array_get(uv, i);
1040 
1041                                 if (ucv_type(op) != UC_ARRAY)
1042                                         continue;
1043 
1044                                 fp->filter[i].code = ucv_to_unsigned(ucv_array_get(op, 0));
1045                                 fp->filter[i].jt = ucv_to_unsigned(ucv_array_get(op, 1));
1046                                 fp->filter[i].jf = ucv_to_unsigned(ucv_array_get(op, 2));
1047                                 fp->filter[i].k = ucv_to_unsigned(ucv_array_get(op, 3));
1048                         }
1049                 }
1050 
1051                 /* Flat opcode array, must be a multiple of 4 */
1052                 else {
1053                         len = ucv_array_length(uv);
1054 
1055                         if (len % 4)
1056                                 err_return(EINVAL, "Opcode array length not a multiple of 4");
1057 
1058                         len /= 4;
1059 
1060                         fp = *fpp = xrealloc(fp, sizeof(struct sock_fprog)
1061                                 + (len * sizeof(struct sock_filter)));
1062 
1063                         fp->filter = (struct sock_filter *)((char *)fp + sizeof(struct sock_fprog));
1064 
1065                         for (i = 0; i < len; i++) {
1066                                 fp->filter[i].code = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 0));
1067                                 fp->filter[i].jt = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 1));
1068                                 fp->filter[i].jf = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 2));
1069                                 fp->filter[i].k = ucv_to_unsigned(ucv_array_get(uv, i * 4 + 3));
1070                         }
1071                 }
1072 
1073                 if (fp->len == 0)
1074                         fp->len = i;
1075         }
1076         else {
1077                 err_return(EINVAL, "Expecting either BPF bytecode string or array of opcodes");
1078         }
1079 
1080         return true;
1081 }
1082 
1083 static struct_t st_sock_fprog = {
1084         .size = sizeof(struct sock_fprog),
1085         .members = (member_t []){
1086                 STRUCT_MEMBER_NP(sock_fprog, len, DT_UNSIGNED),
1087                 STRUCT_MEMBER_CB(filter, filter_to_c, NULL),
1088                 { 0 }
1089         }
1090 };
1091 
1092 static struct_t st_ucred = {
1093         .size = sizeof(struct ucred),
1094         .members = (member_t []){
1095                 STRUCT_MEMBER_NP(ucred, pid, DT_SIGNED),
1096                 STRUCT_MEMBER_NP(ucred, uid, DT_SIGNED),
1097                 STRUCT_MEMBER_NP(ucred, gid, DT_SIGNED),
1098                 { 0 }
1099         }
1100 };
1101 #endif
1102 
1103 static struct_t st_linger = {
1104         .size = sizeof(struct linger),
1105         .members = (member_t []){
1106                 STRUCT_MEMBER(linger, l, onoff, DT_SIGNED),
1107                 STRUCT_MEMBER(linger, l, linger, DT_SIGNED),
1108                 { 0 }
1109         }
1110 };
1111 
1112 static struct_t st_ip_mreqn = {
1113         .size = sizeof(struct ip_mreqn),
1114         .members = (member_t []){
1115                 STRUCT_MEMBER(ip_mreqn, imr, multiaddr, DT_IPV4ADDR),
1116                 STRUCT_MEMBER(ip_mreqn, imr, address, DT_IPV4ADDR),
1117                 STRUCT_MEMBER(ip_mreqn, imr, ifindex, DT_SIGNED),
1118                 { 0 }
1119         }
1120 };
1121 
1122 static struct_t st_ip_mreq_source = {
1123         .size = sizeof(struct ip_mreq_source),
1124         .members = (member_t []){
1125                 STRUCT_MEMBER(ip_mreq_source, imr, multiaddr, DT_IPV4ADDR),
1126                 STRUCT_MEMBER(ip_mreq_source, imr, interface, DT_IPV4ADDR),
1127                 STRUCT_MEMBER(ip_mreq_source, imr, sourceaddr, DT_IPV4ADDR),
1128                 { 0 }
1129         }
1130 };
1131 
1132 /* This structure is declared in kernel, but not libc headers, so redeclare it
1133    locally */
1134 struct in6_flowlabel_req_local {
1135         struct in6_addr flr_dst;
1136         uint32_t flr_label;
1137         uint8_t flr_action;
1138         uint8_t flr_share;
1139         uint16_t flr_flags;
1140         uint16_t flr_expires;
1141         uint16_t flr_linger;
1142 };
1143 
1144 static struct_t st_in6_flowlabel_req = {
1145         .size = sizeof(struct in6_flowlabel_req_local),
1146         .members = (member_t []){
1147                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, dst, DT_IPV6ADDR),
1148                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, label, DT_UNSIGNED),
1149                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, action, DT_UNSIGNED),
1150                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, share, DT_UNSIGNED),
1151                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, flags, DT_UNSIGNED),
1152                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, expires, DT_UNSIGNED),
1153                 STRUCT_MEMBER(in6_flowlabel_req_local, flr, linger, DT_UNSIGNED),
1154                 { 0 }
1155         }
1156 };
1157 
1158 #if defined(__linux__)
1159 static uc_value_t *
1160 in6_ifindex_to_uv(void *st)
1161 {
1162         char ifname[IF_NAMESIZE] = { 0 };
1163         struct ipv6_mreq *mr = st;
1164 
1165         if (mr->ipv6mr_interface > 0 && if_indextoname(mr->ipv6mr_interface, ifname))
1166                 return ucv_string_new(ifname);
1167 
1168         return ucv_int64_new(mr->ipv6mr_interface);
1169 }
1170 
1171 static bool
1172 in6_ifindex_to_c(void *st, uc_value_t *uv)
1173 {
1174         struct ipv6_mreq *mr = *(struct ipv6_mreq **)st;
1175 
1176         if (ucv_type(uv) == UC_STRING) {
1177                 mr->ipv6mr_interface = if_nametoindex(ucv_string_get(uv));
1178 
1179                 if (mr->ipv6mr_interface == 0)
1180                         err_return(errno, "Unable to resolve interface %s",
1181                                 ucv_string_get(uv));
1182         }
1183         else {
1184                 mr->ipv6mr_interface = ucv_to_integer(uv);
1185 
1186                 if (errno)
1187                         err_return(errno, "Unable to convert interface to integer");
1188         }
1189 
1190         return true;
1191 }
1192 
1193 static struct_t st_ipv6_mreq = {
1194         .size = sizeof(struct ipv6_mreq),
1195         .members = (member_t []){
1196                 STRUCT_MEMBER(ipv6_mreq, ipv6mr, multiaddr, DT_IPV6ADDR),
1197                 STRUCT_MEMBER_CB(interface, in6_ifindex_to_c, in6_ifindex_to_uv),
1198                 { 0 }
1199         }
1200 };
1201 
1202 /* NB: this is the same layout as struct ipv6_mreq, so we reuse the callbacks */
1203 static struct_t st_in6_pktinfo = {
1204         .size = sizeof(struct in6_pktinfo),
1205         .members = (member_t []){
1206                 STRUCT_MEMBER(in6_pktinfo, ipi6, addr, DT_IPV6ADDR),
1207                 STRUCT_MEMBER_CB(interface, in6_ifindex_to_c, in6_ifindex_to_uv),
1208                 { 0 }
1209         }
1210 };
1211 
1212 struct ipv6_recv_error_local {
1213         struct {
1214                 uint32_t ee_errno;
1215                 uint8_t ee_origin;
1216                 uint8_t ee_type;
1217                 uint8_t ee_code;
1218                 uint8_t ee_pad;
1219                 uint32_t ee_info;
1220                 union {
1221                         uint32_t ee_data;
1222                         struct {
1223                                 uint16_t ee_len;
1224                                 uint8_t ee_flags;
1225                                 uint8_t ee_reserved;
1226                         } ee_rfc4884;
1227                 } u;
1228         } ee;
1229         struct sockaddr_in6 offender;
1230 };
1231 
1232 static uc_value_t *
1233 offender_to_uv(void *st)
1234 {
1235         struct ipv6_recv_error_local *e = st;
1236         uc_value_t *addr = ucv_object_new(NULL);
1237 
1238         if (sockaddr_to_uv((struct sockaddr_storage *)&e->offender, addr))
1239                 return addr;
1240 
1241         ucv_put(addr);
1242 
1243         return NULL;
1244 }
1245 
1246 static struct_t st_ip_recv_error = {
1247         .size = sizeof(struct ipv6_recv_error_local),
1248         .members = (member_t []){
1249                 STRUCT_MEMBER(ipv6_recv_error_local, ee.ee, errno, DT_UNSIGNED),
1250                 STRUCT_MEMBER(ipv6_recv_error_local, ee.ee, origin, DT_UNSIGNED),
1251                 STRUCT_MEMBER(ipv6_recv_error_local, ee.ee, type, DT_UNSIGNED),
1252                 STRUCT_MEMBER(ipv6_recv_error_local, ee.ee, code, DT_UNSIGNED),
1253                 STRUCT_MEMBER(ipv6_recv_error_local, ee.ee, info, DT_UNSIGNED),
1254                 STRUCT_MEMBER(ipv6_recv_error_local, ee.u.ee, data, DT_UNSIGNED),
1255                 STRUCT_MEMBER(ipv6_recv_error_local, ee.u.ee_rfc4884.ee, len, DT_UNSIGNED),
1256                 STRUCT_MEMBER(ipv6_recv_error_local, ee.u.ee_rfc4884.ee, flags, DT_UNSIGNED),
1257                 STRUCT_MEMBER_CB(offender, NULL, offender_to_uv),
1258                 { 0 }
1259         }
1260 };
1261 
1262 static uc_value_t *
1263 ip6m_addr_to_uv(void *st)
1264 {
1265         struct ip6_mtuinfo *mi = st;
1266         uc_value_t *addr = ucv_object_new(NULL);
1267 
1268         if (sockaddr_to_uv((struct sockaddr_storage *)&mi->ip6m_addr, addr))
1269                 return addr;
1270 
1271         ucv_put(addr);
1272 
1273         return NULL;
1274 }
1275 
1276 static struct_t st_ip6_mtuinfo = {
1277         .size = sizeof(struct ip6_mtuinfo),
1278         .members = (member_t []){
1279                 STRUCT_MEMBER_CB(addr, NULL, ip6m_addr_to_uv),
1280                 STRUCT_MEMBER(ip6_mtuinfo, ip6m, mtu, DT_UNSIGNED),
1281                 { 0 }
1282         }
1283 };
1284 
1285 static struct_t st_ip_msfilter = {
1286         .size = sizeof(struct ip_msfilter),
1287         .members = (member_t []){
1288                 STRUCT_MEMBER(ip_msfilter, imsf, multiaddr, DT_IPV4ADDR),
1289                 STRUCT_MEMBER(ip_msfilter, imsf, interface, DT_IPV4ADDR),
1290                 STRUCT_MEMBER(ip_msfilter, imsf, fmode, DT_SIGNED),
1291                 STRUCT_MEMBER(ip_msfilter, imsf, numsrc, DT_SIGNED),
1292                 STRUCT_MEMBER(ip_msfilter, imsf, slist, DT_SIGNED),
1293                 { 0 }
1294         }
1295 };
1296 
1297 static uc_value_t *
1298 snd_wscale_to_uv(void *st)
1299 {
1300         return ucv_uint64_new(((struct tcp_info *)st)->tcpi_snd_wscale);
1301 }
1302 
1303 static uc_value_t *
1304 rcv_wscale_to_uv(void *st)
1305 {
1306         return ucv_uint64_new(((struct tcp_info *)st)->tcpi_rcv_wscale);
1307 }
1308 
1309 static bool
1310 snd_wscale_to_c(void *st, uc_value_t *uv)
1311 {
1312         struct tcp_info *ti = *(struct tcp_info **)st;
1313 
1314         ti->tcpi_snd_wscale = ucv_to_unsigned(uv);
1315 
1316         if (errno)
1317                 err_return(errno, "Unable to convert field snd_wscale to unsigned");
1318 
1319         return true;
1320 }
1321 
1322 static bool
1323 rcv_wscale_to_c(void *st, uc_value_t *uv)
1324 {
1325         struct tcp_info *ti = *(struct tcp_info **)st;
1326 
1327         ti->tcpi_rcv_wscale = ucv_to_unsigned(uv);
1328 
1329         if (errno)
1330                 err_return(errno, "Unable to convert field rcv_wscale to unsigned");
1331 
1332         return true;
1333 }
1334 
1335 static struct_t st_tcp_info = {
1336         .size = sizeof(struct tcp_info),
1337         .members = (member_t []){
1338                 STRUCT_MEMBER(tcp_info, tcpi, state, DT_UNSIGNED),
1339                 STRUCT_MEMBER(tcp_info, tcpi, ca_state, DT_UNSIGNED),
1340                 STRUCT_MEMBER(tcp_info, tcpi, retransmits, DT_UNSIGNED),
1341                 STRUCT_MEMBER(tcp_info, tcpi, probes, DT_UNSIGNED),
1342                 STRUCT_MEMBER(tcp_info, tcpi, backoff, DT_UNSIGNED),
1343                 STRUCT_MEMBER(tcp_info, tcpi, options, DT_UNSIGNED),
1344                 STRUCT_MEMBER_CB(snd_wscale, snd_wscale_to_c, snd_wscale_to_uv),
1345                 STRUCT_MEMBER_CB(rcv_wscale, rcv_wscale_to_c, rcv_wscale_to_uv),
1346                 STRUCT_MEMBER(tcp_info, tcpi, rto, DT_UNSIGNED),
1347                 STRUCT_MEMBER(tcp_info, tcpi, ato, DT_UNSIGNED),
1348                 STRUCT_MEMBER(tcp_info, tcpi, snd_mss, DT_UNSIGNED),
1349                 STRUCT_MEMBER(tcp_info, tcpi, rcv_mss, DT_UNSIGNED),
1350                 STRUCT_MEMBER(tcp_info, tcpi, unacked, DT_UNSIGNED),
1351                 STRUCT_MEMBER(tcp_info, tcpi, sacked, DT_UNSIGNED),
1352                 STRUCT_MEMBER(tcp_info, tcpi, lost, DT_UNSIGNED),
1353                 STRUCT_MEMBER(tcp_info, tcpi, retrans, DT_UNSIGNED),
1354                 STRUCT_MEMBER(tcp_info, tcpi, fackets, DT_UNSIGNED),
1355                 STRUCT_MEMBER(tcp_info, tcpi, last_data_sent, DT_UNSIGNED),
1356                 STRUCT_MEMBER(tcp_info, tcpi, last_ack_sent, DT_UNSIGNED),
1357                 STRUCT_MEMBER(tcp_info, tcpi, last_data_recv, DT_UNSIGNED),
1358                 STRUCT_MEMBER(tcp_info, tcpi, last_ack_recv, DT_UNSIGNED),
1359                 STRUCT_MEMBER(tcp_info, tcpi, pmtu, DT_UNSIGNED),
1360                 STRUCT_MEMBER(tcp_info, tcpi, rcv_ssthresh, DT_UNSIGNED),
1361                 STRUCT_MEMBER(tcp_info, tcpi, rtt, DT_UNSIGNED),
1362                 STRUCT_MEMBER(tcp_info, tcpi, rttvar, DT_UNSIGNED),
1363                 STRUCT_MEMBER(tcp_info, tcpi, snd_ssthresh, DT_UNSIGNED),
1364                 STRUCT_MEMBER(tcp_info, tcpi, snd_cwnd, DT_UNSIGNED),
1365                 STRUCT_MEMBER(tcp_info, tcpi, advmss, DT_UNSIGNED),
1366                 STRUCT_MEMBER(tcp_info, tcpi, reordering, DT_UNSIGNED),
1367                 STRUCT_MEMBER(tcp_info, tcpi, rcv_rtt, DT_UNSIGNED),
1368                 STRUCT_MEMBER(tcp_info, tcpi, rcv_space, DT_UNSIGNED),
1369                 STRUCT_MEMBER(tcp_info, tcpi, total_retrans, DT_UNSIGNED),
1370                 { 0 }
1371         }
1372 };
1373 #endif
1374 
1375 static uc_value_t *
1376 ai_addr_to_uv(void *st)
1377 {
1378         uc_value_t *rv = ucv_object_new(NULL);
1379         struct sockaddr_storage ss = { 0 };
1380         struct addrinfo *ai = st;
1381 
1382         memcpy(&ss, ai->ai_addr, ai->ai_addrlen);
1383 
1384         if (!sockaddr_to_uv(&ss, rv)) {
1385                 ucv_put(rv);
1386                 return NULL;
1387         }
1388 
1389         return rv;
1390 }
1391 
1392 static uc_value_t *
1393 ai_canonname_to_uv(void *st)
1394 {
1395         struct addrinfo *ai = st;
1396         return ai->ai_canonname ? ucv_string_new(ai->ai_canonname) : NULL;
1397 }
1398 
1399 /**
1400  * Represents a network address information object returned by
1401  * {@link module:socket#addrinfo|`addrinfo()`}.
1402  *
1403  * @typedef {Object} module:socket.AddressInfo
1404  *
1405  * @property {module:socket.socket.SocketAddress} addr - A socket address structure.
1406  * @property {string} [canonname=null] - The canonical hostname associated with the address.
1407  * @property {number} family - The address family (e.g., `2` for `AF_INET`, `10` for `AF_INET6`).
1408  * @property {number} flags - Additional flags indicating properties of the address.
1409  * @property {number} protocol - The protocol number.
1410  * @property {number} socktype - The socket type (e.g., `1` for `SOCK_STREAM`, `2` for `SOCK_DGRAM`).
1411  */
1412 static struct_t st_addrinfo = {
1413         .size = sizeof(struct addrinfo),
1414         .members = (member_t []){
1415                 STRUCT_MEMBER(addrinfo, ai, flags, DT_SIGNED),
1416                 STRUCT_MEMBER(addrinfo, ai, family, DT_SIGNED),
1417                 STRUCT_MEMBER(addrinfo, ai, socktype, DT_SIGNED),
1418                 STRUCT_MEMBER(addrinfo, ai, protocol, DT_SIGNED),
1419                 STRUCT_MEMBER_CB(addr, NULL, ai_addr_to_uv),
1420                 STRUCT_MEMBER_CB(canonname, NULL, ai_canonname_to_uv),
1421                 { 0 }
1422         }
1423 };
1424 
1425 #if defined(__linux__)
1426 static uc_value_t *
1427 mr_ifindex_to_uv(void *st)
1428 {
1429         char ifname[IF_NAMESIZE] = { 0 };
1430         struct packet_mreq *mr = st;
1431 
1432         if (mr->mr_ifindex > 0 && if_indextoname(mr->mr_ifindex, ifname))
1433                 return ucv_string_new(ifname);
1434 
1435         return ucv_int64_new(mr->mr_ifindex);
1436 }
1437 
1438 static bool
1439 mr_ifindex_to_c(void *st, uc_value_t *uv)
1440 {
1441         struct packet_mreq *mr = *(struct packet_mreq **)st;
1442 
1443         if (ucv_type(uv) == UC_STRING) {
1444                 mr->mr_ifindex = if_nametoindex(ucv_string_get(uv));
1445 
1446                 if (mr->mr_ifindex == 0)
1447                         err_return(errno, "Unable to resolve interface %s",
1448                                 ucv_string_get(uv));
1449         }
1450         else {
1451                 mr->mr_ifindex = ucv_to_integer(uv);
1452 
1453                 if (errno)
1454                         err_return(errno, "Unable to convert interface to integer");
1455         }
1456 
1457         return true;
1458 }
1459 
1460 static uc_value_t *
1461 mr_address_to_uv(void *st)
1462 {
1463         struct packet_mreq *mr = st;
1464 
1465         return hwaddr_to_uv(mr->mr_address, mr->mr_alen);
1466 }
1467 
1468 static bool
1469 mr_address_to_c(void *st, uc_value_t *uv)
1470 {
1471         struct packet_mreq *mr = *(struct packet_mreq **)st;
1472         size_t len;
1473 
1474         if (!uv_to_hwaddr(uv, mr->mr_address, &len))
1475                 return false;
1476 
1477         mr->mr_alen = len;
1478 
1479         return true;
1480 }
1481 
1482 static struct_t st_packet_mreq = {
1483         .size = sizeof(struct packet_mreq),
1484         .members = (member_t []){
1485                 STRUCT_MEMBER_CB(interface, mr_ifindex_to_c, mr_ifindex_to_uv),
1486                 STRUCT_MEMBER(packet_mreq, mr, type, DT_UNSIGNED),
1487                 STRUCT_MEMBER_CB(address, mr_address_to_c, mr_address_to_uv),
1488                 { 0 }
1489         }
1490 };
1491 
1492 static struct_t st_tpacket_req = {
1493         .size = sizeof(struct tpacket_req),
1494         .members = (member_t []){
1495                 STRUCT_MEMBER(tpacket_req, tp, block_size, DT_UNSIGNED),
1496                 STRUCT_MEMBER(tpacket_req, tp, block_nr, DT_UNSIGNED),
1497                 STRUCT_MEMBER(tpacket_req, tp, frame_size, DT_UNSIGNED),
1498                 STRUCT_MEMBER(tpacket_req, tp, frame_nr, DT_UNSIGNED),
1499                 { 0 }
1500         }
1501 };
1502 
1503 static struct_t st_tpacket_stats = {
1504         .size = sizeof(struct tpacket_stats),
1505         .members = (member_t []){
1506                 STRUCT_MEMBER(tpacket_stats, tp, packets, DT_UNSIGNED),
1507                 STRUCT_MEMBER(tpacket_stats, tp, drops, DT_UNSIGNED),
1508                 { 0 }
1509         }
1510 };
1511 
1512 static struct_t st_tpacket_auxdata = {
1513         .size = sizeof(struct tpacket_auxdata),
1514         .members = (member_t []){
1515                 STRUCT_MEMBER(tpacket_auxdata, tp, status, DT_UNSIGNED),
1516                 STRUCT_MEMBER(tpacket_auxdata, tp, len, DT_UNSIGNED),
1517                 STRUCT_MEMBER(tpacket_auxdata, tp, snaplen, DT_UNSIGNED),
1518                 STRUCT_MEMBER(tpacket_auxdata, tp, mac, DT_UNSIGNED),
1519                 STRUCT_MEMBER(tpacket_auxdata, tp, net, DT_UNSIGNED),
1520                 STRUCT_MEMBER(tpacket_auxdata, tp, vlan_tci, DT_UNSIGNED),
1521                 STRUCT_MEMBER(tpacket_auxdata, tp, vlan_tpid, DT_UNSIGNED),
1522                 { 0 }
1523         }
1524 };
1525 
1526 struct fanout_args_local {
1527 #if __BYTE_ORDER == __LITTLE_ENDIAN
1528         uint16_t id;
1529         uint16_t type_flags;
1530 #else
1531         uint16_t type_flags;
1532         uint16_t id;
1533 #endif
1534         uint32_t max_num_members;
1535 };
1536 
1537 static struct_t st_fanout_args = {
1538         .size = sizeof(struct fanout_args_local),
1539         .members = (member_t []){
1540                 STRUCT_MEMBER_NP(fanout_args_local, id, DT_UNSIGNED),
1541                 STRUCT_MEMBER_NP(fanout_args_local, type_flags, DT_UNSIGNED),
1542                 STRUCT_MEMBER_NP(fanout_args_local, max_num_members, DT_UNSIGNED),
1543                 { 0 }
1544         }
1545 };
1546 
1547 struct timeval_old_local {
1548         long tv_sec;
1549 #if defined(__sparc__) && defined(__arch64__)
1550         int tv_usec;
1551 #else
1552         long tv_usec;
1553 #endif
1554 };
1555 
1556 static struct_t st_timeval_old = {
1557         .size = sizeof(struct timeval_old_local),
1558         .members = (member_t []){
1559                 STRUCT_MEMBER(timeval_old_local, tv, sec, DT_SIGNED),
1560                 STRUCT_MEMBER(timeval_old_local, tv, usec, DT_SIGNED),
1561                 { 0 }
1562         }
1563 };
1564 
1565 # ifdef SO_TIMESTAMP_NEW
1566 struct timeval_new_local { int64_t tv_sec; int64_t tv_usec; };
1567 static struct_t st_timeval_new = {
1568         .size = sizeof(struct timeval_old_local),
1569         .members = (member_t []){
1570                 STRUCT_MEMBER(timeval_new_local, tv, sec, DT_SIGNED),
1571                 STRUCT_MEMBER(timeval_new_local, tv, usec, DT_SIGNED),
1572                 { 0 }
1573         }
1574 };
1575 # endif
1576 
1577 struct timespec_old_local { long tv_sec; long tv_nsec; };
1578 static struct_t st_timespec_old = {
1579         .size = sizeof(struct timespec_old_local),
1580         .members = (member_t []){
1581                 STRUCT_MEMBER(timespec_old_local, tv, sec, DT_SIGNED),
1582                 STRUCT_MEMBER(timespec_old_local, tv, nsec, DT_SIGNED),
1583                 { 0 }
1584         }
1585 };
1586 
1587 # ifdef SO_TIMESTAMPNS_NEW
1588 struct timespec_new_local { long long tv_sec; long long tv_nsec; };
1589 static struct_t st_timespec_new = {
1590         .size = sizeof(struct timespec_new_local),
1591         .members = (member_t []){
1592                 STRUCT_MEMBER(timespec_new_local, tv, sec, DT_SIGNED),
1593                 STRUCT_MEMBER(timespec_new_local, tv, nsec, DT_SIGNED),
1594                 { 0 }
1595         }
1596 };
1597 # endif
1598 #endif
1599 
1600 #define SV_VOID         (struct_t *)0
1601 #define SV_INT          (struct_t *)1
1602 #define SV_INT_RO       (struct_t *)2
1603 #define SV_BOOL         (struct_t *)3
1604 #define SV_STRING       (struct_t *)4
1605 #define SV_IFNAME       (struct_t *)5
1606 
1607 #define CV_INT          (struct_t *)0
1608 #define CV_UINT         (struct_t *)1
1609 #define CV_BE32         (struct_t *)2
1610 #define CV_STRING       (struct_t *)3
1611 #define CV_SOCKADDR     (struct_t *)4
1612 #define CV_FDS          (struct_t *)5
1613 
1614 static sockopt_t sockopts[] = {
1615     { SOL_SOCKET, SO_ACCEPTCONN, SV_BOOL },
1616     { SOL_SOCKET, SO_BROADCAST, SV_BOOL },
1617     { SOL_SOCKET, SO_DEBUG, SV_BOOL },
1618     { SOL_SOCKET, SO_ERROR, SV_INT_RO },
1619     { SOL_SOCKET, SO_DONTROUTE, SV_BOOL },
1620     { SOL_SOCKET, SO_KEEPALIVE, SV_BOOL },
1621     { SOL_SOCKET, SO_LINGER, &st_linger },
1622     { SOL_SOCKET, SO_OOBINLINE, SV_BOOL },
1623     { SOL_SOCKET, SO_RCVBUF, SV_INT },
1624     { SOL_SOCKET, SO_RCVLOWAT, SV_INT },
1625     { SOL_SOCKET, SO_RCVTIMEO, &st_timeval },
1626     { SOL_SOCKET, SO_REUSEADDR, SV_BOOL },
1627     { SOL_SOCKET, SO_REUSEPORT, SV_BOOL },
1628     { SOL_SOCKET, SO_SNDBUF, SV_INT },
1629     { SOL_SOCKET, SO_SNDLOWAT, SV_INT },
1630     { SOL_SOCKET, SO_SNDTIMEO, &st_timeval },
1631     { SOL_SOCKET, SO_TIMESTAMP, SV_BOOL },
1632     { SOL_SOCKET, SO_TYPE, SV_INT },
1633 #if defined(__linux__)
1634     { SOL_SOCKET, SO_ATTACH_FILTER, &st_sock_fprog },
1635     { SOL_SOCKET, SO_ATTACH_BPF, SV_INT },
1636     { SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, SV_STRING },
1637     { SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, SV_INT },
1638     { SOL_SOCKET, SO_BINDTODEVICE, SV_STRING },
1639     { SOL_SOCKET, SO_DETACH_FILTER, SV_VOID },
1640     { SOL_SOCKET, SO_DETACH_BPF, SV_VOID },
1641     { SOL_SOCKET, SO_DOMAIN, SV_INT_RO },
1642     { SOL_SOCKET, SO_INCOMING_CPU, SV_INT },
1643     { SOL_SOCKET, SO_INCOMING_NAPI_ID, SV_INT_RO },
1644     { SOL_SOCKET, SO_LOCK_FILTER, SV_INT },
1645     { SOL_SOCKET, SO_MARK, SV_INT },
1646     { SOL_SOCKET, SO_PASSCRED, SV_BOOL },
1647     { SOL_SOCKET, SO_PASSSEC, SV_BOOL },
1648     { SOL_SOCKET, SO_PEEK_OFF, SV_INT },
1649     { SOL_SOCKET, SO_PEERCRED, &st_ucred },
1650     { SOL_SOCKET, SO_PEERSEC, SV_STRING },
1651     { SOL_SOCKET, SO_PRIORITY, SV_INT },
1652     { SOL_SOCKET, SO_PROTOCOL, SV_INT },
1653     { SOL_SOCKET, SO_RCVBUFFORCE, SV_INT },
1654     { SOL_SOCKET, SO_RXQ_OVFL, SV_BOOL },
1655     { SOL_SOCKET, SO_SNDBUFFORCE, SV_INT },
1656     { SOL_SOCKET, SO_TIMESTAMPNS, SV_BOOL },
1657     { SOL_SOCKET, SO_BUSY_POLL, SV_INT },
1658 #endif
1659 
1660     { IPPROTO_IP, IP_ADD_MEMBERSHIP, &st_ip_mreqn },
1661     { IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &st_ip_mreq_source },
1662     { IPPROTO_IP, IP_BLOCK_SOURCE, &st_ip_mreq_source },
1663     { IPPROTO_IP, IP_DROP_MEMBERSHIP, &st_ip_mreqn },
1664     { IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, &st_ip_mreq_source },
1665     { IPPROTO_IP, IP_HDRINCL, SV_BOOL },
1666     { IPPROTO_IP, IP_MULTICAST_IF, &st_ip_mreqn },
1667     { IPPROTO_IP, IP_MULTICAST_LOOP, SV_BOOL },
1668     { IPPROTO_IP, IP_MULTICAST_TTL, SV_INT },
1669     { IPPROTO_IP, IP_OPTIONS, SV_STRING },
1670     { IPPROTO_IP, IP_PKTINFO, SV_BOOL },
1671     { IPPROTO_IP, IP_RECVOPTS, SV_BOOL },
1672     { IPPROTO_IP, IP_RECVTOS, SV_BOOL },
1673     { IPPROTO_IP, IP_RECVTTL, SV_BOOL },
1674     { IPPROTO_IP, IP_RETOPTS, SV_BOOL },
1675     { IPPROTO_IP, IP_TOS, SV_INT },
1676     { IPPROTO_IP, IP_TTL, SV_INT },
1677     { IPPROTO_IP, IP_UNBLOCK_SOURCE, &st_ip_mreq_source },
1678 #if defined(__linux__)
1679     { IPPROTO_IP, IP_MSFILTER, &st_ip_msfilter },
1680     { IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, SV_BOOL },
1681     { IPPROTO_IP, IP_FREEBIND, SV_BOOL },
1682     { IPPROTO_IP, IP_MTU, SV_INT },
1683     { IPPROTO_IP, IP_MTU_DISCOVER, SV_INT },
1684     { IPPROTO_IP, IP_MULTICAST_ALL, SV_BOOL },
1685     { IPPROTO_IP, IP_NODEFRAG, SV_BOOL },
1686     { IPPROTO_IP, IP_PASSSEC, SV_BOOL },
1687     { IPPROTO_IP, IP_RECVERR, SV_BOOL },
1688     { IPPROTO_IP, IP_RECVORIGDSTADDR, SV_BOOL },
1689     { IPPROTO_IP, IP_ROUTER_ALERT, SV_BOOL },
1690     { IPPROTO_IP, IP_TRANSPARENT, SV_BOOL },
1691 #endif
1692 
1693         { IPPROTO_IPV6, IPV6_FLOWINFO_SEND, SV_BOOL },
1694         { IPPROTO_IPV6, IPV6_FLOWINFO, SV_BOOL },
1695         { IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, &st_in6_flowlabel_req },
1696         { IPPROTO_IPV6, IPV6_MULTICAST_HOPS, SV_INT },
1697         { IPPROTO_IPV6, IPV6_MULTICAST_IF, SV_IFNAME },
1698         { IPPROTO_IPV6, IPV6_MULTICAST_LOOP, SV_BOOL },
1699         { IPPROTO_IPV6, IPV6_RECVTCLASS, SV_BOOL },
1700         { IPPROTO_IPV6, IPV6_TCLASS, SV_INT },
1701         { IPPROTO_IPV6, IPV6_UNICAST_HOPS, SV_INT },
1702         { IPPROTO_IPV6, IPV6_V6ONLY, SV_BOOL },
1703 #if defined(__linux__)
1704         { IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &st_ipv6_mreq },
1705         { IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, SV_INT },
1706         { IPPROTO_IPV6, IPV6_ADDRFORM, SV_INT },
1707         { IPPROTO_IPV6, IPV6_AUTHHDR, SV_BOOL },
1708         { IPPROTO_IPV6, IPV6_AUTOFLOWLABEL, SV_BOOL },
1709         { IPPROTO_IPV6, IPV6_DONTFRAG, SV_BOOL },
1710         { IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &st_ipv6_mreq },
1711         { IPPROTO_IPV6, IPV6_DSTOPTS, SV_STRING },
1712         { IPPROTO_IPV6, IPV6_FREEBIND, SV_BOOL },
1713         { IPPROTO_IPV6, IPV6_HOPLIMIT, SV_BOOL },
1714         { IPPROTO_IPV6, IPV6_HOPOPTS, SV_STRING },
1715         { IPPROTO_IPV6, IPV6_JOIN_ANYCAST, &st_ipv6_mreq },
1716         { IPPROTO_IPV6, IPV6_LEAVE_ANYCAST, &st_ipv6_mreq },
1717         { IPPROTO_IPV6, IPV6_MINHOPCOUNT, SV_INT },
1718         { IPPROTO_IPV6, IPV6_MTU_DISCOVER, SV_INT },
1719         { IPPROTO_IPV6, IPV6_MTU, SV_INT },
1720         { IPPROTO_IPV6, IPV6_MULTICAST_ALL, SV_BOOL },
1721         { IPPROTO_IPV6, IPV6_PKTINFO, &st_in6_pktinfo },
1722         { IPPROTO_IPV6, IPV6_RECVDSTOPTS, SV_BOOL },
1723         { IPPROTO_IPV6, IPV6_RECVERR, SV_BOOL },
1724         { IPPROTO_IPV6, IPV6_RECVFRAGSIZE, SV_BOOL },
1725         { IPPROTO_IPV6, IPV6_RECVHOPLIMIT, SV_BOOL },
1726         { IPPROTO_IPV6, IPV6_RECVHOPOPTS, SV_BOOL },
1727         { IPPROTO_IPV6, IPV6_RECVORIGDSTADDR, SV_BOOL },
1728         { IPPROTO_IPV6, IPV6_RECVPATHMTU, SV_BOOL },
1729         { IPPROTO_IPV6, IPV6_RECVPKTINFO, SV_BOOL },
1730         { IPPROTO_IPV6, IPV6_RECVRTHDR, SV_BOOL },
1731         { IPPROTO_IPV6, IPV6_ROUTER_ALERT_ISOLATE, SV_BOOL },
1732         { IPPROTO_IPV6, IPV6_ROUTER_ALERT, SV_BOOL },
1733         { IPPROTO_IPV6, IPV6_RTHDR, SV_STRING },
1734         { IPPROTO_IPV6, IPV6_RTHDRDSTOPTS, SV_STRING },
1735         { IPPROTO_IPV6, IPV6_TRANSPARENT, SV_BOOL },
1736         { IPPROTO_IPV6, IPV6_UNICAST_IF, SV_IFNAME },
1737 #endif
1738 
1739     { IPPROTO_TCP, TCP_KEEPCNT, SV_INT },
1740     { IPPROTO_TCP, TCP_KEEPINTVL, SV_INT },
1741     { IPPROTO_TCP, TCP_MAXSEG, SV_INT },
1742     { IPPROTO_TCP, TCP_NODELAY, SV_BOOL },
1743     { IPPROTO_TCP, TCP_FASTOPEN, SV_INT },
1744 #if defined(__linux__)
1745     { IPPROTO_TCP, TCP_CONGESTION, SV_STRING },
1746     { IPPROTO_TCP, TCP_CORK, SV_BOOL },
1747     { IPPROTO_TCP, TCP_DEFER_ACCEPT, SV_INT },
1748         { IPPROTO_TCP, TCP_INFO, &st_tcp_info },
1749     { IPPROTO_TCP, TCP_KEEPIDLE, SV_INT },
1750     { IPPROTO_TCP, TCP_LINGER2, SV_INT },
1751     { IPPROTO_TCP, TCP_QUICKACK, SV_BOOL },
1752     { IPPROTO_TCP, TCP_SYNCNT, SV_INT },
1753     { IPPROTO_TCP, TCP_USER_TIMEOUT, SV_INT },
1754     { IPPROTO_TCP, TCP_WINDOW_CLAMP, SV_INT },
1755     { IPPROTO_TCP, TCP_FASTOPEN_CONNECT, SV_INT },
1756 #endif
1757 
1758 #if defined(__linux__)
1759     { IPPROTO_UDP, UDP_CORK, SV_BOOL },
1760 #endif
1761 
1762 #if defined(__linux__)
1763         { SOL_PACKET, PACKET_ADD_MEMBERSHIP, &st_packet_mreq },
1764         { SOL_PACKET, PACKET_DROP_MEMBERSHIP, &st_packet_mreq },
1765         { SOL_PACKET, PACKET_AUXDATA, SV_BOOL },
1766         { SOL_PACKET, PACKET_FANOUT, &st_fanout_args },
1767         { SOL_PACKET, PACKET_LOSS, SV_BOOL },
1768         { SOL_PACKET, PACKET_RESERVE, SV_INT },
1769         { SOL_PACKET, PACKET_RX_RING, &st_tpacket_req },
1770         { SOL_PACKET, PACKET_STATISTICS, &st_tpacket_stats },
1771         { SOL_PACKET, PACKET_TIMESTAMP, SV_INT },
1772         { SOL_PACKET, PACKET_TX_RING, &st_tpacket_req },
1773         { SOL_PACKET, PACKET_VERSION, SV_INT },
1774         { SOL_PACKET, PACKET_QDISC_BYPASS, SV_BOOL },
1775 #endif
1776 
1777 #if defined(__linux__)
1778         { SOL_CAN_RAW, CAN_RAW_FILTER, SV_STRING },
1779         { SOL_CAN_RAW, CAN_RAW_ERR_FILTER, SV_INT },
1780         { SOL_CAN_RAW, CAN_RAW_LOOPBACK, SV_BOOL },
1781         { SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, SV_BOOL },
1782         { SOL_CAN_RAW, CAN_RAW_FD_FRAMES, SV_BOOL },
1783         { SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS, SV_BOOL },
1784 # ifdef CAN_RAW_XL_FRAMES
1785         { SOL_CAN_RAW, CAN_RAW_XL_FRAMES, SV_BOOL },
1786 # endif
1787 #endif
1788 };
1789 
1790 static cmsgtype_t cmsgtypes[] = {
1791 #if defined(__linux__)
1792         { SOL_PACKET, PACKET_AUXDATA, &st_tpacket_auxdata },
1793 
1794         { SOL_SOCKET, SO_TIMESTAMP_OLD, &st_timeval_old },
1795 # ifdef SO_TIMESTAMP_NEW
1796         { SOL_SOCKET, SO_TIMESTAMP_NEW, &st_timeval_new },
1797 # endif
1798         { SOL_SOCKET, SO_TIMESTAMPNS_OLD, &st_timespec_old },
1799 # ifdef SO_TIMESTAMPNS_NEW
1800         { SOL_SOCKET, SO_TIMESTAMPNS_NEW, &st_timespec_new },
1801 # endif
1802 
1803         { SOL_SOCKET, SCM_CREDENTIALS, &st_ucred },
1804         { SOL_SOCKET, SCM_RIGHTS, CV_FDS },
1805 #endif
1806 
1807         { IPPROTO_IP, IP_RECVOPTS, SV_STRING },
1808         { IPPROTO_IP, IP_RETOPTS, SV_STRING },
1809         { IPPROTO_IP, IP_TOS, CV_INT },
1810         { IPPROTO_IP, IP_TTL, CV_INT },
1811 #if defined(__linux__)
1812         { IPPROTO_IP, IP_CHECKSUM, CV_UINT },
1813         { IPPROTO_IP, IP_ORIGDSTADDR, CV_SOCKADDR },
1814         { IPPROTO_IP, IP_RECVERR, &st_ip_recv_error },
1815         { IPPROTO_IP, IP_RECVFRAGSIZE, CV_INT },
1816 #endif
1817 
1818         { IPPROTO_IPV6, IPV6_TCLASS, CV_INT },
1819         { IPPROTO_IPV6, IPV6_FLOWINFO, CV_BE32 },
1820 #if defined(__linux__)
1821         { IPPROTO_IPV6, IPV6_DSTOPTS, CV_STRING },
1822         { IPPROTO_IPV6, IPV6_HOPLIMIT, CV_INT },
1823         { IPPROTO_IPV6, IPV6_HOPOPTS, CV_STRING },
1824         { IPPROTO_IPV6, IPV6_ORIGDSTADDR, CV_SOCKADDR },
1825         { IPPROTO_IPV6, IPV6_PATHMTU, &st_ip6_mtuinfo },
1826         { IPPROTO_IPV6, IPV6_PKTINFO, &st_in6_pktinfo },
1827         { IPPROTO_IPV6, IPV6_RECVERR, &st_ip_recv_error },
1828         { IPPROTO_IPV6, IPV6_RECVFRAGSIZE, CV_INT },
1829         { IPPROTO_IPV6, IPV6_RTHDR, CV_STRING },
1830 
1831         { IPPROTO_TCP, TCP_CM_INQ, CV_INT },
1832         { IPPROTO_UDP, UDP_GRO, CV_INT },
1833 #endif
1834 };
1835 
1836 
1837 static char *
1838 uv_to_struct(uc_value_t *uv, struct_t *spec)
1839 {
1840         uc_value_t *fv;
1841         const char *s;
1842         uint64_t u64;
1843         int64_t s64;
1844         member_t *m;
1845         bool found;
1846         char *st;
1847 
1848         union {
1849                 int8_t s8;
1850                 int16_t s16;
1851                 int32_t s32;
1852                 int64_t s64;
1853                 uint8_t u8;
1854                 uint16_t u16;
1855                 uint32_t u32;
1856                 uint64_t u64;
1857         } v;
1858 
1859         st = xalloc(spec->size);
1860 
1861         for (size_t i = 0; spec->members[i].name; i++) {
1862                 m = &spec->members[i];
1863                 fv = ucv_object_get(uv, m->name, &found);
1864 
1865                 if (!found || !fv)
1866                         continue;
1867 
1868                 switch (spec->members[i].type) {
1869                 case DT_UNSIGNED:
1870                         u64 = ucv_to_unsigned(fv);
1871 
1872                         if (errno) {
1873                                 free(st);
1874                                 err_return(errno,
1875                                         "Unable to convert field %s to unsigned",
1876                                         m->name);
1877                         }
1878 
1879                         switch (m->u2.size) {
1880                         case 1:  v.u8 =  (uint8_t)u64; break;
1881                         case 2: v.u16 = (uint16_t)u64; break;
1882                         case 4: v.u32 = (uint32_t)u64; break;
1883                         case 8: v.u64 = (uint64_t)u64; break;
1884                         }
1885 
1886                         memcpy(st + m->u1.offset, &v, m->u2.size);
1887                         break;
1888 
1889                 case DT_SIGNED:
1890                         s64 = ucv_to_integer(fv);
1891 
1892                         if (errno) {
1893                                 free(st);
1894                                 err_return(errno,
1895                                         "Unable to convert field %s to integer", m->name);
1896                         }
1897 
1898                         switch (m->u2.size) {
1899                         case 1:  v.s8 =  (int8_t)s64; break;
1900                         case 2: v.s16 = (int16_t)s64; break;
1901                         case 4: v.s32 = (int32_t)s64; break;
1902                         case 8: v.s64 = (int64_t)s64; break;
1903                         }
1904 
1905                         memcpy(st + m->u1.offset, &v, m->u2.size);
1906                         break;
1907 
1908                 case DT_IPV4ADDR:
1909                         s = ucv_string_get(fv);
1910 
1911                         if (!s || inet_pton(AF_INET, s, st + m->u1.offset) != 1) {
1912                                 free(st);
1913                                 err_return(EINVAL,
1914                                         "Unable to convert field %s to IP address", m->name);
1915                         }
1916 
1917                         break;
1918 
1919                 case DT_IPV6ADDR:
1920                         s = ucv_string_get(fv);
1921 
1922                         if (!s || inet_pton(AF_INET6, s, st + m->u1.offset) != 1) {
1923                                 free(st);
1924                                 err_return(EINVAL,
1925                                         "Unable to convert field %s to IPv6 address", m->name);
1926                         }
1927 
1928                         break;
1929 
1930                 case DT_CALLBACK:
1931                         if (m->u1.to_c && !m->u1.to_c(&st, fv)) {
1932                                 free(st);
1933                                 return NULL;
1934                         }
1935 
1936                         break;
1937                 }
1938         }
1939 
1940         return st;
1941 }
1942 
1943 static uc_value_t *
1944 struct_to_uv(char *st, struct_t *spec)
1945 {
1946         char s[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
1947         uc_value_t *uv, *fv;
1948         member_t *m;
1949 
1950         uv = ucv_object_new(NULL);
1951 
1952         for (size_t i = 0; spec->members[i].name; i++) {
1953                 m = &spec->members[i];
1954                 fv = NULL;
1955 
1956                 switch (spec->members[i].type) {
1957                 case DT_UNSIGNED:
1958                         switch (spec->members[i].u2.size) {
1959                         case 1:
1960                                 fv = ucv_uint64_new(*(uint8_t *)(st + m->u1.offset));
1961                                 break;
1962 
1963                         case 2:
1964                                 fv = ucv_uint64_new(*(uint16_t *)(st + m->u1.offset));
1965                                 break;
1966 
1967                         case 4:
1968                                 fv = ucv_uint64_new(*(uint32_t *)(st + m->u1.offset));
1969                                 break;
1970 
1971                         case 8:
1972                                 fv = ucv_uint64_new(*(uint64_t *)(st + m->u1.offset));
1973                                 break;
1974                         }
1975 
1976                         break;
1977 
1978                 case DT_SIGNED:
1979                         switch (spec->members[i].u2.size) {
1980                         case 1:
1981                                 fv = ucv_int64_new(*(int8_t *)(st + m->u1.offset));
1982                                 break;
1983 
1984                         case 2:
1985                                 fv = ucv_int64_new(*(int16_t *)(st + m->u1.offset));
1986                                 break;
1987 
1988                         case 4:
1989                                 fv = ucv_int64_new(*(int32_t *)(st + m->u1.offset));
1990                                 break;
1991 
1992                         case 8:
1993                                 fv = ucv_int64_new(*(int64_t *)(st + m->u1.offset));
1994                                 break;
1995                         }
1996 
1997                         break;
1998 
1999                 case DT_IPV4ADDR:
2000                         if (inet_ntop(AF_INET, st + m->u1.offset, s, sizeof(s)))
2001                                 fv = ucv_string_new(s);
2002 
2003                         break;
2004 
2005                 case DT_IPV6ADDR:
2006                         if (inet_ntop(AF_INET6, st + m->u1.offset, s, sizeof(s)))
2007                                 fv = ucv_string_new(s);
2008 
2009                         break;
2010 
2011                 case DT_CALLBACK:
2012                         fv = m->u2.to_uv ? m->u2.to_uv(st) : NULL;
2013                         break;
2014                 }
2015 
2016                 ucv_object_add(uv, m->name, fv);
2017         }
2018 
2019         return uv;
2020 }
2021 
2022 /**
2023  * Sets options on the socket.
2024  *
2025  * Sets the specified option on the socket to the given value.
2026  *
2027  * Returns `true` if the option was successfully set.
2028  *
2029  * Returns `null` if an error occurred.
2030  *
2031  * @function module:socket.socket#setopt
2032  *
2033  * @param {number} level
2034  * The protocol level at which the option resides. This can be a level such as
2035  * `SOL_SOCKET` for the socket API level or a specific protocol level defined
2036  * by the system.
2037  *
2038  * @param {number} option
2039  * The socket option to set. This can be an integer representing the option,
2040  * such as `SO_REUSEADDR`, or a constant defined by the system.
2041  *
2042  * @param {*} value
2043  * The value to set the option to. The type of this argument depends on the
2044  * specific option being set. It can be an integer, a boolean, a string, or a
2045  * dictionary representing the value to set. If a dictionary is provided, it is
2046  * internally translated to the corresponding C struct type required by the
2047  * option.
2048  *
2049  * @returns {?boolean}
2050  */
2051 static uc_value_t *
2052 uc_socket_inst_setopt(uc_vm_t *vm, size_t nargs)
2053 {
2054         int sockfd, solvl, soopt, soval, ret;
2055         uc_value_t *level, *option, *value;
2056         void *valptr = NULL, *st = NULL;
2057         socklen_t vallen = 0;
2058         size_t i;
2059 
2060         args_get(vm, nargs, &sockfd,
2061                 "level", UC_INTEGER, false, &level,
2062                 "option", UC_INTEGER, false, &option,
2063                 "value", UC_NULL, false, &value);
2064 
2065         solvl = ucv_int64_get(level);
2066         soopt = ucv_int64_get(option);
2067 
2068         for (i = 0; i < ARRAY_SIZE(sockopts); i++) {
2069                 if (sockopts[i].level != solvl || sockopts[i].option != soopt)
2070                         continue;
2071 
2072                 switch ((uintptr_t)sockopts[i].ctype) {
2073                 case (uintptr_t)SV_INT_RO:
2074                         err_return(EOPNOTSUPP, "Socket option is read only");
2075 
2076                 case (uintptr_t)SV_VOID:
2077                         valptr = NULL;
2078                         vallen = 0;
2079                         break;
2080 
2081                 case (uintptr_t)SV_INT:
2082                         soval = ucv_to_integer(value);
2083 
2084                         if (errno)
2085                                 err_return(errno, "Unable to convert value to integer");
2086 
2087                         valptr = &soval;
2088                         vallen = sizeof(int);
2089                         break;
2090 
2091                 case (uintptr_t)SV_BOOL:
2092                         soval = ucv_to_unsigned(value) ? 1 : 0;
2093 
2094                         if (errno)
2095                                 err_return(errno, "Unable to convert value to boolean");
2096 
2097                         valptr = &soval;
2098                         vallen = sizeof(int);
2099                         break;
2100 
2101                 case (uintptr_t)SV_STRING:
2102                         valptr = ucv_string_get(value);
2103                         vallen = ucv_string_length(value);
2104                         break;
2105 
2106                 case (uintptr_t)SV_IFNAME:
2107                         if (ucv_type(value) == UC_STRING) {
2108                                 soval = if_nametoindex(ucv_string_get(value));
2109 
2110                                 if (soval <= 0)
2111                                         err_return(errno, "Unable to resolve interface %s",
2112                                                 ucv_string_get(value));
2113                         }
2114                         else {
2115                                 soval = ucv_to_integer(value);
2116 
2117                                 if (errno)
2118                                         err_return(errno, "Unable to convert value to integer");
2119                         }
2120 
2121                         valptr = &soval;
2122                         vallen = sizeof(int);
2123                         break;
2124 
2125                 default:
2126                         st = uv_to_struct(value, sockopts[i].ctype);
2127                         valptr = st;
2128                         vallen = sockopts[i].ctype->size;
2129                         break;
2130                 }
2131 
2132                 break;
2133         }
2134 
2135         if (i == ARRAY_SIZE(sockopts))
2136                 err_return(EINVAL, "Unknown socket level or option");
2137 
2138         ret = setsockopt(sockfd, solvl, soopt, valptr, vallen);
2139 
2140         free(st);
2141 
2142         if (ret == -1)
2143                 err_return(errno, "setsockopt()");
2144 
2145         ok_return(ucv_boolean_new(true));
2146 }
2147 
2148 /**
2149  * Gets options from the socket.
2150  *
2151  * Retrieves the value of the specified option from the socket.
2152  *
2153  * Returns the value of the requested option.
2154  *
2155  * Returns `null` if an error occurred or if the option is not supported.
2156  *
2157  * @function module:socket.socket#getopt
2158  *
2159  * @param {number} level
2160  * The protocol level at which the option resides. This can be a level such as
2161  * `SOL_SOCKET` for the socket API level or a specific protocol level defined
2162  * by the system.
2163  *
2164  * @param {number} option
2165  * The socket option to retrieve. This can be an integer representing the
2166  * option, such as `SO_REUSEADDR`, or a constant defined by the system.
2167  *
2168  * @returns {?*}
2169  * The value of the requested option. The type of the returned value depends
2170  * on the specific option being retrieved. It can be an integer, a boolean, a
2171  * string, or a dictionary representing a complex data structure.
2172  */
2173 static uc_value_t *
2174 uc_socket_inst_getopt(uc_vm_t *vm, size_t nargs)
2175 {
2176         uc_value_t *level, *option, *value = NULL;
2177         char ival[sizeof(int64_t)] = { 0 };
2178         void *valptr = NULL, *st = NULL;
2179         int sockfd, solvl, soopt, ret;
2180         uc_stringbuf_t *sb = NULL;
2181         socklen_t vallen;
2182         size_t i;
2183 
2184         args_get(vm, nargs, &sockfd,
2185                 "level", UC_INTEGER, false, &level,
2186                 "option", UC_INTEGER, false, &option);
2187 
2188         solvl = ucv_int64_get(level);
2189         soopt = ucv_int64_get(option);
2190 
2191         for (i = 0; i < ARRAY_SIZE(sockopts); i++) {
2192                 if (sockopts[i].level != solvl || sockopts[i].option != soopt)
2193                         continue;
2194 
2195                 switch ((uintptr_t)sockopts[i].ctype) {
2196                 case (uintptr_t)SV_VOID:
2197                         err_return(EOPNOTSUPP, "Socket option is write only");
2198 
2199                 case (uintptr_t)SV_INT:
2200                 case (uintptr_t)SV_INT_RO:
2201                 case (uintptr_t)SV_BOOL:
2202                 case (uintptr_t)SV_IFNAME:
2203                         valptr = ival;
2204                         vallen = sizeof(ival);
2205                         break;
2206 
2207                 case (uintptr_t)SV_STRING:
2208                         sb = strbuf_alloc(64);
2209                         valptr = strbuf_data(sb);
2210                         vallen = strbuf_size(sb);
2211                         break;
2212 
2213                 default:
2214                         st = xalloc(sockopts[i].ctype->size);
2215                         valptr = st;
2216                         vallen = sockopts[i].ctype->size;
2217                         break;
2218                 }
2219 
2220                 break;
2221         }
2222 
2223         if (i == ARRAY_SIZE(sockopts))
2224                 err_return(EINVAL, "Unknown socket level or option");
2225 
2226         while (true) {
2227                 ret = getsockopt(sockfd, solvl, soopt, valptr, &vallen);
2228 
2229                 if (sockopts[i].ctype == SV_STRING &&
2230                     (ret == 0 || (ret == -1 && errno == ERANGE)) &&
2231                     vallen > strbuf_size(sb)) {
2232 
2233                         if (!strbuf_grow(sb, vallen))
2234                                 return NULL;
2235 
2236                         valptr = strbuf_data(sb);
2237                         continue;
2238                 }
2239 
2240                 break;
2241         }
2242 
2243         if (ret == 0) {
2244                 char ifname[IF_NAMESIZE];
2245                 int ifidx;
2246 
2247                 switch ((uintptr_t)sockopts[i].ctype) {
2248                 case (uintptr_t)SV_VOID:
2249                         break;
2250 
2251                 case (uintptr_t)SV_INT:
2252                 case (uintptr_t)SV_INT_RO:
2253                         value = ucv_int64_new(parse_integer(ival, vallen));
2254                         break;
2255 
2256                 case (uintptr_t)SV_BOOL:
2257                         value = ucv_boolean_new(parse_integer(ival, vallen) != 0);
2258                         break;
2259 
2260                 case (uintptr_t)SV_STRING:
2261                         value = strbuf_finish(&sb, vallen);
2262                         break;
2263 
2264                 case (uintptr_t)SV_IFNAME:
2265                         ifidx = parse_integer(ival, vallen);
2266                         if (if_indextoname(ifidx, ifname))
2267                                 value = ucv_string_new(ifname);
2268                         else
2269                                 value = ucv_int64_new(ifidx);
2270                         break;
2271 
2272                 default:
2273                         value = struct_to_uv(st, sockopts[i].ctype);
2274                         break;
2275                 }
2276         }
2277 
2278         strbuf_free(sb);
2279         free(st);
2280 
2281         if (ret == -1)
2282                 err_return(errno, "getsockopt()");
2283 
2284         ok_return(value);
2285 }
2286 
2287 /**
2288  * Returns the UNIX file descriptor number associated with the socket.
2289  *
2290  * Returns the file descriptor number.
2291  *
2292  * Returns `-1` if an error occurred.
2293  *
2294  * @function module:socket.socket#fileno
2295  *
2296  * @returns {number}
2297  */
2298 static uc_value_t *
2299 uc_socket_inst_fileno(uc_vm_t *vm, size_t nargs)
2300 {
2301         int sockfd;
2302 
2303         args_get(vm, nargs, &sockfd);
2304 
2305         ok_return(ucv_int64_new(sockfd));
2306 }
2307 
2308 /**
2309  * Query error information.
2310  *
2311  * Returns a string containing a description of the last occurred error when
2312  * the *numeric* argument is absent or false.
2313  *
2314  * Returns a positive (`errno`) or negative (`EAI_*` constant) error code number
2315  * when the *numeric* argument is `true`.
2316  *
2317  * Returns `null` if there is no error information.
2318  *
2319  * @function module:socket#error
2320  *
2321  * @param {boolean} [numeric]
2322  * Whether to return a numeric error code (`true`) or a human readable error
2323  * message (false).
2324  *
2325  * @returns {?string|?number}
2326  *
2327  * @example
2328  * // Trigger socket error by attempting to bind IPv6 address with IPv4 socket
2329  * socket.create(socket.AF_INET, socket.SOCK_STREAM, 0).bind("::", 8080);
2330  *
2331  * // Print error (should yield "Address family not supported by protocol")
2332  * print(socket.error(), "\n");
2333  *
2334  * // Trigger resolve error
2335  * socket.addrinfo("doesnotexist.org");
2336  *
2337  * // Query error code (should yield -2 for EAI_NONAME)
2338  * print(socket.error(true), "\n");  //
2339  */
2340 static uc_value_t *
2341 uc_socket_error(uc_vm_t *vm, size_t nargs)
2342 {
2343         uc_value_t *numeric = uc_fn_arg(0), *rv;
2344         uc_stringbuf_t *buf;
2345 
2346         if (last_error.code == 0)
2347                 return NULL;
2348 
2349         if (ucv_is_truish(numeric)) {
2350                 rv = ucv_int64_new(last_error.code);
2351         }
2352         else {
2353                 buf = ucv_stringbuf_new();
2354 
2355                 if (last_error.msg)
2356                         ucv_stringbuf_printf(buf, "%s: ", last_error.msg);
2357 
2358                 if (last_error.code >= 0)
2359                         ucv_stringbuf_printf(buf, "%s", strerror(last_error.code));
2360                 else
2361                         ucv_stringbuf_printf(buf, "%s", gai_strerror(last_error.code));
2362 
2363                 rv = ucv_stringbuf_finish(buf);
2364         }
2365 
2366         return rv;
2367 }
2368 
2369 /**
2370  * Returns a string containing a description of the positive (`errno`) or
2371  * negative (`EAI_*` constant) error code number given by the *code* argument.
2372  *
2373  * Returns `null` if the error code number is unknown.
2374  *
2375  * @function module:socket#strerror
2376  *
2377  * @param {number} code
2378  * The error code.
2379  *
2380  * @returns {?string}
2381  *
2382  * @example
2383  * // Should output 'Name or service not known'.
2384  * print(socket.strerror(-2), '\n');
2385  *
2386  * // Should output 'No route to host'.
2387  * print(socket.strerror(113), '\n');
2388  */
2389 static uc_value_t *
2390 uc_socket_strerror(uc_vm_t *vm, size_t nargs)
2391 {
2392         uc_value_t *codearg, *rv;
2393         int code;
2394 
2395         args_get(vm, nargs, NULL,
2396                 "code", UC_INTEGER, false, &codearg);
2397 
2398         code = ucv_to_integer(codearg);
2399 
2400         if (code < 0)
2401                 rv = ucv_string_new( gai_strerror(code) );
2402         else
2403                 rv = ucv_string_new( strerror(code) );
2404 
2405         return rv;
2406 }
2407 
2408 /**
2409  * @typedef {Object} module:socket.socket.SocketAddress
2410  * @property {number} family
2411  * Address family, one of AF_INET, AF_INET6, AF_UNIX, AF_PACKET or AF_CAN.
2412  *
2413  * @property {string} address
2414  * IPv4/IPv6 address string (AF_INET or AF_INET6 only) or hardware address in
2415  * hexadecimal notation (AF_PACKET only).
2416  *
2417  * @property {number} [port]
2418  * Port number (AF_INET or AF_INET6 only).
2419  *
2420  * @property {number} [flowinfo]
2421  * IPv6 flow information (AF_INET6 only).
2422  *
2423  * @property {string|number} [interface]
2424  * Link local address scope (for IPv6 sockets) or bound network interface
2425  * (for packet and CAN sockets), either a network device name string or a
2426  * nonzero positive integer representing a network interface index (AF_INET6,
2427  * AF_PACKET and AF_CAN only).
2428  *
2429  * @property {string} path
2430  * Domain socket filesystem path (AF_UNIX only).
2431  *
2432  * @property {number} [protocol=0]
2433  * Physical layer protocol (AF_PACKET only).
2434  *
2435  * @property {number} [hardware_type=0]
2436  * ARP hardware type (AF_PACKET only).
2437  *
2438  * @property {number} [packet_type=PACKET_HOST]
2439  * Packet type (AF_PACKET only).
2440  */
2441 
2442 /**
2443  * Parses the provided address value into a socket address representation.
2444  *
2445  * This function parses the given address value into a socket address
2446  * representation required for a number of socket operations. The address value
2447  * can be provided in various formats:
2448  * - For IPv4 addresses, it can be a string representing the IP address,
2449  *   optionally followed by a port number separated by colon, e.g.
2450  *   `192.168.0.1:8080`.
2451  * - For IPv6 addresses, it must be an address string enclosed in square
2452  *   brackets if a port number is specified, otherwise the brackets are
2453  *   optional. The address string may also include a scope ID in the form
2454  *   `%ifname` or `%number`, e.g. `[fe80::1%eth0]:8080` or `fe80::1%15`.
2455  * - Any string value containing a slash is treated as UNIX domain socket path.
2456  * - Alternatively, it can be provided as an array returned by
2457  *   {@link module:core#iptoarr|iptoarr()}, representing the address octets.
2458  * - It can also be an object representing a network address, with properties
2459  *   for `address` (the IP address) and `port` or a single property `path` to
2460  *   denote a UNIX domain socket address.
2461  *
2462  * @function module:socket#sockaddr
2463  *
2464  * @param {string|number[]|module:socket.socket.SocketAddress} address
2465  * The address value to parse.
2466  *
2467  * @returns {?module:socket.socket.SocketAddress}
2468  * A socket address representation of the provided address value, or `null` if
2469  * the address could not be parsed.
2470  *
2471  * @example
2472  * // Parse an IP address string with port
2473  * const address1 = sockaddr('192.168.0.1:8080');
2474  *
2475  * // Parse an IPv6 address string with port and scope identifier
2476  * const address2 = sockaddr('[fe80::1%eth0]:8080');
2477  *
2478  * // Parse an array representing an IP address
2479  * const address3 = sockaddr([192, 168, 0, 1]);
2480  *
2481  * // Parse a network address object
2482  * const address4 = sockaddr({ address: '192.168.0.1', port: 8080 });
2483  *
2484  * // Convert a path value to a UNIX domain socket address
2485  * const address5 = sockaddr('/var/run/daemon.sock');
2486  */
2487 static uc_value_t *
2488 uc_socket_sockaddr(uc_vm_t *vm, size_t nargs)
2489 {
2490         struct sockaddr_storage ss = { 0 };
2491         uc_value_t *addr, *rv;
2492         socklen_t slen;
2493 
2494         args_get(vm, nargs, NULL,
2495                 "address", UC_NULL, false, &addr);
2496 
2497         if (!uv_to_sockaddr(addr, &ss, &slen))
2498                 return NULL;
2499 
2500         rv = ucv_object_new(vm);
2501 
2502         if (!sockaddr_to_uv(&ss, rv)) {
2503                 ucv_put(rv);
2504                 return NULL;
2505         }
2506 
2507         ok_return(rv);
2508 }
2509 
2510 /**
2511  * Resolves the given network address into hostname and service name.
2512  *
2513  * The `nameinfo()` function provides an API for reverse DNS lookup and service
2514  * name resolution. It returns an object containing the following properties:
2515  * - `hostname`: The resolved hostname.
2516  * - `service`: The resolved service name.
2517  *
2518  * Returns an object representing the resolved hostname and service name.
2519  * Return `null` if an error occurred during resolution.
2520  *
2521  * @function module:socket#nameinfo
2522  *
2523  * @param {string|module:socket.socket.SocketAddress} address
2524  * The network address to resolve. It can be specified as:
2525  * - A string representing the IP address.
2526  * - An object representing the address with properties `address` and `port`.
2527  *
2528  * @param {number} [flags]
2529  * Optional flags that provide additional control over the resolution process,
2530  * specified as bitwise OR-ed number of `NI_*` constants.
2531  *
2532  * @returns {?{hostname: string, service: string}}
2533  *
2534  * @see {@link module:socket~"Socket Types"|Socket Types}
2535  * @see {@link module:socket~"Name Info Constants"|AName Info Constants}
2536  *
2537  * @example
2538  * // Resolve a network address into hostname and service name
2539  * const result = network.getnameinfo('192.168.1.1:80');
2540  * print(result); // { "hostname": "example.com", "service": "http" }
2541  */
2542 static uc_value_t *
2543 uc_socket_nameinfo(uc_vm_t *vm, size_t nargs)
2544 {
2545         char host[NI_MAXHOST], serv[NI_MAXSERV];
2546         uc_value_t *addr, *flags, *rv;
2547         struct sockaddr_storage ss;
2548         socklen_t slen;
2549         int ret;
2550 
2551         args_get(vm, nargs, NULL,
2552                 "address", UC_NULL, false, &addr,
2553                 "flags", UC_INTEGER, true, &flags);
2554 
2555         if (!uv_to_sockaddr(addr, &ss, &slen))
2556                 return NULL;
2557 
2558         ret = getnameinfo((struct sockaddr *)&ss, slen,
2559                 host, sizeof(host), serv, sizeof(serv),
2560                 flags ? ucv_int64_get(flags) : 0);
2561 
2562         if (ret != 0)
2563                 err_return((ret == EAI_SYSTEM) ? errno : ret, "getnameinfo()");
2564 
2565         rv = ucv_object_new(vm);
2566 
2567         ucv_object_add(rv, "hostname", ucv_string_new(host));
2568         ucv_object_add(rv, "service", ucv_string_new(serv));
2569 
2570         ok_return(rv);
2571 }
2572 
2573 /**
2574  * Resolves the given hostname and optional service name into a list of network
2575  * addresses, according to the provided hints.
2576  *
2577  * The `addrinfo()` function provides an API for performing DNS and service name
2578  * resolution. It returns an array of objects, each representing a resolved
2579  * address.
2580  *
2581  * Returns an array of resolved addresses.
2582  * Returns `null` if an error occurred during resolution.
2583  *
2584  * @function module:socket#addrinfo
2585  *
2586  * @param {string} hostname
2587  * The hostname to resolve.
2588  *
2589  * @param {string} [service]
2590  * Optional service name to resolve. If not provided, the service field of the
2591  * resulting address information structures is left uninitialized.
2592  *
2593  * @param {Object} [hints]
2594  * Optional hints object that provides additional control over the resolution
2595  * process. It can contain the following properties:
2596  * - `family`: The preferred address family (`AF_INET` or `AF_INET6`).
2597  * - `socktype`: The socket type (`SOCK_STREAM`, `SOCK_DGRAM`, etc.).
2598  * - `protocol`: The protocol of returned addresses.
2599  * - `flags`: Bitwise OR-ed `AI_*` flags to control the resolution behavior.
2600  *
2601  * @returns {?module:socket.AddressInfo[]}
2602  *
2603  * @see {@link module:socket~"Socket Types"|Socket Types}
2604  * @see {@link module:socket~"Address Info Flags"|Address Info Flags}
2605  *
2606  * @example
2607  * // Resolve all addresses
2608  * const addresses = socket.addrinfo('example.org');
2609  *
2610  * // Resolve IPv4 addresses for a given hostname and service
2611  * const ipv4addresses = socket.addrinfo('example.com', 'http', { family: socket.AF_INET });
2612  *
2613  * // Resolve IPv6 addresses without specifying a service
2614  * const ipv6Addresses = socket.addrinfo('example.com', null, { family: socket.AF_INET6 });
2615  */
2616 
2617 static uc_value_t *
2618 uc_socket_addrinfo(uc_vm_t *vm, size_t nargs)
2619 {
2620         char hostbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255%interface012345")];
2621         struct addrinfo *ai_hints = NULL, *ai_res;
2622         uc_value_t *host, *serv, *hints, *rv;
2623         char *hostname, *servstr;
2624         size_t hostlen;
2625         int ret;
2626 
2627         args_get(vm, nargs, NULL,
2628                 "hostname", UC_STRING, false, &host,
2629                 "service", UC_NULL, true, &serv,
2630                 "hints", UC_OBJECT, true, &hints);
2631 
2632         if (hints) {
2633                 ai_hints = (struct addrinfo *)uv_to_struct(hints, &st_addrinfo);
2634 
2635                 if (!ai_hints)
2636                         return NULL;
2637         }
2638 
2639         hostname = ucv_string_get(host);
2640         hostlen = ucv_string_length(host);
2641 
2642         if (hostlen > 2 && hostname[0] == '[' && hostname[hostlen - 1] == ']'
2643             && hostlen - 2 < sizeof(hostbuf)) {
2644                 memcpy(hostbuf, hostname + 1, hostlen - 2);
2645                 hostbuf[hostlen - 2] = '\0';
2646                 hostname = hostbuf;
2647         }
2648 
2649         servstr = (serv && ucv_type(serv) != UC_STRING) ? ucv_to_string(vm, serv) : NULL;
2650         ret = getaddrinfo(hostname,
2651                 servstr ? servstr : ucv_string_get(serv),
2652                 ai_hints, &ai_res);
2653 
2654         free(ai_hints);
2655         free(servstr);
2656 
2657         if (ret != 0)
2658                 err_return((ret == EAI_SYSTEM) ? errno : ret, "getaddrinfo()");
2659 
2660         rv = ucv_array_new(vm);
2661 
2662         for (struct addrinfo *ai = ai_res; ai; ai = ai->ai_next) {
2663                 uc_value_t *item = struct_to_uv((char *)ai, &st_addrinfo);
2664 
2665                 if (item)
2666                         ucv_array_push(rv, item);
2667         }
2668 
2669         freeaddrinfo(ai_res);
2670 
2671         ok_return(rv);
2672 }
2673 
2674 /**
2675  * Represents a poll state serving as input parameter and return value type for
2676  * {@link module:socket#poll|`poll()`}.
2677  *
2678  * @typedef {Array} module:socket.PollSpec
2679  * @property {module:socket.socket} 0
2680  * The polled socket instance.
2681  *
2682  * @property {number} 1
2683  * Requested or returned status flags of the polled socket instance.
2684  */
2685 
2686 /**
2687  * Polls a number of sockets for state changes.
2688  *
2689  * Returns an array of `[socket, flags]` tuples for each socket with pending
2690  * events. When a tuple is passed as socket argument, it is included as-is into
2691  * the result tuple array, with the flags entry changed to a bitwise OR-ed value
2692  * describing the pending events for this socket. When a plain socket instance
2693  * (or another kind of handle) is passed, a new tuple array is created for this
2694  * socket within the result tuple array, containing this socket as first and the
2695  * bitwise OR-ed pending events as second element.
2696  *
2697  * Returns `null` if an error occurred.
2698  *
2699  * @function module:socket#poll
2700  *
2701  * @param {number} timeout
2702  * Amount of milliseconds to wait for socket activity before aborting the poll
2703  * call. If set to `0`, the poll call will return immediately if none of the
2704  * provided sockets has pending events, if set to a negative value, the poll
2705  * call will wait indefinitely, in all other cases the poll call will wait at
2706  * most for the given amount of milliseconds before returning.
2707  *
2708  * @param {...(module:socket.socket|module:socket.PollSpec)} sockets
2709  * An arbitrary amount of socket arguments. Each argument may be either a plain
2710  * {@link module:socket.socket|socket instance} (or any other kind of handle
2711  * implementing a `fileno()` method) or a `[socket, flags]` tuple specifying the
2712  * socket and requested poll flags. If a plain socket (or other kind of handle)
2713  * instead of a tuple is provided, the requested poll flags default to
2714  * `POLLIN|POLLERR|POLLHUP` for this socket.
2715  *
2716  * @returns {module:socket.PollSpec[]}
2717  *
2718  * @example
2719  * let x = socket.connect("example.org", 80);
2720  * let y = socket.connect("example.com", 80);
2721  *
2722  * // Pass plain socket arguments
2723  * let events = socket.poll(10, x, y);
2724  * print(events); // [ [ "<socket 0x7>", 0 ], [ "<socket 0x8>", 0 ] ]
2725  *
2726  * // Passing tuples allows attaching state information and requesting
2727  * // different I/O events
2728  * let events = socket.poll(10,
2729  *      [ x, socket.POLLOUT | socket.POLLHUP, "This is example.org" ],
2730  *      [ y, socket.POLLOUT | socket.POLLHUP, "This is example.com" ]
2731  * );
2732  * print(events); // [ [ "<socket 0x7>", 4, "This is example.org" ],
2733  *                //   [ "<socket 0x8>", 4, "This is example.com" ] ]
2734  */
2735 static uc_value_t *
2736 uc_socket_poll(uc_vm_t *vm, size_t nargs)
2737 {
2738         struct { struct pollfd *entries; size_t count; } pfds = { 0 };
2739         uc_value_t *timeoutarg, *rv, *item;
2740         int64_t timeout;
2741         int ret;
2742 
2743         args_get(vm, nargs, NULL, "timeout", UC_INTEGER, false, &timeoutarg);
2744 
2745         timeout = ucv_to_integer(timeoutarg);
2746 
2747         if (errno != 0 || timeout < (int64_t)INT_MIN || timeout > (int64_t)INT_MAX)
2748                 err_return(ERANGE, "Invalid timeout value");
2749 
2750         size_t argoff = vm->stack.count - nargs;
2751 
2752         rv = ucv_array_new(vm);
2753         uc_vm_stack_push(vm, ucv_get(rv));
2754 
2755         for (size_t i = 1; i < nargs; i++) {
2756                 uc_vector_grow(&pfds);
2757                 item = uv_to_pollfd(vm, vm->stack.entries[argoff + i], &pfds.entries[pfds.count]);
2758 
2759                 if (item)
2760                         ucv_array_set(rv, pfds.count++, item);
2761         }
2762 
2763         ret = poll(pfds.entries, pfds.count, timeout);
2764 
2765         if (ret == -1) {
2766                 ucv_put(uc_vm_stack_pop(vm));
2767                 ucv_put(rv);
2768                 uc_vector_clear(&pfds);
2769                 err_return(errno, "poll()");
2770         }
2771 
2772         for (size_t i = 0; i < pfds.count; i++)
2773                 ucv_array_set(ucv_array_get(rv, i), 1,
2774                         ucv_int64_new(pfds.entries[i].revents));
2775 
2776         ucv_put(uc_vm_stack_pop(vm));
2777         uc_vector_clear(&pfds);
2778         ok_return(rv);
2779 }
2780 
2781 static bool
2782 should_resolve(uc_value_t *host)
2783 {
2784         char *s = ucv_string_get(host);
2785 
2786         return (s != NULL && memchr(s, '/', ucv_string_length(host)) == NULL);
2787 }
2788 
2789 /**
2790  * Creates a network socket and connects it to the specified host and service.
2791  *
2792  * This high level function combines the functionality of
2793  * {@link module:socket#create|create()},
2794  * {@link module:socket#addrinfo|addrinfo()} and
2795  * {@link module:socket.socket#connect|connect()} to simplify connection
2796  * establishment with the socket module.
2797  *
2798  * @function module:socket#connect
2799  *
2800  * @param {string|number[]|module:socket.socket.SocketAddress} host
2801  * The host to connect to, can be an IP address, hostname,
2802  * {@link module:socket.socket.SocketAddress|SocketAddress}, or an array value
2803  * returned by {@link module:core#iptoarr|iptoarr()}.
2804  *
2805  * @param {string|number} [service]
2806  * The service to connect to, can be a symbolic service name (such as "http") or
2807  * a port number. Optional if host is specified as
2808  * {@link module:socket.socket.SocketAddress|SocketAddress}.
2809  *
2810  * @param {Object} [hints]
2811  * Optional preferences for the socket. It can contain the following properties:
2812  * - `family`: The preferred address family (`AF_INET` or `AF_INET6`).
2813  * - `socktype`: The socket type (`SOCK_STREAM`, `SOCK_DGRAM`, etc.).
2814  * - `protocol`: The protocol of the created socket.
2815  * - `flags`: Bitwise OR-ed `AI_*` flags to control the resolution behavior.
2816  *
2817  * If no hints are not provided, the default socket type preference is set to
2818  * `SOCK_STREAM`.
2819  *
2820  * @param {number} [timeout=-1]
2821  * The timeout in milliseconds for socket connect operations. If set to a
2822  * negative value, no specifc time limit is imposed and the function will
2823  * block until either a connection was successfull or the underlying operating
2824  * system timeout is reached.
2825  *
2826  * @returns {module:socket.socket}
2827  *
2828  * @example
2829  * // Resolve host, try to connect to both resulting IPv4 and IPv6 addresses
2830  * let conn = socket.connect("example.org", 80);
2831  *
2832  * // Enforce usage of IPv6
2833  * let conn = socket.connect("example.com", 80, { family: socket.AF_INET6 });
2834  *
2835  * // Connect a UDP socket
2836  * let conn = socket.connect("192.168.1.1", 53, { socktype: socket.SOCK_DGRAM });
2837  *
2838  * // Bypass name resolution by specifying a SocketAddress structure
2839  * let conn = socket.connect({ address: "127.0.0.1", port: 9000 });
2840  *
2841  * // Use SocketAddress structure to connect a UNIX domain socket
2842  * let conn = socket.connect({ path: "/var/run/daemon.sock" });
2843  */
2844 static uc_value_t *
2845 uc_socket_connect(uc_vm_t *vm, size_t nargs)
2846 {
2847         struct address {
2848                 struct sockaddr_storage ss;
2849                 struct addrinfo ai;
2850                 int flags;
2851                 int fd;
2852         } *ap;
2853 
2854         struct { struct address *entries; size_t count; } addresses = { 0 };
2855         struct { struct pollfd *entries; size_t count; } pollfds = { 0 };
2856         struct addrinfo *ai_results, *ai_hints, *ai;
2857         uc_value_t *host, *serv, *hints, *timeout;
2858         const char *errmsg = NULL;
2859         struct pollfd *pp = NULL;
2860         size_t slot, connected;
2861         int ret, err;
2862 
2863         args_get(vm, nargs, NULL,
2864                 "host", UC_NULL, false, &host,
2865                 "service", UC_NULL, true, &serv,
2866                 "hints", UC_OBJECT, true, &hints,
2867                 "timeout", UC_INTEGER, true, &timeout);
2868 
2869         ai_hints = hints
2870                 ? (struct addrinfo *)uv_to_struct(hints, &st_addrinfo) : NULL;
2871 
2872         if (should_resolve(host)) {
2873                 char *servstr = (ucv_type(serv) != UC_STRING)
2874                         ? ucv_to_string(vm, serv) : NULL;
2875 
2876                 ret = getaddrinfo(ucv_string_get(host),
2877                         servstr ? servstr : ucv_string_get(serv),
2878                         ai_hints ? ai_hints : &(struct addrinfo){
2879                                 .ai_socktype = SOCK_STREAM
2880                         }, &ai_results);
2881 
2882                 if (ret != 0) {
2883                         free(servstr);
2884                         free(ai_hints);
2885                         err_return((ret == EAI_SYSTEM) ? errno : ret,
2886                                 "getaddrinfo()");
2887                 }
2888 
2889                 for (ai = ai_results; ai != NULL; ai = ai->ai_next) {
2890                         if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2891                                 continue;
2892 
2893                         uc_vector_grow(&addresses);
2894                         ap = &addresses.entries[addresses.count++];
2895                         memcpy(&ap->ss, ai->ai_addr, ai->ai_addrlen);
2896                         memcpy(&ap->ai, ai, sizeof(*ai));
2897                         ap->ai.ai_addr = (struct sockaddr *)&ap->ss;
2898                 }
2899 
2900                 freeaddrinfo(ai_results);
2901                 free(servstr);
2902         }
2903         else {
2904                 uc_vector_grow(&addresses);
2905                 ap = &addresses.entries[addresses.count++];
2906 
2907                 if (!uv_to_sockaddr(host, &ap->ss, &ap->ai.ai_addrlen)) {
2908                         free(ai_hints);
2909                         uc_vector_clear(&addresses);
2910                         return NULL;
2911                 }
2912 
2913                 if (serv) {
2914                         uint64_t port = ucv_to_unsigned(serv);
2915 
2916                         if (port > 65535)
2917                                 errno = ERANGE;
2918 
2919                         if (errno != 0) {
2920                                 free(ai_hints);
2921                                 uc_vector_clear(&addresses);
2922                                 err_return(errno, "Invalid port number");
2923                         }
2924 
2925                         ((struct sockaddr_in *)&ap->ss)->sin_port = htons(port);
2926                 }
2927 
2928                 ap->ai.ai_addr = (struct sockaddr *)&ap->ss;
2929                 ap->ai.ai_family = ap->ss.ss_family;
2930                 ap->ai.ai_socktype = ai_hints ? ai_hints->ai_socktype : SOCK_STREAM;
2931                 ap->ai.ai_protocol = ai_hints ? ai_hints->ai_protocol : 0;
2932         }
2933 
2934         free(ai_hints);
2935 
2936         for (connected = 0, slot = 0, ap = &addresses.entries[slot];
2937              slot < addresses.count;
2938              slot++, ap = &addresses.entries[slot])
2939         {
2940                 uc_vector_grow(&pollfds);
2941                 pp = &pollfds.entries[pollfds.count++];
2942                 pp->events = POLLIN | POLLOUT | POLLHUP | POLLERR;
2943                 pp->fd = socket(ap->ai.ai_family, ap->ai.ai_socktype, ap->ai.ai_protocol);
2944 
2945                 if (pp->fd == -1)
2946                         continue;
2947 
2948                 if ((ap->flags = fcntl(pp->fd, F_GETFL, 0)) == -1) {
2949                         xclose(&pp->fd);
2950                         continue;
2951                 }
2952 
2953                 if (fcntl(pp->fd, F_SETFL, ap->flags | O_NONBLOCK) == -1) {
2954                         xclose(&pp->fd);
2955                         continue;
2956                 }
2957 
2958                 ret = connect(pp->fd, ap->ai.ai_addr, ap->ai.ai_addrlen);
2959 
2960                 if (ret == -1 && errno != EINPROGRESS) {
2961                         xclose(&pp->fd);
2962                         continue;
2963                 }
2964 
2965                 connected++;
2966         }
2967 
2968         if (connected == 0) {
2969                 err = EAI_NONAME;
2970                 errmsg = "Could not connect to any host address";
2971                 goto out;
2972         }
2973 
2974         ret = poll(pollfds.entries, pollfds.count,
2975                 timeout ? ucv_int64_get(timeout) : -1);
2976 
2977         if (ret == -1) {
2978                 err = errno;
2979                 errmsg = "poll()";
2980                 goto out;
2981         }
2982 
2983         err = 0;
2984         errmsg = NULL;
2985 
2986         for (slot = 0, ap = NULL, pp = NULL; slot < pollfds.count; slot++) {
2987                 if (pollfds.entries[slot].revents & (POLLIN|POLLOUT)) {
2988                         ret = getsockopt(pollfds.entries[slot].fd, SOL_SOCKET, SO_ERROR,
2989                                          &err, &(socklen_t){ sizeof(err) });
2990 
2991                         if (ret == -1) {
2992                                 err = errno;
2993                                 errmsg = "getsockopt()";
2994                                 continue;
2995                         }
2996                         else if (err != 0) {
2997                                 errmsg = "connect()";
2998                                 continue;
2999                         }
3000 
3001                         ap = &addresses.entries[slot];
3002                         pp = &pollfds.entries[slot];
3003                         break;
3004                 }
3005         }
3006 
3007         if (!ap) {
3008                 if (!errmsg) {
3009                         err = ETIMEDOUT;
3010                         errmsg = "Connection timed out";
3011                 }
3012 
3013                 goto out;
3014         }
3015 
3016         if (fcntl(pp->fd, F_SETFL, ap->flags) == -1) {
3017                 err = errno;
3018                 errmsg = "fcntl(F_SETFL)";
3019                 goto out;
3020         }
3021 
3022 out:
3023         for (slot = 0, ret = -1; slot < pollfds.count; slot++) {
3024                 if (pp == &pollfds.entries[slot])
3025                         ret = pollfds.entries[slot].fd;
3026                 else
3027                         xclose(&pollfds.entries[slot].fd);
3028         }
3029 
3030         uc_vector_clear(&addresses);
3031         uc_vector_clear(&pollfds);
3032 
3033         if (errmsg)
3034                 err_return(err, "%s", errmsg);
3035 
3036         ok_return(ucv_socket_new(vm, ret));
3037 }
3038 
3039 /**
3040  * Binds a listening network socket to the specified host and service.
3041  *
3042  * This high-level function combines the functionality of
3043  * {@link module:socket#create|create()},
3044  * {@link module:socket#addrinfo|addrinfo()},
3045  * {@link module:socket.socket#bind|bind()}, and
3046  * {@link module:socket.socket#listen|listen()} to simplify setting up a
3047  * listening socket with the socket module.
3048  *
3049  * @function module:socket#listen
3050  *
3051  * @param {string|number[]|module:socket.socket.SocketAddress} host
3052  * The host to bind to, can be an IP address, hostname,
3053  * {@link module:socket.socket.SocketAddress|SocketAddress}, or an array value
3054  * returned by {@link module:core#iptoarr|iptoarr()}.
3055  *
3056  * @param {string|number} [service]
3057  * The service to listen on, can be a symbolic service name (such as "http") or
3058  * a port number. Optional if host is specified as
3059  * {@link module:socket.socket.SocketAddress|SocketAddress}.
3060  *
3061  * @param {Object} [hints]
3062  * Optional preferences for the socket. It can contain the following properties:
3063  * - `family`: The preferred address family (`AF_INET` or `AF_INET6`).
3064  * - `socktype`: The socket type (`SOCK_STREAM`, `SOCK_DGRAM`, etc.).
3065  * - `protocol`: The protocol of the created socket.
3066  * - `flags`: Bitwise OR-ed `AI_*` flags to control the resolution behavior.
3067  *
3068  * If no hints are provided, the default socket type preference is set to
3069  * `SOCK_STREAM`.
3070  *
3071  * @param {number} [backlog=128]
3072  * The maximum length of the queue of pending connections.
3073  *
3074  * @param {boolean} [reuseaddr]
3075  * Whether to set the SO_REUSEADDR option before calling bind().
3076  *
3077  * @returns {module:socket.socket}
3078  *
3079  * @example
3080  * // Listen for incoming TCP connections on port 80
3081  * let server = socket.listen("localhost", 80);
3082  *
3083  * // Listen on IPv6 address only
3084  * let server = socket.listen("machine.local", 8080, { family: socket.AF_INET6 });
3085  *
3086  * // Listen on a UNIX domain socket
3087  * let server = socket.listen({ path: "/var/run/server.sock" });
3088  */
3089 static uc_value_t *
3090 uc_socket_listen(uc_vm_t *vm, size_t nargs)
3091 {
3092         int ret, fd, curr_weight, prev_weight, socktype = 0, protocol = 0;
3093         struct addrinfo *ai_results, *ai_hints, *ai;
3094         uc_value_t *host, *serv, *hints, *backlog, *reuseaddr;
3095         struct sockaddr_storage ss = { 0 };
3096         bool v6, lo, ll;
3097         socklen_t slen;
3098 
3099         args_get(vm, nargs, NULL,
3100                 "host", UC_NULL, true, &host,
3101                 "service", UC_NULL, true, &serv,
3102                 "hints", UC_OBJECT, true, &hints,
3103                 "backlog", UC_INTEGER, true, &backlog,
3104                 "reuseaddr", UC_BOOLEAN, true, &reuseaddr);
3105 
3106         ai_hints = hints
3107                 ? (struct addrinfo *)uv_to_struct(hints, &st_addrinfo) : NULL;
3108 
3109         if (host == NULL || should_resolve(host)) {
3110                 char *servstr = (ucv_type(serv) != UC_STRING)
3111                         ? ucv_to_string(vm, serv) : NULL;
3112 
3113                 ret = getaddrinfo(ucv_string_get(host),
3114                         servstr ? servstr : ucv_string_get(serv),
3115                         ai_hints ? ai_hints : &(struct addrinfo){
3116                                 .ai_flags = AI_PASSIVE | AI_ADDRCONFIG,
3117                                 .ai_socktype = SOCK_STREAM
3118                         }, &ai_results);
3119 
3120                 free(servstr);
3121 
3122                 if (ret != 0) {
3123                         free(ai_hints);
3124                         err_return((ret == EAI_SYSTEM) ? errno : ret,
3125                                 "getaddrinfo()");
3126                 }
3127 
3128                 for (ai = ai_results, prev_weight = -1; ai != NULL; ai = ai->ai_next) {
3129                         struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ai->ai_addr;
3130                         struct sockaddr_in *s4 = (struct sockaddr_in *)ai->ai_addr;
3131 
3132                         v6 = (s6->sin6_family == AF_INET6);
3133                         ll = v6
3134                                 ? IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)
3135                                 : ((ntohl(s4->sin_addr.s_addr) & 0xffff0000) == 0xa9fe0000);
3136                         lo = v6
3137                                 ? IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr)
3138                                 : ((ntohl(s4->sin_addr.s_addr) & 0xff000000) == 0x7f000000);
3139 
3140                         curr_weight = (!lo << 2) | (v6 << 1) | (!ll << 0);
3141 
3142                         if (curr_weight > prev_weight) {
3143                                 prev_weight = curr_weight;
3144                                 socktype = ai->ai_socktype;
3145                                 protocol = ai->ai_protocol;
3146                                 slen     = ai->ai_addrlen;
3147                                 memcpy(&ss, ai->ai_addr, slen);
3148                         }
3149                 }
3150 
3151                 freeaddrinfo(ai_results);
3152         }
3153         else {
3154                 if (!uv_to_sockaddr(host, &ss, &slen)) {
3155                         free(ai_hints);
3156                         return NULL;
3157                 }
3158 
3159                 if (serv) {
3160                         uint64_t port = ucv_to_unsigned(serv);
3161 
3162                         if (port > 65535)
3163                                 errno = ERANGE;
3164 
3165                         if (errno != 0) {
3166                                 free(ai_hints);
3167                                 err_return(errno, "Invalid port number");
3168                         }
3169 
3170                         ((struct sockaddr_in *)&ss)->sin_port = htons(port);
3171                 }
3172 
3173                 int default_socktype = SOCK_STREAM;
3174 
3175                 if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6)
3176                         default_socktype = SOCK_DGRAM;
3177 
3178                 socktype = ai_hints ? ai_hints->ai_socktype : default_socktype;
3179                 protocol = ai_hints ? ai_hints->ai_protocol : 0;
3180         }
3181 
3182         free(ai_hints);
3183 
3184         if (ss.ss_family == AF_UNSPEC)
3185                 err_return(EAI_NONAME, "Could not resolve host address");
3186 
3187         fd = socket(ss.ss_family, socktype, protocol);
3188 
3189         if (fd == -1)
3190                 err_return(errno, "socket()");
3191 
3192         if (ucv_is_truish(reuseaddr)) {
3193                 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int));
3194 
3195                 if (ret == -1)
3196                         err_return(errno, "setsockopt()");
3197         }
3198 
3199         ret = bind(fd, (struct sockaddr *)&ss, slen);
3200 
3201         if (ret == -1) {
3202                 close(fd);
3203                 err_return(errno, "bind()");
3204         }
3205 
3206         ret = listen(fd, backlog ? ucv_to_unsigned(backlog) : 128);
3207 
3208         if (ret == -1 && errno != EOPNOTSUPP) {
3209                 close(fd);
3210                 err_return(errno, "listen()");
3211         }
3212 
3213         ok_return(ucv_socket_new(vm, fd));
3214 }
3215 
3216 /**
3217  * Represents a socket handle.
3218  *
3219  * @class module:socket.socket
3220  * @hideconstructor
3221  *
3222  * @borrows module:socket#error as module:socket.socket#error
3223  *
3224  * @see {@link module:socket#create|create()}
3225  *
3226  * @example
3227  *
3228  * const sock = create(…);
3229  *
3230  * sock.getopt(…);
3231  * sock.setopt(…);
3232  *
3233  * sock.connect(…);
3234  * sock.listen(…);
3235  * sock.accept(…);
3236  * sock.bind(…);
3237  *
3238  * sock.send(…);
3239  * sock.recv(…);
3240  *
3241  * sock.shutdown(…);
3242  *
3243  * sock.fileno();
3244  * sock.peername();
3245  * sock.sockname();
3246  *
3247  * sock.close();
3248  *
3249  * sock.error();
3250  */
3251 
3252 /**
3253  * Creates a network socket instance.
3254  *
3255  * This function creates a new network socket with the specified domain and
3256  * type, determined by one of the modules `AF_*` and `SOCK_*` constants
3257  * respectively, and returns the resulting socket instance for use in subsequent
3258  * socket operations.
3259  *
3260  * The domain argument specifies the protocol family, such as AF_INET or
3261  * AF_INET6, and defaults to AF_INET if not provided.
3262  *
3263  * The type argument specifies the socket type, such as SOCK_STREAM or
3264  * SOCK_DGRAM, and defaults to SOCK_STREAM if not provided. It may also
3265  * be bitwise OR-ed with SOCK_NONBLOCK to enable non-blocking mode or
3266  * SOCK_CLOEXEC to enable close-on-exec semantics.
3267  *
3268  * The protocol argument may be used to indicate a particular protocol
3269  * to be used with the socket, and it defaults to 0 (automatically
3270  * determined protocol) if not provided.
3271  *
3272  * Returns a socket descriptor representing the newly created socket.
3273  *
3274  * Returns `null` if an error occurred during socket creation.
3275  *
3276  * @function module:socket#create
3277  *
3278  * @param {number} [domain=AF_INET]
3279  * The communication domain for the socket, e.g., AF_INET or AF_INET6.
3280  *
3281  * @param {number} [type=SOCK_STREAM]
3282  * The socket type, e.g., SOCK_STREAM or SOCK_DGRAM. It may also be
3283  * bitwise OR-ed with SOCK_NONBLOCK or SOCK_CLOEXEC.
3284  *
3285  * @param {number} [protocol=0]
3286  * The protocol to be used with the socket.
3287  *
3288  * @returns {?module:socket.socket}
3289  * A socket instance representing the newly created socket.
3290  *
3291  * @example
3292  * // Create a TCP socket
3293  * const tcp_socket = create(AF_INET, SOCK_STREAM);
3294  *
3295  * // Create a nonblocking IPv6 UDP socket
3296  * const udp_socket = create(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK);
3297  */
3298 static uc_value_t *
3299 uc_socket_create(uc_vm_t *vm, size_t nargs)
3300 {
3301         uc_value_t *domain, *type, *protocol;
3302         int sockfd, socktype;
3303 
3304         args_get(vm, nargs, NULL,
3305                 "domain", UC_INTEGER, true, &domain,
3306                 "type", UC_INTEGER, true, &type,
3307                 "protocol", UC_INTEGER, true, &protocol);
3308 
3309         socktype = type ? (int)ucv_int64_get(type) : SOCK_STREAM;
3310 
3311         sockfd = socket(
3312                 domain ? (int)ucv_int64_get(domain) : AF_INET,
3313 #if defined(__APPLE__)
3314                 socktype & ~(SOCK_NONBLOCK|SOCK_CLOEXEC),
3315 #else
3316                 socktype,
3317 #endif
3318                 protocol ? (int)ucv_int64_get(protocol) : 0);
3319 
3320         if (sockfd == -1)
3321                 err_return(errno, "socket()");
3322 
3323 #if defined(__APPLE__)
3324         if (socktype & SOCK_NONBLOCK) {
3325                 int flags = fcntl(sockfd, F_GETFL);
3326 
3327                 if (flags == -1) {
3328                         close(sockfd);
3329                         err_return(errno, "fcntl(F_GETFL)");
3330                 }
3331 
3332                 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
3333                         close(sockfd);
3334                         err_return(errno, "fcntl(F_SETFL)");
3335                 }
3336         }
3337 
3338         if (socktype & SOCK_CLOEXEC) {
3339                 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
3340                         close(sockfd);
3341                         err_return(errno, "fcntl(F_SETFD)");
3342                 }
3343         }
3344 #endif
3345 
3346         ok_return(ucv_socket_new(vm, sockfd));
3347 }
3348 
3349 /**
3350  * Creates a network socket instance from an existing file descriptor.
3351  *
3352  * Returns a socket descriptor representing the newly created socket.
3353  *
3354  * Returns `null` if an error occurred during socket creation.
3355  *
3356  * @function module:socket#open
3357  *
3358  * @param {number} [fd]
3359  * The file descriptor number
3360  *
3361  * @returns {?module:socket.socket}
3362  * A socket instance representing the socket.
3363  */
3364 static uc_value_t *
3365 uc_socket_open(uc_vm_t *vm, size_t nargs)
3366 {
3367         uc_value_t *fd;
3368 
3369         args_get(vm, nargs, NULL,
3370                 "fd", UC_INTEGER, false, &fd);
3371 
3372         ok_return(ucv_socket_new(vm, ucv_int64_get(fd)));
3373 }
3374 
3375 /**
3376  * Creates a connected socket instance with a pair file descriptor.
3377  *
3378  * This function creates new network sockets with the specified type,
3379  * determined by one of the `SOCK_*` constants, and returns resulting socket
3380  * instances for use in subsequent socket operations.
3381  *
3382  * The type argument specifies the socket type, such as SOCK_STREAM or
3383  * SOCK_DGRAM, and defaults to SOCK_STREAM if not provided. It may also
3384  * be bitwise OR-ed with SOCK_NONBLOCK to enable non-blocking mode or
3385  * SOCK_CLOEXEC to enable close-on-exec semantics.
3386  *
3387  * Returns an array of socket descriptors.
3388  *
3389  * Returns `null` if an error occurred during socket creation.
3390  *
3391  * @function module:socket#pair
3392  *
3393  * @param {number} [type=SOCK_STREAM]
3394  * The socket type, e.g., SOCK_STREAM or SOCK_DGRAM. It may also be
3395  * bitwise OR-ed with SOCK_NONBLOCK or SOCK_CLOEXEC.
3396  *
3397  * @returns {Array.<?module:socket.socket>}
3398  * Socket instances representing the newly created sockets.
3399  *
3400  * @example
3401  * // Create a TCP socket pair
3402  * const tcp_sockets = pair(SOCK_STREAM);
3403  *
3404  * // Create a nonblocking IPv6 UDP socket pair
3405  * const udp_sockets = pair(SOCK_DGRAM | SOCK_NONBLOCK);
3406  */
3407 static uc_value_t *
3408 uc_socket_pair(uc_vm_t *vm, size_t nargs)
3409 {
3410         uc_value_t *type, *res;
3411         int sockfds[2], socktype;
3412 
3413         args_get(vm, nargs, NULL,
3414                 "type", UC_INTEGER, true, &type);
3415 
3416         socktype = type ? (int)ucv_int64_get(type) : SOCK_STREAM;
3417 
3418         if (socketpair(AF_UNIX,
3419 #if defined(__APPLE__)
3420                 socktype & ~(SOCK_NONBLOCK|SOCK_CLOEXEC),
3421 #else
3422                 socktype,
3423 #endif
3424                 0, sockfds) < 0)
3425                 err_return(errno, "socketpair()");
3426 
3427 #if defined(__APPLE__)
3428         if (socktype & SOCK_NONBLOCK) {
3429                 int flags = fcntl(sockfds[0], F_GETFL);
3430 
3431                 if (flags == -1)
3432                         goto error;
3433 
3434                 if (fcntl(sockfds[0], F_SETFL, flags | O_NONBLOCK) == -1)
3435                         goto error;
3436         }
3437 
3438         if (socktype & SOCK_CLOEXEC) {
3439                 if (fcntl(sockfds[0], F_SETFD, FD_CLOEXEC) == -1)
3440                         goto error;
3441         }
3442 #endif
3443 
3444         res = ucv_array_new(vm);
3445         ucv_array_set(res, 0, ucv_socket_new(vm, sockfds[0]));
3446         ucv_array_set(res, 1, ucv_socket_new(vm, sockfds[1]));
3447         ok_return(res);
3448 
3449 #if defined(__APPLE__)
3450 error:
3451 #endif
3452         close(sockfds[0]);
3453         close(sockfds[1]);
3454         err_return(errno, "fcntl");
3455 }
3456 
3457 /**
3458  * Connects the socket to a remote address.
3459  *
3460  * Attempts to establish a connection to the specified remote address.
3461  *
3462  * Returns `true` if the connection is successfully established.
3463  * Returns `null` if an error occurred during the connection attempt.
3464  *
3465  * @function module:socket.socket#connect
3466  *
3467  * @param {string|module:socket.socket.SocketAddress} address
3468  * The address of the remote endpoint to connect to.
3469  *
3470  * @param {number} port
3471  * The port number of the remote endpoint to connect to.
3472  *
3473  * @returns {?boolean}
3474  */
3475 static uc_value_t *
3476 uc_socket_inst_connect(uc_vm_t *vm, size_t nargs)
3477 {
3478         struct sockaddr_storage ss;
3479         uc_value_t *addr, *port;
3480         unsigned long n;
3481         int ret, sockfd;
3482         socklen_t slen;
3483 
3484         args_get(vm, nargs, &sockfd,
3485                 "address", UC_NULL, false, &addr,
3486                 "port", UC_INTEGER, true, &port);
3487 
3488         if (!uv_to_sockaddr(addr, &ss, &slen))
3489                 return NULL;
3490 
3491         if (port) {
3492                  if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6)
3493                         err_return(EINVAL, "Port argument is only valid for IPv4 and IPv6 addresses");
3494 
3495                 n = ucv_to_unsigned(port);
3496 
3497                 if (n > 65535)
3498                         errno = ERANGE;
3499 
3500                 if (errno != 0)
3501                         err_return(errno, "Invalid port number");
3502 
3503                 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(n);
3504         }
3505 
3506         ret = connect(sockfd, (struct sockaddr *)&ss, slen);
3507 
3508         if (ret == -1)
3509                 err_return(errno, "connect()");
3510 
3511         ok_return(ucv_boolean_new(true));
3512 }
3513 
3514 /**
3515  * Sends data through the socket.
3516  *
3517  * Sends the provided data through the socket handle to the specified remote
3518  * address, if provided.
3519  *
3520  * Returns the number of bytes sent.
3521  * Returns `null` if an error occurred during the send operation.
3522  *
3523  * @function module:socket.socket#send
3524  *
3525  * @param {*} data
3526  * The data to be sent through the socket. String data is sent as-is, any other
3527  * type is implicitly converted to a string first before being sent on the
3528  * socket.
3529  *
3530  * @param {number} [flags]
3531  * Optional flags that modify the behavior of the send operation.
3532  *
3533  * @param {module:socket.socket.SocketAddress|number[]|string} [address]
3534  * The address of the remote endpoint to send the data to. It can be either an
3535  * IP address string, an array returned by {@link module:core#iptoarr|iptoarr()},
3536  * or an object representing a network address. If not provided, the data is
3537  * sent to the remote endpoint the socket is connected to.
3538  *
3539  * @returns {?number}
3540  *
3541  * @see {@link module:socket#sockaddr|sockaddr()}
3542  *
3543  * @example
3544  * // Send to connected socket
3545  * let tcp_sock = socket.create(socket.AF_INET, socket.SOCK_STREAM);
3546  * tcp_sock.connect("192.168.1.1", 80);
3547  * tcp_sock.send("GET / HTTP/1.0\r\n\r\n");
3548  *
3549  * // Send a datagram on unconnected socket
3550  * let udp_sock = socket.create(socket.AF_INET, socket.SOCK_DGRAM);
3551  * udp_sock.send("Hello there!", 0, "255.255.255.255:9000");
3552  * udp_sock.send("Hello there!", 0, {
3553  *   family: socket.AF_INET,      // optional
3554  *   address: "255.255.255.255",
3555  *   port: 9000
3556  * });
3557  */
3558 static uc_value_t *
3559 uc_socket_inst_send(uc_vm_t *vm, size_t nargs)
3560 {
3561         uc_value_t *data, *flags, *addr;
3562         struct sockaddr_storage ss = { 0 };
3563         struct sockaddr *sa = NULL;
3564         socklen_t salen = 0;
3565         char *buf = NULL;
3566         ssize_t ret;
3567         int sockfd;
3568 
3569         args_get(vm, nargs, &sockfd,
3570                 "data", UC_NULL, false, &data,
3571                 "flags", UC_INTEGER, true, &flags,
3572                 "address", UC_NULL, true, &addr);
3573 
3574         if (addr) {
3575                 if (!uv_to_sockaddr(addr, &ss, &salen))
3576                         return NULL;
3577 
3578                 sa = (struct sockaddr *)&ss;
3579         }
3580 
3581         if (ucv_type(data) != UC_STRING)
3582                 buf = ucv_to_string(vm, data);
3583 
3584         ret = sendto(sockfd,
3585                 buf ? buf : ucv_string_get(data),
3586                 buf ? strlen(buf) : ucv_string_length(data),
3587                 (flags ? ucv_int64_get(flags) : 0) | MSG_NOSIGNAL, sa, salen);
3588 
3589         free(buf);
3590 
3591         if (ret == -1)
3592                 err_return(errno, "send()");
3593 
3594         ok_return(ucv_int64_new(ret));
3595 }
3596 
3597 /**
3598  * Receives data from the socket.
3599  *
3600  * Receives data from the socket handle, optionally specifying the maximum
3601  * length of data to receive, flags to modify the receive behavior, and an
3602  * optional address dictionary where the function will place the address from
3603  * which the data was received (for unconnected sockets).
3604  *
3605  * Returns a string containing the received data.
3606  * Returns an empty string if the remote side closed the socket.
3607  * Returns `null` if an error occurred during the receive operation.
3608  *
3609  * @function module:socket.socket#recv
3610  *
3611  * @param {number} [length=4096]
3612  * The maximum number of bytes to receive.
3613  *
3614  * @param {number} [flags]
3615  * Optional flags that modify the behavior of the receive operation.
3616  *
3617  * @param {Object} [address]
3618  * An object where the function will store the address from which the data was
3619  * received. If provided, it will be filled with the details obtained from the
3620  * sockaddr argument of the underlying `recvfrom()` syscall. See the type
3621  * definition of {@link module:socket.socket.SocketAddress|SocketAddress} for
3622  * details on the format.
3623  *
3624  * @returns {?string}
3625  */
3626 static uc_value_t *
3627 uc_socket_inst_recv(uc_vm_t *vm, size_t nargs)
3628 {
3629         uc_value_t *length, *flags, *addrobj;
3630         struct sockaddr_storage ss = { 0 };
3631         uc_stringbuf_t *buf;
3632         ssize_t len, ret;
3633         socklen_t sslen;
3634         int sockfd;
3635 
3636         args_get(vm, nargs, &sockfd,
3637                 "length", UC_INTEGER, true, &length,
3638                 "flags", UC_INTEGER, true, &flags,
3639                 "address", UC_OBJECT, true, &addrobj);
3640 
3641         if (length) {
3642                 len = ucv_to_integer(length);
3643 
3644                 if (errno || len <= 0)
3645                         err_return(errno, "Invalid length argument");
3646         }
3647         else {
3648                 len = 4096;
3649         }
3650 
3651         buf = strbuf_alloc(len);
3652 
3653         if (!buf)
3654                 return NULL;
3655 
3656         do {
3657                 sslen = sizeof(ss);
3658                 ret = recvfrom(sockfd, strbuf_data(buf), len,
3659                         flags ? ucv_int64_get(flags) : 0, (struct sockaddr *)&ss, &sslen);
3660         } while (ret == -1 && errno == EINTR);
3661 
3662         if (ret == -1) {
3663                 strbuf_free(buf);
3664                 err_return(errno, "recv()");
3665         }
3666 
3667         if (addrobj)
3668                 sockaddr_to_uv(&ss, addrobj);
3669 
3670         ok_return(strbuf_finish(&buf, ret));
3671 }
3672 
3673 uc_declare_vector(strbuf_array_t, uc_stringbuf_t *);
3674 
3675 #if defined(__linux__)
3676 static void optmem_max(size_t *sz) {
3677         char buf[sizeof("18446744073709551615")] = { 0 };
3678         int fd, rv;
3679 
3680         fd = open("/proc/sys/net/core/optmem_max", O_RDONLY);
3681 
3682         if (fd >= 0) {
3683                 if (read(fd, buf, sizeof(buf) - 1) > 0) {
3684                         rv = strtol(buf, NULL, 10);
3685 
3686                         if (rv > 0 && (size_t)rv < *sz)
3687                                 *sz = rv;
3688                 }
3689 
3690                 if (fd > 2)
3691                         close(fd);
3692         }
3693 }
3694 #else
3695 # define optmem_max(x)
3696 #endif
3697 
3698 
3699 /**
3700  * Represents a single control (ancillary data) message returned
3701  * in the *ancillary* array by {@link module:socket.socket#recvmsg|`recvmsg()`}.
3702  *
3703  * @typedef {Object} module:socket.socket.ControlMessage
3704  * @property {number} level
3705  * The message socket level (`cmsg_level`), e.g. `SOL_SOCKET`.
3706  *
3707  * @property {number} type
3708  * The protocol specific message type (`cmsg_type`), e.g. `SCM_RIGHTS`.
3709  *
3710  * @property {*} data
3711  * The payload of the control message. If the control message type is known by
3712  * the socket module, it is represented as a mixed value (array, object, number,
3713  * etc.) with structure specific to the control message type. If the control
3714  * message cannot be decoded, *data* is set to a string value containing the raw
3715  * payload.
3716  */
3717 static uc_value_t *
3718 decode_cmsg(uc_vm_t *vm, struct cmsghdr *cmsg)
3719 {
3720         char *s = (char *)CMSG_DATA(cmsg);
3721         size_t sz = cmsg->cmsg_len - sizeof(*cmsg);
3722         struct sockaddr_storage *ss;
3723         uc_value_t *fdarr;
3724         struct stat st;
3725         int *fds;
3726 
3727         for (size_t i = 0; i < ARRAY_SIZE(cmsgtypes); i++) {
3728 
3729                 if (cmsgtypes[i].level != cmsg->cmsg_level)
3730                         continue;
3731 
3732                 if (cmsgtypes[i].type != cmsg->cmsg_type)
3733                         continue;
3734 
3735                 switch ((uintptr_t)cmsgtypes[i].ctype) {
3736                 case (uintptr_t)CV_INT:
3737                         return ucv_int64_new(parse_integer(s, sz));
3738 
3739                 case (uintptr_t)CV_UINT:
3740                 case (uintptr_t)CV_BE32:
3741                         return ucv_uint64_new(parse_unsigned(s, sz));
3742 
3743                 case (uintptr_t)CV_SOCKADDR:
3744                         ss = (struct sockaddr_storage *)s;
3745 
3746                         if ((sz >= sizeof(struct sockaddr_in) &&
3747                              ss->ss_family == AF_INET) ||
3748                             (sz >= sizeof(struct sockaddr_in6) &&
3749                              ss->ss_family == AF_INET6))
3750                         {
3751                                 uc_value_t *addr = ucv_object_new(vm);
3752 
3753                                 if (sockaddr_to_uv(ss, addr))
3754                                         return addr;
3755 
3756                                 ucv_put(addr);
3757                         }
3758 
3759                         return NULL;
3760 
3761                 case (uintptr_t)CV_FDS:
3762                         fdarr = ucv_array_new_length(vm, sz / sizeof(int));
3763                         fds = (int *)s;
3764 
3765                         for (size_t i = 0; i < sz / sizeof(int); i++) {
3766                                 if (fstat(fds[i], &st) == 0) {
3767                                         uc_resource_type_t *t;
3768 
3769                                         if (S_ISSOCK(st.st_mode)) {
3770                                                 t = ucv_resource_type_lookup(vm, "socket");
3771 
3772                                                 ucv_array_push(fdarr,
3773                                                         ucv_resource_new(t, (void *)(intptr_t)fds[i]));
3774 
3775                                                 continue;
3776                                         }
3777                                         else if (S_ISDIR(st.st_mode)) {
3778                                                 t = ucv_resource_type_lookup(vm, "fs.dir");
3779 
3780                                                 if (t) {
3781                                                         DIR *d = fdopendir(fds[i]);
3782 
3783                                                         if (d) {
3784                                                                 ucv_array_push(fdarr, ucv_resource_new(t, d));
3785                                                                 continue;
3786                                                         }
3787                                                 }
3788                                         }
3789                                         else {
3790                                                 t = ucv_resource_type_lookup(vm, "fs.file");
3791 
3792                                                 if (t) {
3793                                                         int n = fcntl(fds[i], F_GETFL);
3794                                                         const char *mode;
3795 
3796                                                         if (n <= 0 || (n & O_ACCMODE) == O_RDONLY)
3797                                                                 mode = "r";
3798                                                         else if ((n & O_ACCMODE) == O_WRONLY)
3799                                                                 mode = (n & O_APPEND) ? "a" : "w";
3800                                                         else
3801                                                                 mode = (n & O_APPEND) ? "a+" : "w+";
3802 
3803                                                         FILE *f = fdopen(fds[i], mode);
3804 
3805                                                         if (f) {
3806                                                                 ucv_array_push(fdarr, uc_resource_new(t, f));
3807                                                                 continue;
3808                                                         }
3809                                                 }
3810                                         }
3811                                 }
3812 
3813                                 ucv_array_push(fdarr, ucv_int64_new(fds[i]));
3814                         }
3815 
3816                         return fdarr;
3817 
3818                 case (uintptr_t)CV_STRING:
3819                         break;
3820 
3821                 default:
3822                         if (sz >= cmsgtypes[i].ctype->size)
3823                                 return struct_to_uv(s, cmsgtypes[i].ctype);
3824                 }
3825 
3826                 break;
3827         }
3828 
3829         return ucv_string_new_length(s, sz);
3830 }
3831 
3832 static size_t
3833 estimate_cmsg_size(uc_value_t *uv)
3834 {
3835         int cmsg_level = ucv_to_integer(ucv_object_get(uv, "level", NULL));
3836         int cmsg_type = ucv_to_integer(ucv_object_get(uv, "type", NULL));
3837         uc_value_t *val = ucv_object_get(uv, "data", NULL);
3838 
3839         for (size_t i = 0; i < ARRAY_SIZE(cmsgtypes); i++) {
3840                 if (cmsgtypes[i].level != cmsg_level)
3841                         continue;
3842 
3843                 if (cmsgtypes[i].type != cmsg_type)
3844                         continue;
3845 
3846                 switch ((uintptr_t)cmsgtypes[i].ctype) {
3847                 case (uintptr_t)CV_INT:      return sizeof(int);
3848                 case (uintptr_t)CV_UINT:     return sizeof(unsigned int);
3849                 case (uintptr_t)CV_BE32:     return sizeof(uint32_t);
3850                 case (uintptr_t)CV_SOCKADDR: return sizeof(struct sockaddr_storage);
3851                 case (uintptr_t)CV_FDS:      return ucv_array_length(val) * sizeof(int);
3852                 case (uintptr_t)CV_STRING:   return ucv_string_length(val);
3853                 default:                     return cmsgtypes[i].ctype->size;
3854                 }
3855         }
3856 
3857         switch (ucv_type(val)) {
3858                 case UC_BOOLEAN: return sizeof(unsigned int);
3859                 case UC_INTEGER: return sizeof(int);
3860                 case UC_STRING:  return ucv_string_length(val);
3861                 default:         return 0;
3862         }
3863 }
3864 
3865 static bool
3866 encode_cmsg(uc_vm_t *vm, uc_value_t *uv, struct cmsghdr *cmsg)
3867 {
3868         struct { int *entries; size_t count; } fds = { 0 };
3869         void *dataptr = NULL;
3870         socklen_t datasz = 0;
3871         char *st = NULL;
3872         size_t i;
3873         union {
3874                 int i;
3875                 unsigned int u;
3876                 uint32_t u32;
3877                 struct sockaddr_storage ss;
3878         } val;
3879 
3880         cmsg->cmsg_level = ucv_to_integer(ucv_object_get(uv, "level", NULL));
3881         cmsg->cmsg_type = ucv_to_integer(ucv_object_get(uv, "type", NULL));
3882 
3883         uc_value_t *data = ucv_object_get(uv, "data", NULL);
3884 
3885         for (i = 0; i < ARRAY_SIZE(cmsgtypes); i++) {
3886                 if (cmsgtypes[i].level != cmsg->cmsg_level)
3887                         continue;
3888 
3889                 if (cmsgtypes[i].type != cmsg->cmsg_type)
3890                         continue;
3891 
3892                 switch ((uintptr_t)cmsgtypes[i].ctype) {
3893                 case (uintptr_t)CV_INT:
3894                         val.i = ucv_to_integer(data);
3895                         datasz = sizeof(val.i);
3896                         dataptr = &val;
3897                         break;
3898 
3899                 case (uintptr_t)CV_UINT:
3900                         val.u = ucv_to_unsigned(data);
3901                         datasz = sizeof(val.u);
3902                         dataptr = &val;
3903                         break;
3904 
3905                 case (uintptr_t)CV_BE32:
3906                         val.u32 = ucv_to_unsigned(data);
3907                         datasz = sizeof(val.u32);
3908                         dataptr = &val;
3909                         break;
3910 
3911                 case (uintptr_t)CV_SOCKADDR:
3912                         if (uv_to_sockaddr(data, &val.ss, &datasz))
3913                                 dataptr = &val;
3914                         else
3915                                 datasz = 0, dataptr = NULL;
3916                         break;
3917 
3918                 case (uintptr_t)CV_FDS:
3919                         if (ucv_type(data) == UC_ARRAY) {
3920                                 for (size_t i = 0; i < ucv_array_length(data); i++) {
3921                                         int fd;
3922 
3923                                         if (uv_to_fileno(vm, ucv_array_get(data, i), &fd))
3924                                                 uc_vector_push(&fds, fd);
3925                                 }
3926                         }
3927 
3928                         datasz = sizeof(fds.entries[0]) * fds.count;
3929                         dataptr = fds.entries;
3930                         break;
3931 
3932                 case (uintptr_t)CV_STRING:
3933                         datasz = ucv_string_length(data);
3934                         dataptr = ucv_string_get(data);
3935                         break;
3936 
3937                 default:
3938                         st = uv_to_struct(data, cmsgtypes[i].ctype);
3939                         datasz = st ? cmsgtypes[i].ctype->size : 0;
3940                         dataptr = st;
3941                         break;
3942                 }
3943 
3944                 break;
3945         }
3946 
3947         /* we don't know this kind of control message, guess encoding */
3948         if (i == ARRAY_SIZE(cmsgtypes)) {
3949                 switch (ucv_type(data)) {
3950                 /* treat boolean as int with values 1 or 0 */
3951                 case UC_BOOLEAN:
3952                         val.u = ucv_boolean_get(data);
3953                         dataptr = &val;
3954                         datasz = sizeof(val.u);
3955                         break;
3956 
3957                 /* treat integers as int */
3958                 case UC_INTEGER:
3959                         if (ucv_is_u64(data)) {
3960                                 val.u = ucv_uint64_get(data);
3961                                 datasz = sizeof(val.u);
3962                         }
3963                         else {
3964                                 val.i = ucv_int64_get(data);
3965                                 datasz = sizeof(val.i);
3966                         }
3967 
3968                         dataptr = &val;
3969                         break;
3970 
3971                 /* pass strings as-is */
3972                 case UC_STRING:
3973                         dataptr = ucv_string_get(data);
3974                         datasz = ucv_string_length(data);
3975                         break;
3976 
3977                 default:
3978                         break;
3979                 }
3980         }
3981 
3982         cmsg->cmsg_len = CMSG_LEN(datasz);
3983 
3984         if (dataptr)
3985                 memcpy(CMSG_DATA(cmsg), dataptr, datasz);
3986 
3987         uc_vector_clear(&fds);
3988         free(st);
3989 
3990         return true;
3991 }
3992 
3993 /**
3994  * Sends a message through the socket.
3995  *
3996  * Sends a message through the socket handle, supporting complex message
3997  * structures including multiple data buffers and ancillary data. This function
3998  * allows for precise control over the message content and delivery behavior.
3999  *
4000  * Returns the number of sent bytes.
4001  *
4002  * Returns `null` if an error occurred.
4003  *
4004  * @function module:socket.socket#sendmsg
4005  *
4006  * @param {*} [data]
4007  * The data to be sent. If a string is provided, it is sent as is. If an array
4008  * is specified, each item is sent as a separate `struct iovec`. Non-string
4009  * values are implicitly converted to a string and sent. If omitted, only
4010  * ancillary data and address are considered.
4011  *
4012  * @param {module:socket.socket.ControlMessage[]|string} [ancillaryData]
4013  * Optional ancillary data to be sent. If an array is provided, each element is
4014  * converted to a control message. If a string is provided, it is sent as-is
4015  * without further interpretation. Refer to
4016  * {@link module:socket.socket#recvmsg|`recvmsg()`} and
4017  * {@link module:socket.socket.ControlMessage|ControlMessage} for details.
4018  *
4019  * @param {module:socket.socket.SocketAddress} [address]
4020  * The destination address for the message. If provided, it sets or overrides
4021  * the packet destination address.
4022  *
4023  * @param {number} [flags]
4024  * Optional flags to modify the behavior of the send operation. This should be a
4025  * bitwise OR-ed combination of `MSG_*` flag values.
4026  *
4027  * @returns {?number}
4028  * Returns the number of bytes sent on success, or `null` if an error occurred.
4029  *
4030  * @example
4031  * // Send file descriptors over domain socket
4032  * const f1 = fs.open("example.txt", "w");
4033  * const f2 = fs.popen("date +%s", "r");
4034  * const sk = socket.connect({ family: socket.AF_UNIX, path: "/tmp/socket" });
4035 
4036  * sk.sendmsg("Hi there, here's some descriptors!", [
4037  *      { level: socket.SOL_SOCKET, type: socket.SCM_RIGHTS, data: [ f1, f2 ] }
4038  * ]);
4039  *
4040  * // Send multiple values in one datagram
4041  * sk.sendmsg([ "This", "is", "one", "message" ]);
4042  */
4043 static uc_value_t *
4044 uc_socket_inst_sendmsg(uc_vm_t *vm, size_t nargs)
4045 {
4046         uc_value_t *data, *ancdata, *addr, *flags;
4047         struct sockaddr_storage ss = { 0 };
4048         strbuf_array_t sbarr = { 0 };
4049         struct msghdr msg = { 0 };
4050         struct iovec vec = { 0 };
4051         int flagval, sockfd;
4052         socklen_t slen;
4053         ssize_t ret;
4054 
4055         args_get(vm, nargs, &sockfd,
4056                 "data", UC_NULL, true, &data,
4057                 "ancillary data", UC_NULL, true, &ancdata,
4058                 "address", UC_OBJECT, true, &addr,
4059                 "flags", UC_INTEGER, true, &flags);
4060 
4061         flagval = flags ? ucv_int64_get(flags) : 0;
4062 
4063         /* treat string ancdata arguemnt as raw controldata buffer */
4064         if (ucv_type(ancdata) == UC_STRING) {
4065                 msg.msg_control = ucv_string_get(ancdata);
4066                 msg.msg_controllen = ucv_string_length(ancdata);
4067         }
4068         /* encode ancdata passed as array */
4069         else if (ucv_type(ancdata) == UC_ARRAY) {
4070                 msg.msg_controllen = 0;
4071 
4072                 for (size_t i = 0; i < ucv_array_length(ancdata); i++) {
4073                         size_t sz = estimate_cmsg_size(ucv_array_get(ancdata, i));
4074 
4075                         if (sz > 0)
4076                                 msg.msg_controllen += CMSG_SPACE(sz);
4077                 }
4078 
4079                 if (msg.msg_controllen > 0) {
4080                         msg.msg_control = xalloc(msg.msg_controllen);
4081 
4082                         struct cmsghdr *cmsg = NULL;
4083 
4084                         for (size_t i = 0; i < ucv_array_length(ancdata); i++) {
4085 #ifdef __clang_analyzer__
4086                                 /* Clang static analyzer assumes that CMSG_*HDR() returns
4087                                  * allocated heap pointers and not pointers into the
4088                                  * msg.msg_control buffer. Nudge it. */
4089                                 cmsg = (struct cmsghdr *)msg.msg_control;
4090 #else
4091                                 cmsg = cmsg ? CMSG_NXTHDR(&msg, cmsg) : CMSG_FIRSTHDR(&msg);
4092 #endif
4093 
4094                                 if (!cmsg) {
4095                                         free(msg.msg_control);
4096                                         err_return(ENOBUFS, "Not enough CMSG buffer space");
4097                                 }
4098 
4099                                 if (!encode_cmsg(vm, ucv_array_get(ancdata, i), cmsg)) {
4100                                         free(msg.msg_control);
4101                                         return NULL;
4102                                 }
4103                         }
4104 
4105                         msg.msg_controllen = (cmsg != NULL)
4106                                 ? (char *)cmsg - (char *)msg.msg_control + CMSG_SPACE(cmsg->cmsg_len)
4107                                 : 0;
4108                 }
4109         }
4110         else if (ancdata) {
4111                 err_return(EINVAL, "Ancillary data must be string or array value");
4112         }
4113 
4114         /* prepare iov array */
4115         if (ucv_type(data) == UC_ARRAY) {
4116                 msg.msg_iovlen = ucv_array_length(data);
4117                 msg.msg_iov = (msg.msg_iovlen > 1)
4118                         ? xalloc(sizeof(vec) * msg.msg_iovlen) : &vec;
4119 
4120                 for (size_t i = 0; i < (size_t)msg.msg_iovlen; i++) {
4121                         uc_value_t *item = ucv_array_get(data, i);
4122 
4123                         if (ucv_type(item) == UC_STRING) {
4124                                 msg.msg_iov[i].iov_base = _ucv_string_get(&((uc_array_t *)data)->entries[i]);
4125                                 msg.msg_iov[i].iov_len = ucv_string_length(item);
4126                         }
4127                         else if (item) {
4128                                 struct printbuf *pb = xprintbuf_new();
4129                                 uc_vector_push(&sbarr, pb);
4130                                 ucv_to_stringbuf(vm, pb, item, false);
4131                                 msg.msg_iov[i].iov_base = pb->buf;
4132                                 msg.msg_iov[i].iov_len = pb->bpos;
4133                         }
4134                 }
4135         }
4136         else if (ucv_type(data) == UC_STRING) {
4137                 msg.msg_iovlen = 1;
4138                 msg.msg_iov = &vec;
4139                 vec.iov_base = ucv_string_get(data);
4140                 vec.iov_len = ucv_string_length(data);
4141         }
4142         else if (data) {
4143                 struct printbuf *pb = xprintbuf_new();
4144                 uc_vector_push(&sbarr, pb);
4145                 ucv_to_stringbuf(vm, pb, data, false);
4146                 msg.msg_iovlen = 1;
4147                 msg.msg_iov = &vec;
4148                 vec.iov_base = pb->buf;
4149                 vec.iov_len = pb->bpos;
4150         }
4151 
4152         /* prepare address */
4153         if (addr && uv_to_sockaddr(addr, &ss, &slen)) {
4154                 msg.msg_name = &ss;
4155                 msg.msg_namelen = slen;
4156         }
4157 
4158         /* now send actual data */
4159         do {
4160                 ret = sendmsg(sockfd, &msg, flagval);
4161         } while (ret == -1 && errno == EINTR);
4162 
4163         while (sbarr.count > 0)
4164                 printbuf_free(sbarr.entries[--sbarr.count]);
4165 
4166         uc_vector_clear(&sbarr);
4167 
4168         if (msg.msg_iov != &vec)
4169                 free(msg.msg_iov);
4170 
4171         free(msg.msg_control);
4172 
4173         if (ret == -1)
4174                 err_return(errno, "sendmsg()");
4175 
4176         ok_return(ucv_int64_new(ret));
4177 }
4178 
4179 
4180 
4181 /**
4182  * Represents a message object returned by
4183  * {@link module:socket.socket#recvmsg|`recvmsg()`}.
4184  *
4185  * @typedef {Object} module:socket.socket.ReceivedMessage
4186  * @property {number} flags
4187  * Integer value containing bitwise OR-ed `MSG_*` result flags returned by the
4188  * underlying receive call.
4189  *
4190  * @property {number} length
4191  * Integer value containing the number of bytes returned by the `recvmsg()`
4192  * syscall, which might be larger than the received data in case `MSG_TRUNC`
4193  * was passed.
4194  *
4195  * @property {module:socket.socket.SocketAddress} address
4196  * The address from which the message was received.
4197  *
4198  * @property {string[]|string} data
4199  * An array of strings, each representing the received message data.
4200  * Each string corresponds to one buffer size specified in the *sizes* argument.
4201  * If a single receive size was passed instead of an array of sizes, *data* will
4202  * hold a string containing the received data.
4203  *
4204  * @property {module:socket.socket.ControlMessage[]} [ancillary]
4205  * An array of received control messages. Only included if a non-zero positive
4206  * *ancillarySize* was passed to `recvmsg()`.
4207  */
4208 
4209 /**
4210  * Receives a message from the socket.
4211  *
4212  * Receives a message from the socket handle, allowing for more complex data
4213  * reception compared to `recv()`. This includes the ability to receive
4214  * ancillary data (such as file descriptors, credentials, etc.), multiple
4215  * message segments, and optional flags to modify the receive behavior.
4216  *
4217  * Returns an object containing the received message data, ancillary data,
4218  * and the sender's address.
4219  *
4220  * Returns `null` if an error occurred during the receive operation.
4221  *
4222  * @function module:socket.socket#recvmsg
4223  *
4224  * @param {number[]|number} [sizes]
4225  * Specifies the sizes of the buffers used for receiving the message. If an
4226  * array of numbers is provided, each number determines the size of an
4227  * individual buffer segment, creating multiple `struct iovec` for reception.
4228  * If a single number is provided, a single buffer of that size is used.
4229  *
4230  * @param {number} [ancillarySize]
4231  * The size allocated for the ancillary data buffer. If not provided, ancillary
4232  * data is not processed.
4233  *
4234  * @param {number} [flags]
4235  * Optional flags to modify the behavior of the receive operation. This should
4236  * be a bitwise OR-ed combination of flag values.
4237  *
4238  * @returns {?module:socket.socket.ReceivedMessage}
4239  * An object containing the received message data, ancillary data,
4240  * and the sender's address.
4241  *
4242  * @example
4243  * // Receive file descriptors over domain socket
4244  * const sk = socket.listen({ family: socket.AF_UNIX, path: "/tmp/socket" });
4245  * sk.setopt(socket.SOL_SOCKET, socket.SO_PASSCRED, true);
4246  *
4247  * const msg = sk.recvmsg(1024, 1024); *
4248  * for (let cmsg in msg.ancillary)
4249  *   if (cmsg.level == socket.SOL_SOCKET && cmsg.type == socket.SCM_RIGHTS)
4250  *     print(`Got some descriptors: ${cmsg.data}!\n`);
4251  *
4252  * // Receive message in segments of 10, 128 and 512 bytes
4253  * const msg = sk.recvmsg([ 10, 128, 512 ]);
4254  * print(`Message parts: ${msg.data[0]}, ${msg.data[1]}, ${msg.data[2]}\n`);
4255  *
4256  * // Peek buffer
4257  * const msg = sk.recvmsg(0, 0, socket.MSG_PEEK|socket.MSG_TRUNC);
4258  * print(`Received ${length(msg.data)} bytes, ${msg.length} bytes available\n`);
4259  */
4260 static uc_value_t *
4261 uc_socket_inst_recvmsg(uc_vm_t *vm, size_t nargs)
4262 {
4263         uc_value_t *length, *anclength, *flags, *rv;
4264         struct sockaddr_storage ss = { 0 };
4265         strbuf_array_t sbarr = { 0 };
4266         struct msghdr msg = { 0 };
4267         struct iovec vec = { 0 };
4268         int flagval, sockfd;
4269         ssize_t ret;
4270 
4271         args_get(vm, nargs, &sockfd,
4272                 "length", UC_NULL, true, &length,
4273                 "ancillary length", UC_INTEGER, true, &anclength,
4274                 "flags", UC_INTEGER, true, &flags);
4275 
4276         flagval = flags ? ucv_int64_get(flags) : 0;
4277 
4278         /* prepare ancillary data buffer */
4279         if (anclength) {
4280                 size_t sz = ucv_to_unsigned(anclength);
4281 
4282                 if (errno != 0)
4283                         err_return(errno, "Invalid ancillary data length");
4284 
4285                 optmem_max(&sz);
4286 
4287                 if (sz > 0) {
4288                         msg.msg_controllen = sz;
4289                         msg.msg_control = xalloc(sz);
4290                 }
4291         }
4292 
4293         /* prepare iov array */
4294         if (ucv_type(length) == UC_ARRAY) {
4295                 msg.msg_iovlen = ucv_array_length(length);
4296                 msg.msg_iov = (msg.msg_iovlen > 1)
4297                         ? xalloc(sizeof(vec) * msg.msg_iovlen) : &vec;
4298 
4299                 for (size_t i = 0; i < (size_t)msg.msg_iovlen; i++) {
4300                         size_t sz = ucv_to_unsigned(ucv_array_get(length, i));
4301 
4302                         if (errno != 0) {
4303                                 while (sbarr.count > 0)
4304                                         strbuf_free(sbarr.entries[--sbarr.count]);
4305 
4306                                 uc_vector_clear(&sbarr);
4307 
4308                                 if (msg.msg_iov != &vec)
4309                                         free(msg.msg_iov);
4310 
4311                                 free(msg.msg_control);
4312 
4313                                 err_return(errno, "Invalid length value");
4314                         }
4315 
4316                         uc_vector_push(&sbarr, strbuf_alloc(sz));
4317                         msg.msg_iov[i].iov_base = strbuf_data(sbarr.entries[i]);
4318                         msg.msg_iov[i].iov_len = sz;
4319                 }
4320         }
4321         else {
4322                 size_t sz = ucv_to_unsigned(length);
4323 
4324                 if (errno != 0) {
4325                         free(msg.msg_control);
4326                         err_return(errno, "Invalid length value");
4327                 }
4328 
4329                 uc_vector_push(&sbarr, strbuf_alloc(sz));
4330 
4331                 msg.msg_iovlen = 1;
4332                 msg.msg_iov = &vec;
4333                 vec.iov_base = strbuf_data(sbarr.entries[0]);
4334                 vec.iov_len = sz;
4335         }
4336 
4337         /* now receive actual data */
4338         msg.msg_name = &ss;
4339         msg.msg_namelen = sizeof(ss);
4340 
4341         do {
4342                 ret = recvmsg(sockfd, &msg, flagval);
4343         } while (ret == -1 && errno == EINTR);
4344 
4345         if (ret == -1) {
4346                 while (sbarr.count > 0)
4347                         strbuf_free(sbarr.entries[--sbarr.count]);
4348 
4349                 uc_vector_clear(&sbarr);
4350 
4351                 if (msg.msg_iov != &vec)
4352                         free(msg.msg_iov);
4353 
4354                 free(msg.msg_control);
4355 
4356                 err_return(errno, "recvmsg()");
4357         }
4358 
4359         rv = ucv_object_new(vm);
4360 
4361         ucv_object_add(rv, "flags", ucv_int64_new(msg.msg_flags));
4362         ucv_object_add(rv, "length", ucv_int64_new(ret));
4363 
4364         if (msg.msg_namelen > 0) {
4365                 uc_value_t *addr = ucv_object_new(vm);
4366 
4367                 if (sockaddr_to_uv(&ss, addr))
4368                         ucv_object_add(rv, "address", addr);
4369                 else
4370                         ucv_put(addr);
4371         }
4372 
4373         if (msg.msg_controllen > 0) {
4374                 uc_value_t *ancillary = ucv_array_new(vm);
4375 
4376                 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
4377                      cmsg != NULL;
4378                      cmsg = CMSG_NXTHDR(&msg, cmsg))
4379                 {
4380                         uc_value_t *c = ucv_object_new(vm);
4381 
4382                         ucv_object_add(c, "level", ucv_int64_new(cmsg->cmsg_level));
4383                         ucv_object_add(c, "type", ucv_int64_new(cmsg->cmsg_type));
4384                         ucv_object_add(c, "data", decode_cmsg(vm, cmsg));
4385 
4386                         ucv_array_push(ancillary, c);
4387                 }
4388 
4389                 ucv_object_add(rv, "ancillary", ancillary);
4390         }
4391 
4392         if (ret >= 0) {
4393                 if (ucv_type(length) == UC_ARRAY) {
4394                         uc_value_t *data = ucv_array_new_length(vm, msg.msg_iovlen);
4395 
4396                         for (size_t i = 0; i < (size_t)msg.msg_iovlen; i++) {
4397                                 size_t sz = ret;
4398 
4399                                 if (sz > msg.msg_iov[i].iov_len)
4400                                         sz = msg.msg_iov[i].iov_len;
4401 
4402                                 ucv_array_push(data, strbuf_finish(&sbarr.entries[i], sz));
4403                                 ret -= sz;
4404                         }
4405 
4406                         ucv_object_add(rv, "data", data);
4407                 }
4408                 else {
4409                         size_t sz = ret;
4410 
4411                         if (sz > msg.msg_iov[0].iov_len)
4412                                 sz = msg.msg_iov[0].iov_len;
4413 
4414                         ucv_object_add(rv, "data", strbuf_finish(&sbarr.entries[0], sz));
4415                 }
4416         }
4417 
4418         uc_vector_clear(&sbarr);
4419 
4420         if (msg.msg_iov != &vec)
4421                 free(msg.msg_iov);
4422 
4423         free(msg.msg_control);
4424 
4425         ok_return(rv);
4426 }
4427 
4428 /**
4429  * Binds a socket to a specific address.
4430  *
4431  * This function binds the socket to the specified address.
4432  *
4433  * Returns `true` if the socket is successfully bound.
4434  *
4435  * Returns `null` on error, e.g. when the address is in use.
4436  *
4437  * @function module:socket.socket#bind
4438  *
4439  * @param {string|module:socket.socket.SocketAddress} address
4440  * The IP address to bind the socket to.
4441  *
4442  * @returns {?boolean}
4443  *
4444  * @example
4445  * const sock = socket.create(…);
4446  * const success = sock.bind("192.168.0.1:80");
4447  *
4448  * if (success)
4449  *     print(`Socket bound successfully!\n`);
4450  * else
4451  *     print(`Failed to bind socket: ${sock.error()}.\n`);
4452  */
4453 static uc_value_t *
4454 uc_socket_inst_bind(uc_vm_t *vm, size_t nargs)
4455 {
4456         struct sockaddr_storage ss = { 0 };
4457         uc_value_t *addr;
4458         socklen_t slen;
4459         int sockfd;
4460 
4461         args_get(vm, nargs, &sockfd,
4462                 "address", UC_NULL, true, &addr);
4463 
4464         if (addr) {
4465                 if (!uv_to_sockaddr(addr, &ss, &slen))
4466                         return NULL;
4467 
4468                 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1)
4469                         err_return(errno, "bind()");
4470         }
4471         else {
4472 #if defined(__linux__)
4473                 int sval = 0;
4474                 slen = sizeof(sval);
4475 
4476                 if (getsockopt(sockfd, SOL_SOCKET, SO_DOMAIN, &sval, &slen) == -1)
4477                         err_return(errno, "getsockopt()");
4478 
4479                 switch (sval) {
4480                 case AF_INET6:
4481                         ss.ss_family = AF_INET6;
4482                         slen = sizeof(struct sockaddr_in6);
4483                         break;
4484 
4485                 case AF_INET:
4486                         ss.ss_family = AF_INET;
4487                         slen = sizeof(struct sockaddr_in);
4488                         break;
4489 
4490                 default:
4491                         err_return(EAFNOSUPPORT, "Unsupported socket address family");
4492                 }
4493 
4494                 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1)
4495                         err_return(errno, "bind()");
4496 #else
4497                 ss.ss_family = AF_INET6;
4498                 slen = sizeof(struct sockaddr_in6);
4499 
4500                 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1) {
4501                         if (errno != EAFNOSUPPORT)
4502                                 err_return(errno, "bind()");
4503 
4504                         ss.ss_family = AF_INET;
4505                         slen = sizeof(struct sockaddr_in);
4506 
4507                         if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1)
4508                                 err_return(errno, "bind()");
4509                 }
4510 #endif
4511         }
4512 
4513         ok_return(ucv_boolean_new(true));
4514 }
4515 
4516 /**
4517  * Listen for connections on a socket.
4518  *
4519  * This function marks the socket as a passive socket, that is, as a socket that
4520  * will be used to accept incoming connection requests using `accept()`.
4521  *
4522  * The `backlog` parameter specifies the maximum length to which the queue of
4523  * pending connections may grow. If a connection request arrives when the queue
4524  * is full, the client connection might get refused.
4525  *
4526  * If `backlog` is not provided, it defaults to 128.
4527  *
4528  * Returns `true` if the socket is successfully marked as passive.
4529  * Returns `null` if an error occurred, e.g. when the requested port is in use.
4530  *
4531  * @function module:socket.socket#listen
4532  *
4533  * @param {number} [backlog=128]
4534  * The maximum length of the queue of pending connections.
4535  *
4536  * @returns {?boolean}
4537  *
4538  * @see {@link module:socket.socket#accept|accept()}
4539  *
4540  * @example
4541  * const sock = socket.create(…);
4542  * sock.bind(…);
4543  *
4544  * const success = sock.listen(10);
4545  * if (success)
4546  *     print(`Socket is listening for incoming connections!\n`);
4547  * else
4548  *     print(`Failed to listen on socket: ${sock.error()}\n`);
4549  */
4550 static uc_value_t *
4551 uc_socket_inst_listen(uc_vm_t *vm, size_t nargs)
4552 {
4553         uc_value_t *backlog;
4554         int ret, sockfd;
4555 
4556         args_get(vm, nargs, &sockfd,
4557                 "backlog", UC_INTEGER, true, &backlog);
4558 
4559         ret = listen(sockfd, backlog ? ucv_to_unsigned(backlog) : 128);
4560 
4561         if (ret == -1)
4562                 err_return(errno, "listen()");
4563 
4564         ok_return(ucv_boolean_new(true));
4565 }
4566 
4567 /**
4568  * Accept a connection on a socket.
4569  *
4570  * This function accepts a connection on the socket. It extracts the first
4571  * connection request on the queue of pending connections, creates a new
4572  * connected socket, and returns a new socket handle referring to that socket.
4573  * The newly created socket is not in listening state and has no backlog.
4574  *
4575  * When a optional `address` dictionary is provided, it is populated with the
4576  * remote address details of the peer socket.
4577  *
4578  * The optional `flags` parameter is a bitwise-or-ed number of flags to modify
4579  * the behavior of accepted peer socket. Possible values are:
4580  * - `SOCK_CLOEXEC`: Enable close-on-exec semantics for the new socket.
4581  * - `SOCK_NONBLOCK`: Enable nonblocking mode for the new socket.
4582  *
4583  * Returns a socket handle representing the newly created peer socket of the
4584  * accepted connection.
4585  *
4586  * Returns `null` if an error occurred.
4587  *
4588  * @function module:socket.socket#accept
4589  *
4590  * @param {object} [address]
4591  * An optional dictionary to receive the address details of the peer socket.
4592  * See {@link module:socket.socket.SocketAddress|SocketAddress} for details.
4593  *
4594  * @param {number} [flags]
4595  * Optional flags to modify the behavior of the peer socket.
4596  *
4597  * @returns {?module:socket.socket}
4598  *
4599  * @example
4600  * const sock = socket.create(…);
4601  * sock.bind(…);
4602  * sock.listen();
4603  *
4604  * const peerAddress = {};
4605  * const newSocket = sock.accept(peerAddress, socket.SOCK_CLOEXEC);
4606  * if (newSocket)
4607  *     print(`Accepted connection from: ${peerAddress}\n`);
4608  * else
4609  *     print(`Failed to accept connection: ${sock.error()}\n`);
4610  */
4611 static uc_value_t *
4612 uc_socket_inst_accept(uc_vm_t *vm, size_t nargs)
4613 {
4614         struct sockaddr_storage ss = { 0 };
4615         int peerfd, sockfd, sockflags;
4616         uc_value_t *addrobj, *flags;
4617         socklen_t slen;
4618 
4619         args_get(vm, nargs, &sockfd,
4620                 "address", UC_OBJECT, true, &addrobj,
4621                 "flags", UC_INTEGER, true, &flags);
4622 
4623         slen = sizeof(ss);
4624         sockflags = flags ? ucv_to_integer(flags) : 0;
4625 
4626 #ifdef __APPLE__
4627         peerfd = accept(sockfd, (struct sockaddr *)&ss, &slen);
4628 
4629         if (peerfd == -1)
4630                 err_return(errno, "accept()");
4631 
4632         if (sockflags & SOCK_CLOEXEC) {
4633                 if (fcntl(peerfd, F_SETFD, FD_CLOEXEC) == -1) {
4634                         close(peerfd);
4635                         err_return(errno, "fcntl(F_SETFD)");
4636                 }
4637         }
4638 
4639         if (sockflags & SOCK_NONBLOCK) {
4640                 sockflags = fcntl(peerfd, F_GETFL);
4641 
4642                 if (sockflags == -1) {
4643                         close(peerfd);
4644                         err_return(errno, "fcntl(F_GETFL)");
4645                 }
4646 
4647                 if (fcntl(peerfd, F_SETFL, sockflags | O_NONBLOCK) == -1) {
4648                         close(peerfd);
4649                         err_return(errno, "fcntl(F_SETFL)");
4650                 }
4651         }
4652 #else
4653         peerfd = accept4(sockfd, (struct sockaddr *)&ss, &slen, sockflags);
4654 
4655         if (peerfd == -1)
4656                 err_return(errno, "accept4()");
4657 #endif
4658 
4659         if (addrobj)
4660                 sockaddr_to_uv(&ss, addrobj);
4661 
4662         ok_return(ucv_socket_new(vm, peerfd));
4663 }
4664 
4665 /**
4666  * Shutdown part of a full-duplex connection.
4667  *
4668  * This function shuts down part of the full-duplex connection associated with
4669  * the socket handle. The `how` parameter specifies which half of the connection
4670  * to shut down. It can take one of the following constant values:
4671  *
4672  * - `SHUT_RD`: Disables further receive operations.
4673  * - `SHUT_WR`: Disables further send operations.
4674  * - `SHUT_RDWR`: Disables further send and receive operations.
4675  *
4676  * Returns `true` if the shutdown operation is successful.
4677  * Returns `null` if an error occurred.
4678  *
4679  * @function module:socket.socket#shutdown
4680  *
4681  * @param {number} how
4682  * Specifies which half of the connection to shut down.
4683  * It can be one of the following constant values: `SHUT_RD`, `SHUT_WR`,
4684  * or `SHUT_RDWR`.
4685  *
4686  * @returns {?boolean}
4687  *
4688  * @example
4689  * const sock = socket.create(…);
4690  * sock.connect(…);
4691  * // Perform data exchange…
4692  *
4693  * const success = sock.shutdown(socket.SHUT_WR);
4694  * if (success)
4695  *     print(`Send operations on socket shut down successfully.\n`);
4696  * else
4697  *     print(`Failed to shut down send operations: ${sock.error()}\n`);
4698  */
4699 static uc_value_t *
4700 uc_socket_inst_shutdown(uc_vm_t *vm, size_t nargs)
4701 {
4702         uc_value_t *how;
4703         int sockfd, ret;
4704 
4705         args_get(vm, nargs, &sockfd,
4706                 "how", UC_INTEGER, true, &how);
4707 
4708         ret = shutdown(sockfd, ucv_int64_get(how));
4709 
4710         if (ret == -1)
4711                 err_return(errno, "shutdown()");
4712 
4713         ok_return(ucv_boolean_new(true));
4714 }
4715 
4716 /**
4717  * Represents a credentials information object returned by
4718  * {@link module:socket.socket#peercred|`peercred()`}.
4719  *
4720  * @typedef {Object} module:socket.socket.PeerCredentials
4721  * @property {number} uid
4722  * The effective user ID the remote socket endpoint.
4723  *
4724  * @property {number} gid
4725  * The effective group ID the remote socket endpoint.
4726  *
4727  * @property {number} pid
4728  * The ID of the process the remote socket endpoint belongs to.
4729  */
4730 
4731 /**
4732  * Retrieves the peer credentials.
4733  *
4734  * This function retrieves the remote uid, gid and pid of a connected UNIX
4735  * domain socket.
4736  *
4737  * Returns the remote credentials if the operation is successful.
4738  * Returns `null` on error.
4739  *
4740  * @function module:socket.socket#peercred
4741  *
4742  * @returns {?module:socket.socket.PeerCredentials}
4743  *
4744  * @example
4745  * const sock = socket.create(socket.AF_UNIX, …);
4746  * sock.connect(…);
4747  *
4748  * const peerCredentials = sock.peercred();
4749  * if (peerCredentials)
4750  *     print(`Peer credentials: ${peerCredentials}\n`);
4751  * else
4752  *     print(`Failed to retrieve peer credentials: ${sock.error()}\n`);
4753  */
4754 static uc_value_t *
4755 uc_socket_inst_peercred(uc_vm_t *vm, size_t nargs)
4756 {
4757         uc_value_t *rv = NULL;
4758         socklen_t optlen;
4759         int ret, sockfd;
4760 
4761         args_get(vm, nargs, &sockfd);
4762 
4763 #if defined(__linux__)
4764         struct ucred cred;
4765 
4766         optlen = sizeof(cred);
4767         ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &optlen);
4768 
4769         if (ret == -1)
4770                 err_return(errno, "getsockopt()");
4771 
4772         if (optlen != sizeof(cred))
4773                 err_return(EINVAL, "Invalid credentials received");
4774 
4775         rv = ucv_object_new(vm);
4776 
4777         ucv_object_add(rv, "uid", ucv_uint64_new(cred.uid));
4778         ucv_object_add(rv, "gid", ucv_uint64_new(cred.gid));
4779         ucv_object_add(rv, "pid", ucv_int64_new(cred.pid));
4780 #elif defined(__APPLE__)
4781         struct xucred cred;
4782         pid_t pid;
4783 
4784         optlen = sizeof(cred);
4785         ret = getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &cred, &optlen);
4786 
4787         if (ret == -1)
4788                 err_return(errno, "getsockopt(LOCAL_PEERCRED)");
4789 
4790         if (optlen != sizeof(cred) || cred.cr_version != XUCRED_VERSION)
4791                 err_return(EINVAL, "Invalid credentials received");
4792 
4793         rv = ucv_object_new(vm);
4794 
4795         ucv_object_add(rv, "uid", ucv_uint64_new(cred.cr_uid));
4796         ucv_object_add(rv, "gid", ucv_uint64_new(cred.cr_gid));
4797 
4798         optlen = sizeof(pid);
4799         ret = getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERPID, &pid, &optlen);
4800 
4801         if (ret == -1) {
4802                 ucv_put(rv);
4803                 err_return(errno, "getsockopt(LOCAL_PEERPID)");
4804         }
4805 
4806         ucv_object_add(rv, "pid", ucv_int64_new(pid));
4807 #else
4808         err_return(ENOSYS, "Operation not supported on this system");
4809 #endif
4810 
4811         ok_return(rv);
4812 }
4813 
4814 /**
4815  * Retrieves the remote address.
4816  *
4817  * This function retrieves the remote address of a connected socket.
4818  *
4819  * Returns the remote address if the operation is successful.
4820  * Returns `null` on error.
4821  *
4822  * @function module:socket.socket#peername
4823  *
4824  * @returns {?module:socket.socket.SocketAddress}
4825  *
4826  * @see {@link module:socket.socket#sockname|sockname()}
4827  *
4828  * @example
4829  * const sock = socket.create(…);
4830  * sock.connect(…);
4831  *
4832  * const peerAddress = sock.peername();
4833  * if (peerAddress)
4834  *     print(`Connected to ${peerAddress}\n`);
4835  * else
4836  *     print(`Failed to retrieve peer address: ${sock.error()}\n`);
4837  */
4838 static uc_value_t *
4839 uc_socket_inst_peername(uc_vm_t *vm, size_t nargs)
4840 {
4841         struct sockaddr_storage ss = { 0 };
4842         uc_value_t *addr;
4843         socklen_t sslen;
4844         int sockfd, ret;
4845 
4846         args_get(vm, nargs, &sockfd);
4847 
4848         sslen = sizeof(ss);
4849         ret = getpeername(sockfd, (struct sockaddr *)&ss, &sslen);
4850 
4851         if (ret == -1)
4852                 err_return(errno, "getpeername()");
4853 
4854         addr = ucv_object_new(vm);
4855         sockaddr_to_uv(&ss, addr);
4856 
4857         ok_return(addr);
4858 }
4859 
4860 /**
4861  * Retrieves the local address.
4862  *
4863  * This function retrieves the local address of a bound or connected socket.
4864  *
4865  * Returns the local address if the operation is successful.
4866  * Returns `null` on error.
4867  *
4868  * @function module:socket.socket#sockname
4869  *
4870  * @returns {?module:socket.socket.SocketAddress}
4871  *
4872  * @see {@link module:socket.socket#peername|peername()}
4873  *
4874  * @example
4875  * const sock = socket.create(…);
4876  * sock.connect(…);
4877  *
4878  * const myAddress = sock.sockname();
4879  * if (myAddress)
4880  *     print(`My source IP address is ${myAddress}\n`);
4881  * else
4882  *     print(`Failed to retrieve peer address: ${sock.error()}\n`);
4883  */
4884 static uc_value_t *
4885 uc_socket_inst_sockname(uc_vm_t *vm, size_t nargs)
4886 {
4887         struct sockaddr_storage ss = { 0 };
4888         uc_value_t *addr;
4889         socklen_t sslen;
4890         int sockfd, ret;
4891 
4892         args_get(vm, nargs, &sockfd);
4893 
4894         sslen = sizeof(ss);
4895         ret = getsockname(sockfd, (struct sockaddr *)&ss, &sslen);
4896 
4897         if (ret == -1)
4898                 err_return(errno, "getsockname()");
4899 
4900         addr = ucv_object_new(vm);
4901         sockaddr_to_uv(&ss, addr);
4902 
4903         ok_return(addr);
4904 }
4905 
4906 /**
4907  * Closes the socket.
4908  *
4909  * This function closes the socket, releasing its resources and terminating its
4910  * associated connections.
4911  *
4912  * Returns `true` if the socket was successfully closed.
4913  * Returns `null` on error.
4914  *
4915  * @function module:socket.socket#close
4916  *
4917  * @returns {?boolean}
4918  *
4919  * @example
4920  * const sock = socket.create(…);
4921  * sock.connect(…);
4922  * // Perform operations with the socket…
4923  * sock.close();
4924  */
4925 static uc_value_t *
4926 uc_socket_inst_close(uc_vm_t *vm, size_t nargs)
4927 {
4928         int *sockfd = uc_fn_this("socket");
4929 
4930         if (!sockfd || *sockfd == -1)
4931                 err_return(EBADF, "Invalid socket context");
4932 
4933         if (!xclose(sockfd))
4934                 err_return(errno, "close()");
4935 
4936         ok_return(ucv_boolean_new(true));
4937 }
4938 
4939 static void
4940 close_socket(void *ud)
4941 {
4942         int fd = (intptr_t)ud;
4943 
4944         if (fd != -1)
4945                 close(fd);
4946 }
4947 
4948 static const uc_function_list_t socket_fns[] = {
4949         { "connect",    uc_socket_inst_connect },
4950         { "bind",               uc_socket_inst_bind },
4951         { "listen",             uc_socket_inst_listen },
4952         { "accept",             uc_socket_inst_accept },
4953         { "send",               uc_socket_inst_send },
4954         { "sendmsg",    uc_socket_inst_sendmsg },
4955         { "recv",           uc_socket_inst_recv },
4956         { "recvmsg",    uc_socket_inst_recvmsg },
4957         { "setopt",             uc_socket_inst_setopt },
4958         { "getopt",             uc_socket_inst_getopt },
4959         { "fileno",             uc_socket_inst_fileno },
4960         { "shutdown",   uc_socket_inst_shutdown },
4961         { "peercred",   uc_socket_inst_peercred },
4962         { "peername",   uc_socket_inst_peername },
4963         { "sockname",   uc_socket_inst_sockname },
4964         { "close",              uc_socket_inst_close },
4965         { "error",              uc_socket_error },
4966 };
4967 
4968 static const uc_function_list_t global_fns[] = {
4969         { "sockaddr",   uc_socket_sockaddr },
4970         { "create",             uc_socket_create },
4971         { "pair",               uc_socket_pair },
4972         { "open",               uc_socket_open },
4973         { "nameinfo",   uc_socket_nameinfo },
4974         { "addrinfo",   uc_socket_addrinfo },
4975         { "poll",               uc_socket_poll },
4976         { "connect",    uc_socket_connect },
4977         { "listen",             uc_socket_listen },
4978         { "error",              uc_socket_error },
4979         { "strerror",   uc_socket_strerror },
4980 };
4981 
4982 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
4983 {
4984         uc_function_list_register(scope, global_fns);
4985 
4986 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x))
4987 
4988         /**
4989          * @typedef
4990          * @name Address Families
4991          * @description Constants representing address families and socket domains.
4992          * @property {number} AF_UNSPEC - Unspecified address family.
4993          * @property {number} AF_UNIX - UNIX domain sockets.
4994          * @property {number} AF_INET - IPv4 Internet protocols.
4995          * @property {number} AF_INET6 - IPv6 Internet protocols.
4996          * @property {number} AF_PACKET - Low-level packet interface.
4997          * @property {number} AF_CAN - Controller Area Network sockets.
4998          */
4999         ADD_CONST(AF_UNSPEC);
5000         ADD_CONST(AF_UNIX);
5001         ADD_CONST(AF_INET);
5002         ADD_CONST(AF_INET6);
5003 #if defined(__linux__)
5004         ADD_CONST(AF_PACKET);
5005         ADD_CONST(AF_CAN);
5006 #endif
5007 
5008         /**
5009          * @typedef
5010          * @name Socket Types
5011          * @description
5012          * The `SOCK_*` type and flag constants are used by
5013          * {@link module:socket#create|create()} to specify the type of socket to
5014          * open. The {@link module:socket.socket#accept|accept()} function
5015          * recognizes the `SOCK_NONBLOCK` and `SOCK_CLOEXEC` flags and applies them
5016          * to accepted peer sockets.
5017          * @property {number} SOCK_STREAM - Provides sequenced, reliable, two-way, connection-based byte streams.
5018          * @property {number} SOCK_DGRAM - Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
5019          * @property {number} SOCK_RAW - Provides raw network protocol access.
5020          * @property {number} SOCK_PACKET - Obsolete and should not be used.
5021          * @property {number} SOCK_NONBLOCK - Enables non-blocking operation.
5022          * @property {number} SOCK_CLOEXEC - Sets the close-on-exec flag on the new file descriptor.
5023          */
5024         ADD_CONST(SOCK_STREAM);
5025         ADD_CONST(SOCK_DGRAM);
5026         ADD_CONST(SOCK_RAW);
5027         ADD_CONST(SOCK_NONBLOCK);
5028         ADD_CONST(SOCK_CLOEXEC);
5029 #if defined(__linux__)
5030         ADD_CONST(SOCK_PACKET);
5031 #endif
5032 
5033         /**
5034          * @typedef
5035          * @name Message Flags
5036          * @description
5037          * The `MSG_*` flag constants are commonly used in conjunction with the
5038          * {@link module:socket.socket#send|send()} and
5039          * {@link module:socket.socket#recv|recv()} functions.
5040          * @property {number} MSG_CONFIRM - Confirm path validity.
5041          * @property {number} MSG_DONTROUTE - Send without using routing tables.
5042          * @property {number} MSG_DONTWAIT - Enables non-blocking operation.
5043          * @property {number} MSG_EOR - End of record.
5044          * @property {number} MSG_MORE - Sender will send more.
5045          * @property {number} MSG_NOSIGNAL - Do not generate SIGPIPE.
5046          * @property {number} MSG_OOB - Process out-of-band data.
5047          * @property {number} MSG_FASTOPEN - Send data in TCP SYN.
5048          * @property {number} MSG_CMSG_CLOEXEC - Sets the close-on-exec flag on the received file descriptor.
5049          * @property {number} MSG_ERRQUEUE - Receive errors from ICMP.
5050          * @property {number} MSG_PEEK - Peeks at incoming messages.
5051          * @property {number} MSG_TRUNC - Report if datagram truncation occurred.
5052          * @property {number} MSG_WAITALL - Wait for full message.
5053          */
5054         ADD_CONST(MSG_DONTROUTE);
5055         ADD_CONST(MSG_DONTWAIT);
5056         ADD_CONST(MSG_EOR);
5057         ADD_CONST(MSG_NOSIGNAL);
5058         ADD_CONST(MSG_OOB);
5059         ADD_CONST(MSG_PEEK);
5060         ADD_CONST(MSG_TRUNC);
5061         ADD_CONST(MSG_WAITALL);
5062 #if defined(__linux__)
5063         ADD_CONST(MSG_CONFIRM);
5064         ADD_CONST(MSG_MORE);
5065         ADD_CONST(MSG_FASTOPEN);
5066         ADD_CONST(MSG_CMSG_CLOEXEC);
5067         ADD_CONST(MSG_ERRQUEUE);
5068 #endif
5069 
5070         /**
5071          * @typedef
5072          * @name IP Protocol Constants
5073          * @description
5074          * The `IPPROTO_IP` constant specifies the IP protocol number and may be
5075          * passed as third argument to {@link module:socket#create|create()} as well
5076          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
5077          * and {@link module:socket.socket#setopt|setopt()}.
5078          *
5079          * The `IP_*` constants are option names recognized by
5080          * {@link module:socket.socket#getopt|getopt()}
5081          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5082          * the `IPPROTO_IP` socket level.
5083          * @property {number} IPPROTO_IP - Dummy protocol for IP.
5084          * @property {number} IP_ADD_MEMBERSHIP - Add an IP group membership.
5085          * @property {number} IP_ADD_SOURCE_MEMBERSHIP - Add an IP group/source membership.
5086          * @property {number} IP_BIND_ADDRESS_NO_PORT - Bind to the device only.
5087          * @property {number} IP_BLOCK_SOURCE - Block IP group/source.
5088          * @property {number} IP_DROP_MEMBERSHIP - Drop an IP group membership.
5089          * @property {number} IP_DROP_SOURCE_MEMBERSHIP - Drop an IP group/source membership.
5090          * @property {number} IP_FREEBIND - Allow binding to an IP address not assigned to a network interface.
5091          * @property {number} IP_HDRINCL - Header is included with data.
5092          * @property {number} IP_MSFILTER - Filter IP multicast source memberships.
5093          * @property {number} IP_MTU - Path MTU discovery.
5094          * @property {number} IP_MTU_DISCOVER - Control Path MTU discovery.
5095          * @property {number} IP_MULTICAST_ALL - Receive all multicast packets.
5096          * @property {number} IP_MULTICAST_IF - Set outgoing interface for multicast packets.
5097          * @property {number} IP_MULTICAST_LOOP - Control multicast packet looping.
5098          * @property {number} IP_MULTICAST_TTL - Set time-to-live for outgoing multicast packets.
5099          * @property {number} IP_NODEFRAG - Don't fragment IP packets.
5100          * @property {number} IP_OPTIONS - Set/get IP options.
5101          * @property {number} IP_PASSSEC - Pass security information.
5102          * @property {number} IP_PKTINFO - Receive packet information.
5103          * @property {number} IP_RECVERR - Receive all ICMP errors.
5104          * @property {number} IP_RECVOPTS - Receive all IP options.
5105          * @property {number} IP_RECVORIGDSTADDR - Receive original destination address of the socket.
5106          * @property {number} IP_RECVTOS - Receive IP TOS.
5107          * @property {number} IP_RECVTTL - Receive IP TTL.
5108          * @property {number} IP_RETOPTS - Set/get IP options.
5109          * @property {number} IP_ROUTER_ALERT - Receive ICMP msgs generated by router.
5110          * @property {number} IP_TOS - IP type of service and precedence.
5111          * @property {number} IP_TRANSPARENT - Transparent proxy support.
5112          * @property {number} IP_TTL - IP time-to-live.
5113          * @property {number} IP_UNBLOCK_SOURCE - Unblock IP group/source.
5114          */
5115         ADD_CONST(IPPROTO_IP);
5116         ADD_CONST(IP_ADD_MEMBERSHIP);
5117         ADD_CONST(IP_ADD_SOURCE_MEMBERSHIP);
5118         ADD_CONST(IP_BLOCK_SOURCE);
5119         ADD_CONST(IP_DROP_MEMBERSHIP);
5120         ADD_CONST(IP_DROP_SOURCE_MEMBERSHIP);
5121         ADD_CONST(IP_HDRINCL);
5122         ADD_CONST(IP_MSFILTER);
5123         ADD_CONST(IP_MULTICAST_IF);
5124         ADD_CONST(IP_MULTICAST_LOOP);
5125         ADD_CONST(IP_MULTICAST_TTL);
5126         ADD_CONST(IP_OPTIONS);
5127         ADD_CONST(IP_PKTINFO);
5128         ADD_CONST(IP_RECVOPTS);
5129         ADD_CONST(IP_RECVTOS);
5130         ADD_CONST(IP_RECVTTL);
5131         ADD_CONST(IP_RETOPTS);
5132         ADD_CONST(IP_TOS);
5133         ADD_CONST(IP_TTL);
5134         ADD_CONST(IP_UNBLOCK_SOURCE);
5135 #if defined(__linux__)
5136         ADD_CONST(IP_BIND_ADDRESS_NO_PORT);
5137         ADD_CONST(IP_FREEBIND);
5138         ADD_CONST(IP_MTU);
5139         ADD_CONST(IP_MTU_DISCOVER);
5140         ADD_CONST(IP_MULTICAST_ALL);
5141         ADD_CONST(IP_NODEFRAG);
5142         ADD_CONST(IP_PASSSEC);
5143         ADD_CONST(IP_RECVERR);
5144         ADD_CONST(IP_RECVORIGDSTADDR);
5145         ADD_CONST(IP_ROUTER_ALERT);
5146         ADD_CONST(IP_TRANSPARENT);
5147 #endif
5148 
5149         /**
5150          * @typedef {Object} IPv6 Protocol Constants
5151          * @description
5152          * The `IPPROTO_IPV6` constant specifies the IPv6 protocol number and may be
5153          * passed as third argument to {@link module:socket#create|create()} as well
5154          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
5155          * and {@link module:socket.socket#setopt|setopt()}.
5156          *
5157          * The `IPV6_*` constants are option names recognized by
5158          * {@link module:socket.socket#getopt|getopt()}
5159          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5160          * the `IPPROTO_IPV6` socket level.
5161          * @property {number} IPPROTO_IPV6 - The IPv6 protocol.
5162          * @property {number} IPV6_ADDRFORM - Turn an AF_INET6 socket into a socket of a different address family. Only AF_INET is supported.
5163          * @property {number} IPV6_ADDR_PREFERENCES - Specify preferences for address selection.
5164          * @property {number} IPV6_ADD_MEMBERSHIP - Add an IPv6 group membership.
5165          * @property {number} IPV6_AUTHHDR - Set delivery of the authentication header control message for incoming datagrams.
5166          * @property {number} IPV6_AUTOFLOWLABEL - Enable or disable automatic flow labels.
5167          * @property {number} IPV6_DONTFRAG - Control whether the socket allows IPv6 fragmentation.
5168          * @property {number} IPV6_DROP_MEMBERSHIP - Drop an IPv6 group membership.
5169          * @property {number} IPV6_DSTOPTS - Set delivery of the destination options control message for incoming datagrams.
5170          * @property {number} IPV6_FLOWINFO_SEND - Control whether flow information is sent.
5171          * @property {number} IPV6_FLOWINFO - Set delivery of the flow ID control message for incoming datagrams.
5172          * @property {number} IPV6_FLOWLABEL_MGR - Manage flow labels.
5173          * @property {number} IPV6_FREEBIND - Allow binding to an IP address not assigned to a network interface.
5174          * @property {number} IPV6_HOPLIMIT - Set delivery of the hop limit control message for incoming datagrams.
5175          * @property {number} IPV6_HOPOPTS - Set delivery of the hop options control message for incoming datagrams.
5176          * @property {number} IPV6_JOIN_ANYCAST - Join an anycast group.
5177          * @property {number} IPV6_LEAVE_ANYCAST - Leave an anycast group.
5178          * @property {number} IPV6_MINHOPCOUNT - Set the minimum hop count.
5179          * @property {number} IPV6_MTU - Retrieve or set the MTU to be used for the socket.
5180          * @property {number} IPV6_MTU_DISCOVER - Control path-MTU discovery on the socket.
5181          * @property {number} IPV6_MULTICAST_ALL - Control whether the socket receives all multicast packets.
5182          * @property {number} IPV6_MULTICAST_HOPS - Set the multicast hop limit for the socket.
5183          * @property {number} IPV6_MULTICAST_IF - Set the device for outgoing multicast packets on the socket.
5184          * @property {number} IPV6_MULTICAST_LOOP - Control whether the socket sees multicast packets that it has sent itself.
5185          * @property {number} IPV6_PKTINFO - Set delivery of the IPV6_PKTINFO control message on incoming datagrams.
5186          * @property {number} IPV6_RECVDSTOPTS - Control receiving of the destination options control message.
5187          * @property {number} IPV6_RECVERR - Control receiving of asynchronous error options.
5188          * @property {number} IPV6_RECVFRAGSIZE - Control receiving of fragment size.
5189          * @property {number} IPV6_RECVHOPLIMIT - Control receiving of hop limit.
5190          * @property {number} IPV6_RECVHOPOPTS - Control receiving of hop options.
5191          * @property {number} IPV6_RECVORIGDSTADDR - Control receiving of the original destination address.
5192          * @property {number} IPV6_RECVPATHMTU - Control receiving of path MTU.
5193          * @property {number} IPV6_RECVPKTINFO - Control receiving of packet information.
5194          * @property {number} IPV6_RECVRTHDR - Control receiving of routing header.
5195          * @property {number} IPV6_RECVTCLASS - Control receiving of traffic class.
5196          * @property {number} IPV6_ROUTER_ALERT_ISOLATE - Control isolation of router alert messages.
5197          * @property {number} IPV6_ROUTER_ALERT - Pass forwarded packets containing a router alert hop-by-hop option to this socket.
5198          * @property {number} IPV6_RTHDR - Set delivery of the routing header control message for incoming datagrams.
5199          * @property {number} IPV6_RTHDRDSTOPTS - Set delivery of the routing header destination options control message.
5200          * @property {number} IPV6_TCLASS - Set the traffic class.
5201          * @property {number} IPV6_TRANSPARENT - Enable transparent proxy support.
5202          * @property {number} IPV6_UNICAST_HOPS - Set the unicast hop limit for the socket.
5203          * @property {number} IPV6_UNICAST_IF - Set the interface for outgoing unicast packets.
5204          * @property {number} IPV6_V6ONLY - Restrict the socket to sending and receiving IPv6 packets only.
5205          */
5206         ADD_CONST(IPPROTO_IPV6);
5207         ADD_CONST(IPV6_FLOWINFO_SEND);
5208         ADD_CONST(IPV6_FLOWINFO);
5209         ADD_CONST(IPV6_FLOWLABEL_MGR);
5210         ADD_CONST(IPV6_MULTICAST_HOPS);
5211         ADD_CONST(IPV6_MULTICAST_IF);
5212         ADD_CONST(IPV6_MULTICAST_LOOP);
5213         ADD_CONST(IPV6_RECVTCLASS);
5214         ADD_CONST(IPV6_TCLASS);
5215         ADD_CONST(IPV6_UNICAST_HOPS);
5216         ADD_CONST(IPV6_V6ONLY);
5217 #if defined(__linux__)
5218         ADD_CONST(IPV6_ADD_MEMBERSHIP);
5219         ADD_CONST(IPV6_ADDR_PREFERENCES);
5220         ADD_CONST(IPV6_ADDRFORM);
5221         ADD_CONST(IPV6_AUTHHDR);
5222         ADD_CONST(IPV6_AUTOFLOWLABEL);
5223         ADD_CONST(IPV6_DONTFRAG);
5224         ADD_CONST(IPV6_DROP_MEMBERSHIP);
5225         ADD_CONST(IPV6_DSTOPTS);
5226         ADD_CONST(IPV6_FREEBIND);
5227         ADD_CONST(IPV6_HOPLIMIT);
5228         ADD_CONST(IPV6_HOPOPTS);
5229         ADD_CONST(IPV6_JOIN_ANYCAST);
5230         ADD_CONST(IPV6_LEAVE_ANYCAST);
5231         ADD_CONST(IPV6_MINHOPCOUNT);
5232         ADD_CONST(IPV6_MTU_DISCOVER);
5233         ADD_CONST(IPV6_MTU);
5234         ADD_CONST(IPV6_MULTICAST_ALL);
5235         ADD_CONST(IPV6_PKTINFO);
5236         ADD_CONST(IPV6_RECVDSTOPTS);
5237         ADD_CONST(IPV6_RECVERR);
5238         ADD_CONST(IPV6_RECVFRAGSIZE);
5239         ADD_CONST(IPV6_RECVHOPLIMIT);
5240         ADD_CONST(IPV6_RECVHOPOPTS);
5241         ADD_CONST(IPV6_RECVORIGDSTADDR);
5242         ADD_CONST(IPV6_RECVPATHMTU);
5243         ADD_CONST(IPV6_RECVPKTINFO);
5244         ADD_CONST(IPV6_RECVRTHDR);
5245         ADD_CONST(IPV6_ROUTER_ALERT_ISOLATE);
5246         ADD_CONST(IPV6_ROUTER_ALERT);
5247         ADD_CONST(IPV6_RTHDR);
5248         ADD_CONST(IPV6_RTHDRDSTOPTS);
5249         ADD_CONST(IPV6_TRANSPARENT);
5250         ADD_CONST(IPV6_UNICAST_IF);
5251 #endif
5252 
5253         /**
5254          * @typedef
5255          * @name Socket Option Constants
5256          * @description
5257          * The `SOL_SOCKET` constant is passed as *level* argument to the
5258          * {@link module:socket.socket#getopt|getopt()} and
5259          * {@link module:socket.socket#setopt|setopt()} functions in order to set
5260          * or retrieve generic socket option values.
5261          *
5262          * The `SO_*` constants are passed as *option* argument in conjunction with
5263          * the `SOL_SOCKET` level to specify the specific option to get or set on
5264          * the socket.
5265          * @property {number} SOL_SOCKET - Socket options at the socket API level.
5266          * @property {number} SO_ACCEPTCONN - Reports whether socket listening is enabled.
5267          * @property {number} SO_ATTACH_BPF - Attach BPF program to socket.
5268          * @property {number} SO_ATTACH_FILTER - Attach a socket filter.
5269          * @property {number} SO_ATTACH_REUSEPORT_CBPF - Attach BPF program for cgroup and skb program reuseport hook.
5270          * @property {number} SO_ATTACH_REUSEPORT_EBPF - Attach eBPF program for cgroup and skb program reuseport hook.
5271          * @property {number} SO_BINDTODEVICE - Bind socket to a specific interface.
5272          * @property {number} SO_BROADCAST - Allow transmission of broadcast messages.
5273          * @property {number} SO_BUSY_POLL - Enable busy polling.
5274          * @property {number} SO_DEBUG - Enable socket debugging.
5275          * @property {number} SO_DETACH_BPF - Detach BPF program from socket.
5276          * @property {number} SO_DETACH_FILTER - Detach a socket filter.
5277          * @property {number} SO_DOMAIN - Retrieves the domain of the socket.
5278          * @property {number} SO_DONTROUTE - Send packets directly without routing.
5279          * @property {number} SO_ERROR - Retrieves and clears the error status for the socket.
5280          * @property {number} SO_INCOMING_CPU - Retrieves the CPU number on which the last packet was received.
5281          * @property {number} SO_INCOMING_NAPI_ID - Retrieves the NAPI ID of the device.
5282          * @property {number} SO_KEEPALIVE - Enable keep-alive packets.
5283          * @property {number} SO_LINGER - Set linger on close.
5284          * @property {number} SO_LOCK_FILTER - Set or get the socket filter lock state.
5285          * @property {number} SO_MARK - Set the mark for packets sent through the socket.
5286          * @property {number} SO_OOBINLINE - Enables out-of-band data to be received in the normal data stream.
5287          * @property {number} SO_PASSCRED - Enable the receiving of SCM_CREDENTIALS control messages.
5288          * @property {number} SO_PASSSEC - Enable the receiving of security context.
5289          * @property {number} SO_PEEK_OFF - Returns the number of bytes in the receive buffer without removing them.
5290          * @property {number} SO_PEERCRED - Retrieves the credentials of the foreign peer.
5291          * @property {number} SO_PEERSEC - Retrieves the security context of the foreign peer.
5292          * @property {number} SO_PRIORITY - Set the protocol-defined priority for all packets.
5293          * @property {number} SO_PROTOCOL - Retrieves the protocol number.
5294          * @property {number} SO_RCVBUF - Set the receive buffer size.
5295          * @property {number} SO_RCVBUFFORCE - Set the receive buffer size forcefully.
5296          * @property {number} SO_RCVLOWAT - Set the minimum number of bytes to process for input operations.
5297          * @property {number} SO_RCVTIMEO - Set the timeout for receiving data.
5298          * @property {number} SO_REUSEADDR - Allow the socket to be bound to an address that is already in use.
5299          * @property {number} SO_REUSEPORT - Enable duplicate address and port bindings.
5300          * @property {number} SO_RXQ_OVFL - Reports if the receive queue has overflown.
5301          * @property {number} SO_SNDBUF - Set the send buffer size.
5302          * @property {number} SO_SNDBUFFORCE - Set the send buffer size forcefully.
5303          * @property {number} SO_SNDLOWAT - Set the minimum number of bytes to process for output operations.
5304          * @property {number} SO_SNDTIMEO - Set the timeout for sending data.
5305          * @property {number} SO_TIMESTAMP - Enable receiving of timestamps.
5306          * @property {number} SO_TIMESTAMPNS - Enable receiving of nanosecond timestamps.
5307          * @property {number} SO_TYPE - Retrieves the type of the socket (e.g., SOCK_STREAM).
5308          */
5309         ADD_CONST(SOL_SOCKET);
5310         ADD_CONST(SO_ACCEPTCONN);
5311         ADD_CONST(SO_BROADCAST);
5312         ADD_CONST(SO_DEBUG);
5313         ADD_CONST(SO_DONTROUTE);
5314         ADD_CONST(SO_ERROR);
5315         ADD_CONST(SO_KEEPALIVE);
5316         ADD_CONST(SO_LINGER);
5317         ADD_CONST(SO_OOBINLINE);
5318         ADD_CONST(SO_RCVBUF);
5319         ADD_CONST(SO_RCVLOWAT);
5320         ADD_CONST(SO_RCVTIMEO);
5321         ADD_CONST(SO_REUSEADDR);
5322         ADD_CONST(SO_REUSEPORT);
5323         ADD_CONST(SO_SNDBUF);
5324         ADD_CONST(SO_SNDLOWAT);
5325         ADD_CONST(SO_SNDTIMEO);
5326         ADD_CONST(SO_TIMESTAMP);
5327         ADD_CONST(SO_TYPE);
5328 #if defined(__linux__)
5329         ADD_CONST(SO_ATTACH_BPF);
5330         ADD_CONST(SO_ATTACH_FILTER);
5331         ADD_CONST(SO_ATTACH_REUSEPORT_CBPF);
5332         ADD_CONST(SO_ATTACH_REUSEPORT_EBPF);
5333         ADD_CONST(SO_BINDTODEVICE);
5334         ADD_CONST(SO_BUSY_POLL);
5335         ADD_CONST(SO_DETACH_BPF);
5336         ADD_CONST(SO_DETACH_FILTER);
5337         ADD_CONST(SO_DOMAIN);
5338         ADD_CONST(SO_INCOMING_CPU);
5339         ADD_CONST(SO_INCOMING_NAPI_ID);
5340         ADD_CONST(SO_LOCK_FILTER);
5341         ADD_CONST(SO_MARK);
5342         ADD_CONST(SO_PASSCRED);
5343         ADD_CONST(SO_PASSSEC);
5344         ADD_CONST(SO_PEEK_OFF);
5345         ADD_CONST(SO_PEERCRED);
5346         ADD_CONST(SO_PEERSEC);
5347         ADD_CONST(SO_PRIORITY);
5348         ADD_CONST(SO_PROTOCOL);
5349         ADD_CONST(SO_RCVBUFFORCE);
5350         ADD_CONST(SO_RXQ_OVFL);
5351         ADD_CONST(SO_SNDBUFFORCE);
5352         ADD_CONST(SO_TIMESTAMPNS);
5353 
5354         ADD_CONST(SCM_CREDENTIALS);
5355         ADD_CONST(SCM_RIGHTS);
5356 #endif
5357 
5358         /**
5359          * @typedef
5360          * @name TCP Protocol Constants
5361          * @description
5362          * The `IPPROTO_TCP` constant specifies the TCP protocol number and may be
5363          * passed as third argument to {@link module:socket#create|create()} as well
5364          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
5365          * and {@link module:socket.socket#setopt|setopt()}.
5366          *
5367          * The `TCP_*` constants are *option* argument values recognized by
5368          * {@link module:socket.socket#getopt|getopt()}
5369          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5370          * the `IPPROTO_TCP` socket level.
5371          * @property {number} IPPROTO_TCP - TCP protocol.
5372          * @property {number} TCP_CONGESTION - Set the congestion control algorithm.
5373          * @property {number} TCP_CORK - Delay packet transmission until full-sized packets are available.
5374          * @property {number} TCP_DEFER_ACCEPT - Delay accepting incoming connections until data arrives.
5375          * @property {number} TCP_FASTOPEN - Enable TCP Fast Open.
5376          * @property {number} TCP_FASTOPEN_CONNECT - Perform TFO connect.
5377          * @property {number} TCP_INFO - Retrieve TCP statistics.
5378          * @property {number} TCP_KEEPCNT - Number of keepalive probes.
5379          * @property {number} TCP_KEEPIDLE - Time before keepalive probes begin.
5380          * @property {number} TCP_KEEPINTVL - Interval between keepalive probes.
5381          * @property {number} TCP_LINGER2 - Lifetime of orphaned FIN_WAIT2 state sockets.
5382          * @property {number} TCP_MAXSEG - Maximum segment size.
5383          * @property {number} TCP_NODELAY - Disable Nagle's algorithm.
5384          * @property {number} TCP_QUICKACK - Enable quick ACKs.
5385          * @property {number} TCP_SYNCNT - Number of SYN retransmits.
5386          * @property {number} TCP_USER_TIMEOUT - Set the user timeout.
5387          * @property {number} TCP_WINDOW_CLAMP - Set the maximum window.
5388          */
5389         ADD_CONST(IPPROTO_TCP);
5390         ADD_CONST(TCP_FASTOPEN);
5391         ADD_CONST(TCP_KEEPCNT);
5392         ADD_CONST(TCP_KEEPINTVL);
5393         ADD_CONST(TCP_MAXSEG);
5394         ADD_CONST(TCP_NODELAY);
5395 #if defined(__linux__)
5396         ADD_CONST(TCP_CONGESTION);
5397         ADD_CONST(TCP_CORK);
5398         ADD_CONST(TCP_DEFER_ACCEPT);
5399         ADD_CONST(TCP_FASTOPEN_CONNECT);
5400         ADD_CONST(TCP_INFO);
5401         ADD_CONST(TCP_KEEPIDLE);
5402         ADD_CONST(TCP_LINGER2);
5403         ADD_CONST(TCP_QUICKACK);
5404         ADD_CONST(TCP_SYNCNT);
5405         ADD_CONST(TCP_USER_TIMEOUT);
5406         ADD_CONST(TCP_WINDOW_CLAMP);
5407 #endif
5408 
5409         /**
5410          * @typedef
5411          * @name Packet Socket Constants
5412          * @description
5413          * The `SOL_PACKET` constant specifies the packet socket level and may be
5414          * passed as *level* argument value to
5415          * {@link module:socket.socket#getopt|getopt()} and
5416          * {@link module:socket.socket#setopt|setopt()}.
5417          *
5418          * Most `PACKET_*` constants are *option* argument values recognized by
5419          * {@link module:socket.socket#getopt|getopt()}
5420          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5421          * the `SOL_PACKET` socket level.
5422          *
5423          * The constants `PACKET_MR_PROMISC`, `PACKET_MR_MULTICAST` and
5424          * `PACKET_MR_ALLMULTI` are used in conjunction with the
5425          * `PACKET_ADD_MEMBERSHIP` and `PACKET_DROP_MEMBERSHIP` options to specify
5426          * the packet socket receive mode.
5427          *
5428          * The constants `PACKET_HOST`, `PACKET_BROADCAST`, `PACKET_MULTICAST`,
5429          * `PACKET_OTHERHOST` and `PACKET_OUTGOING` may be used as *packet_type*
5430          * value in {@link module:socket.socket.SocketAddress|socket address}
5431          * structures.
5432          * @property {number} SOL_PACKET - Socket options at the packet API level.
5433          * @property {number} PACKET_ADD_MEMBERSHIP - Add a multicast group membership.
5434          * @property {number} PACKET_DROP_MEMBERSHIP - Drop a multicast group membership.
5435          * @property {number} PACKET_AUXDATA - Receive auxiliary data (packet info).
5436          * @property {number} PACKET_FANOUT - Configure packet fanout.
5437          * @property {number} PACKET_LOSS - Retrieve the current packet loss statistics.
5438          * @property {number} PACKET_RESERVE - Reserve space for packet headers.
5439          * @property {number} PACKET_RX_RING - Configure a receive ring buffer.
5440          * @property {number} PACKET_STATISTICS - Retrieve packet statistics.
5441          * @property {number} PACKET_TIMESTAMP - Retrieve packet timestamps.
5442          * @property {number} PACKET_TX_RING - Configure a transmit ring buffer.
5443          * @property {number} PACKET_VERSION - Set the packet protocol version.
5444          * @property {number} PACKET_QDISC_BYPASS - Bypass queuing discipline for outgoing packets.
5445          *
5446          * @property {number} PACKET_MR_PROMISC - Enable promiscuous mode.
5447          * @property {number} PACKET_MR_MULTICAST - Receive multicast packets.
5448          * @property {number} PACKET_MR_ALLMULTI - Receive all multicast packets.
5449          *
5450          * @property {number} PACKET_HOST - Receive packets destined for this host.
5451          * @property {number} PACKET_BROADCAST - Receive broadcast packets.
5452          * @property {number} PACKET_MULTICAST - Receive multicast packets.
5453          * @property {number} PACKET_OTHERHOST - Receive packets destined for other hosts.
5454          * @property {number} PACKET_OUTGOING - Transmit packets.
5455          */
5456 #if defined(__linux__)
5457         ADD_CONST(SOL_PACKET);
5458         ADD_CONST(PACKET_ADD_MEMBERSHIP);
5459         ADD_CONST(PACKET_DROP_MEMBERSHIP);
5460         ADD_CONST(PACKET_AUXDATA);
5461         ADD_CONST(PACKET_FANOUT);
5462         ADD_CONST(PACKET_LOSS);
5463         ADD_CONST(PACKET_RESERVE);
5464         ADD_CONST(PACKET_RX_RING);
5465         ADD_CONST(PACKET_STATISTICS);
5466         ADD_CONST(PACKET_TIMESTAMP);
5467         ADD_CONST(PACKET_TX_RING);
5468         ADD_CONST(PACKET_VERSION);
5469         ADD_CONST(PACKET_QDISC_BYPASS);
5470 
5471         ADD_CONST(PACKET_MR_PROMISC);
5472         ADD_CONST(PACKET_MR_MULTICAST);
5473         ADD_CONST(PACKET_MR_ALLMULTI);
5474 
5475         ADD_CONST(PACKET_HOST);
5476         ADD_CONST(PACKET_BROADCAST);
5477         ADD_CONST(PACKET_MULTICAST);
5478         ADD_CONST(PACKET_OTHERHOST);
5479         ADD_CONST(PACKET_OUTGOING);
5480 #endif
5481 
5482         /**
5483          * @typedef
5484          * @name CAN Protocol Constants
5485          * @description
5486          * The `CAN_RAW` and `CAN_BCM` constants specify SocketCAN protocol numbers
5487          * and may be passed as third argument to
5488          * {@link module:socket#create|create()} for `AF_CAN` sockets.
5489          *
5490          * The `SOL_CAN_RAW` constant specifies the raw CAN socket level and the
5491          * `CAN_RAW_*` constants are option names recognized by
5492          * {@link module:socket.socket#getopt|getopt()} and
5493          * {@link module:socket.socket#setopt|setopt()}, in conjunction with the
5494          * `SOL_CAN_RAW` socket level.
5495          *
5496          * The remaining constants describe the layout of the fixed size CAN frames
5497          * exchanged over raw CAN sockets: bit flags within the 32 bit CAN ID, ID
5498          * masks, frame sizes and payload limits as well as the flag bits used by
5499          * CAN FD frames.
5500          * @property {number} CAN_RAW - Raw CAN protocol.
5501          * @property {number} CAN_BCM - Broadcast manager CAN protocol.
5502          * @property {number} SOL_CAN_RAW - Raw CAN socket option level.
5503          * @property {number} CAN_RAW_FILTER - Set receive filter list, a packed array of 32 bit id/mask pairs.
5504          * @property {number} CAN_RAW_ERR_FILTER - Set error frame filter mask.
5505          * @property {number} CAN_RAW_LOOPBACK - Control local loopback of sent frames.
5506          * @property {number} CAN_RAW_RECV_OWN_MSGS - Control reception of own sent frames.
5507          * @property {number} CAN_RAW_FD_FRAMES - Enable CAN FD frame support.
5508          * @property {number} CAN_RAW_JOIN_FILTERS - All filters must match instead of any.
5509          * @property {number} CAN_RAW_XL_FRAMES - Enable CAN XL frame support.
5510          * @property {number} CAN_EFF_FLAG - Extended (29 bit) frame format flag within the CAN ID.
5511          * @property {number} CAN_RTR_FLAG - Remote transmission request flag within the CAN ID.
5512          * @property {number} CAN_ERR_FLAG - Error message frame flag within the CAN ID.
5513          * @property {number} CAN_SFF_MASK - Standard (11 bit) frame format ID mask.
5514          * @property {number} CAN_EFF_MASK - Extended (29 bit) frame format ID mask.
5515          * @property {number} CAN_ERR_MASK - Error frame class mask.
5516          * @property {number} CAN_MTU - Size of a classic CAN frame.
5517          * @property {number} CANFD_MTU - Size of a CAN FD frame.
5518          * @property {number} CANFD_BRS - CAN FD bit rate switch flag.
5519          * @property {number} CANFD_ESI - CAN FD error state indicator flag.
5520          * @property {number} CAN_MAX_DLEN - Maximum classic CAN payload length.
5521          * @property {number} CANFD_MAX_DLEN - Maximum CAN FD payload length.
5522          */
5523 #if defined(__linux__)
5524         ADD_CONST(CAN_RAW);
5525         ADD_CONST(CAN_BCM);
5526         ADD_CONST(SOL_CAN_RAW);
5527         ADD_CONST(CAN_RAW_FILTER);
5528         ADD_CONST(CAN_RAW_ERR_FILTER);
5529         ADD_CONST(CAN_RAW_LOOPBACK);
5530         ADD_CONST(CAN_RAW_RECV_OWN_MSGS);
5531         ADD_CONST(CAN_RAW_FD_FRAMES);
5532         ADD_CONST(CAN_RAW_JOIN_FILTERS);
5533 # ifdef CAN_RAW_XL_FRAMES
5534         ADD_CONST(CAN_RAW_XL_FRAMES);
5535 # endif
5536 
5537         ADD_CONST(CAN_EFF_FLAG);
5538         ADD_CONST(CAN_RTR_FLAG);
5539         ADD_CONST(CAN_ERR_FLAG);
5540         ADD_CONST(CAN_SFF_MASK);
5541         ADD_CONST(CAN_EFF_MASK);
5542         ADD_CONST(CAN_ERR_MASK);
5543 
5544         ADD_CONST(CAN_MTU);
5545         ADD_CONST(CANFD_MTU);
5546         ADD_CONST(CANFD_BRS);
5547         ADD_CONST(CANFD_ESI);
5548         ADD_CONST(CAN_MAX_DLEN);
5549         ADD_CONST(CANFD_MAX_DLEN);
5550 #endif
5551 
5552         /**
5553          * @typedef
5554          * @name UDP Protocol Constants
5555          * @description
5556          * The `IPPROTO_UDP` constant specifies the UDP protocol number and may be
5557          * passed as third argument to {@link module:socket#create|create()} as well
5558          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
5559          * and {@link module:socket.socket#setopt|setopt()}.
5560          *
5561          * The `UDP_*` constants are *option* argument values recognized by
5562          * {@link module:socket.socket#getopt|getopt()}
5563          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5564          * the `IPPROTO_UDP` socket level.
5565          * @property {number} IPPROTO_UDP - UDP protocol.
5566          * @property {number} UDP_CORK - Cork data until flush.
5567          */
5568         ADD_CONST(IPPROTO_UDP);
5569 #if defined(__linux__)
5570         ADD_CONST(UDP_CORK);
5571 #endif
5572 
5573         /**
5574          * @typedef
5575          * @name Shutdown Constants
5576          * @description
5577          * The `SHUT_*` constants are passed as argument to the
5578          * {@link module:socket.socket#shutdown|shutdown()} function to specify
5579          * which direction of a full duplex connection to shut down.
5580          * @property {number} SHUT_RD - Disallow further receptions.
5581          * @property {number} SHUT_WR - Disallow further transmissions.
5582          * @property {number} SHUT_RDWR - Disallow further receptions and transmissions.
5583          */
5584         ADD_CONST(SHUT_RD);
5585         ADD_CONST(SHUT_WR);
5586         ADD_CONST(SHUT_RDWR);
5587 
5588         /**
5589          * @typedef
5590          * @name Address Info Flags
5591          * @description
5592          * The `AI_*` flags may be passed as bitwise OR-ed number in the *flags*
5593          * property of the *hints* dictionary argument of
5594          * {@link module:socket#addrinfo|addrinfo()}.
5595          * @property {number} AI_ADDRCONFIG - Address configuration flag.
5596          * @property {number} AI_ALL - Return IPv4 and IPv6 socket addresses.
5597          * @property {number} AI_CANONIDN - Canonicalize using the IDNA standard.
5598          * @property {number} AI_CANONNAME - Fill in the canonical name field.
5599          * @property {number} AI_IDN - Enable IDN encoding.
5600          * @property {number} AI_NUMERICHOST - Prevent hostname resolution.
5601          * @property {number} AI_NUMERICSERV - Prevent service name resolution.
5602          * @property {number} AI_PASSIVE - Use passive socket.
5603          * @property {number} AI_V4MAPPED - Map IPv6 addresses to IPv4-mapped format.
5604          */
5605         ADD_CONST(AI_ADDRCONFIG);
5606         ADD_CONST(AI_ALL);
5607         ADD_CONST(AI_CANONIDN);
5608         ADD_CONST(AI_CANONNAME);
5609         ADD_CONST(AI_IDN);
5610         ADD_CONST(AI_NUMERICHOST);
5611         ADD_CONST(AI_NUMERICSERV);
5612         ADD_CONST(AI_PASSIVE);
5613         ADD_CONST(AI_V4MAPPED);
5614 
5615         /**
5616          * @typedef
5617          * @name Name Info Constants
5618          * @description
5619          * The `NI_*` flags may be passed as bitwise OR-ed number via the *flags*
5620          * argument of {@link module:socket#nameinfo|nameinfo()}.
5621          * @property {number} NI_DGRAM - Datagram socket type.
5622          * @property {number} NI_IDN - Enable IDN encoding.
5623          * @property {number} NI_NAMEREQD - Hostname resolution required.
5624          * @property {number} NI_NOFQDN - Do not force fully qualified domain name.
5625          * @property {number} NI_NUMERICHOST - Return numeric form of the hostname.
5626          * @property {number} NI_NUMERICSERV - Return numeric form of the service name.
5627          */
5628         ADD_CONST(NI_DGRAM);
5629         ADD_CONST(NI_IDN);
5630         ADD_CONST(NI_MAXHOST);
5631         ADD_CONST(NI_MAXSERV);
5632         ADD_CONST(NI_NAMEREQD);
5633         ADD_CONST(NI_NOFQDN);
5634         ADD_CONST(NI_NUMERICHOST);
5635         ADD_CONST(NI_NUMERICSERV);
5636 
5637         /**
5638          * @typedef
5639          * @name Poll Event Constants
5640          * @description
5641          * The following constants represent event types for polling operations and
5642          * are set or returned as part of a
5643          * {@link module:socket.PollSpec|PollSpec} tuple by the
5644          * {@link module:socket#poll|poll()} function. When passed via an argument
5645          * PollSpec to `poll()`, they specify the I/O events to watch for on the
5646          * corresponding handle. When appearing in a PollSpec returned by `poll()`,
5647          * they specify the I/O events that occurred on a watched handle.
5648          * @property {number} POLLIN - Data available to read.
5649          * @property {number} POLLPRI - Priority data available to read.
5650          * @property {number} POLLOUT - Writable data available.
5651          * @property {number} POLLERR - Error condition.
5652          * @property {number} POLLHUP - Hang up.
5653          * @property {number} POLLNVAL - Invalid request.
5654          * @property {number} POLLRDHUP - Peer closed or shutdown writing.
5655          */
5656         ADD_CONST(POLLIN);
5657         ADD_CONST(POLLPRI);
5658         ADD_CONST(POLLOUT);
5659         ADD_CONST(POLLERR);
5660         ADD_CONST(POLLHUP);
5661         ADD_CONST(POLLNVAL);
5662 #if defined(__linux__)
5663         ADD_CONST(POLLRDHUP);
5664 #endif
5665 
5666         uc_type_declare(vm, "socket", socket_fns, close_socket);
5667 }
5668 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt