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