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