• 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, alen);
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  * Connects the socket to a remote address.
3287  *
3288  * Attempts to establish a connection to the specified remote address.
3289  *
3290  * Returns `true` if the connection is successfully established.
3291  * Returns `null` if an error occurred during the connection attempt.
3292  *
3293  * @function module:socket.socket#connect
3294  *
3295  * @param {string|module:socket.socket.SocketAddress} address
3296  * The address of the remote endpoint to connect to.
3297  *
3298  * @param {number} port
3299  * The port number of the remote endpoint to connect to.
3300  *
3301  * @returns {?boolean}
3302  */
3303 static uc_value_t *
3304 uc_socket_inst_connect(uc_vm_t *vm, size_t nargs)
3305 {
3306         struct sockaddr_storage ss;
3307         uc_value_t *addr, *port;
3308         unsigned long n;
3309         int ret, sockfd;
3310         socklen_t slen;
3311 
3312         args_get(vm, nargs, &sockfd,
3313                 "address", UC_NULL, false, &addr,
3314                 "port", UC_INTEGER, true, &port);
3315 
3316         if (!uv_to_sockaddr(addr, &ss, &slen))
3317                 return NULL;
3318 
3319         if (port) {
3320                  if (ss.ss_family != AF_INET && ss.ss_family != AF_INET6)
3321                         err_return(EINVAL, "Port argument is only valid for IPv4 and IPv6 addresses");
3322 
3323                 n = ucv_to_unsigned(port);
3324 
3325                 if (n > 65535)
3326                         errno = ERANGE;
3327 
3328                 if (errno != 0)
3329                         err_return(errno, "Invalid port number");
3330 
3331                 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(n);
3332         }
3333 
3334         ret = connect(sockfd, (struct sockaddr *)&ss, slen);
3335 
3336         if (ret == -1)
3337                 err_return(errno, "connect()");
3338 
3339         ok_return(ucv_boolean_new(true));
3340 }
3341 
3342 /**
3343  * Sends data through the socket.
3344  *
3345  * Sends the provided data through the socket handle to the specified remote
3346  * address, if provided.
3347  *
3348  * Returns the number of bytes sent.
3349  * Returns `null` if an error occurred during the send operation.
3350  *
3351  * @function module:socket.socket#send
3352  *
3353  * @param {*} data
3354  * The data to be sent through the socket. String data is sent as-is, any other
3355  * type is implicitly converted to a string first before being sent on the
3356  * socket.
3357  *
3358  * @param {number} [flags]
3359  * Optional flags that modify the behavior of the send operation.
3360  *
3361  * @param {module:socket.socket.SocketAddress|number[]|string} [address]
3362  * The address of the remote endpoint to send the data to. It can be either an
3363  * IP address string, an array returned by {@link module:core#iptoarr|iptoarr()},
3364  * or an object representing a network address. If not provided, the data is
3365  * sent to the remote endpoint the socket is connected to.
3366  *
3367  * @returns {?number}
3368  *
3369  * @see {@link module:socket#sockaddr|sockaddr()}
3370  *
3371  * @example
3372  * // Send to connected socket
3373  * let tcp_sock = socket.create(socket.AF_INET, socket.SOCK_STREAM);
3374  * tcp_sock.connect("192.168.1.1", 80);
3375  * tcp_sock.send("GET / HTTP/1.0\r\n\r\n");
3376  *
3377  * // Send a datagram on unconnected socket
3378  * let udp_sock = socket.create(socket.AF_INET, socket.SOCK_DGRAM);
3379  * udp_sock.send("Hello there!", 0, "255.255.255.255:9000");
3380  * udp_sock.send("Hello there!", 0, {
3381  *   family: socket.AF_INET,      // optional
3382  *   address: "255.255.255.255",
3383  *   port: 9000
3384  * });
3385  */
3386 static uc_value_t *
3387 uc_socket_inst_send(uc_vm_t *vm, size_t nargs)
3388 {
3389         uc_value_t *data, *flags, *addr;
3390         struct sockaddr_storage ss = { 0 };
3391         struct sockaddr *sa = NULL;
3392         socklen_t salen = 0;
3393         char *buf = NULL;
3394         ssize_t ret;
3395         int sockfd;
3396 
3397         args_get(vm, nargs, &sockfd,
3398                 "data", UC_NULL, false, &data,
3399                 "flags", UC_INTEGER, true, &flags,
3400                 "address", UC_NULL, true, &addr);
3401 
3402         if (addr) {
3403                 if (!uv_to_sockaddr(addr, &ss, &salen))
3404                         return NULL;
3405 
3406                 sa = (struct sockaddr *)&ss;
3407         }
3408 
3409         if (ucv_type(data) != UC_STRING)
3410                 buf = ucv_to_string(vm, data);
3411 
3412         ret = sendto(sockfd,
3413                 buf ? buf : ucv_string_get(data),
3414                 buf ? strlen(buf) : ucv_string_length(data),
3415                 (flags ? ucv_int64_get(flags) : 0) | MSG_NOSIGNAL, sa, salen);
3416 
3417         free(buf);
3418 
3419         if (ret == -1)
3420                 err_return(errno, "send()");
3421 
3422         ok_return(ucv_int64_new(ret));
3423 }
3424 
3425 /**
3426  * Receives data from the socket.
3427  *
3428  * Receives data from the socket handle, optionally specifying the maximum
3429  * length of data to receive, flags to modify the receive behavior, and an
3430  * optional address dictionary where the function will place the address from
3431  * which the data was received (for unconnected sockets).
3432  *
3433  * Returns a string containing the received data.
3434  * Returns an empty string if the remote side closed the socket.
3435  * Returns `null` if an error occurred during the receive operation.
3436  *
3437  * @function module:socket.socket#recv
3438  *
3439  * @param {number} [length=4096]
3440  * The maximum number of bytes to receive.
3441  *
3442  * @param {number} [flags]
3443  * Optional flags that modify the behavior of the receive operation.
3444  *
3445  * @param {Object} [address]
3446  * An object where the function will store the address from which the data was
3447  * received. If provided, it will be filled with the details obtained from the
3448  * sockaddr argument of the underlying `recvfrom()` syscall. See the type
3449  * definition of {@link module:socket.socket.SocketAddress|SocketAddress} for
3450  * details on the format.
3451  *
3452  * @returns {?string}
3453  */
3454 static uc_value_t *
3455 uc_socket_inst_recv(uc_vm_t *vm, size_t nargs)
3456 {
3457         uc_value_t *length, *flags, *addrobj;
3458         struct sockaddr_storage ss = { 0 };
3459         uc_stringbuf_t *buf;
3460         ssize_t len, ret;
3461         socklen_t sslen;
3462         int sockfd;
3463 
3464         args_get(vm, nargs, &sockfd,
3465                 "length", UC_INTEGER, true, &length,
3466                 "flags", UC_INTEGER, true, &flags,
3467                 "address", UC_OBJECT, true, &addrobj);
3468 
3469         len = length ? ucv_to_integer(length) : 4096;
3470 
3471         if (errno || len <= 0)
3472                 err_return(errno, "Invalid length argument");
3473 
3474         buf = strbuf_alloc(len);
3475 
3476         if (!buf)
3477                 return NULL;
3478 
3479         do {
3480                 sslen = sizeof(ss);
3481                 ret = recvfrom(sockfd, strbuf_data(buf), len,
3482                         flags ? ucv_int64_get(flags) : 0, (struct sockaddr *)&ss, &sslen);
3483         } while (ret == -1 && errno == EINTR);
3484 
3485         if (ret == -1) {
3486                 strbuf_free(buf);
3487                 err_return(errno, "recv()");
3488         }
3489 
3490         if (addrobj)
3491                 sockaddr_to_uv(&ss, addrobj);
3492 
3493         ok_return(strbuf_finish(&buf, ret));
3494 }
3495 
3496 uc_declare_vector(strbuf_array_t, uc_stringbuf_t *);
3497 
3498 #if defined(__linux__)
3499 static void optmem_max(size_t *sz) {
3500         char buf[sizeof("18446744073709551615")] = { 0 };
3501         int fd, rv;
3502 
3503         fd = open("/proc/sys/net/core/optmem_max", O_RDONLY);
3504 
3505         if (fd >= 0) {
3506                 if (read(fd, buf, sizeof(buf) - 1) > 0) {
3507                         rv = strtol(buf, NULL, 10);
3508 
3509                         if (rv > 0 && (size_t)rv < *sz)
3510                                 *sz = rv;
3511                 }
3512 
3513                 if (fd > 2)
3514                         close(fd);
3515         }
3516 }
3517 #else
3518 # define optmem_max(x)
3519 #endif
3520 
3521 
3522 /**
3523  * Represents a single control (ancillary data) message returned
3524  * in the *ancillary* array by {@link module:socket.socket#recvmsg|`recvmsg()`}.
3525  *
3526  * @typedef {Object} module:socket.socket.ControlMessage
3527  * @property {number} level
3528  * The message socket level (`cmsg_level`), e.g. `SOL_SOCKET`.
3529  *
3530  * @property {number} type
3531  * The protocol specific message type (`cmsg_type`), e.g. `SCM_RIGHTS`.
3532  *
3533  * @property {*} data
3534  * The payload of the control message. If the control message type is known by
3535  * the socket module, it is represented as a mixed value (array, object, number,
3536  * etc.) with structure specific to the control message type. If the control
3537  * message cannot be decoded, *data* is set to a string value containing the raw
3538  * payload.
3539  */
3540 static uc_value_t *
3541 decode_cmsg(uc_vm_t *vm, struct cmsghdr *cmsg)
3542 {
3543         char *s = (char *)CMSG_DATA(cmsg);
3544         size_t sz = cmsg->cmsg_len - sizeof(*cmsg);
3545         struct sockaddr_storage *ss;
3546         uc_value_t *fdarr;
3547         struct stat st;
3548         int *fds;
3549 
3550         for (size_t i = 0; i < ARRAY_SIZE(cmsgtypes); i++) {
3551 
3552                 if (cmsgtypes[i].level != cmsg->cmsg_level)
3553                         continue;
3554 
3555                 if (cmsgtypes[i].type != cmsg->cmsg_type)
3556                         continue;
3557 
3558                 switch ((uintptr_t)cmsgtypes[i].ctype) {
3559                 case (uintptr_t)CV_INT:
3560                         return ucv_int64_new(parse_integer(s, sz));
3561 
3562                 case (uintptr_t)CV_UINT:
3563                 case (uintptr_t)CV_BE32:
3564                         return ucv_uint64_new(parse_unsigned(s, sz));
3565 
3566                 case (uintptr_t)CV_SOCKADDR:
3567                         ss = (struct sockaddr_storage *)s;
3568 
3569                         if ((sz >= sizeof(struct sockaddr_in) &&
3570                              ss->ss_family == AF_INET) ||
3571                             (sz >= sizeof(struct sockaddr_in6) &&
3572                              ss->ss_family == AF_INET6))
3573                         {
3574                                 uc_value_t *addr = ucv_object_new(vm);
3575 
3576                                 if (sockaddr_to_uv(ss, addr))
3577                                         return addr;
3578 
3579                                 ucv_put(addr);
3580                         }
3581 
3582                         return NULL;
3583 
3584                 case (uintptr_t)CV_FDS:
3585                         fdarr = ucv_array_new_length(vm, sz / sizeof(int));
3586                         fds = (int *)s;
3587 
3588                         for (size_t i = 0; i < sz / sizeof(int); i++) {
3589                                 if (fstat(fds[i], &st) == 0) {
3590                                         uc_resource_type_t *t;
3591 
3592                                         if (S_ISSOCK(st.st_mode)) {
3593                                                 t = ucv_resource_type_lookup(vm, "socket");
3594 
3595                                                 ucv_array_push(fdarr,
3596                                                         ucv_resource_new(t, (void *)(intptr_t)fds[i]));
3597 
3598                                                 continue;
3599                                         }
3600                                         else if (S_ISDIR(st.st_mode)) {
3601                                                 t = ucv_resource_type_lookup(vm, "fs.dir");
3602 
3603                                                 if (t) {
3604                                                         DIR *d = fdopendir(fds[i]);
3605 
3606                                                         if (d) {
3607                                                                 ucv_array_push(fdarr, ucv_resource_new(t, d));
3608                                                                 continue;
3609                                                         }
3610                                                 }
3611                                         }
3612                                         else {
3613                                                 t = ucv_resource_type_lookup(vm, "fs.file");
3614 
3615                                                 if (t) {
3616                                                         int n = fcntl(fds[i], F_GETFL);
3617                                                         const char *mode;
3618 
3619                                                         if (n <= 0 || (n & O_ACCMODE) == O_RDONLY)
3620                                                                 mode = "r";
3621                                                         else if ((n & O_ACCMODE) == O_WRONLY)
3622                                                                 mode = (n & O_APPEND) ? "a" : "w";
3623                                                         else
3624                                                                 mode = (n & O_APPEND) ? "a+" : "w+";
3625 
3626                                                         FILE *f = fdopen(fds[i], mode);
3627 
3628                                                         if (f) {
3629                                                                 ucv_array_push(fdarr, uc_resource_new(t, f));
3630                                                                 continue;
3631                                                         }
3632                                                 }
3633                                         }
3634                                 }
3635 
3636                                 ucv_array_push(fdarr, ucv_int64_new(fds[i]));
3637                         }
3638 
3639                         return fdarr;
3640 
3641                 case (uintptr_t)CV_STRING:
3642                         break;
3643 
3644                 default:
3645                         if (sz >= cmsgtypes[i].ctype->size)
3646                                 return struct_to_uv(s, cmsgtypes[i].ctype);
3647                 }
3648 
3649                 break;
3650         }
3651 
3652         return ucv_string_new_length(s, sz);
3653 }
3654 
3655 static size_t
3656 estimate_cmsg_size(uc_value_t *uv)
3657 {
3658         int cmsg_level = ucv_to_integer(ucv_object_get(uv, "level", NULL));
3659         int cmsg_type = ucv_to_integer(ucv_object_get(uv, "type", NULL));
3660         uc_value_t *val = ucv_object_get(uv, "data", NULL);
3661 
3662         for (size_t i = 0; i < ARRAY_SIZE(cmsgtypes); i++) {
3663                 if (cmsgtypes[i].level != cmsg_level)
3664                         continue;
3665 
3666                 if (cmsgtypes[i].type != cmsg_type)
3667                         continue;
3668 
3669                 switch ((uintptr_t)cmsgtypes[i].ctype) {
3670                 case (uintptr_t)CV_INT:      return sizeof(int);
3671                 case (uintptr_t)CV_UINT:     return sizeof(unsigned int);
3672                 case (uintptr_t)CV_BE32:     return sizeof(uint32_t);
3673                 case (uintptr_t)CV_SOCKADDR: return sizeof(struct sockaddr_storage);
3674                 case (uintptr_t)CV_FDS:      return ucv_array_length(val) * sizeof(int);
3675                 case (uintptr_t)CV_STRING:   return ucv_string_length(val);
3676                 default:                     return cmsgtypes[i].ctype->size;
3677                 }
3678         }
3679 
3680         switch (ucv_type(val)) {
3681                 case UC_BOOLEAN: return sizeof(unsigned int);
3682                 case UC_INTEGER: return sizeof(int);
3683                 case UC_STRING:  return ucv_string_length(val);
3684                 default:         return 0;
3685         }
3686 }
3687 
3688 static bool
3689 encode_cmsg(uc_vm_t *vm, uc_value_t *uv, struct cmsghdr *cmsg)
3690 {
3691         struct { int *entries; size_t count; } fds = { 0 };
3692         void *dataptr = NULL;
3693         socklen_t datasz = 0;
3694         char *st = NULL;
3695         size_t i;
3696         union {
3697                 int i;
3698                 unsigned int u;
3699                 uint32_t u32;
3700                 struct sockaddr_storage ss;
3701         } val;
3702 
3703         cmsg->cmsg_level = ucv_to_integer(ucv_object_get(uv, "level", NULL));
3704         cmsg->cmsg_type = ucv_to_integer(ucv_object_get(uv, "type", NULL));
3705 
3706         uc_value_t *data = ucv_object_get(uv, "data", NULL);
3707 
3708         for (i = 0; i < ARRAY_SIZE(cmsgtypes); i++) {
3709                 if (cmsgtypes[i].level != cmsg->cmsg_level)
3710                         continue;
3711 
3712                 if (cmsgtypes[i].type != cmsg->cmsg_type)
3713                         continue;
3714 
3715                 switch ((uintptr_t)cmsgtypes[i].ctype) {
3716                 case (uintptr_t)CV_INT:
3717                         val.i = ucv_to_integer(data);
3718                         datasz = sizeof(val.i);
3719                         dataptr = &val;
3720                         break;
3721 
3722                 case (uintptr_t)CV_UINT:
3723                         val.u = ucv_to_unsigned(data);
3724                         datasz = sizeof(val.u);
3725                         dataptr = &val;
3726                         break;
3727 
3728                 case (uintptr_t)CV_BE32:
3729                         val.u32 = ucv_to_unsigned(data);
3730                         datasz = sizeof(val.u32);
3731                         dataptr = &val;
3732                         break;
3733 
3734                 case (uintptr_t)CV_SOCKADDR:
3735                         if (uv_to_sockaddr(data, &val.ss, &datasz))
3736                                 dataptr = &val;
3737                         else
3738                                 datasz = 0, dataptr = NULL;
3739                         break;
3740 
3741                 case (uintptr_t)CV_FDS:
3742                         if (ucv_type(data) == UC_ARRAY) {
3743                                 for (size_t i = 0; i < ucv_array_length(data); i++) {
3744                                         int fd;
3745 
3746                                         if (uv_to_fileno(vm, ucv_array_get(data, i), &fd))
3747                                                 uc_vector_push(&fds, fd);
3748                                 }
3749                         }
3750 
3751                         datasz = sizeof(fds.entries[0]) * fds.count;
3752                         dataptr = fds.entries;
3753                         break;
3754 
3755                 case (uintptr_t)CV_STRING:
3756                         datasz = ucv_string_length(data);
3757                         dataptr = ucv_string_get(data);
3758                         break;
3759 
3760                 default:
3761                         st = uv_to_struct(data, cmsgtypes[i].ctype);
3762                         datasz = st ? cmsgtypes[i].ctype->size : 0;
3763                         dataptr = st;
3764                         break;
3765                 }
3766 
3767                 break;
3768         }
3769 
3770         /* we don't know this kind of control message, guess encoding */
3771         if (i == ARRAY_SIZE(cmsgtypes)) {
3772                 switch (ucv_type(data)) {
3773                 /* treat boolean as int with values 1 or 0 */
3774                 case UC_BOOLEAN:
3775                         val.u = ucv_boolean_get(data);
3776                         dataptr = &val;
3777                         datasz = sizeof(val.u);
3778                         break;
3779 
3780                 /* treat integers as int */
3781                 case UC_INTEGER:
3782                         if (ucv_is_u64(data)) {
3783                                 val.u = ucv_uint64_get(data);
3784                                 datasz = sizeof(val.u);
3785                         }
3786                         else {
3787                                 val.i = ucv_int64_get(data);
3788                                 datasz = sizeof(val.i);
3789                         }
3790 
3791                         dataptr = &val;
3792                         break;
3793 
3794                 /* pass strings as-is */
3795                 case UC_STRING:
3796                         dataptr = ucv_string_get(data);
3797                         datasz = ucv_string_length(data);
3798                         break;
3799 
3800                 default:
3801                         break;
3802                 }
3803         }
3804 
3805         cmsg->cmsg_len = CMSG_LEN(datasz);
3806 
3807         if (dataptr)
3808                 memcpy(CMSG_DATA(cmsg), dataptr, datasz);
3809 
3810         uc_vector_clear(&fds);
3811         free(st);
3812 
3813         return true;
3814 }
3815 
3816 /**
3817  * Sends a message through the socket.
3818  *
3819  * Sends a message through the socket handle, supporting complex message
3820  * structures including multiple data buffers and ancillary data. This function
3821  * allows for precise control over the message content and delivery behavior.
3822  *
3823  * Returns the number of sent bytes.
3824  *
3825  * Returns `null` if an error occurred.
3826  *
3827  * @function module:socket.socket#sendmsg
3828  *
3829  * @param {*} [data]
3830  * The data to be sent. If a string is provided, it is sent as is. If an array
3831  * is specified, each item is sent as a separate `struct iovec`. Non-string
3832  * values are implicitly converted to a string and sent. If omitted, only
3833  * ancillary data and address are considered.
3834  *
3835  * @param {module:socket.socket.ControlMessage[]|string} [ancillaryData]
3836  * Optional ancillary data to be sent. If an array is provided, each element is
3837  * converted to a control message. If a string is provided, it is sent as-is
3838  * without further interpretation. Refer to
3839  * {@link module:socket.socket#recvmsg|`recvmsg()`} and
3840  * {@link module:socket.socket.ControlMessage|ControlMessage} for details.
3841  *
3842  * @param {module:socket.socket.SocketAddress} [address]
3843  * The destination address for the message. If provided, it sets or overrides
3844  * the packet destination address.
3845  *
3846  * @param {number} [flags]
3847  * Optional flags to modify the behavior of the send operation. This should be a
3848  * bitwise OR-ed combination of `MSG_*` flag values.
3849  *
3850  * @returns {?number}
3851  * Returns the number of bytes sent on success, or `null` if an error occurred.
3852  *
3853  * @example
3854  * // Send file descriptors over domain socket
3855  * const f1 = fs.open("example.txt", "w");
3856  * const f2 = fs.popen("date +%s", "r");
3857  * const sk = socket.connect({ family: socket.AF_UNIX, path: "/tmp/socket" });
3858 
3859  * sk.sendmsg("Hi there, here's some descriptors!", [
3860  *      { level: socket.SOL_SOCKET, type: socket.SCM_RIGHTS, data: [ f1, f2 ] }
3861  * ]);
3862  *
3863  * // Send multiple values in one datagram
3864  * sk.sendmsg([ "This", "is", "one", "message" ]);
3865  */
3866 static uc_value_t *
3867 uc_socket_inst_sendmsg(uc_vm_t *vm, size_t nargs)
3868 {
3869         uc_value_t *data, *ancdata, *addr, *flags;
3870         struct sockaddr_storage ss = { 0 };
3871         strbuf_array_t sbarr = { 0 };
3872         struct msghdr msg = { 0 };
3873         struct iovec vec = { 0 };
3874         int flagval, sockfd;
3875         socklen_t slen;
3876         ssize_t ret;
3877 
3878         args_get(vm, nargs, &sockfd,
3879                 "data", UC_NULL, true, &data,
3880                 "ancillary data", UC_NULL, true, &ancdata,
3881                 "address", UC_OBJECT, true, &addr,
3882                 "flags", UC_INTEGER, true, &flags);
3883 
3884         flagval = flags ? ucv_int64_get(flags) : 0;
3885 
3886         /* treat string ancdata arguemnt as raw controldata buffer */
3887         if (ucv_type(ancdata) == UC_STRING) {
3888                 msg.msg_control = ucv_string_get(ancdata);
3889                 msg.msg_controllen = ucv_string_length(ancdata);
3890         }
3891         /* encode ancdata passed as array */
3892         else if (ucv_type(ancdata) == UC_ARRAY) {
3893                 msg.msg_controllen = 0;
3894 
3895                 for (size_t i = 0; i < ucv_array_length(ancdata); i++) {
3896                         size_t sz = estimate_cmsg_size(ucv_array_get(ancdata, i));
3897 
3898                         if (sz > 0)
3899                                 msg.msg_controllen += CMSG_SPACE(sz);
3900                 }
3901 
3902                 if (msg.msg_controllen > 0) {
3903                         msg.msg_control = xalloc(msg.msg_controllen);
3904 
3905                         struct cmsghdr *cmsg = NULL;
3906 
3907                         for (size_t i = 0; i < ucv_array_length(ancdata); i++) {
3908 #ifdef __clang_analyzer__
3909                                 /* Clang static analyzer assumes that CMSG_*HDR() returns
3910                                  * allocated heap pointers and not pointers into the
3911                                  * msg.msg_control buffer. Nudge it. */
3912                                 cmsg = (struct cmsghdr *)msg.msg_control;
3913 #else
3914                                 cmsg = cmsg ? CMSG_NXTHDR(&msg, cmsg) : CMSG_FIRSTHDR(&msg);
3915 #endif
3916 
3917                                 if (!cmsg) {
3918                                         free(msg.msg_control);
3919                                         err_return(ENOBUFS, "Not enough CMSG buffer space");
3920                                 }
3921 
3922                                 if (!encode_cmsg(vm, ucv_array_get(ancdata, i), cmsg)) {
3923                                         free(msg.msg_control);
3924                                         return NULL;
3925                                 }
3926                         }
3927 
3928                         msg.msg_controllen = (cmsg != NULL)
3929                                 ? (char *)cmsg - (char *)msg.msg_control + CMSG_SPACE(cmsg->cmsg_len)
3930                                 : 0;
3931                 }
3932         }
3933         else if (ancdata) {
3934                 err_return(EINVAL, "Ancillary data must be string or array value");
3935         }
3936 
3937         /* prepare iov array */
3938         if (ucv_type(data) == UC_ARRAY) {
3939                 msg.msg_iovlen = ucv_array_length(data);
3940                 msg.msg_iov = (msg.msg_iovlen > 1)
3941                         ? xalloc(sizeof(vec) * msg.msg_iovlen) : &vec;
3942 
3943                 for (size_t i = 0; i < (size_t)msg.msg_iovlen; i++) {
3944                         uc_value_t *item = ucv_array_get(data, i);
3945 
3946                         if (ucv_type(item) == UC_STRING) {
3947                                 msg.msg_iov[i].iov_base = _ucv_string_get(&((uc_array_t *)data)->entries[i]);
3948                                 msg.msg_iov[i].iov_len = ucv_string_length(item);
3949                         }
3950                         else if (item) {
3951                                 struct printbuf *pb = xprintbuf_new();
3952                                 uc_vector_push(&sbarr, pb);
3953                                 ucv_to_stringbuf(vm, pb, item, false);
3954                                 msg.msg_iov[i].iov_base = pb->buf;
3955                                 msg.msg_iov[i].iov_len = pb->bpos;
3956                         }
3957                 }
3958         }
3959         else if (ucv_type(data) == UC_STRING) {
3960                 msg.msg_iovlen = 1;
3961                 msg.msg_iov = &vec;
3962                 vec.iov_base = ucv_string_get(data);
3963                 vec.iov_len = ucv_string_length(data);
3964         }
3965         else if (data) {
3966                 struct printbuf *pb = xprintbuf_new();
3967                 uc_vector_push(&sbarr, pb);
3968                 ucv_to_stringbuf(vm, pb, data, false);
3969                 msg.msg_iovlen = 1;
3970                 msg.msg_iov = &vec;
3971                 vec.iov_base = pb->buf;
3972                 vec.iov_len = pb->bpos;
3973         }
3974 
3975         /* prepare address */
3976         if (addr && uv_to_sockaddr(addr, &ss, &slen)) {
3977                 msg.msg_name = &ss;
3978                 msg.msg_namelen = slen;
3979         }
3980 
3981         /* now send actual data */
3982         do {
3983                 ret = sendmsg(sockfd, &msg, flagval);
3984         } while (ret == -1 && errno == EINTR);
3985 
3986         while (sbarr.count > 0)
3987                 printbuf_free(sbarr.entries[--sbarr.count]);
3988 
3989         uc_vector_clear(&sbarr);
3990 
3991         if (msg.msg_iov != &vec)
3992                 free(msg.msg_iov);
3993 
3994         free(msg.msg_control);
3995 
3996         if (ret == -1)
3997                 err_return(errno, "sendmsg()");
3998 
3999         ok_return(ucv_int64_new(ret));
4000 }
4001 
4002 
4003 
4004 /**
4005  * Represents a message object returned by
4006  * {@link module:socket.socket#recvmsg|`recvmsg()`}.
4007  *
4008  * @typedef {Object} module:socket.socket.ReceivedMessage
4009  * @property {number} flags
4010  * Integer value containing bitwise OR-ed `MSG_*` result flags returned by the
4011  * underlying receive call.
4012  *
4013  * @property {number} length
4014  * Integer value containing the number of bytes returned by the `recvmsg()`
4015  * syscall, which might be larger than the received data in case `MSG_TRUNC`
4016  * was passed.
4017  *
4018  * @property {module:socket.socket.SocketAddress} address
4019  * The address from which the message was received.
4020  *
4021  * @property {string[]|string} data
4022  * An array of strings, each representing the received message data.
4023  * Each string corresponds to one buffer size specified in the *sizes* argument.
4024  * If a single receive size was passed instead of an array of sizes, *data* will
4025  * hold a string containing the received data.
4026  *
4027  * @property {module:socket.socket.ControlMessage[]} [ancillary]
4028  * An array of received control messages. Only included if a non-zero positive
4029  * *ancillarySize* was passed to `recvmsg()`.
4030  */
4031 
4032 /**
4033  * Receives a message from the socket.
4034  *
4035  * Receives a message from the socket handle, allowing for more complex data
4036  * reception compared to `recv()`. This includes the ability to receive
4037  * ancillary data (such as file descriptors, credentials, etc.), multiple
4038  * message segments, and optional flags to modify the receive behavior.
4039  *
4040  * Returns an object containing the received message data, ancillary data,
4041  * and the sender's address.
4042  *
4043  * Returns `null` if an error occurred during the receive operation.
4044  *
4045  * @function module:socket.socket#recvmsg
4046  *
4047  * @param {number[]|number} [sizes]
4048  * Specifies the sizes of the buffers used for receiving the message. If an
4049  * array of numbers is provided, each number determines the size of an
4050  * individual buffer segment, creating multiple `struct iovec` for reception.
4051  * If a single number is provided, a single buffer of that size is used.
4052  *
4053  * @param {number} [ancillarySize]
4054  * The size allocated for the ancillary data buffer. If not provided, ancillary
4055  * data is not processed.
4056  *
4057  * @param {number} [flags]
4058  * Optional flags to modify the behavior of the receive operation. This should
4059  * be a bitwise OR-ed combination of flag values.
4060  *
4061  * @returns {?module:socket.socket.ReceivedMessage}
4062  * An object containing the received message data, ancillary data,
4063  * and the sender's address.
4064  *
4065  * @example
4066  * // Receive file descriptors over domain socket
4067  * const sk = socket.listen({ family: socket.AF_UNIX, path: "/tmp/socket" });
4068  * sk.setopt(socket.SOL_SOCKET, socket.SO_PASSCRED, true);
4069  *
4070  * const msg = sk.recvmsg(1024, 1024); *
4071  * for (let cmsg in msg.ancillary)
4072  *   if (cmsg.level == socket.SOL_SOCKET && cmsg.type == socket.SCM_RIGHTS)
4073  *     print(`Got some descriptors: ${cmsg.data}!\n`);
4074  *
4075  * // Receive message in segments of 10, 128 and 512 bytes
4076  * const msg = sk.recvmsg([ 10, 128, 512 ]);
4077  * print(`Message parts: ${msg.data[0]}, ${msg.data[1]}, ${msg.data[2]}\n`);
4078  *
4079  * // Peek buffer
4080  * const msg = sk.recvmsg(0, 0, socket.MSG_PEEK|socket.MSG_TRUNC);
4081  * print(`Received ${length(msg.data)} bytes, ${msg.length} bytes available\n`);
4082  */
4083 static uc_value_t *
4084 uc_socket_inst_recvmsg(uc_vm_t *vm, size_t nargs)
4085 {
4086         uc_value_t *length, *anclength, *flags, *rv;
4087         struct sockaddr_storage ss = { 0 };
4088         strbuf_array_t sbarr = { 0 };
4089         struct msghdr msg = { 0 };
4090         struct iovec vec = { 0 };
4091         int flagval, sockfd;
4092         ssize_t ret;
4093 
4094         args_get(vm, nargs, &sockfd,
4095                 "length", UC_NULL, true, &length,
4096                 "ancillary length", UC_INTEGER, true, &anclength,
4097                 "flags", UC_INTEGER, true, &flags);
4098 
4099         flagval = flags ? ucv_int64_get(flags) : 0;
4100 
4101         /* prepare ancillary data buffer */
4102         if (anclength) {
4103                 size_t sz = ucv_to_unsigned(anclength);
4104 
4105                 if (errno != 0)
4106                         err_return(errno, "Invalid ancillary data length");
4107 
4108                 optmem_max(&sz);
4109 
4110                 if (sz > 0) {
4111                         msg.msg_controllen = sz;
4112                         msg.msg_control = xalloc(sz);
4113                 }
4114         }
4115 
4116         /* prepare iov array */
4117         if (ucv_type(length) == UC_ARRAY) {
4118                 msg.msg_iovlen = ucv_array_length(length);
4119                 msg.msg_iov = (msg.msg_iovlen > 1)
4120                         ? xalloc(sizeof(vec) * msg.msg_iovlen) : &vec;
4121 
4122                 for (size_t i = 0; i < (size_t)msg.msg_iovlen; i++) {
4123                         size_t sz = ucv_to_unsigned(ucv_array_get(length, i));
4124 
4125                         if (errno != 0) {
4126                                 while (sbarr.count > 0)
4127                                         strbuf_free(sbarr.entries[--sbarr.count]);
4128 
4129                                 uc_vector_clear(&sbarr);
4130 
4131                                 if (msg.msg_iov != &vec)
4132                                         free(msg.msg_iov);
4133 
4134                                 free(msg.msg_control);
4135 
4136                                 err_return(errno, "Invalid length value");
4137                         }
4138 
4139                         uc_vector_push(&sbarr, strbuf_alloc(sz));
4140                         msg.msg_iov[i].iov_base = strbuf_data(sbarr.entries[i]);
4141                         msg.msg_iov[i].iov_len = sz;
4142                 }
4143         }
4144         else {
4145                 size_t sz = ucv_to_unsigned(length);
4146 
4147                 if (errno != 0) {
4148                         free(msg.msg_control);
4149                         err_return(errno, "Invalid length value");
4150                 }
4151 
4152                 uc_vector_push(&sbarr, strbuf_alloc(sz));
4153 
4154                 msg.msg_iovlen = 1;
4155                 msg.msg_iov = &vec;
4156                 vec.iov_base = strbuf_data(sbarr.entries[0]);
4157                 vec.iov_len = sz;
4158         }
4159 
4160         /* now receive actual data */
4161         msg.msg_name = &ss;
4162         msg.msg_namelen = sizeof(ss);
4163 
4164         do {
4165                 ret = recvmsg(sockfd, &msg, flagval);
4166         } while (ret == -1 && errno == EINTR);
4167 
4168         if (ret == -1) {
4169                 while (sbarr.count > 0)
4170                         strbuf_free(sbarr.entries[--sbarr.count]);
4171 
4172                 uc_vector_clear(&sbarr);
4173 
4174                 if (msg.msg_iov != &vec)
4175                         free(msg.msg_iov);
4176 
4177                 free(msg.msg_control);
4178 
4179                 err_return(errno, "recvmsg()");
4180         }
4181 
4182         rv = ucv_object_new(vm);
4183 
4184         ucv_object_add(rv, "flags", ucv_int64_new(msg.msg_flags));
4185         ucv_object_add(rv, "length", ucv_int64_new(ret));
4186 
4187         if (msg.msg_namelen > 0) {
4188                 uc_value_t *addr = ucv_object_new(vm);
4189 
4190                 if (sockaddr_to_uv(&ss, addr))
4191                         ucv_object_add(rv, "address", addr);
4192                 else
4193                         ucv_put(addr);
4194         }
4195 
4196         if (msg.msg_controllen > 0) {
4197                 uc_value_t *ancillary = ucv_array_new(vm);
4198 
4199                 for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
4200                      cmsg != NULL;
4201                      cmsg = CMSG_NXTHDR(&msg, cmsg))
4202                 {
4203                         uc_value_t *c = ucv_object_new(vm);
4204 
4205                         ucv_object_add(c, "level", ucv_int64_new(cmsg->cmsg_level));
4206                         ucv_object_add(c, "type", ucv_int64_new(cmsg->cmsg_type));
4207                         ucv_object_add(c, "data", decode_cmsg(vm, cmsg));
4208 
4209                         ucv_array_push(ancillary, c);
4210                 }
4211 
4212                 ucv_object_add(rv, "ancillary", ancillary);
4213         }
4214 
4215         if (ret >= 0) {
4216                 if (ucv_type(length) == UC_ARRAY) {
4217                         uc_value_t *data = ucv_array_new_length(vm, msg.msg_iovlen);
4218 
4219                         for (size_t i = 0; i < (size_t)msg.msg_iovlen; i++) {
4220                                 size_t sz = ret;
4221 
4222                                 if (sz > msg.msg_iov[i].iov_len)
4223                                         sz = msg.msg_iov[i].iov_len;
4224 
4225                                 ucv_array_push(data, strbuf_finish(&sbarr.entries[i], sz));
4226                                 ret -= sz;
4227                         }
4228 
4229                         ucv_object_add(rv, "data", data);
4230                 }
4231                 else {
4232                         size_t sz = ret;
4233 
4234                         if (sz > msg.msg_iov[0].iov_len)
4235                                 sz = msg.msg_iov[0].iov_len;
4236 
4237                         ucv_object_add(rv, "data", strbuf_finish(&sbarr.entries[0], sz));
4238                 }
4239         }
4240 
4241         uc_vector_clear(&sbarr);
4242 
4243         if (msg.msg_iov != &vec)
4244                 free(msg.msg_iov);
4245 
4246         free(msg.msg_control);
4247 
4248         ok_return(rv);
4249 }
4250 
4251 /**
4252  * Binds a socket to a specific address.
4253  *
4254  * This function binds the socket to the specified address.
4255  *
4256  * Returns `true` if the socket is successfully bound.
4257  *
4258  * Returns `null` on error, e.g. when the address is in use.
4259  *
4260  * @function module:socket.socket#bind
4261  *
4262  * @param {string|module:socket.socket.SocketAddress} address
4263  * The IP address to bind the socket to.
4264  *
4265  * @returns {?boolean}
4266  *
4267  * @example
4268  * const sock = socket.create(…);
4269  * const success = sock.bind("192.168.0.1:80");
4270  *
4271  * if (success)
4272  *     print(`Socket bound successfully!\n`);
4273  * else
4274  *     print(`Failed to bind socket: ${sock.error()}.\n`);
4275  */
4276 static uc_value_t *
4277 uc_socket_inst_bind(uc_vm_t *vm, size_t nargs)
4278 {
4279         struct sockaddr_storage ss = { 0 };
4280         uc_value_t *addr;
4281         socklen_t slen;
4282         int sockfd;
4283 
4284         args_get(vm, nargs, &sockfd,
4285                 "address", UC_NULL, true, &addr);
4286 
4287         if (addr) {
4288                 if (!uv_to_sockaddr(addr, &ss, &slen))
4289                         return NULL;
4290 
4291                 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1)
4292                         err_return(errno, "bind()");
4293         }
4294         else {
4295 #if defined(__linux__)
4296                 int sval = 0;
4297                 slen = sizeof(sval);
4298 
4299                 if (getsockopt(sockfd, SOL_SOCKET, SO_DOMAIN, &sval, &slen) == -1)
4300                         err_return(errno, "getsockopt()");
4301 
4302                 switch (sval) {
4303                 case AF_INET6:
4304                         ss.ss_family = AF_INET6;
4305                         slen = sizeof(struct sockaddr_in6);
4306                         break;
4307 
4308                 case AF_INET:
4309                         ss.ss_family = AF_INET;
4310                         slen = sizeof(struct sockaddr_in);
4311                         break;
4312 
4313                 default:
4314                         err_return(EAFNOSUPPORT, "Unsupported socket address family");
4315                 }
4316 
4317                 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1)
4318                         err_return(errno, "bind()");
4319 #else
4320                 ss.ss_family = AF_INET6;
4321                 slen = sizeof(struct sockaddr_in6);
4322 
4323                 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1) {
4324                         if (errno != EAFNOSUPPORT)
4325                                 err_return(errno, "bind()");
4326 
4327                         ss.ss_family = AF_INET;
4328                         slen = sizeof(struct sockaddr_in);
4329 
4330                         if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1)
4331                                 err_return(errno, "bind()");
4332                 }
4333 #endif
4334         }
4335 
4336         ok_return(ucv_boolean_new(true));
4337 }
4338 
4339 /**
4340  * Listen for connections on a socket.
4341  *
4342  * This function marks the socket as a passive socket, that is, as a socket that
4343  * will be used to accept incoming connection requests using `accept()`.
4344  *
4345  * The `backlog` parameter specifies the maximum length to which the queue of
4346  * pending connections may grow. If a connection request arrives when the queue
4347  * is full, the client connection might get refused.
4348  *
4349  * If `backlog` is not provided, it defaults to 128.
4350  *
4351  * Returns `true` if the socket is successfully marked as passive.
4352  * Returns `null` if an error occurred, e.g. when the requested port is in use.
4353  *
4354  * @function module:socket.socket#listen
4355  *
4356  * @param {number} [backlog=128]
4357  * The maximum length of the queue of pending connections.
4358  *
4359  * @returns {?boolean}
4360  *
4361  * @see {@link module:socket.socket#accept|accept()}
4362  *
4363  * @example
4364  * const sock = socket.create(…);
4365  * sock.bind(…);
4366  *
4367  * const success = sock.listen(10);
4368  * if (success)
4369  *     print(`Socket is listening for incoming connections!\n`);
4370  * else
4371  *     print(`Failed to listen on socket: ${sock.error()}\n`);
4372  */
4373 static uc_value_t *
4374 uc_socket_inst_listen(uc_vm_t *vm, size_t nargs)
4375 {
4376         uc_value_t *backlog;
4377         int ret, sockfd;
4378 
4379         args_get(vm, nargs, &sockfd,
4380                 "backlog", UC_INTEGER, true, &backlog);
4381 
4382         ret = listen(sockfd, backlog ? ucv_to_unsigned(backlog) : 128);
4383 
4384         if (ret == -1)
4385                 err_return(errno, "listen()");
4386 
4387         ok_return(ucv_boolean_new(true));
4388 }
4389 
4390 /**
4391  * Accept a connection on a socket.
4392  *
4393  * This function accepts a connection on the socket. It extracts the first
4394  * connection request on the queue of pending connections, creates a new
4395  * connected socket, and returns a new socket handle referring to that socket.
4396  * The newly created socket is not in listening state and has no backlog.
4397  *
4398  * When a optional `address` dictionary is provided, it is populated with the
4399  * remote address details of the peer socket.
4400  *
4401  * The optional `flags` parameter is a bitwise-or-ed number of flags to modify
4402  * the behavior of accepted peer socket. Possible values are:
4403  * - `SOCK_CLOEXEC`: Enable close-on-exec semantics for the new socket.
4404  * - `SOCK_NONBLOCK`: Enable nonblocking mode for the new socket.
4405  *
4406  * Returns a socket handle representing the newly created peer socket of the
4407  * accepted connection.
4408  *
4409  * Returns `null` if an error occurred.
4410  *
4411  * @function module:socket.socket#accept
4412  *
4413  * @param {object} [address]
4414  * An optional dictionary to receive the address details of the peer socket.
4415  * See {@link module:socket.socket.SocketAddress|SocketAddress} for details.
4416  *
4417  * @param {number} [flags]
4418  * Optional flags to modify the behavior of the peer socket.
4419  *
4420  * @returns {?module:socket.socket}
4421  *
4422  * @example
4423  * const sock = socket.create(…);
4424  * sock.bind(…);
4425  * sock.listen();
4426  *
4427  * const peerAddress = {};
4428  * const newSocket = sock.accept(peerAddress, socket.SOCK_CLOEXEC);
4429  * if (newSocket)
4430  *     print(`Accepted connection from: ${peerAddress}\n`);
4431  * else
4432  *     print(`Failed to accept connection: ${sock.error()}\n`);
4433  */
4434 static uc_value_t *
4435 uc_socket_inst_accept(uc_vm_t *vm, size_t nargs)
4436 {
4437         struct sockaddr_storage ss = { 0 };
4438         int peerfd, sockfd, sockflags;
4439         uc_value_t *addrobj, *flags;
4440         socklen_t slen;
4441 
4442         args_get(vm, nargs, &sockfd,
4443                 "address", UC_OBJECT, true, &addrobj,
4444                 "flags", UC_INTEGER, true, &flags);
4445 
4446         slen = sizeof(ss);
4447         sockflags = flags ? ucv_to_integer(flags) : 0;
4448 
4449 #ifdef __APPLE__
4450         peerfd = accept(sockfd, (struct sockaddr *)&ss, &slen);
4451 
4452         if (peerfd == -1)
4453                 err_return(errno, "accept()");
4454 
4455         if (sockflags & SOCK_CLOEXEC) {
4456                 if (fcntl(peerfd, F_SETFD, FD_CLOEXEC) == -1) {
4457                         close(peerfd);
4458                         err_return(errno, "fcntl(F_SETFD)");
4459                 }
4460         }
4461 
4462         if (sockflags & SOCK_NONBLOCK) {
4463                 sockflags = fcntl(peerfd, F_GETFL);
4464 
4465                 if (sockflags == -1) {
4466                         close(peerfd);
4467                         err_return(errno, "fcntl(F_GETFL)");
4468                 }
4469 
4470                 if (fcntl(peerfd, F_SETFL, sockflags | O_NONBLOCK) == -1) {
4471                         close(peerfd);
4472                         err_return(errno, "fcntl(F_SETFL)");
4473                 }
4474         }
4475 #else
4476         peerfd = accept4(sockfd, (struct sockaddr *)&ss, &slen, sockflags);
4477 
4478         if (peerfd == -1)
4479                 err_return(errno, "accept4()");
4480 #endif
4481 
4482         if (addrobj)
4483                 sockaddr_to_uv(&ss, addrobj);
4484 
4485         ok_return(ucv_socket_new(vm, peerfd));
4486 }
4487 
4488 /**
4489  * Shutdown part of a full-duplex connection.
4490  *
4491  * This function shuts down part of the full-duplex connection associated with
4492  * the socket handle. The `how` parameter specifies which half of the connection
4493  * to shut down. It can take one of the following constant values:
4494  *
4495  * - `SHUT_RD`: Disables further receive operations.
4496  * - `SHUT_WR`: Disables further send operations.
4497  * - `SHUT_RDWR`: Disables further send and receive operations.
4498  *
4499  * Returns `true` if the shutdown operation is successful.
4500  * Returns `null` if an error occurred.
4501  *
4502  * @function module:socket.socket#shutdown
4503  *
4504  * @param {number} how
4505  * Specifies which half of the connection to shut down.
4506  * It can be one of the following constant values: `SHUT_RD`, `SHUT_WR`,
4507  * or `SHUT_RDWR`.
4508  *
4509  * @returns {?boolean}
4510  *
4511  * @example
4512  * const sock = socket.create(…);
4513  * sock.connect(…);
4514  * // Perform data exchange…
4515  *
4516  * const success = sock.shutdown(socket.SHUT_WR);
4517  * if (success)
4518  *     print(`Send operations on socket shut down successfully.\n`);
4519  * else
4520  *     print(`Failed to shut down send operations: ${sock.error()}\n`);
4521  */
4522 static uc_value_t *
4523 uc_socket_inst_shutdown(uc_vm_t *vm, size_t nargs)
4524 {
4525         uc_value_t *how;
4526         int sockfd, ret;
4527 
4528         args_get(vm, nargs, &sockfd,
4529                 "how", UC_INTEGER, true, &how);
4530 
4531         ret = shutdown(sockfd, ucv_int64_get(how));
4532 
4533         if (ret == -1)
4534                 err_return(errno, "shutdown()");
4535 
4536         ok_return(ucv_boolean_new(true));
4537 }
4538 
4539 /**
4540  * Represents a credentials information object returned by
4541  * {@link module:socket.socket#peercred|`peercred()`}.
4542  *
4543  * @typedef {Object} module:socket.socket.PeerCredentials
4544  * @property {number} uid
4545  * The effective user ID the remote socket endpoint.
4546  *
4547  * @property {number} gid
4548  * The effective group ID the remote socket endpoint.
4549  *
4550  * @property {number} pid
4551  * The ID of the process the remote socket endpoint belongs to.
4552  */
4553 
4554 /**
4555  * Retrieves the peer credentials.
4556  *
4557  * This function retrieves the remote uid, gid and pid of a connected UNIX
4558  * domain socket.
4559  *
4560  * Returns the remote credentials if the operation is successful.
4561  * Returns `null` on error.
4562  *
4563  * @function module:socket.socket#peercred
4564  *
4565  * @returns {?module:socket.socket.PeerCredentials}
4566  *
4567  * @example
4568  * const sock = socket.create(socket.AF_UNIX, …);
4569  * sock.connect(…);
4570  *
4571  * const peerCredentials = sock.peercred();
4572  * if (peerCredentials)
4573  *     print(`Peer credentials: ${peerCredentials}\n`);
4574  * else
4575  *     print(`Failed to retrieve peer credentials: ${sock.error()}\n`);
4576  */
4577 static uc_value_t *
4578 uc_socket_inst_peercred(uc_vm_t *vm, size_t nargs)
4579 {
4580         uc_value_t *rv = NULL;
4581         socklen_t optlen;
4582         int ret, sockfd;
4583 
4584         args_get(vm, nargs, &sockfd);
4585 
4586 #if defined(__linux__)
4587         struct ucred cred;
4588 
4589         optlen = sizeof(cred);
4590         ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &optlen);
4591 
4592         if (ret == -1)
4593                 err_return(errno, "getsockopt()");
4594 
4595         if (optlen != sizeof(cred))
4596                 err_return(EINVAL, "Invalid credentials received");
4597 
4598         rv = ucv_object_new(vm);
4599 
4600         ucv_object_add(rv, "uid", ucv_uint64_new(cred.uid));
4601         ucv_object_add(rv, "gid", ucv_uint64_new(cred.gid));
4602         ucv_object_add(rv, "pid", ucv_int64_new(cred.pid));
4603 #elif defined(__APPLE__)
4604         struct xucred cred;
4605         pid_t pid;
4606 
4607         optlen = sizeof(cred);
4608         ret = getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &cred, &optlen);
4609 
4610         if (ret == -1)
4611                 err_return(errno, "getsockopt(LOCAL_PEERCRED)");
4612 
4613         if (optlen != sizeof(cred) || cred.cr_version != XUCRED_VERSION)
4614                 err_return(EINVAL, "Invalid credentials received");
4615 
4616         rv = ucv_object_new(vm);
4617 
4618         ucv_object_add(rv, "uid", ucv_uint64_new(cred.cr_uid));
4619         ucv_object_add(rv, "gid", ucv_uint64_new(cred.cr_gid));
4620 
4621         optlen = sizeof(pid);
4622         ret = getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERPID, &pid, &optlen);
4623 
4624         if (ret == -1) {
4625                 ucv_put(rv);
4626                 err_return(errno, "getsockopt(LOCAL_PEERPID)");
4627         }
4628 
4629         ucv_object_add(rv, "pid", ucv_int64_new(pid));
4630 #else
4631         err_return(ENOSYS, "Operation not supported on this system");
4632 #endif
4633 
4634         ok_return(rv);
4635 }
4636 
4637 /**
4638  * Retrieves the remote address.
4639  *
4640  * This function retrieves the remote address of a connected socket.
4641  *
4642  * Returns the remote address if the operation is successful.
4643  * Returns `null` on error.
4644  *
4645  * @function module:socket.socket#peername
4646  *
4647  * @returns {?module:socket.socket.SocketAddress}
4648  *
4649  * @see {@link module:socket.socket#sockname|sockname()}
4650  *
4651  * @example
4652  * const sock = socket.create(…);
4653  * sock.connect(…);
4654  *
4655  * const peerAddress = sock.peername();
4656  * if (peerAddress)
4657  *     print(`Connected to ${peerAddress}\n`);
4658  * else
4659  *     print(`Failed to retrieve peer address: ${sock.error()}\n`);
4660  */
4661 static uc_value_t *
4662 uc_socket_inst_peername(uc_vm_t *vm, size_t nargs)
4663 {
4664         struct sockaddr_storage ss = { 0 };
4665         uc_value_t *addr;
4666         socklen_t sslen;
4667         int sockfd, ret;
4668 
4669         args_get(vm, nargs, &sockfd);
4670 
4671         sslen = sizeof(ss);
4672         ret = getpeername(sockfd, (struct sockaddr *)&ss, &sslen);
4673 
4674         if (ret == -1)
4675                 err_return(errno, "getpeername()");
4676 
4677         addr = ucv_object_new(vm);
4678         sockaddr_to_uv(&ss, addr);
4679 
4680         ok_return(addr);
4681 }
4682 
4683 /**
4684  * Retrieves the local address.
4685  *
4686  * This function retrieves the local address of a bound or connected socket.
4687  *
4688  * Returns the local address if the operation is successful.
4689  * Returns `null` on error.
4690  *
4691  * @function module:socket.socket#sockname
4692  *
4693  * @returns {?module:socket.socket.SocketAddress}
4694  *
4695  * @see {@link module:socket.socket#peername|peername()}
4696  *
4697  * @example
4698  * const sock = socket.create(…);
4699  * sock.connect(…);
4700  *
4701  * const myAddress = sock.sockname();
4702  * if (myAddress)
4703  *     print(`My source IP address is ${myAddress}\n`);
4704  * else
4705  *     print(`Failed to retrieve peer address: ${sock.error()}\n`);
4706  */
4707 static uc_value_t *
4708 uc_socket_inst_sockname(uc_vm_t *vm, size_t nargs)
4709 {
4710         struct sockaddr_storage ss = { 0 };
4711         uc_value_t *addr;
4712         socklen_t sslen;
4713         int sockfd, ret;
4714 
4715         args_get(vm, nargs, &sockfd);
4716 
4717         sslen = sizeof(ss);
4718         ret = getsockname(sockfd, (struct sockaddr *)&ss, &sslen);
4719 
4720         if (ret == -1)
4721                 err_return(errno, "getsockname()");
4722 
4723         addr = ucv_object_new(vm);
4724         sockaddr_to_uv(&ss, addr);
4725 
4726         ok_return(addr);
4727 }
4728 
4729 /**
4730  * Closes the socket.
4731  *
4732  * This function closes the socket, releasing its resources and terminating its
4733  * associated connections.
4734  *
4735  * Returns `true` if the socket was successfully closed.
4736  * Returns `null` on error.
4737  *
4738  * @function module:socket.socket#close
4739  *
4740  * @returns {?boolean}
4741  *
4742  * @example
4743  * const sock = socket.create(…);
4744  * sock.connect(…);
4745  * // Perform operations with the socket…
4746  * sock.close();
4747  */
4748 static uc_value_t *
4749 uc_socket_inst_close(uc_vm_t *vm, size_t nargs)
4750 {
4751         int *sockfd = uc_fn_this("socket");
4752 
4753         if (!sockfd || *sockfd == -1)
4754                 err_return(EBADF, "Invalid socket context");
4755 
4756         if (!xclose(sockfd))
4757                 err_return(errno, "close()");
4758 
4759         ok_return(ucv_boolean_new(true));
4760 }
4761 
4762 static void
4763 close_socket(void *ud)
4764 {
4765         int fd = (intptr_t)ud;
4766 
4767         if (fd != -1)
4768                 close(fd);
4769 }
4770 
4771 static const uc_function_list_t socket_fns[] = {
4772         { "connect",    uc_socket_inst_connect },
4773         { "bind",               uc_socket_inst_bind },
4774         { "listen",             uc_socket_inst_listen },
4775         { "accept",             uc_socket_inst_accept },
4776         { "send",               uc_socket_inst_send },
4777         { "sendmsg",    uc_socket_inst_sendmsg },
4778         { "recv",           uc_socket_inst_recv },
4779         { "recvmsg",    uc_socket_inst_recvmsg },
4780         { "setopt",             uc_socket_inst_setopt },
4781         { "getopt",             uc_socket_inst_getopt },
4782         { "fileno",             uc_socket_inst_fileno },
4783         { "shutdown",   uc_socket_inst_shutdown },
4784         { "peercred",   uc_socket_inst_peercred },
4785         { "peername",   uc_socket_inst_peername },
4786         { "sockname",   uc_socket_inst_sockname },
4787         { "close",              uc_socket_inst_close },
4788         { "error",              uc_socket_error },
4789 };
4790 
4791 static const uc_function_list_t global_fns[] = {
4792         { "sockaddr",   uc_socket_sockaddr },
4793         { "create",             uc_socket_create },
4794         { "nameinfo",   uc_socket_nameinfo },
4795         { "addrinfo",   uc_socket_addrinfo },
4796         { "poll",               uc_socket_poll },
4797         { "connect",    uc_socket_connect },
4798         { "listen",             uc_socket_listen },
4799         { "error",              uc_socket_error },
4800         { "strerror",   uc_socket_strerror },
4801 };
4802 
4803 void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
4804 {
4805         uc_function_list_register(scope, global_fns);
4806 
4807 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x))
4808 
4809         /**
4810          * @typedef
4811          * @name Address Families
4812          * @description Constants representing address families and socket domains.
4813          * @property {number} AF_UNSPEC - Unspecified address family.
4814          * @property {number} AF_UNIX - UNIX domain sockets.
4815          * @property {number} AF_INET - IPv4 Internet protocols.
4816          * @property {number} AF_INET6 - IPv6 Internet protocols.
4817          * @property {number} AF_PACKET - Low-level packet interface.
4818          */
4819         ADD_CONST(AF_UNSPEC);
4820         ADD_CONST(AF_UNIX);
4821         ADD_CONST(AF_INET);
4822         ADD_CONST(AF_INET6);
4823 #if defined(__linux__)
4824         ADD_CONST(AF_PACKET);
4825 #endif
4826 
4827         /**
4828          * @typedef
4829          * @name Socket Types
4830          * @description
4831          * The `SOCK_*` type and flag constants are used by
4832          * {@link module:socket#create|create()} to specify the type of socket to
4833          * open. The {@link module:socket.socket#accept|accept()} function
4834          * recognizes the `SOCK_NONBLOCK` and `SOCK_CLOEXEC` flags and applies them
4835          * to accepted peer sockets.
4836          * @property {number} SOCK_STREAM - Provides sequenced, reliable, two-way, connection-based byte streams.
4837          * @property {number} SOCK_DGRAM - Supports datagrams (connectionless, unreliable messages of a fixed maximum length).
4838          * @property {number} SOCK_RAW - Provides raw network protocol access.
4839          * @property {number} SOCK_PACKET - Obsolete and should not be used.
4840          * @property {number} SOCK_NONBLOCK - Enables non-blocking operation.
4841          * @property {number} SOCK_CLOEXEC - Sets the close-on-exec flag on the new file descriptor.
4842          */
4843         ADD_CONST(SOCK_STREAM);
4844         ADD_CONST(SOCK_DGRAM);
4845         ADD_CONST(SOCK_RAW);
4846         ADD_CONST(SOCK_NONBLOCK);
4847         ADD_CONST(SOCK_CLOEXEC);
4848 #if defined(__linux__)
4849         ADD_CONST(SOCK_PACKET);
4850 #endif
4851 
4852         /**
4853          * @typedef
4854          * @name Message Flags
4855          * @description
4856          * The `MSG_*` flag constants are commonly used in conjunction with the
4857          * {@link module:socket.socket#send|send()} and
4858          * {@link module:socket.socket#recv|recv()} functions.
4859          * @property {number} MSG_CONFIRM - Confirm path validity.
4860          * @property {number} MSG_DONTROUTE - Send without using routing tables.
4861          * @property {number} MSG_DONTWAIT - Enables non-blocking operation.
4862          * @property {number} MSG_EOR - End of record.
4863          * @property {number} MSG_MORE - Sender will send more.
4864          * @property {number} MSG_NOSIGNAL - Do not generate SIGPIPE.
4865          * @property {number} MSG_OOB - Process out-of-band data.
4866          * @property {number} MSG_FASTOPEN - Send data in TCP SYN.
4867          * @property {number} MSG_CMSG_CLOEXEC - Sets the close-on-exec flag on the received file descriptor.
4868          * @property {number} MSG_ERRQUEUE - Receive errors from ICMP.
4869          * @property {number} MSG_PEEK - Peeks at incoming messages.
4870          * @property {number} MSG_TRUNC - Report if datagram truncation occurred.
4871          * @property {number} MSG_WAITALL - Wait for full message.
4872          */
4873         ADD_CONST(MSG_DONTROUTE);
4874         ADD_CONST(MSG_DONTWAIT);
4875         ADD_CONST(MSG_EOR);
4876         ADD_CONST(MSG_NOSIGNAL);
4877         ADD_CONST(MSG_OOB);
4878         ADD_CONST(MSG_PEEK);
4879         ADD_CONST(MSG_TRUNC);
4880         ADD_CONST(MSG_WAITALL);
4881 #if defined(__linux__)
4882         ADD_CONST(MSG_CONFIRM);
4883         ADD_CONST(MSG_MORE);
4884         ADD_CONST(MSG_FASTOPEN);
4885         ADD_CONST(MSG_CMSG_CLOEXEC);
4886         ADD_CONST(MSG_ERRQUEUE);
4887 #endif
4888 
4889         /**
4890          * @typedef
4891          * @name IP Protocol Constants
4892          * @description
4893          * The `IPPROTO_IP` constant specifies the IP protocol number and may be
4894          * passed as third argument to {@link module:socket#create|create()} as well
4895          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
4896          * and {@link module:socket.socket#setopt|setopt()}.
4897          *
4898          * The `IP_*` constants are option names recognized by
4899          * {@link module:socket.socket#getopt|getopt()}
4900          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
4901          * the `IPPROTO_IP` socket level.
4902          * @property {number} IPPROTO_IP - Dummy protocol for IP.
4903          * @property {number} IP_ADD_MEMBERSHIP - Add an IP group membership.
4904          * @property {number} IP_ADD_SOURCE_MEMBERSHIP - Add an IP group/source membership.
4905          * @property {number} IP_BIND_ADDRESS_NO_PORT - Bind to the device only.
4906          * @property {number} IP_BLOCK_SOURCE - Block IP group/source.
4907          * @property {number} IP_DROP_MEMBERSHIP - Drop an IP group membership.
4908          * @property {number} IP_DROP_SOURCE_MEMBERSHIP - Drop an IP group/source membership.
4909          * @property {number} IP_FREEBIND - Allow binding to an IP address not assigned to a network interface.
4910          * @property {number} IP_HDRINCL - Header is included with data.
4911          * @property {number} IP_MSFILTER - Filter IP multicast source memberships.
4912          * @property {number} IP_MTU - Path MTU discovery.
4913          * @property {number} IP_MTU_DISCOVER - Control Path MTU discovery.
4914          * @property {number} IP_MULTICAST_ALL - Receive all multicast packets.
4915          * @property {number} IP_MULTICAST_IF - Set outgoing interface for multicast packets.
4916          * @property {number} IP_MULTICAST_LOOP - Control multicast packet looping.
4917          * @property {number} IP_MULTICAST_TTL - Set time-to-live for outgoing multicast packets.
4918          * @property {number} IP_NODEFRAG - Don't fragment IP packets.
4919          * @property {number} IP_OPTIONS - Set/get IP options.
4920          * @property {number} IP_PASSSEC - Pass security information.
4921          * @property {number} IP_PKTINFO - Receive packet information.
4922          * @property {number} IP_RECVERR - Receive all ICMP errors.
4923          * @property {number} IP_RECVOPTS - Receive all IP options.
4924          * @property {number} IP_RECVORIGDSTADDR - Receive original destination address of the socket.
4925          * @property {number} IP_RECVTOS - Receive IP TOS.
4926          * @property {number} IP_RECVTTL - Receive IP TTL.
4927          * @property {number} IP_RETOPTS - Set/get IP options.
4928          * @property {number} IP_ROUTER_ALERT - Receive ICMP msgs generated by router.
4929          * @property {number} IP_TOS - IP type of service and precedence.
4930          * @property {number} IP_TRANSPARENT - Transparent proxy support.
4931          * @property {number} IP_TTL - IP time-to-live.
4932          * @property {number} IP_UNBLOCK_SOURCE - Unblock IP group/source.
4933          */
4934         ADD_CONST(IPPROTO_IP);
4935         ADD_CONST(IP_ADD_MEMBERSHIP);
4936         ADD_CONST(IP_ADD_SOURCE_MEMBERSHIP);
4937         ADD_CONST(IP_BLOCK_SOURCE);
4938         ADD_CONST(IP_DROP_MEMBERSHIP);
4939         ADD_CONST(IP_DROP_SOURCE_MEMBERSHIP);
4940         ADD_CONST(IP_HDRINCL);
4941         ADD_CONST(IP_MSFILTER);
4942         ADD_CONST(IP_MULTICAST_IF);
4943         ADD_CONST(IP_MULTICAST_LOOP);
4944         ADD_CONST(IP_MULTICAST_TTL);
4945         ADD_CONST(IP_OPTIONS);
4946         ADD_CONST(IP_PKTINFO);
4947         ADD_CONST(IP_RECVOPTS);
4948         ADD_CONST(IP_RECVTOS);
4949         ADD_CONST(IP_RECVTTL);
4950         ADD_CONST(IP_RETOPTS);
4951         ADD_CONST(IP_TOS);
4952         ADD_CONST(IP_TTL);
4953         ADD_CONST(IP_UNBLOCK_SOURCE);
4954 #if defined(__linux__)
4955         ADD_CONST(IP_BIND_ADDRESS_NO_PORT);
4956         ADD_CONST(IP_FREEBIND);
4957         ADD_CONST(IP_MTU);
4958         ADD_CONST(IP_MTU_DISCOVER);
4959         ADD_CONST(IP_MULTICAST_ALL);
4960         ADD_CONST(IP_NODEFRAG);
4961         ADD_CONST(IP_PASSSEC);
4962         ADD_CONST(IP_RECVERR);
4963         ADD_CONST(IP_RECVORIGDSTADDR);
4964         ADD_CONST(IP_ROUTER_ALERT);
4965         ADD_CONST(IP_TRANSPARENT);
4966 #endif
4967 
4968         /**
4969          * @typedef {Object} IPv6 Protocol Constants
4970          * @description
4971          * The `IPPROTO_IPV6` constant specifies the IPv6 protocol number and may be
4972          * passed as third argument to {@link module:socket#create|create()} as well
4973          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
4974          * and {@link module:socket.socket#setopt|setopt()}.
4975          *
4976          * The `IPV6_*` constants are option names recognized by
4977          * {@link module:socket.socket#getopt|getopt()}
4978          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
4979          * the `IPPROTO_IPV6` socket level.
4980          * @property {number} IPPROTO_IPV6 - The IPv6 protocol.
4981          * @property {number} IPV6_ADDRFORM - Turn an AF_INET6 socket into a socket of a different address family. Only AF_INET is supported.
4982          * @property {number} IPV6_ADDR_PREFERENCES - Specify preferences for address selection.
4983          * @property {number} IPV6_ADD_MEMBERSHIP - Add an IPv6 group membership.
4984          * @property {number} IPV6_AUTHHDR - Set delivery of the authentication header control message for incoming datagrams.
4985          * @property {number} IPV6_AUTOFLOWLABEL - Enable or disable automatic flow labels.
4986          * @property {number} IPV6_DONTFRAG - Control whether the socket allows IPv6 fragmentation.
4987          * @property {number} IPV6_DROP_MEMBERSHIP - Drop an IPv6 group membership.
4988          * @property {number} IPV6_DSTOPTS - Set delivery of the destination options control message for incoming datagrams.
4989          * @property {number} IPV6_FLOWINFO_SEND - Control whether flow information is sent.
4990          * @property {number} IPV6_FLOWINFO - Set delivery of the flow ID control message for incoming datagrams.
4991          * @property {number} IPV6_FLOWLABEL_MGR - Manage flow labels.
4992          * @property {number} IPV6_FREEBIND - Allow binding to an IP address not assigned to a network interface.
4993          * @property {number} IPV6_HOPLIMIT - Set delivery of the hop limit control message for incoming datagrams.
4994          * @property {number} IPV6_HOPOPTS - Set delivery of the hop options control message for incoming datagrams.
4995          * @property {number} IPV6_JOIN_ANYCAST - Join an anycast group.
4996          * @property {number} IPV6_LEAVE_ANYCAST - Leave an anycast group.
4997          * @property {number} IPV6_MINHOPCOUNT - Set the minimum hop count.
4998          * @property {number} IPV6_MTU - Retrieve or set the MTU to be used for the socket.
4999          * @property {number} IPV6_MTU_DISCOVER - Control path-MTU discovery on the socket.
5000          * @property {number} IPV6_MULTICAST_ALL - Control whether the socket receives all multicast packets.
5001          * @property {number} IPV6_MULTICAST_HOPS - Set the multicast hop limit for the socket.
5002          * @property {number} IPV6_MULTICAST_IF - Set the device for outgoing multicast packets on the socket.
5003          * @property {number} IPV6_MULTICAST_LOOP - Control whether the socket sees multicast packets that it has sent itself.
5004          * @property {number} IPV6_PKTINFO - Set delivery of the IPV6_PKTINFO control message on incoming datagrams.
5005          * @property {number} IPV6_RECVDSTOPTS - Control receiving of the destination options control message.
5006          * @property {number} IPV6_RECVERR - Control receiving of asynchronous error options.
5007          * @property {number} IPV6_RECVFRAGSIZE - Control receiving of fragment size.
5008          * @property {number} IPV6_RECVHOPLIMIT - Control receiving of hop limit.
5009          * @property {number} IPV6_RECVHOPOPTS - Control receiving of hop options.
5010          * @property {number} IPV6_RECVORIGDSTADDR - Control receiving of the original destination address.
5011          * @property {number} IPV6_RECVPATHMTU - Control receiving of path MTU.
5012          * @property {number} IPV6_RECVPKTINFO - Control receiving of packet information.
5013          * @property {number} IPV6_RECVRTHDR - Control receiving of routing header.
5014          * @property {number} IPV6_RECVTCLASS - Control receiving of traffic class.
5015          * @property {number} IPV6_ROUTER_ALERT_ISOLATE - Control isolation of router alert messages.
5016          * @property {number} IPV6_ROUTER_ALERT - Pass forwarded packets containing a router alert hop-by-hop option to this socket.
5017          * @property {number} IPV6_RTHDR - Set delivery of the routing header control message for incoming datagrams.
5018          * @property {number} IPV6_RTHDRDSTOPTS - Set delivery of the routing header destination options control message.
5019          * @property {number} IPV6_TCLASS - Set the traffic class.
5020          * @property {number} IPV6_TRANSPARENT - Enable transparent proxy support.
5021          * @property {number} IPV6_UNICAST_HOPS - Set the unicast hop limit for the socket.
5022          * @property {number} IPV6_UNICAST_IF - Set the interface for outgoing unicast packets.
5023          * @property {number} IPV6_V6ONLY - Restrict the socket to sending and receiving IPv6 packets only.
5024          */
5025         ADD_CONST(IPPROTO_IPV6);
5026         ADD_CONST(IPV6_FLOWINFO_SEND);
5027         ADD_CONST(IPV6_FLOWINFO);
5028         ADD_CONST(IPV6_FLOWLABEL_MGR);
5029         ADD_CONST(IPV6_MULTICAST_HOPS);
5030         ADD_CONST(IPV6_MULTICAST_IF);
5031         ADD_CONST(IPV6_MULTICAST_LOOP);
5032         ADD_CONST(IPV6_RECVTCLASS);
5033         ADD_CONST(IPV6_TCLASS);
5034         ADD_CONST(IPV6_UNICAST_HOPS);
5035         ADD_CONST(IPV6_V6ONLY);
5036 #if defined(__linux__)
5037         ADD_CONST(IPV6_ADD_MEMBERSHIP);
5038         ADD_CONST(IPV6_ADDR_PREFERENCES);
5039         ADD_CONST(IPV6_ADDRFORM);
5040         ADD_CONST(IPV6_AUTHHDR);
5041         ADD_CONST(IPV6_AUTOFLOWLABEL);
5042         ADD_CONST(IPV6_DONTFRAG);
5043         ADD_CONST(IPV6_DROP_MEMBERSHIP);
5044         ADD_CONST(IPV6_DSTOPTS);
5045         ADD_CONST(IPV6_FREEBIND);
5046         ADD_CONST(IPV6_HOPLIMIT);
5047         ADD_CONST(IPV6_HOPOPTS);
5048         ADD_CONST(IPV6_JOIN_ANYCAST);
5049         ADD_CONST(IPV6_LEAVE_ANYCAST);
5050         ADD_CONST(IPV6_MINHOPCOUNT);
5051         ADD_CONST(IPV6_MTU_DISCOVER);
5052         ADD_CONST(IPV6_MTU);
5053         ADD_CONST(IPV6_MULTICAST_ALL);
5054         ADD_CONST(IPV6_PKTINFO);
5055         ADD_CONST(IPV6_RECVDSTOPTS);
5056         ADD_CONST(IPV6_RECVERR);
5057         ADD_CONST(IPV6_RECVFRAGSIZE);
5058         ADD_CONST(IPV6_RECVHOPLIMIT);
5059         ADD_CONST(IPV6_RECVHOPOPTS);
5060         ADD_CONST(IPV6_RECVORIGDSTADDR);
5061         ADD_CONST(IPV6_RECVPATHMTU);
5062         ADD_CONST(IPV6_RECVPKTINFO);
5063         ADD_CONST(IPV6_RECVRTHDR);
5064         ADD_CONST(IPV6_ROUTER_ALERT_ISOLATE);
5065         ADD_CONST(IPV6_ROUTER_ALERT);
5066         ADD_CONST(IPV6_RTHDR);
5067         ADD_CONST(IPV6_RTHDRDSTOPTS);
5068         ADD_CONST(IPV6_TRANSPARENT);
5069         ADD_CONST(IPV6_UNICAST_IF);
5070 #endif
5071 
5072         /**
5073          * @typedef
5074          * @name Socket Option Constants
5075          * @description
5076          * The `SOL_SOCKET` constant is passed as *level* argument to the
5077          * {@link module:socket.socket#getopt|getopt()} and
5078          * {@link module:socket.socket#setopt|setopt()} functions in order to set
5079          * or retrieve generic socket option values.
5080          *
5081          * The `SO_*` constants are passed as *option* argument in conjunction with
5082          * the `SOL_SOCKET` level to specify the specific option to get or set on
5083          * the socket.
5084          * @property {number} SOL_SOCKET - Socket options at the socket API level.
5085          * @property {number} SO_ACCEPTCONN - Reports whether socket listening is enabled.
5086          * @property {number} SO_ATTACH_BPF - Attach BPF program to socket.
5087          * @property {number} SO_ATTACH_FILTER - Attach a socket filter.
5088          * @property {number} SO_ATTACH_REUSEPORT_CBPF - Attach BPF program for cgroup and skb program reuseport hook.
5089          * @property {number} SO_ATTACH_REUSEPORT_EBPF - Attach eBPF program for cgroup and skb program reuseport hook.
5090          * @property {number} SO_BINDTODEVICE - Bind socket to a specific interface.
5091          * @property {number} SO_BROADCAST - Allow transmission of broadcast messages.
5092          * @property {number} SO_BUSY_POLL - Enable busy polling.
5093          * @property {number} SO_DEBUG - Enable socket debugging.
5094          * @property {number} SO_DETACH_BPF - Detach BPF program from socket.
5095          * @property {number} SO_DETACH_FILTER - Detach a socket filter.
5096          * @property {number} SO_DOMAIN - Retrieves the domain of the socket.
5097          * @property {number} SO_DONTROUTE - Send packets directly without routing.
5098          * @property {number} SO_ERROR - Retrieves and clears the error status for the socket.
5099          * @property {number} SO_INCOMING_CPU - Retrieves the CPU number on which the last packet was received.
5100          * @property {number} SO_INCOMING_NAPI_ID - Retrieves the NAPI ID of the device.
5101          * @property {number} SO_KEEPALIVE - Enable keep-alive packets.
5102          * @property {number} SO_LINGER - Set linger on close.
5103          * @property {number} SO_LOCK_FILTER - Set or get the socket filter lock state.
5104          * @property {number} SO_MARK - Set the mark for packets sent through the socket.
5105          * @property {number} SO_OOBINLINE - Enables out-of-band data to be received in the normal data stream.
5106          * @property {number} SO_PASSCRED - Enable the receiving of SCM_CREDENTIALS control messages.
5107          * @property {number} SO_PASSSEC - Enable the receiving of security context.
5108          * @property {number} SO_PEEK_OFF - Returns the number of bytes in the receive buffer without removing them.
5109          * @property {number} SO_PEERCRED - Retrieves the credentials of the foreign peer.
5110          * @property {number} SO_PEERSEC - Retrieves the security context of the foreign peer.
5111          * @property {number} SO_PRIORITY - Set the protocol-defined priority for all packets.
5112          * @property {number} SO_PROTOCOL - Retrieves the protocol number.
5113          * @property {number} SO_RCVBUF - Set the receive buffer size.
5114          * @property {number} SO_RCVBUFFORCE - Set the receive buffer size forcefully.
5115          * @property {number} SO_RCVLOWAT - Set the minimum number of bytes to process for input operations.
5116          * @property {number} SO_RCVTIMEO - Set the timeout for receiving data.
5117          * @property {number} SO_REUSEADDR - Allow the socket to be bound to an address that is already in use.
5118          * @property {number} SO_REUSEPORT - Enable duplicate address and port bindings.
5119          * @property {number} SO_RXQ_OVFL - Reports if the receive queue has overflown.
5120          * @property {number} SO_SNDBUF - Set the send buffer size.
5121          * @property {number} SO_SNDBUFFORCE - Set the send buffer size forcefully.
5122          * @property {number} SO_SNDLOWAT - Set the minimum number of bytes to process for output operations.
5123          * @property {number} SO_SNDTIMEO - Set the timeout for sending data.
5124          * @property {number} SO_TIMESTAMP - Enable receiving of timestamps.
5125          * @property {number} SO_TIMESTAMPNS - Enable receiving of nanosecond timestamps.
5126          * @property {number} SO_TYPE - Retrieves the type of the socket (e.g., SOCK_STREAM).
5127          */
5128         ADD_CONST(SOL_SOCKET);
5129         ADD_CONST(SO_ACCEPTCONN);
5130         ADD_CONST(SO_BROADCAST);
5131         ADD_CONST(SO_DEBUG);
5132         ADD_CONST(SO_DONTROUTE);
5133         ADD_CONST(SO_ERROR);
5134         ADD_CONST(SO_KEEPALIVE);
5135         ADD_CONST(SO_LINGER);
5136         ADD_CONST(SO_OOBINLINE);
5137         ADD_CONST(SO_RCVBUF);
5138         ADD_CONST(SO_RCVLOWAT);
5139         ADD_CONST(SO_RCVTIMEO);
5140         ADD_CONST(SO_REUSEADDR);
5141         ADD_CONST(SO_REUSEPORT);
5142         ADD_CONST(SO_SNDBUF);
5143         ADD_CONST(SO_SNDLOWAT);
5144         ADD_CONST(SO_SNDTIMEO);
5145         ADD_CONST(SO_TIMESTAMP);
5146         ADD_CONST(SO_TYPE);
5147 #if defined(__linux__)
5148         ADD_CONST(SO_ATTACH_BPF);
5149         ADD_CONST(SO_ATTACH_FILTER);
5150         ADD_CONST(SO_ATTACH_REUSEPORT_CBPF);
5151         ADD_CONST(SO_ATTACH_REUSEPORT_EBPF);
5152         ADD_CONST(SO_BINDTODEVICE);
5153         ADD_CONST(SO_BUSY_POLL);
5154         ADD_CONST(SO_DETACH_BPF);
5155         ADD_CONST(SO_DETACH_FILTER);
5156         ADD_CONST(SO_DOMAIN);
5157         ADD_CONST(SO_INCOMING_CPU);
5158         ADD_CONST(SO_INCOMING_NAPI_ID);
5159         ADD_CONST(SO_LOCK_FILTER);
5160         ADD_CONST(SO_MARK);
5161         ADD_CONST(SO_PASSCRED);
5162         ADD_CONST(SO_PASSSEC);
5163         ADD_CONST(SO_PEEK_OFF);
5164         ADD_CONST(SO_PEERCRED);
5165         ADD_CONST(SO_PEERSEC);
5166         ADD_CONST(SO_PRIORITY);
5167         ADD_CONST(SO_PROTOCOL);
5168         ADD_CONST(SO_RCVBUFFORCE);
5169         ADD_CONST(SO_RXQ_OVFL);
5170         ADD_CONST(SO_SNDBUFFORCE);
5171         ADD_CONST(SO_TIMESTAMPNS);
5172 
5173         ADD_CONST(SCM_CREDENTIALS);
5174         ADD_CONST(SCM_RIGHTS);
5175 #endif
5176 
5177         /**
5178          * @typedef
5179          * @name TCP Protocol Constants
5180          * @description
5181          * The `IPPROTO_TCP` constant specifies the TCP protocol number and may be
5182          * passed as third argument to {@link module:socket#create|create()} as well
5183          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
5184          * and {@link module:socket.socket#setopt|setopt()}.
5185          *
5186          * The `TCP_*` constants are *option* argument values recognized by
5187          * {@link module:socket.socket#getopt|getopt()}
5188          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5189          * the `IPPROTO_TCP` socket level.
5190          * @property {number} IPPROTO_TCP - TCP protocol.
5191          * @property {number} TCP_CONGESTION - Set the congestion control algorithm.
5192          * @property {number} TCP_CORK - Delay packet transmission until full-sized packets are available.
5193          * @property {number} TCP_DEFER_ACCEPT - Delay accepting incoming connections until data arrives.
5194          * @property {number} TCP_FASTOPEN - Enable TCP Fast Open.
5195          * @property {number} TCP_FASTOPEN_CONNECT - Perform TFO connect.
5196          * @property {number} TCP_INFO - Retrieve TCP statistics.
5197          * @property {number} TCP_KEEPCNT - Number of keepalive probes.
5198          * @property {number} TCP_KEEPIDLE - Time before keepalive probes begin.
5199          * @property {number} TCP_KEEPINTVL - Interval between keepalive probes.
5200          * @property {number} TCP_LINGER2 - Lifetime of orphaned FIN_WAIT2 state sockets.
5201          * @property {number} TCP_MAXSEG - Maximum segment size.
5202          * @property {number} TCP_NODELAY - Disable Nagle's algorithm.
5203          * @property {number} TCP_QUICKACK - Enable quick ACKs.
5204          * @property {number} TCP_SYNCNT - Number of SYN retransmits.
5205          * @property {number} TCP_USER_TIMEOUT - Set the user timeout.
5206          * @property {number} TCP_WINDOW_CLAMP - Set the maximum window.
5207          */
5208         ADD_CONST(IPPROTO_TCP);
5209         ADD_CONST(TCP_FASTOPEN);
5210         ADD_CONST(TCP_KEEPCNT);
5211         ADD_CONST(TCP_KEEPINTVL);
5212         ADD_CONST(TCP_MAXSEG);
5213         ADD_CONST(TCP_NODELAY);
5214 #if defined(__linux__)
5215         ADD_CONST(TCP_CONGESTION);
5216         ADD_CONST(TCP_CORK);
5217         ADD_CONST(TCP_DEFER_ACCEPT);
5218         ADD_CONST(TCP_FASTOPEN_CONNECT);
5219         ADD_CONST(TCP_INFO);
5220         ADD_CONST(TCP_KEEPIDLE);
5221         ADD_CONST(TCP_LINGER2);
5222         ADD_CONST(TCP_QUICKACK);
5223         ADD_CONST(TCP_SYNCNT);
5224         ADD_CONST(TCP_USER_TIMEOUT);
5225         ADD_CONST(TCP_WINDOW_CLAMP);
5226 #endif
5227 
5228         /**
5229          * @typedef
5230          * @name Packet Socket Constants
5231          * @description
5232          * The `SOL_PACKET` constant specifies the packet socket level and may be
5233          * passed as *level* argument value to
5234          * {@link module:socket.socket#getopt|getopt()} and
5235          * {@link module:socket.socket#setopt|setopt()}.
5236          *
5237          * Most `PACKET_*` constants are *option* argument values recognized by
5238          * {@link module:socket.socket#getopt|getopt()}
5239          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5240          * the `SOL_PACKET` socket level.
5241          *
5242          * The constants `PACKET_MR_PROMISC`, `PACKET_MR_MULTICAST` and
5243          * `PACKET_MR_ALLMULTI` are used in conjunction with the
5244          * `PACKET_ADD_MEMBERSHIP` and `PACKET_DROP_MEMBERSHIP` options to specify
5245          * the packet socket receive mode.
5246          *
5247          * The constants `PACKET_HOST`, `PACKET_BROADCAST`, `PACKET_MULTICAST`,
5248          * `PACKET_OTHERHOST` and `PACKET_OUTGOING` may be used as *packet_type*
5249          * value in {@link module:socket.socket.SocketAddress|socket address}
5250          * structures.
5251          * @property {number} SOL_PACKET - Socket options at the packet API level.
5252          * @property {number} PACKET_ADD_MEMBERSHIP - Add a multicast group membership.
5253          * @property {number} PACKET_DROP_MEMBERSHIP - Drop a multicast group membership.
5254          * @property {number} PACKET_AUXDATA - Receive auxiliary data (packet info).
5255          * @property {number} PACKET_FANOUT - Configure packet fanout.
5256          * @property {number} PACKET_LOSS - Retrieve the current packet loss statistics.
5257          * @property {number} PACKET_RESERVE - Reserve space for packet headers.
5258          * @property {number} PACKET_RX_RING - Configure a receive ring buffer.
5259          * @property {number} PACKET_STATISTICS - Retrieve packet statistics.
5260          * @property {number} PACKET_TIMESTAMP - Retrieve packet timestamps.
5261          * @property {number} PACKET_TX_RING - Configure a transmit ring buffer.
5262          * @property {number} PACKET_VERSION - Set the packet protocol version.
5263          * @property {number} PACKET_QDISC_BYPASS - Bypass queuing discipline for outgoing packets.
5264          *
5265          * @property {number} PACKET_MR_PROMISC - Enable promiscuous mode.
5266          * @property {number} PACKET_MR_MULTICAST - Receive multicast packets.
5267          * @property {number} PACKET_MR_ALLMULTI - Receive all multicast packets.
5268          *
5269          * @property {number} PACKET_HOST - Receive packets destined for this host.
5270          * @property {number} PACKET_BROADCAST - Receive broadcast packets.
5271          * @property {number} PACKET_MULTICAST - Receive multicast packets.
5272          * @property {number} PACKET_OTHERHOST - Receive packets destined for other hosts.
5273          * @property {number} PACKET_OUTGOING - Transmit packets.
5274          */
5275 #if defined(__linux__)
5276         ADD_CONST(SOL_PACKET);
5277         ADD_CONST(PACKET_ADD_MEMBERSHIP);
5278         ADD_CONST(PACKET_DROP_MEMBERSHIP);
5279         ADD_CONST(PACKET_AUXDATA);
5280         ADD_CONST(PACKET_FANOUT);
5281         ADD_CONST(PACKET_LOSS);
5282         ADD_CONST(PACKET_RESERVE);
5283         ADD_CONST(PACKET_RX_RING);
5284         ADD_CONST(PACKET_STATISTICS);
5285         ADD_CONST(PACKET_TIMESTAMP);
5286         ADD_CONST(PACKET_TX_RING);
5287         ADD_CONST(PACKET_VERSION);
5288         ADD_CONST(PACKET_QDISC_BYPASS);
5289 
5290         ADD_CONST(PACKET_MR_PROMISC);
5291         ADD_CONST(PACKET_MR_MULTICAST);
5292         ADD_CONST(PACKET_MR_ALLMULTI);
5293 
5294         ADD_CONST(PACKET_HOST);
5295         ADD_CONST(PACKET_BROADCAST);
5296         ADD_CONST(PACKET_MULTICAST);
5297         ADD_CONST(PACKET_OTHERHOST);
5298         ADD_CONST(PACKET_OUTGOING);
5299 #endif
5300 
5301         /**
5302          * @typedef
5303          * @name UDP Protocol Constants
5304          * @description
5305          * The `IPPROTO_UDP` constant specifies the UDP protocol number and may be
5306          * passed as third argument to {@link module:socket#create|create()} as well
5307          * as *level* argument value to {@link module:socket.socket#getopt|getopt()}
5308          * and {@link module:socket.socket#setopt|setopt()}.
5309          *
5310          * The `UDP_*` constants are *option* argument values recognized by
5311          * {@link module:socket.socket#getopt|getopt()}
5312          * and {@link module:socket.socket#setopt|setopt()}, in conjunction with
5313          * the `IPPROTO_UDP` socket level.
5314          * @property {number} IPPROTO_UDP - UDP protocol.
5315          * @property {number} UDP_CORK - Cork data until flush.
5316          */
5317         ADD_CONST(IPPROTO_UDP);
5318 #if defined(__linux__)
5319         ADD_CONST(UDP_CORK);
5320 #endif
5321 
5322         /**
5323          * @typedef
5324          * @name Shutdown Constants
5325          * @description
5326          * The `SHUT_*` constants are passed as argument to the
5327          * {@link module:socket.socket#shutdown|shutdown()} function to specify
5328          * which direction of a full duplex connection to shut down.
5329          * @property {number} SHUT_RD - Disallow further receptions.
5330          * @property {number} SHUT_WR - Disallow further transmissions.
5331          * @property {number} SHUT_RDWR - Disallow further receptions and transmissions.
5332          */
5333         ADD_CONST(SHUT_RD);
5334         ADD_CONST(SHUT_WR);
5335         ADD_CONST(SHUT_RDWR);
5336 
5337         /**
5338          * @typedef
5339          * @name Address Info Flags
5340          * @description
5341          * The `AI_*` flags may be passed as bitwise OR-ed number in the *flags*
5342          * property of the *hints* dictionary argument of
5343          * {@link module:socket#addrinfo|addrinfo()}.
5344          * @property {number} AI_ADDRCONFIG - Address configuration flag.
5345          * @property {number} AI_ALL - Return IPv4 and IPv6 socket addresses.
5346          * @property {number} AI_CANONIDN - Canonicalize using the IDNA standard.
5347          * @property {number} AI_CANONNAME - Fill in the canonical name field.
5348          * @property {number} AI_IDN - Enable IDN encoding.
5349          * @property {number} AI_NUMERICHOST - Prevent hostname resolution.
5350          * @property {number} AI_NUMERICSERV - Prevent service name resolution.
5351          * @property {number} AI_PASSIVE - Use passive socket.
5352          * @property {number} AI_V4MAPPED - Map IPv6 addresses to IPv4-mapped format.
5353          */
5354         ADD_CONST(AI_ADDRCONFIG);
5355         ADD_CONST(AI_ALL);
5356         ADD_CONST(AI_CANONIDN);
5357         ADD_CONST(AI_CANONNAME);
5358         ADD_CONST(AI_IDN);
5359         ADD_CONST(AI_NUMERICHOST);
5360         ADD_CONST(AI_NUMERICSERV);
5361         ADD_CONST(AI_PASSIVE);
5362         ADD_CONST(AI_V4MAPPED);
5363 
5364         /**
5365          * @typedef
5366          * @name Name Info Constants
5367          * @description
5368          * The `NI_*` flags may be passed as bitwise OR-ed number via the *flags*
5369          * argument of {@link module:socket#nameinfo|nameinfo()}.
5370          * @property {number} NI_DGRAM - Datagram socket type.
5371          * @property {number} NI_IDN - Enable IDN encoding.
5372          * @property {number} NI_NAMEREQD - Hostname resolution required.
5373          * @property {number} NI_NOFQDN - Do not force fully qualified domain name.
5374          * @property {number} NI_NUMERICHOST - Return numeric form of the hostname.
5375          * @property {number} NI_NUMERICSERV - Return numeric form of the service name.
5376          */
5377         ADD_CONST(NI_DGRAM);
5378         ADD_CONST(NI_IDN);
5379         ADD_CONST(NI_MAXHOST);
5380         ADD_CONST(NI_MAXSERV);
5381         ADD_CONST(NI_NAMEREQD);
5382         ADD_CONST(NI_NOFQDN);
5383         ADD_CONST(NI_NUMERICHOST);
5384         ADD_CONST(NI_NUMERICSERV);
5385 
5386         /**
5387          * @typedef
5388          * @name Poll Event Constants
5389          * @description
5390          * The following constants represent event types for polling operations and
5391          * are set or returned as part of a
5392          * {@link module:socket.PollSpec|PollSpec} tuple by the
5393          * {@link module:socket#poll|poll()} function. When passed via an argument
5394          * PollSpec to `poll()`, they specify the I/O events to watch for on the
5395          * corresponding handle. When appearing in a PollSpec returned by `poll()`,
5396          * they specify the I/O events that occurred on a watched handle.
5397          * @property {number} POLLIN - Data available to read.
5398          * @property {number} POLLPRI - Priority data available to read.
5399          * @property {number} POLLOUT - Writable data available.
5400          * @property {number} POLLERR - Error condition.
5401          * @property {number} POLLHUP - Hang up.
5402          * @property {number} POLLNVAL - Invalid request.
5403          * @property {number} POLLRDHUP - Peer closed or shutdown writing.
5404          */
5405         ADD_CONST(POLLIN);
5406         ADD_CONST(POLLPRI);
5407         ADD_CONST(POLLOUT);
5408         ADD_CONST(POLLERR);
5409         ADD_CONST(POLLHUP);
5410         ADD_CONST(POLLNVAL);
5411 #if defined(__linux__)
5412         ADD_CONST(POLLRDHUP);
5413 #endif
5414 
5415         uc_type_declare(vm, "socket", socket_fns, close_socket);
5416 }
5417 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt