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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt