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