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