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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt