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 <sys/types.h> 59 #include <sys/socket.h> 60 #include <sys/un.h> 61 #include <netinet/in.h> 62 #include <netinet/tcp.h> 63 #include <netinet/udp.h> 64 #include <arpa/inet.h> 65 #include <unistd.h> 66 #include <fcntl.h> 67 #include <net/if.h> 68 #include <netdb.h> 69 #include <poll.h> 70 #include <limits.h> 71 72 #include "ucode/module.h" 73 #include "ucode/platform.h" 74 75 #if defined(__APPLE__) 76 # include <sys/ucred.h> 77 78 # define SOCK_NONBLOCK (1 << 16) 79 # define SOCK_CLOEXEC (1 << 17) 80 #endif 81 82 #ifndef NI_IDN 83 # define NI_IDN 0 84 #endif 85 86 #ifndef AI_IDN 87 # define AI_IDN 0 88 #endif 89 90 #ifndef AI_CANONIDN 91 # define AI_CANONIDN 0 92 #endif 93 94 #define ok_return(expr) do { set_error(0, NULL); return (expr); } while(0) 95 #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0) 96 97 static struct { 98 int code; 99 char *msg; 100 } last_error; 101 102 __attribute__((format(printf, 2, 3))) static void 103 set_error(int errcode, const char *fmt, ...) 104 { 105 va_list ap; 106 107 free(last_error.msg); 108 109 last_error.code = errcode; 110 last_error.msg = NULL; 111 112 if (fmt) { 113 va_start(ap, fmt); 114 xvasprintf(&last_error.msg, fmt, ap); 115 va_end(ap); 116 } 117 } 118 119 static char * 120 arg_type_(uc_type_t type) 121 { 122 switch (type) { 123 case UC_INTEGER: return "an integer value"; 124 case UC_BOOLEAN: return "a boolean value"; 125 case UC_STRING: return "a string value"; 126 case UC_DOUBLE: return "a double value"; 127 case UC_ARRAY: return "an array"; 128 case UC_OBJECT: return "an object"; 129 case UC_REGEXP: return "a regular expression"; 130 case UC_CLOSURE: return "a function"; 131 case UC_RESOURCE: return "a resource value"; 132 default: return "the expected type"; 133 } 134 } 135 136 static bool 137 args_get_(uc_vm_t *vm, size_t nargs, int *fdptr, ...) 138 { 139 const char *name, *rtype = NULL; 140 uc_value_t **ptr, *arg; 141 uc_type_t type, t; 142 size_t index = 0; 143 int *sockfd; 144 va_list ap; 145 bool opt; 146 147 if (fdptr) { 148 sockfd = uc_fn_this("socket"); 149 150 if (!sockfd || *sockfd == -1) 151 err_return(EBADF, "Invalid socket context"); 152 153 *fdptr = *sockfd; 154 } 155 156 va_start(ap, fdptr); 157 158 while (true) { 159 name = va_arg(ap, const char *); 160 161 if (!name) 162 break; 163 164 arg = uc_fn_arg(index++); 165 166 type = va_arg(ap, uc_type_t); 167 opt = va_arg(ap, int); 168 ptr = va_arg(ap, uc_value_t **); 169 170 if (type == UC_RESOURCE) { 171 rtype = name; 172 name = strrchr(rtype, '.'); 173 name = name ? name + 1 : rtype; 174 175 if (arg && !ucv_resource_dataptr(arg, rtype)) 176 err_return(EINVAL, 177 "Argument %s is not a %s resource", name, rtype); 178 } 179 180 if (!opt && !arg) 181 err_return(EINVAL, 182 "Argument %s is required", name); 183 184 t = ucv_type(arg); 185 186 if (t == UC_CFUNCTION) 187 t = UC_CLOSURE; 188 189 if (arg && type != UC_NULL && t != type) 190 err_return(EINVAL, 191 "Argument %s is not %s", name, arg_type_(type)); 192 193 *ptr = arg; 194 } 195 196 va_end(ap); 197 198 ok_return(true); 199 } 200 201 #define args_get(vm, nargs, fdptr, ...) do { \ 202 if (!args_get_(vm, nargs, fdptr, ##__VA_ARGS__, NULL)) \ 203 return NULL; \ 204 } while(0) 205 206 static void 207 strbuf_free(uc_stringbuf_t *sb) 208 { 209 printbuf_free(sb); 210 } 211 212 static bool 213 strbuf_grow(uc_stringbuf_t *sb, size_t size) 214 { 215 if (size > 0) { 216 if (printbuf_memset(sb, sizeof(uc_string_t) + size - 1, '\0', 1)) 217 err_return(ENOMEM, "Out of memory"); 218 } 219 220 return true; 221 } 222 223 static char * 224 strbuf_data(uc_stringbuf_t *sb) 225 { 226 return sb->buf + sizeof(uc_string_t); 227 } 228 229 static size_t 230 strbuf_size(uc_stringbuf_t *sb) 231 { 232 return (size_t)sb->bpos - sizeof(uc_string_t); 233 } 234 235 static uc_value_t * 236 strbuf_finish(uc_stringbuf_t **sb, size_t final_size) 237 { 238 uc_string_t *us = (uc_string_t *)(*sb)->buf; 239 size_t buffer_size = strbuf_size(*sb); 240 241 if (final_size > buffer_size) 242 final_size = buffer_size; 243 244 free(*sb); 245 *sb = NULL; 246 247 us = xrealloc(us, sizeof(uc_string_t) + final_size + 1); 248 us->length = final_size; 249 us->str[us->length] = 0; 250 251 return &us->header; 252 } 253 254 static uc_stringbuf_t * 255 strbuf_alloc(size_t size) 256 { 257 uc_stringbuf_t *sb = ucv_stringbuf_new(); 258 259 if (!strbuf_grow(sb, size)) { 260 printbuf_free(sb); 261 262 return NULL; 263 } 264 265 return sb; 266 } 267 268 static bool 269 sockaddr_to_uv(struct sockaddr_storage *ss, uc_value_t *addrobj) 270 { 271 char *ifname, addrstr[INET6_ADDRSTRLEN]; 272 struct sockaddr_in6 *s6; 273 struct sockaddr_in *s4; 274 struct sockaddr_un *su; 275 276 ucv_object_add(addrobj, "family", ucv_uint64_new(ss->ss_family)); 277 278 switch (ss->ss_family) { 279 case AF_INET6: 280 s6 = (struct sockaddr_in6 *)ss; 281 282 inet_ntop(AF_INET6, &s6->sin6_addr, addrstr, sizeof(addrstr)); 283 ucv_object_add(addrobj, "address", 284 ucv_string_new(addrstr)); 285 286 ucv_object_add(addrobj, "port", 287 ucv_uint64_new(ntohs(s6->sin6_port))); 288 289 ucv_object_add(addrobj, "flowinfo", 290 ucv_uint64_new(ntohl(s6->sin6_flowinfo))); 291 292 if (s6->sin6_scope_id) { 293 ifname = if_indextoname(s6->sin6_scope_id, addrstr); 294 295 if (ifname) 296 ucv_object_add(addrobj, "interface", 297 ucv_string_new(ifname)); 298 else 299 ucv_object_add(addrobj, "interface", 300 ucv_uint64_new(s6->sin6_scope_id)); 301 } 302 303 return true; 304 305 case AF_INET: 306 s4 = (struct sockaddr_in *)ss; 307 308 inet_ntop(AF_INET, &s4->sin_addr, addrstr, sizeof(addrstr)); 309 ucv_object_add(addrobj, "address", 310 ucv_string_new(addrstr)); 311 312 ucv_object_add(addrobj, "port", 313 ucv_uint64_new(ntohs(s4->sin_port))); 314 315 return true; 316 317 case AF_UNIX: 318 su = (struct sockaddr_un *)ss; 319 320 ucv_object_add(addrobj, "path", 321 ucv_string_new(su->sun_path)); 322 323 return true; 324 } 325 326 return false; 327 } 328 329 static bool 330 parse_addr(char *addr, struct sockaddr_storage *ss) 331 { 332 bool v6 = (ss->ss_family == 0 || ss->ss_family == AF_INET6); 333 bool v4 = (ss->ss_family == 0 || ss->ss_family == AF_INET); 334 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ss; 335 struct sockaddr_in *s4 = (struct sockaddr_in *)ss; 336 unsigned long n; 337 char *scope, *e; 338 339 if (v6 && (scope = strchr(addr, '%')) != NULL) { 340 *scope++ = 0; 341 n = strtoul(scope, &e, 10); 342 343 if (e == scope || *e != 0) { 344 n = if_nametoindex(scope); 345 346 if (n == 0) 347 err_return(errno, "Unable to resolve interface %s", scope); 348 } 349 350 if (inet_pton(AF_INET6, addr, &s6->sin6_addr) != 1) 351 err_return(errno, "Invalid IPv6 address"); 352 353 s6->sin6_family = AF_INET6; 354 s6->sin6_scope_id = n; 355 356 return true; 357 } 358 else if (v6 && inet_pton(AF_INET6, addr, &s6->sin6_addr) == 1) { 359 s6->sin6_family = AF_INET6; 360 361 return true; 362 } 363 else if (v4 && inet_pton(AF_INET, addr, &s4->sin_addr) == 1) { 364 s4->sin_family = AF_INET; 365 366 return true; 367 } 368 369 err_return(EINVAL, "Unable to parse IP address"); 370 } 371 372 static bool 373 uv_to_sockaddr(uc_value_t *addr, struct sockaddr_storage *ss, socklen_t *slen) 374 { 375 char *s, *p, addrstr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255%2147483648")]; 376 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ss; 377 struct sockaddr_in *s4 = (struct sockaddr_in *)ss; 378 struct sockaddr_un *su = (struct sockaddr_un *)ss; 379 uc_value_t *item; 380 unsigned long n; 381 size_t len; 382 383 memset(ss, 0, sizeof(*ss)); 384 385 if (ucv_type(addr) == UC_STRING) { 386 s = ucv_string_get(addr); 387 len = ucv_string_length(addr); 388 389 if (memchr(s, '/', len) != NULL) { 390 *slen = ucv_string_length(addr); 391 392 if (*slen >= sizeof(su->sun_path)) 393 *slen = sizeof(su->sun_path) - 1; 394 395 memcpy(su->sun_path, s, *slen); 396 su->sun_path[(*slen)++] = 0; 397 su->sun_family = AF_UNIX; 398 399 ok_return(true); 400 } 401 402 if (len == 0) 403 err_return(EINVAL, "Invalid IP address"); 404 405 if (*s == '[') { 406 p = memchr(++s, ']', --len); 407 408 if (!p || (size_t)(p - s) >= sizeof(addrstr)) 409 err_return(EINVAL, "Invalid IPv6 address"); 410 411 memcpy(addrstr, s, p - s); 412 addrstr[(p - s) + 1] = 0; 413 414 ss->ss_family = AF_INET6; 415 len -= ((p - s) + 1); 416 s = p + 1; 417 } 418 else if ((p = memchr(s, ':', len)) != NULL && 419 memchr(p + 1, ':', len - ((p - s) + 1)) == NULL) { 420 if ((size_t)(p - s) >= sizeof(addrstr)) 421 err_return(EINVAL, "Invalid IP address"); 422 423 memcpy(addrstr, s, p - s); 424 addrstr[p - s + 1] = 0; 425 426 ss->ss_family = AF_INET; 427 len -= (p - s); 428 s = p; 429 } 430 else { 431 if (len >= sizeof(addrstr)) 432 err_return(EINVAL, "Invalid IP address"); 433 434 memcpy(addrstr, s, len); 435 addrstr[len] = 0; 436 437 ss->ss_family = 0; 438 len = 0; 439 s = NULL; 440 } 441 442 if (!parse_addr(addrstr, ss)) 443 return NULL; 444 445 if (s && *s == ':') { 446 if (len <= 1) 447 err_return(EINVAL, "Invalid port number"); 448 449 for (s++, len--, n = 0; len > 0; len--, s++) { 450 if (*s < '' || *s > '9') 451 err_return(EINVAL, "Invalid port number"); 452 453 n = n * 10 + (*s - ''); 454 } 455 456 if (n > 65535) 457 err_return(EINVAL, "Invalid port number"); 458 459 s6->sin6_port = htons(n); 460 } 461 462 *slen = (ss->ss_family == AF_INET6) ? sizeof(*s6) : sizeof(*s4); 463 464 ok_return(true); 465 } 466 else if (ucv_type(addr) == UC_ARRAY) { 467 if (ucv_array_length(addr) == 16) { 468 uint8_t *u8 = (uint8_t *)&s6->sin6_addr; 469 470 for (size_t i = 0; i < 16; i++) { 471 item = ucv_array_get(addr, i); 472 n = ucv_uint64_get(item); 473 474 if (ucv_type(item) != UC_INTEGER || errno != 0 || n > 255) 475 err_return(EINVAL, "Invalid IP address array"); 476 477 u8[i] = n; 478 } 479 480 s6->sin6_family = AF_INET6; 481 *slen = sizeof(*s6); 482 483 ok_return(true); 484 } 485 else if (ucv_array_length(addr) == 4) { 486 s4->sin_addr.s_addr = 0; 487 488 for (size_t i = 0; i < 4; i++) { 489 item = ucv_array_get(addr, i); 490 n = ucv_uint64_get(item); 491 492 if (ucv_type(item) != UC_INTEGER || errno != 0 || n > 255) 493 err_return(EINVAL, "Invalid IP address array"); 494 495 s4->sin_addr.s_addr = s4->sin_addr.s_addr * 256 + n; 496 } 497 498 s4->sin_addr.s_addr = htonl(s4->sin_addr.s_addr); 499 s4->sin_family = AF_INET; 500 *slen = sizeof(*s4); 501 502 ok_return(true); 503 } 504 505 err_return(EINVAL, "Invalid IP address array"); 506 } 507 else if (ucv_type(addr) == UC_OBJECT) { 508 n = ucv_to_unsigned(ucv_object_get(addr, "family", NULL)); 509 510 if (n == 0) { 511 if (ucv_type(ucv_object_get(addr, "path", NULL)) == UC_STRING) { 512 n = AF_UNIX; 513 } 514 else { 515 item = ucv_object_get(addr, "address", NULL); 516 len = ucv_string_length(item); 517 s = ucv_string_get(item); 518 n = (s && memchr(s, ':', len) != NULL) ? AF_INET6 : AF_INET; 519 } 520 521 if (n == 0) 522 err_return(EINVAL, "Invalid address object"); 523 } 524 525 switch (n) { 526 case AF_INET6: 527 item = ucv_object_get(addr, "flowinfo", NULL); 528 s6->sin6_flowinfo = htonl(ucv_to_unsigned(item)); 529 530 item = ucv_object_get(addr, "interface", NULL); 531 532 if (ucv_type(item) == UC_STRING) { 533 s6->sin6_scope_id = if_nametoindex(ucv_string_get(item)); 534 535 if (s6->sin6_scope_id == 0) 536 err_return(errno, "Unable to resolve interface %s", 537 ucv_string_get(item)); 538 } 539 else if (item != NULL) { 540 s6->sin6_scope_id = ucv_to_unsigned(item); 541 542 if (errno != 0) 543 err_return(errno, "Invalid scope ID"); 544 } 545 546 /* fall through */ 547 548 case AF_INET: 549 ss->ss_family = n; 550 *slen = (n == AF_INET6) ? sizeof(*s6) : sizeof(*s4); 551 552 item = ucv_object_get(addr, "port", NULL); 553 n = ucv_to_unsigned(item); 554 555 if (errno != 0 || n > 65535) 556 err_return(EINVAL, "Invalid port number"); 557 558 s6->sin6_port = htons(n); 559 560 item = ucv_object_get(addr, "address", NULL); 561 len = ucv_string_length(item); 562 s = ucv_string_get(item); 563 564 if (len >= sizeof(addrstr)) 565 err_return(EINVAL, "Invalid IP address"); 566 567 if (len > 0) { 568 memcpy(addrstr, s, len); 569 addrstr[len] = 0; 570 571 if (!parse_addr(addrstr, ss)) 572 return NULL; 573 } 574 575 ok_return(true); 576 577 case AF_UNIX: 578 item = ucv_object_get(addr, "path", NULL); 579 len = ucv_string_length(item); 580 581 if (len == 0 || len >= sizeof(su->sun_path)) 582 err_return(EINVAL, "Invalid path value"); 583 584 memcpy(su->sun_path, ucv_string_get(item), len); 585 su->sun_path[len++] = 0; 586 su->sun_family = AF_UNIX; 587 *slen = len; 588 589 ok_return(true); 590 } 591 } 592 593 err_return(EINVAL, "Invalid address value"); 594 } 595 596 static bool 597 uv_to_fileno(uc_vm_t *vm, uc_value_t *val, int *fileno) 598 { 599 uc_value_t *fn; 600 int *fdptr; 601 602 fdptr = (int *)ucv_resource_dataptr(val, "socket"); 603 604 if (fdptr) { 605 if (*fdptr < 0) 606 err_return(EBADF, "Socket is closed"); 607 608 *fileno = *fdptr; 609 610 return true; 611 } 612 613 fn = ucv_property_get(val, "fileno"); 614 615 if (ucv_is_callable(fn)) { 616 uc_vm_stack_push(vm, ucv_get(val)); 617 uc_vm_stack_push(vm, ucv_get(fn)); 618 619 if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE) 620 return false; 621 622 val = uc_vm_stack_pop(vm); 623 } 624 else { 625 ucv_get(val); 626 } 627 628 *fileno = ucv_int64_get(val); 629 630 ucv_put(val); 631 632 if (errno != 0 || *fileno < 0) 633 err_return(EBADF, "Invalid file descriptor number"); 634 635 return true; 636 } 637 638 static bool 639 uv_to_pollfd(uc_vm_t *vm, uc_value_t *val, struct pollfd *pfd) 640 { 641 int64_t flags; 642 643 if (ucv_type(val) == UC_ARRAY) { 644 if (!uv_to_fileno(vm, ucv_array_get(val, 0), &pfd->fd)) 645 return false; 646 647 flags = ucv_to_integer(ucv_array_get(val, 1)); 648 649 if (errno != 0 || flags < -32768 || flags > 32767) 650 err_return(ERANGE, "Flags value out of range"); 651 652 pfd->events = flags; 653 pfd->revents = 0; 654 } 655 else { 656 if (!uv_to_fileno(vm, val, &pfd->fd)) 657 return false; 658 659 pfd->events = POLLIN | POLLERR | POLLHUP; 660 pfd->revents = 0; 661 } 662 663 return true; 664 } 665 666 static uc_value_t * 667 ucv_socket_new(uc_vm_t *vm, int fd) 668 { 669 return ucv_resource_new( 670 ucv_resource_type_lookup(vm, "socket"), 671 (void *)(intptr_t)fd 672 ); 673 } 674 675 static bool 676 xclose(int *fdptr) 677 { 678 bool rv = true; 679 680 if (fdptr) { 681 if (*fdptr >= 0) 682 rv = (close(*fdptr) == 0); 683 684 *fdptr = -1; 685 } 686 687 return rv; 688 } 689 690 691 typedef struct { 692 const char *name; 693 enum { DT_SIGNED, DT_UNSIGNED, DT_IPV4ADDR, DT_CALLBACK } type; 694 union { 695 size_t offset; 696 bool (*to_c)(void *, uc_value_t *); 697 } u1; 698 union { 699 size_t size; 700 uc_value_t *(*to_uv)(void *); 701 } u2; 702 } member_t; 703 704 typedef struct { 705 size_t size; 706 member_t *members; 707 } struct_t; 708 709 typedef struct { 710 int level; 711 int option; 712 struct_t *ctype; 713 } sockopt_t; 714 715 #define STRUCT_MEMBER_NP(struct_name, member_name, data_type) \ 716 { #member_name, data_type, \ 717 { .offset = offsetof(struct struct_name, member_name) }, \ 718 { .size = sizeof(((struct struct_name *)NULL)->member_name) } } 719 720 #define STRUCT_MEMBER_CB(member_name, to_c_fn, to_uv_fn) \ 721 { #member_name, DT_CALLBACK, { .to_c = to_c_fn }, { .to_uv = to_uv_fn } } 722 723 #define STRUCT_MEMBER(struct_name, member_prefix, member_name, data_type) \ 724 { #member_name, data_type, \ 725 { .offset = offsetof(struct struct_name, member_prefix##_##member_name) }, \ 726 { .size = sizeof(((struct struct_name *)NULL)->member_prefix##_##member_name) } } 727 728 static struct_t st_timeval = { 729 .size = sizeof(struct timeval), 730 .members = (member_t []){ 731 STRUCT_MEMBER(timeval, tv, sec, DT_SIGNED), 732 STRUCT_MEMBER(timeval, tv, usec, DT_SIGNED), 733 { 0 } 734 } 735 }; 736 737 #if defined(__linux__) 738 static struct_t st_ucred = { 739 .size = sizeof(struct ucred), 740 .members = (member_t []){ 741 STRUCT_MEMBER_NP(ucred, pid, DT_SIGNED), 742 STRUCT_MEMBER_NP(ucred, uid, DT_SIGNED), 743 STRUCT_MEMBER_NP(ucred, gid, DT_SIGNED), 744 { 0 } 745 } 746 }; 747 #endif 748 749 static struct_t st_linger = { 750 .size = sizeof(struct linger), 751 .members = (member_t []){ 752 STRUCT_MEMBER(linger, l, onoff, DT_SIGNED), 753 STRUCT_MEMBER(linger, l, linger, DT_SIGNED), 754 { 0 } 755 } 756 }; 757 758 static struct_t st_ip_mreqn = { 759 .size = sizeof(struct ip_mreqn), 760 .members = (member_t []){ 761 STRUCT_MEMBER(ip_mreqn, imr, multiaddr, DT_IPV4ADDR), 762 STRUCT_MEMBER(ip_mreqn, imr, address, DT_IPV4ADDR), 763 STRUCT_MEMBER(ip_mreqn, imr, ifindex, DT_SIGNED), 764 { 0 } 765 } 766 }; 767 768 static struct_t st_ip_mreq_source = { 769 .size = sizeof(struct ip_mreq_source), 770 .members = (member_t []){ 771 STRUCT_MEMBER(ip_mreq_source, imr, multiaddr, DT_IPV4ADDR), 772 STRUCT_MEMBER(ip_mreq_source, imr, interface, DT_IPV4ADDR), 773 STRUCT_MEMBER(ip_mreq_source, imr, sourceaddr, DT_IPV4ADDR), 774 { 0 } 775 } 776 }; 777 778 #if defined(__linux__) 779 static struct_t st_ip_msfilter = { 780 .size = sizeof(struct ip_msfilter), 781 .members = (member_t []){ 782 STRUCT_MEMBER(ip_msfilter, imsf, multiaddr, DT_IPV4ADDR), 783 STRUCT_MEMBER(ip_msfilter, imsf, interface, DT_IPV4ADDR), 784 STRUCT_MEMBER(ip_msfilter, imsf, fmode, DT_SIGNED), 785 STRUCT_MEMBER(ip_msfilter, imsf, numsrc, DT_SIGNED), 786 STRUCT_MEMBER(ip_msfilter, imsf, slist, DT_SIGNED), 787 { 0 } 788 } 789 }; 790 791 static uc_value_t * 792 snd_wscale_to_uv(void *st) 793 { 794 return ucv_uint64_new(((struct tcp_info *)st)->tcpi_snd_wscale); 795 } 796 797 static uc_value_t * 798 rcv_wscale_to_uv(void *st) 799 { 800 return ucv_uint64_new(((struct tcp_info *)st)->tcpi_rcv_wscale); 801 } 802 803 static bool 804 snd_wscale_to_c(void *st, uc_value_t *uv) 805 { 806 ((struct tcp_info *)st)->tcpi_snd_wscale = ucv_to_unsigned(uv); 807 808 if (errno) 809 err_return(errno, "Unable to convert field snd_wscale to unsigned"); 810 811 return true; 812 } 813 814 static bool 815 rcv_wscale_to_c(void *st, uc_value_t *uv) 816 { 817 ((struct tcp_info *)st)->tcpi_rcv_wscale = ucv_to_unsigned(uv); 818 819 if (errno) 820 err_return(errno, "Unable to convert field rcv_wscale to unsigned"); 821 822 return true; 823 } 824 825 static struct_t st_tcp_info = { 826 .size = sizeof(struct tcp_info), 827 .members = (member_t []){ 828 STRUCT_MEMBER(tcp_info, tcpi, state, DT_UNSIGNED), 829 STRUCT_MEMBER(tcp_info, tcpi, ca_state, DT_UNSIGNED), 830 STRUCT_MEMBER(tcp_info, tcpi, retransmits, DT_UNSIGNED), 831 STRUCT_MEMBER(tcp_info, tcpi, probes, DT_UNSIGNED), 832 STRUCT_MEMBER(tcp_info, tcpi, backoff, DT_UNSIGNED), 833 STRUCT_MEMBER(tcp_info, tcpi, options, DT_UNSIGNED), 834 STRUCT_MEMBER_CB(snd_wscale, snd_wscale_to_c, snd_wscale_to_uv), 835 STRUCT_MEMBER_CB(rcv_wscale, rcv_wscale_to_c, rcv_wscale_to_uv), 836 STRUCT_MEMBER(tcp_info, tcpi, rto, DT_UNSIGNED), 837 STRUCT_MEMBER(tcp_info, tcpi, ato, DT_UNSIGNED), 838 STRUCT_MEMBER(tcp_info, tcpi, snd_mss, DT_UNSIGNED), 839 STRUCT_MEMBER(tcp_info, tcpi, rcv_mss, DT_UNSIGNED), 840 STRUCT_MEMBER(tcp_info, tcpi, unacked, DT_UNSIGNED), 841 STRUCT_MEMBER(tcp_info, tcpi, sacked, DT_UNSIGNED), 842 STRUCT_MEMBER(tcp_info, tcpi, lost, DT_UNSIGNED), 843 STRUCT_MEMBER(tcp_info, tcpi, retrans, DT_UNSIGNED), 844 STRUCT_MEMBER(tcp_info, tcpi, fackets, DT_UNSIGNED), 845 STRUCT_MEMBER(tcp_info, tcpi, last_data_sent, DT_UNSIGNED), 846 STRUCT_MEMBER(tcp_info, tcpi, last_ack_sent, DT_UNSIGNED), 847 STRUCT_MEMBER(tcp_info, tcpi, last_data_recv, DT_UNSIGNED), 848 STRUCT_MEMBER(tcp_info, tcpi, last_ack_recv, DT_UNSIGNED), 849 STRUCT_MEMBER(tcp_info, tcpi, pmtu, DT_UNSIGNED), 850 STRUCT_MEMBER(tcp_info, tcpi, rcv_ssthresh, DT_UNSIGNED), 851 STRUCT_MEMBER(tcp_info, tcpi, rtt, DT_UNSIGNED), 852 STRUCT_MEMBER(tcp_info, tcpi, rttvar, DT_UNSIGNED), 853 STRUCT_MEMBER(tcp_info, tcpi, snd_ssthresh, DT_UNSIGNED), 854 STRUCT_MEMBER(tcp_info, tcpi, snd_cwnd, DT_UNSIGNED), 855 STRUCT_MEMBER(tcp_info, tcpi, advmss, DT_UNSIGNED), 856 STRUCT_MEMBER(tcp_info, tcpi, reordering, DT_UNSIGNED), 857 STRUCT_MEMBER(tcp_info, tcpi, rcv_rtt, DT_UNSIGNED), 858 STRUCT_MEMBER(tcp_info, tcpi, rcv_space, DT_UNSIGNED), 859 STRUCT_MEMBER(tcp_info, tcpi, total_retrans, DT_UNSIGNED), 860 { 0 } 861 } 862 }; 863 #endif 864 865 static uc_value_t * 866 ai_addr_to_uv(void *st) 867 { 868 uc_value_t *rv = ucv_object_new(NULL); 869 struct sockaddr_storage ss = { 0 }; 870 struct addrinfo *ai = st; 871 872 memcpy(&ss, ai->ai_addr, ai->ai_addrlen); 873 874 if (!sockaddr_to_uv(&ss, rv)) { 875 ucv_put(rv); 876 return NULL; 877 } 878 879 return rv; 880 } 881 882 static uc_value_t * 883 ai_canonname_to_uv(void *st) 884 { 885 struct addrinfo *ai = st; 886 return ai->ai_canonname ? ucv_string_new(ai->ai_canonname) : NULL; 887 } 888 889 /** 890 * Represents a network address information object returned by 891 * {@link module:socket#addrinfo|`addrinfo()`}. 892 * 893 * @typedef {Object} module:socket.AddressInfo 894 * 895 * @property {module:socket.socket.SocketAddress} addr - A socket address structure. 896 * @property {string} [canonname=null] - The canonical hostname associated with the address. 897 * @property {number} family - The address family (e.g., `2` for `AF_INET`, `10` for `AF_INET6`). 898 * @property {number} flags - Additional flags indicating properties of the address. 899 * @property {number} protocol - The protocol number. 900 * @property {number} socktype - The socket type (e.g., `1` for `SOCK_STREAM`, `2` for `SOCK_DGRAM`). 901 */ 902 static struct_t st_addrinfo = { 903 .size = sizeof(struct addrinfo), 904 .members = (member_t []){ 905 STRUCT_MEMBER(addrinfo, ai, flags, DT_SIGNED), 906 STRUCT_MEMBER(addrinfo, ai, family, DT_SIGNED), 907 STRUCT_MEMBER(addrinfo, ai, socktype, DT_SIGNED), 908 STRUCT_MEMBER(addrinfo, ai, protocol, DT_SIGNED), 909 STRUCT_MEMBER_CB(addr, NULL, ai_addr_to_uv), 910 STRUCT_MEMBER_CB(canonname, NULL, ai_canonname_to_uv), 911 { 0 } 912 } 913 }; 914 915 #define SV_VOID (struct_t *)0 916 #define SV_INT (struct_t *)1 917 #define SV_INT_RO (struct_t *)2 918 #define SV_BOOL (struct_t *)3 919 #define SV_STRING (struct_t *)4 920 921 static sockopt_t sockopts[] = { 922 { SOL_SOCKET, SO_ACCEPTCONN, SV_BOOL }, 923 { SOL_SOCKET, SO_BROADCAST, SV_BOOL }, 924 { SOL_SOCKET, SO_DEBUG, SV_BOOL }, 925 { SOL_SOCKET, SO_ERROR, SV_INT_RO }, 926 { SOL_SOCKET, SO_DONTROUTE, SV_BOOL }, 927 { SOL_SOCKET, SO_KEEPALIVE, SV_BOOL }, 928 { SOL_SOCKET, SO_LINGER, &st_linger }, 929 { SOL_SOCKET, SO_OOBINLINE, SV_BOOL }, 930 { SOL_SOCKET, SO_RCVBUF, SV_INT }, 931 { SOL_SOCKET, SO_RCVLOWAT, SV_INT }, 932 { SOL_SOCKET, SO_RCVTIMEO, &st_timeval }, 933 { SOL_SOCKET, SO_REUSEADDR, SV_BOOL }, 934 { SOL_SOCKET, SO_REUSEPORT, SV_BOOL }, 935 { SOL_SOCKET, SO_SNDBUF, SV_INT }, 936 { SOL_SOCKET, SO_SNDLOWAT, SV_INT }, 937 { SOL_SOCKET, SO_SNDTIMEO, &st_timeval }, 938 { SOL_SOCKET, SO_TIMESTAMP, SV_BOOL }, 939 { SOL_SOCKET, SO_TYPE, SV_INT }, 940 #if defined(__linux__) 941 { SOL_SOCKET, SO_ATTACH_FILTER, SV_STRING }, 942 { SOL_SOCKET, SO_ATTACH_BPF, SV_INT }, 943 { SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, SV_STRING }, 944 { SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, SV_INT }, 945 { SOL_SOCKET, SO_BINDTODEVICE, SV_STRING }, 946 { SOL_SOCKET, SO_DETACH_FILTER, SV_VOID }, 947 { SOL_SOCKET, SO_DETACH_BPF, SV_VOID }, 948 { SOL_SOCKET, SO_DOMAIN, SV_INT_RO }, 949 { SOL_SOCKET, SO_INCOMING_CPU, SV_INT }, 950 { SOL_SOCKET, SO_INCOMING_NAPI_ID, SV_INT_RO }, 951 { SOL_SOCKET, SO_LOCK_FILTER, SV_INT }, 952 { SOL_SOCKET, SO_MARK, SV_INT }, 953 { SOL_SOCKET, SO_PASSCRED, SV_BOOL }, 954 { SOL_SOCKET, SO_PASSSEC, SV_BOOL }, 955 { SOL_SOCKET, SO_PEEK_OFF, SV_INT }, 956 { SOL_SOCKET, SO_PEERCRED, &st_ucred }, 957 { SOL_SOCKET, SO_PEERSEC, SV_STRING }, 958 { SOL_SOCKET, SO_PRIORITY, SV_INT }, 959 { SOL_SOCKET, SO_PROTOCOL, SV_INT }, 960 { SOL_SOCKET, SO_RCVBUFFORCE, SV_INT }, 961 { SOL_SOCKET, SO_RXQ_OVFL, SV_BOOL }, 962 { SOL_SOCKET, SO_SNDBUFFORCE, SV_INT }, 963 { SOL_SOCKET, SO_TIMESTAMPNS, SV_BOOL }, 964 { SOL_SOCKET, SO_BUSY_POLL, SV_INT }, 965 #endif 966 967 { IPPROTO_IP, IP_ADD_MEMBERSHIP, &st_ip_mreqn }, 968 { IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, &st_ip_mreq_source }, 969 { IPPROTO_IP, IP_BLOCK_SOURCE, &st_ip_mreq_source }, 970 { IPPROTO_IP, IP_DROP_MEMBERSHIP, &st_ip_mreqn }, 971 { IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, &st_ip_mreq_source }, 972 { IPPROTO_IP, IP_HDRINCL, SV_BOOL }, 973 { IPPROTO_IP, IP_MULTICAST_IF, &st_ip_mreqn }, 974 { IPPROTO_IP, IP_MULTICAST_LOOP, SV_BOOL }, 975 { IPPROTO_IP, IP_MULTICAST_TTL, SV_INT }, 976 { IPPROTO_IP, IP_OPTIONS, SV_STRING }, 977 { IPPROTO_IP, IP_PKTINFO, SV_BOOL }, 978 { IPPROTO_IP, IP_RECVOPTS, SV_BOOL }, 979 { IPPROTO_IP, IP_RECVTOS, SV_BOOL }, 980 { IPPROTO_IP, IP_RECVTTL, SV_BOOL }, 981 { IPPROTO_IP, IP_RETOPTS, SV_BOOL }, 982 { IPPROTO_IP, IP_TOS, SV_INT }, 983 { IPPROTO_IP, IP_TTL, SV_INT }, 984 { IPPROTO_IP, IP_UNBLOCK_SOURCE, &st_ip_mreq_source }, 985 #if defined(__linux__) 986 { IPPROTO_IP, IP_MSFILTER, &st_ip_msfilter }, 987 { IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, SV_BOOL }, 988 { IPPROTO_IP, IP_FREEBIND, SV_BOOL }, 989 { IPPROTO_IP, IP_MTU, SV_INT }, 990 { IPPROTO_IP, IP_MTU_DISCOVER, SV_INT }, 991 { IPPROTO_IP, IP_MULTICAST_ALL, SV_BOOL }, 992 { IPPROTO_IP, IP_NODEFRAG, SV_BOOL }, 993 { IPPROTO_IP, IP_PASSSEC, SV_BOOL }, 994 { IPPROTO_IP, IP_RECVERR, SV_BOOL }, 995 { IPPROTO_IP, IP_RECVORIGDSTADDR, SV_BOOL }, 996 { IPPROTO_IP, IP_ROUTER_ALERT, SV_BOOL }, 997 { IPPROTO_IP, IP_TRANSPARENT, SV_BOOL }, 998 #endif 999 1000 { IPPROTO_TCP, TCP_KEEPCNT, SV_INT }, 1001 { IPPROTO_TCP, TCP_KEEPINTVL, SV_INT }, 1002 { IPPROTO_TCP, TCP_MAXSEG, SV_INT }, 1003 { IPPROTO_TCP, TCP_NODELAY, SV_BOOL }, 1004 { IPPROTO_TCP, TCP_FASTOPEN, SV_INT }, 1005 #if defined(__linux__) 1006 { IPPROTO_TCP, TCP_CONGESTION, SV_STRING }, 1007 { IPPROTO_TCP, TCP_CORK, SV_BOOL }, 1008 { IPPROTO_TCP, TCP_DEFER_ACCEPT, SV_INT }, 1009 { IPPROTO_TCP, TCP_INFO, &st_tcp_info }, 1010 { IPPROTO_TCP, TCP_KEEPIDLE, SV_INT }, 1011 { IPPROTO_TCP, TCP_LINGER2, SV_INT }, 1012 { IPPROTO_TCP, TCP_QUICKACK, SV_BOOL }, 1013 { IPPROTO_TCP, TCP_SYNCNT, SV_INT }, 1014 { IPPROTO_TCP, TCP_USER_TIMEOUT, SV_INT }, 1015 { IPPROTO_TCP, TCP_WINDOW_CLAMP, SV_INT }, 1016 { IPPROTO_TCP, TCP_FASTOPEN_CONNECT, SV_INT }, 1017 #endif 1018 1019 #if defined(__linux__) 1020 { IPPROTO_UDP, UDP_CORK, SV_BOOL } 1021 #endif 1022 }; 1023 1024 1025 static char * 1026 uv_to_struct(uc_value_t *uv, struct_t *spec) 1027 { 1028 uc_value_t *fv; 1029 const char *s; 1030 uint64_t u64; 1031 int64_t s64; 1032 member_t *m; 1033 bool found; 1034 char *st; 1035 1036 union { 1037 int8_t s8; 1038 int16_t s16; 1039 int32_t s32; 1040 int64_t s64; 1041 uint8_t u8; 1042 uint16_t u16; 1043 uint32_t u32; 1044 uint64_t u64; 1045 } v; 1046 1047 st = xalloc(spec->size); 1048 1049 for (size_t i = 0; spec->members[i].name; i++) { 1050 m = &spec->members[i]; 1051 fv = ucv_object_get(uv, m->name, &found); 1052 1053 if (!found || !fv) 1054 continue; 1055 1056 switch (spec->members[i].type) { 1057 case DT_UNSIGNED: 1058 u64 = ucv_to_unsigned(fv); 1059 1060 if (errno) { 1061 free(st); 1062 err_return(errno, 1063 "Unable to convert field %s to unsigned", 1064 m->name); 1065 } 1066 1067 switch (m->u2.size) { 1068 case 1: v.u8 = (uint8_t)u64; break; 1069 case 2: v.u16 = (uint16_t)u64; break; 1070 case 4: v.u32 = (uint32_t)u64; break; 1071 case 8: v.u64 = (uint64_t)u64; break; 1072 } 1073 1074 memcpy(st + m->u1.offset, &v, m->u2.size); 1075 break; 1076 1077 case DT_SIGNED: 1078 s64 = ucv_to_integer(fv); 1079 1080 if (errno) { 1081 free(st); 1082 err_return(errno, 1083 "Unable to convert field %s to integer", m->name); 1084 } 1085 1086 switch (m->u2.size) { 1087 case 1: v.s8 = (int8_t)s64; break; 1088 case 2: v.s16 = (int16_t)s64; break; 1089 case 4: v.s32 = (int32_t)s64; break; 1090 case 8: v.s64 = (int64_t)s64; break; 1091 } 1092 1093 memcpy(st + m->u1.offset, &v, m->u2.size); 1094 break; 1095 1096 case DT_IPV4ADDR: 1097 s = ucv_string_get(fv); 1098 1099 if (!s || inet_pton(AF_INET, s, st + m->u1.offset) != 1) { 1100 free(st); 1101 err_return(EINVAL, 1102 "Unable to convert field %s to IP address", m->name); 1103 } 1104 1105 break; 1106 1107 case DT_CALLBACK: 1108 if (m->u1.to_c && !m->u1.to_c(st, fv)) { 1109 free(st); 1110 return NULL; 1111 } 1112 1113 break; 1114 } 1115 } 1116 1117 return st; 1118 } 1119 1120 static uc_value_t * 1121 struct_to_uv(char *st, struct_t *spec) 1122 { 1123 char s[sizeof("255.255.255.255")]; 1124 uc_value_t *uv, *fv; 1125 member_t *m; 1126 1127 uv = ucv_object_new(NULL); 1128 1129 for (size_t i = 0; spec->members[i].name; i++) { 1130 m = &spec->members[i]; 1131 fv = NULL; 1132 1133 switch (spec->members[i].type) { 1134 case DT_UNSIGNED: 1135 switch (spec->members[i].u2.size) { 1136 case 1: 1137 fv = ucv_uint64_new(*(uint8_t *)(st + m->u1.offset)); 1138 break; 1139 1140 case 2: 1141 fv = ucv_uint64_new(*(uint16_t *)(st + m->u1.offset)); 1142 break; 1143 1144 case 4: 1145 fv = ucv_uint64_new(*(uint32_t *)(st + m->u1.offset)); 1146 break; 1147 1148 case 8: 1149 fv = ucv_uint64_new(*(uint64_t *)(st + m->u1.offset)); 1150 break; 1151 } 1152 1153 break; 1154 1155 case DT_SIGNED: 1156 switch (spec->members[i].u2.size) { 1157 case 1: 1158 fv = ucv_int64_new(*(int8_t *)(st + m->u1.offset)); 1159 break; 1160 1161 case 2: 1162 fv = ucv_int64_new(*(int16_t *)(st + m->u1.offset)); 1163 break; 1164 1165 case 4: 1166 fv = ucv_int64_new(*(int32_t *)(st + m->u1.offset)); 1167 break; 1168 1169 case 8: 1170 fv = ucv_int64_new(*(int64_t *)(st + m->u1.offset)); 1171 break; 1172 } 1173 1174 break; 1175 1176 case DT_IPV4ADDR: 1177 if (inet_ntop(AF_INET, st + m->u1.offset, s, sizeof(s))) 1178 fv = ucv_string_new(s); 1179 1180 break; 1181 1182 case DT_CALLBACK: 1183 fv = m->u2.to_uv ? m->u2.to_uv(st) : NULL; 1184 break; 1185 } 1186 1187 ucv_object_add(uv, m->name, fv); 1188 } 1189 1190 return uv; 1191 } 1192 1193 /** 1194 * Sets options on the socket. 1195 * 1196 * Sets the specified option on the socket to the given value. 1197 * 1198 * Returns `true` if the option was successfully set. 1199 * 1200 * Returns `null` if an error occurred. 1201 * 1202 * @function module:socket.socket#setopt 1203 * 1204 * @param {number} level 1205 * The protocol level at which the option resides. This can be a level such as 1206 * `SOL_SOCKET` for the socket API level or a specific protocol level defined 1207 * by the system. 1208 * 1209 * @param {number} option 1210 * The socket option to set. This can be an integer representing the option, 1211 * such as `SO_REUSEADDR`, or a constant defined by the system. 1212 * 1213 * @param {*} value 1214 * The value to set the option to. The type of this argument depends on the 1215 * specific option being set. It can be an integer, a boolean, a string, or a 1216 * dictionary representing the value to set. If a dictionary is provided, it is 1217 * internally translated to the corresponding C struct type required by the 1218 * option. 1219 * 1220 * @returns {?boolean} 1221 */ 1222 static uc_value_t * 1223 uc_socket_inst_setopt(uc_vm_t *vm, size_t nargs) 1224 { 1225 int sockfd, solvl, soopt, soval, ret; 1226 uc_value_t *level, *option, *value; 1227 void *valptr = NULL, *st = NULL; 1228 socklen_t vallen = 0; 1229 size_t i; 1230 1231 args_get(vm, nargs, &sockfd, 1232 "level", UC_INTEGER, false, &level, 1233 "option", UC_INTEGER, false, &option, 1234 "value", UC_NULL, false, &value); 1235 1236 solvl = ucv_int64_get(level); 1237 soopt = ucv_int64_get(option); 1238 1239 for (i = 0; i < ARRAY_SIZE(sockopts); i++) { 1240 if (sockopts[i].level != solvl || sockopts[i].option != soopt) 1241 continue; 1242 1243 switch ((uintptr_t)sockopts[i].ctype) { 1244 case (uintptr_t)SV_INT_RO: 1245 err_return(EOPNOTSUPP, "Socket option is read only"); 1246 1247 case (uintptr_t)SV_VOID: 1248 valptr = NULL; 1249 vallen = 0; 1250 break; 1251 1252 case (uintptr_t)SV_INT: 1253 soval = ucv_to_integer(value); 1254 1255 if (errno) 1256 err_return(errno, "Unable to convert value to integer"); 1257 1258 valptr = &soval; 1259 vallen = sizeof(int); 1260 break; 1261 1262 case (uintptr_t)SV_BOOL: 1263 soval = ucv_to_unsigned(value) ? 1 : 0; 1264 1265 if (errno) 1266 err_return(errno, "Unable to convert value to boolean"); 1267 1268 valptr = &soval; 1269 vallen = sizeof(int); 1270 break; 1271 1272 case (uintptr_t)SV_STRING: 1273 valptr = ucv_string_get(value); 1274 vallen = ucv_string_length(value); 1275 break; 1276 1277 default: 1278 st = uv_to_struct(value, sockopts[i].ctype); 1279 valptr = st; 1280 vallen = sockopts[i].ctype->size; 1281 break; 1282 } 1283 1284 break; 1285 } 1286 1287 if (i == ARRAY_SIZE(sockopts)) 1288 err_return(EINVAL, "Unknown socket level or option"); 1289 1290 ret = setsockopt(sockfd, solvl, soopt, valptr, vallen); 1291 1292 free(st); 1293 1294 if (ret == -1) 1295 err_return(errno, "setsockopt()"); 1296 1297 ok_return(ucv_boolean_new(true)); 1298 } 1299 1300 /** 1301 * Gets options from the socket. 1302 * 1303 * Retrieves the value of the specified option from the socket. 1304 * 1305 * Returns the value of the requested option. 1306 * 1307 * Returns `null` if an error occurred or if the option is not supported. 1308 * 1309 * @function module:socket.socket#getopt 1310 * 1311 * @param {number} level 1312 * The protocol level at which the option resides. This can be a level such as 1313 * `SOL_SOCKET` for the socket API level or a specific protocol level defined 1314 * by the system. 1315 * 1316 * @param {number} option 1317 * The socket option to retrieve. This can be an integer representing the 1318 * option, such as `SO_REUSEADDR`, or a constant defined by the system. 1319 * 1320 * @returns {?*} 1321 * The value of the requested option. The type of the returned value depends 1322 * on the specific option being retrieved. It can be an integer, a boolean, a 1323 * string, or a dictionary representing a complex data structure. 1324 */ 1325 static uc_value_t * 1326 uc_socket_inst_getopt(uc_vm_t *vm, size_t nargs) 1327 { 1328 uc_value_t *level, *option, *value = NULL; 1329 int sockfd, solvl, soopt, soval, ret; 1330 void *valptr = NULL, *st = NULL; 1331 uc_stringbuf_t *sb = NULL; 1332 socklen_t vallen; 1333 size_t i; 1334 1335 args_get(vm, nargs, &sockfd, 1336 "level", UC_INTEGER, false, &level, 1337 "option", UC_INTEGER, false, &option); 1338 1339 solvl = ucv_int64_get(level); 1340 soopt = ucv_int64_get(option); 1341 soval = 0; 1342 1343 for (i = 0; i < ARRAY_SIZE(sockopts); i++) { 1344 if (sockopts[i].level != solvl || sockopts[i].option != soopt) 1345 continue; 1346 1347 switch ((uintptr_t)sockopts[i].ctype) { 1348 case (uintptr_t)SV_VOID: 1349 err_return(EOPNOTSUPP, "Socket option is write only"); 1350 1351 case (uintptr_t)SV_INT: 1352 case (uintptr_t)SV_INT_RO: 1353 case (uintptr_t)SV_BOOL: 1354 valptr = &soval; 1355 vallen = sizeof(int); 1356 break; 1357 1358 case (uintptr_t)SV_STRING: 1359 sb = strbuf_alloc(64); 1360 valptr = strbuf_data(sb); 1361 vallen = strbuf_size(sb); 1362 break; 1363 1364 default: 1365 st = xalloc(sockopts[i].ctype->size); 1366 valptr = st; 1367 vallen = sockopts[i].ctype->size; 1368 break; 1369 } 1370 1371 break; 1372 } 1373 1374 if (i == ARRAY_SIZE(sockopts)) 1375 err_return(EINVAL, "Unknown socket level or option"); 1376 1377 while (true) { 1378 ret = getsockopt(sockfd, solvl, soopt, valptr, &vallen); 1379 1380 if (sockopts[i].ctype == SV_STRING && 1381 (ret == 0 || (ret == -1 && errno == ERANGE)) && 1382 vallen > strbuf_size(sb)) { 1383 1384 if (!strbuf_grow(sb, vallen)) 1385 return NULL; 1386 1387 valptr = strbuf_data(sb); 1388 continue; 1389 } 1390 1391 break; 1392 } 1393 1394 if (ret == 0) { 1395 switch ((uintptr_t)sockopts[i].ctype) { 1396 case (uintptr_t)SV_VOID: 1397 break; 1398 1399 case (uintptr_t)SV_INT: 1400 case (uintptr_t)SV_INT_RO: 1401 value = ucv_int64_new(soval); 1402 break; 1403 1404 case (uintptr_t)SV_BOOL: 1405 value = ucv_boolean_new(soval); 1406 break; 1407 1408 case (uintptr_t)SV_STRING: 1409 value = strbuf_finish(&sb, vallen); 1410 break; 1411 1412 default: 1413 value = struct_to_uv(st, sockopts[i].ctype); 1414 break; 1415 } 1416 } 1417 1418 strbuf_free(sb); 1419 free(st); 1420 1421 if (ret == -1) 1422 err_return(errno, "getsockopt()"); 1423 1424 ok_return(value); 1425 } 1426 1427 /** 1428 * Returns the UNIX file descriptor number associated with the socket. 1429 * 1430 * Returns the file descriptor number. 1431 * 1432 * Returns `-1` if an error occurred. 1433 * 1434 * @function module:socket.socket#fileno 1435 * 1436 * @returns {number} 1437 */ 1438 static uc_value_t * 1439 uc_socket_inst_fileno(uc_vm_t *vm, size_t nargs) 1440 { 1441 int sockfd; 1442 1443 args_get(vm, nargs, &sockfd); 1444 1445 ok_return(ucv_int64_new(sockfd)); 1446 } 1447 1448 /** 1449 * Query error information. 1450 * 1451 * Returns a string containing a description of the last occurred error when 1452 * the *numeric* argument is absent or false. 1453 * 1454 * Returns a positive (`errno`) or negative (`EAI_*` constant) error code number 1455 * when the *numeric* argument is `true`. 1456 * 1457 * Returns `null` if there is no error information. 1458 * 1459 * @function module:socket#error 1460 * 1461 * @param {boolean} [numeric] 1462 * Whether to return a numeric error code (`true`) or a human readable error 1463 * message (false). 1464 * 1465 * @returns {?string|?number} 1466 * 1467 * @example 1468 * // Trigger socket error by attempting to bind IPv6 address with IPv4 socket 1469 * socket.create(socket.AF_INET, socket.SOCK_STREAM, 0).bind("::", 8080); 1470 * 1471 * // Print error (should yield "Address family not supported by protocol") 1472 * print(socket.error(), "\n"); 1473 * 1474 * // Trigger resolve error 1475 * socket.addrinfo("doesnotexist.org"); 1476 * 1477 * // Query error code (should yield -2 for EAI_NONAME) 1478 * print(socket.error(true), "\n"); // 1479 */ 1480 static uc_value_t * 1481 uc_socket_error(uc_vm_t *vm, size_t nargs) 1482 { 1483 uc_value_t *numeric = uc_fn_arg(0), *rv; 1484 uc_stringbuf_t *buf; 1485 1486 if (last_error.code == 0) 1487 return NULL; 1488 1489 if (ucv_is_truish(numeric)) { 1490 rv = ucv_int64_new(last_error.code); 1491 } 1492 else { 1493 buf = ucv_stringbuf_new(); 1494 1495 if (last_error.msg) 1496 ucv_stringbuf_printf(buf, "%s: ", last_error.msg); 1497 1498 if (last_error.code >= 0) 1499 ucv_stringbuf_printf(buf, "%s", strerror(last_error.code)); 1500 else 1501 ucv_stringbuf_printf(buf, "%s", gai_strerror(last_error.code)); 1502 1503 rv = ucv_stringbuf_finish(buf); 1504 } 1505 1506 ok_return(rv); 1507 } 1508 1509 /** 1510 * @typedef {Object} module:socket.socket.SocketAddress 1511 * @property {number} family 1512 * Address family, one of AF_INET, AF_INET6 or AF_UNIX. 1513 * 1514 * @property {string} address 1515 * IPv4 or IPv6 address string (AF_INET or AF_INET6 only). 1516 * 1517 * @property {number} [port] 1518 * Port number (AF_INET or AF_INET6 only). 1519 * 1520 * @property {number} [flowinfo] 1521 * IPv6 flow information (AF_INET6 only). 1522 * 1523 * @property {string|number} [interface] 1524 * Link local address scope, either a network device name string or a nonzero 1525 * positive integer representing a network interface index (AF_INET6 only). 1526 * 1527 * @property {string} path 1528 * Domain socket filesystem path (AF_UNIX only). 1529 */ 1530 1531 /** 1532 * Parses the provided address value into a socket address representation. 1533 * 1534 * This function parses the given address value into a socket address 1535 * representation required for a number of socket operations. The address value 1536 * can be provided in various formats: 1537 * - For IPv4 addresses, it can be a string representing the IP address, 1538 * optionally followed by a port number separated by colon, e.g. 1539 * `192.168.0.1:8080`. 1540 * - For IPv6 addresses, it must be an address string enclosed in square 1541 * brackets if a port number is specified, otherwise the brackets are 1542 * optional. The address string may also include a scope ID in the form 1543 * `%ifname` or `%number`, e.g. `[fe80::1%eth0]:8080` or `fe80::1%15`. 1544 * - Any string value containing a slash is treated as UNIX domain socket path. 1545 * - Alternatively, it can be provided as an array returned by 1546 * {@link module:core#iptoarr|iptoarr()}, representing the address octets. 1547 * - It can also be an object representing a network address, with properties 1548 * for `address` (the IP address) and `port` or a single property `path` to 1549 * denote a UNIX domain socket address. 1550 * 1551 * @function module:socket#sockaddr 1552 * 1553 * @param {string|number[]|module:socket.socket.SocketAddress} address 1554 * The address value to parse. 1555 * 1556 * @returns {?module:socket.socket.SocketAddress} 1557 * A socket address representation of the provided address value, or `null` if 1558 * the address could not be parsed. 1559 * 1560 * @example 1561 * // Parse an IP address string with port 1562 * const address1 = sockaddr('192.168.0.1:8080'); 1563 * 1564 * // Parse an IPv6 address string with port and scope identifier 1565 * const address2 = sockaddr('[fe80::1%eth0]:8080'); 1566 * 1567 * // Parse an array representing an IP address 1568 * const address3 = sockaddr([192, 168, 0, 1]); 1569 * 1570 * // Parse a network address object 1571 * const address4 = sockaddr({ address: '192.168.0.1', port: 8080 }); 1572 * 1573 * // Convert a path value to a UNIX domain socket address 1574 * const address5 = sockaddr('/var/run/daemon.sock'); 1575 */ 1576 static uc_value_t * 1577 uc_socket_sockaddr(uc_vm_t *vm, size_t nargs) 1578 { 1579 struct sockaddr_storage ss = { 0 }; 1580 uc_value_t *addr, *rv; 1581 socklen_t slen; 1582 1583 args_get(vm, nargs, NULL, 1584 "address", UC_NULL, false, &addr); 1585 1586 if (!uv_to_sockaddr(addr, &ss, &slen)) 1587 return NULL; 1588 1589 rv = ucv_object_new(vm); 1590 1591 if (!sockaddr_to_uv(&ss, rv)) { 1592 ucv_put(rv); 1593 return NULL; 1594 } 1595 1596 ok_return(rv); 1597 } 1598 1599 /** 1600 * Resolves the given network address into hostname and service name. 1601 * 1602 * The `nameinfo()` function provides an API for reverse DNS lookup and service 1603 * name resolution. It returns an object containing the following properties: 1604 * - `hostname`: The resolved hostname. 1605 * - `service`: The resolved service name. 1606 * 1607 * Returns an object representing the resolved hostname and service name. 1608 * Return `null` if an error occurred during resolution. 1609 * 1610 * @function module:socket#nameinfo 1611 * 1612 * @param {string|module:socket.socket.SocketAddress} address 1613 * The network address to resolve. It can be specified as: 1614 * - A string representing the IP address. 1615 * - An object representing the address with properties `address` and `port`. 1616 * 1617 * @param {number} [flags] 1618 * Optional flags that provide additional control over the resolution process, 1619 * specified as bitwise OR-ed number of `NI_*` constants. 1620 * 1621 * @returns {?{hostname: string, service: string}} 1622 * 1623 * @see {@link module:socket~"Socket Types"|Socket Types} 1624 * @see {@link module:socket~"Name Info Constants"|AName Info Constants} 1625 * 1626 * @example 1627 * // Resolve a network address into hostname and service name 1628 * const result = network.getnameinfo('192.168.1.1:80'); 1629 * print(result); // { "hostname": "example.com", "service": "http" } 1630 */ 1631 static uc_value_t * 1632 uc_socket_nameinfo(uc_vm_t *vm, size_t nargs) 1633 { 1634 char host[NI_MAXHOST], serv[NI_MAXSERV]; 1635 uc_value_t *addr, *flags, *rv; 1636 struct sockaddr_storage ss; 1637 socklen_t slen; 1638 int ret; 1639 1640 args_get(vm, nargs, NULL, 1641 "address", UC_NULL, false, &addr, 1642 "flags", UC_INTEGER, true, &flags); 1643 1644 if (!uv_to_sockaddr(addr, &ss, &slen)) 1645 return NULL; 1646 1647 ret = getnameinfo((struct sockaddr *)&ss, slen, 1648 host, sizeof(host), serv, sizeof(serv), 1649 flags ? ucv_int64_get(flags) : 0); 1650 1651 if (ret != 0) 1652 err_return((ret == EAI_SYSTEM) ? errno : ret, "getnameinfo()"); 1653 1654 rv = ucv_object_new(vm); 1655 1656 ucv_object_add(rv, "hostname", ucv_string_new(host)); 1657 ucv_object_add(rv, "service", ucv_string_new(serv)); 1658 1659 ok_return(rv); 1660 } 1661 1662 /** 1663 * Resolves the given hostname and optional service name into a list of network 1664 * addresses, according to the provided hints. 1665 * 1666 * The `addrinfo()` function provides an API for performing DNS and service name 1667 * resolution. It returns an array of objects, each representing a resolved 1668 * address. 1669 * 1670 * Returns an array of resolved addresses. 1671 * Returns `null` if an error occurred during resolution. 1672 * 1673 * @function module:socket#addrinfo 1674 * 1675 * @param {string} hostname 1676 * The hostname to resolve. 1677 * 1678 * @param {string} [service] 1679 * Optional service name to resolve. If not provided, the service field of the 1680 * resulting address information structures is left uninitialized. 1681 * 1682 * @param {Object} [hints] 1683 * Optional hints object that provides additional control over the resolution 1684 * process. It can contain the following properties: 1685 * - `family`: The preferred address family (`AF_INET` or `AF_INET6`). 1686 * - `socktype`: The socket type (`SOCK_STREAM`, `SOCK_DGRAM`, etc.). 1687 * - `protocol`: The protocol of returned addresses. 1688 * - `flags`: Bitwise OR-ed `AI_*` flags to control the resolution behavior. 1689 * 1690 * @returns {?module:socket.AddressInfo[]} 1691 * 1692 * @see {@link module:socket~"Socket Types"|Socket Types} 1693 * @see {@link module:socket~"Address Info Flags"|Address Info Flags} 1694 * 1695 * @example 1696 * // Resolve all addresses 1697 * const addresses = socket.addrinfo('example.org'); 1698 * 1699 * // Resolve IPv4 addresses for a given hostname and service 1700 * const ipv4addresses = socket.addrinfo('example.com', 'http', { family: socket.AF_INET }); 1701 * 1702 * // Resolve IPv6 addresses without specifying a service 1703 * const ipv6Addresses = socket.addrinfo('example.com', null, { family: socket.AF_INET6 }); 1704 */ 1705 1706 static uc_value_t * 1707 uc_socket_addrinfo(uc_vm_t *vm, size_t nargs) 1708 { 1709 struct addrinfo *ai_hints = NULL, *ai_res; 1710 uc_value_t *host, *serv, *hints, *rv; 1711 char *servstr; 1712 int ret; 1713 1714 args_get(vm, nargs, NULL, 1715 "hostname", UC_STRING, false, &host, 1716 "service", UC_NULL, true, &serv, 1717 "hints", UC_OBJECT, true, &hints); 1718 1719 if (hints) { 1720 ai_hints = (struct addrinfo *)uv_to_struct(hints, &st_addrinfo); 1721 1722 if (!ai_hints) 1723 return NULL; 1724 } 1725 1726 servstr = (ucv_type(serv) != UC_STRING) ? ucv_to_string(vm, serv) : NULL; 1727 ret = getaddrinfo(ucv_string_get(host), 1728 servstr ? servstr : ucv_string_get(serv), 1729 ai_hints, &ai_res); 1730 1731 free(ai_hints); 1732 free(servstr); 1733 1734 if (ret != 0) 1735 err_return((ret == EAI_SYSTEM) ? errno : ret, "getaddrinfo()"); 1736 1737 rv = ucv_array_new(vm); 1738 1739 for (struct addrinfo *ai = ai_res; ai; ai = ai->ai_next) { 1740 uc_value_t *item = struct_to_uv((char *)ai, &st_addrinfo); 1741 1742 if (item) 1743 ucv_array_push(rv, item); 1744 } 1745 1746 freeaddrinfo(ai_res); 1747 1748 ok_return(rv); 1749 } 1750 1751 /** 1752 * Represents a poll state serving as input parameter and return value type for 1753 * {@link module:socket#poll|`poll()`}. 1754 * 1755 * @typedef {Array} module:socket.PollSpec 1756 * @property {module:socket.socket} 0 1757 * The polled socket instance. 1758 * 1759 * @property {number} 1 1760 * Requested or returned status flags of the polled socket instance. 1761 */ 1762 1763 /** 1764 * Polls a number of sockets for state changes. 1765 * 1766 * Returns an array of socket poll states. 1767 * Returns `null` if an error occurred. 1768 * 1769 * @function module:socket#poll 1770 * 1771 * @param {number} timeout 1772 * Amount of milliseconds to wait for socket activity before aborting the poll 1773 * call. If set to `0`, the poll call will return immediately if none of the 1774 * provided sockets has pending events, if set to a negative value, the poll 1775 * call will wait indefinitely, in all other cases the poll call will wait at 1776 * most for the given amount of milliseconds before returning. 1777 * 1778 * @param {...(module:socket.socket|module:socket.PollSpec)} sockets 1779 * An arbitrary amount of socket arguments. Each argument may be either a plain 1780 * {@link module:socket.socket|socket instance} or a `[socket, flags]` tuple 1781 * specifying the socket and requested poll flags. If a plain socket and not a 1782 * tuple is provided, the requested poll flags default to 1783 * `POLLIN|POLLERR|POLLHUP` for this socket. 1784 * 1785 * @returns {module:socket.PollSpec[]} 1786 */ 1787 static uc_value_t * 1788 uc_socket_poll(uc_vm_t *vm, size_t nargs) 1789 { 1790 struct { struct pollfd *entries; size_t count; } pfds = { 0 }; 1791 uc_value_t *timeoutarg, *rv, *item; 1792 int64_t timeout; 1793 int ret; 1794 1795 args_get(vm, nargs, NULL, "timeout", UC_INTEGER, false, &timeoutarg); 1796 1797 timeout = ucv_to_integer(timeoutarg); 1798 1799 if (errno != 0 || timeout < (int64_t)INT_MIN || timeout > (int64_t)INT_MAX) 1800 err_return(ERANGE, "Invalid timeout value"); 1801 1802 rv = ucv_array_new(vm); 1803 1804 for (size_t i = 1; i < nargs; i++) { 1805 uc_vector_grow(&pfds); 1806 1807 if (uv_to_pollfd(vm, uc_fn_arg(i), &pfds.entries[pfds.count])) { 1808 item = ucv_array_new_length(vm, 2); 1809 ucv_array_set(item, 0, ucv_get(uc_fn_arg(i))); 1810 ucv_array_set(rv, pfds.count++, item); 1811 } 1812 } 1813 1814 ret = poll(pfds.entries, pfds.count, timeout); 1815 1816 if (ret == -1) { 1817 ucv_put(rv); 1818 uc_vector_clear(&pfds); 1819 err_return(errno, "poll()"); 1820 } 1821 1822 for (size_t i = 0; i < pfds.count; i++) 1823 ucv_array_set(ucv_array_get(rv, i), 1, 1824 ucv_int64_new(pfds.entries[i].revents)); 1825 1826 uc_vector_clear(&pfds); 1827 ok_return(rv); 1828 } 1829 1830 /** 1831 * Creates a network socket and connects it to the specified host and service. 1832 * 1833 * This high level function combines the functionality of 1834 * {@link module:socket#create|create()}, 1835 * {@link module:socket#addrinfo|addrinfo()} and 1836 * {@link module:socket.socket#connect|connect()} to simplify connection 1837 * establishment with the socket module. 1838 * 1839 * @function module:socket#connect 1840 * 1841 * @param {string|number[]|module:socket.socket.SocketAddress} host 1842 * The host to connect to, can be an IP address, hostname, 1843 * {@link module:socket.socket.SocketAddress|SocketAddress}, or an array value 1844 * returned by {@link module:core#iptoarr|iptoarr()}. 1845 * 1846 * @param {string|number} [service] 1847 * The service to connect to, can be a symbolic service name (such as "http") or 1848 * a port number. Optional if host is specified as 1849 * {@link module:socket.socket.SocketAddress|SocketAddress}. 1850 * 1851 * @param {Object} [hints] 1852 * Optional preferences for the socket. It can contain the following properties: 1853 * - `family`: The preferred address family (`AF_INET` or `AF_INET6`). 1854 * - `socktype`: The socket type (`SOCK_STREAM`, `SOCK_DGRAM`, etc.). 1855 * - `protocol`: The protocol of the created socket. 1856 * - `flags`: Bitwise OR-ed `AI_*` flags to control the resolution behavior. 1857 * 1858 * If no hints are not provided, the default socket type preference is set to 1859 * `SOCK_STREAM`. 1860 * 1861 * @param {number} [timeout=-1] 1862 * The timeout in milliseconds for socket connect operations. If set to a 1863 * negative value, no specifc time limit is imposed and the function will 1864 * block until either a connection was successfull or the underlying operating 1865 * system timeout is reached. 1866 * 1867 * @returns {module:socket.socket} 1868 * 1869 * @example 1870 * // Resolve host, try to connect to both resulting IPv4 and IPv6 addresses 1871 * let conn = socket.connect("example.org", 80); 1872 * 1873 * // Enforce usage of IPv6 1874 * let conn = socket.connect("example.com", 80, { family: socket.AF_INET6 }); 1875 * 1876 * // Connect a UDP socket 1877 * let conn = socket.connect("192.168.1.1", 53, { socktype: socket.SOCK_DGRAM }); 1878 * 1879 * // Bypass name resolution by specifying a SocketAddress structure 1880 * let conn = socket.connect({ address: "127.0.0.1", port: 9000 }); 1881 * 1882 * // Use SocketAddress structure to connect a UNIX domain socket 1883 * let conn = socket.connect({ path: "/var/run/daemon.sock" }); 1884 */ 1885 static uc_value_t * 1886 uc_socket_connect(uc_vm_t *vm, size_t nargs) 1887 { 1888 struct address { 1889 struct sockaddr_storage ss; 1890 struct addrinfo ai; 1891 int flags; 1892 int fd; 1893 } *ap; 1894 1895 struct { struct address *entries; size_t count; } addresses = { 0 }; 1896 struct { struct pollfd *entries; size_t count; } pollfds = { 0 }; 1897 struct addrinfo *ai_results, *ai_hints, *ai; 1898 uc_value_t *host, *serv, *hints, *timeout; 1899 const char *errmsg = NULL; 1900 struct pollfd *pp = NULL; 1901 size_t slot, connected; 1902 int ret, err; 1903 1904 args_get(vm, nargs, NULL, 1905 "host", UC_NULL, false, &host, 1906 "service", UC_NULL, true, &serv, 1907 "hints", UC_OBJECT, true, &hints, 1908 "timeout", UC_INTEGER, true, &timeout); 1909 1910 ai_hints = hints 1911 ? (struct addrinfo *)uv_to_struct(hints, &st_addrinfo) : NULL; 1912 1913 if (ucv_type(host) == UC_STRING) { 1914 char *servstr = (ucv_type(serv) != UC_STRING) 1915 ? ucv_to_string(vm, serv) : NULL; 1916 1917 ret = getaddrinfo(ucv_string_get(host), 1918 servstr ? servstr : ucv_string_get(serv), 1919 ai_hints ? ai_hints : &(struct addrinfo){ 1920 .ai_socktype = SOCK_STREAM 1921 }, &ai_results); 1922 1923 if (ret != 0) { 1924 free(servstr); 1925 free(ai_hints); 1926 err_return((ret == EAI_SYSTEM) ? errno : ret, 1927 "getaddrinfo()"); 1928 } 1929 1930 for (ai = ai_results; ai != NULL; ai = ai->ai_next) { 1931 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 1932 continue; 1933 1934 uc_vector_grow(&addresses); 1935 ap = &addresses.entries[addresses.count++]; 1936 memcpy(&ap->ss, ai->ai_addr, ai->ai_addrlen); 1937 memcpy(&ap->ai, ai, sizeof(*ai)); 1938 ap->ai.ai_addr = (struct sockaddr *)&ap->ss; 1939 } 1940 1941 freeaddrinfo(ai_results); 1942 free(servstr); 1943 } 1944 else { 1945 uc_vector_grow(&addresses); 1946 ap = &addresses.entries[addresses.count++]; 1947 1948 if (!uv_to_sockaddr(host, &ap->ss, &ap->ai.ai_addrlen)) 1949 return NULL; 1950 1951 if (serv) { 1952 uint64_t port = ucv_to_unsigned(serv); 1953 1954 if (port > 65535) 1955 errno = ERANGE; 1956 1957 if (errno != 0) { 1958 free(ai_hints); 1959 uc_vector_clear(&addresses); 1960 err_return(errno, "Invalid port number"); 1961 } 1962 1963 ((struct sockaddr_in *)&ap->ss)->sin_port = htons(port); 1964 } 1965 1966 ap->ai.ai_addr = (struct sockaddr *)&ap->ss; 1967 ap->ai.ai_family = ap->ss.ss_family; 1968 ap->ai.ai_socktype = ai_hints ? ai_hints->ai_socktype : SOCK_STREAM; 1969 ap->ai.ai_protocol = ai_hints ? ai_hints->ai_protocol : 0; 1970 } 1971 1972 free(ai_hints); 1973 1974 for (connected = 0, slot = 0, ap = &addresses.entries[slot]; 1975 slot < addresses.count; 1976 slot++, ap = &addresses.entries[slot]) 1977 { 1978 uc_vector_grow(&pollfds); 1979 pp = &pollfds.entries[pollfds.count++]; 1980 pp->events = POLLIN | POLLOUT | POLLHUP | POLLERR; 1981 pp->fd = socket(ap->ai.ai_family, ap->ai.ai_socktype, ap->ai.ai_protocol); 1982 1983 if (pp->fd == -1) 1984 continue; 1985 1986 if ((ap->flags = fcntl(pp->fd, F_GETFL, 0)) == -1) { 1987 xclose(&pp->fd); 1988 continue; 1989 } 1990 1991 if (fcntl(pp->fd, F_SETFL, ap->flags | O_NONBLOCK) == -1) { 1992 xclose(&pp->fd); 1993 continue; 1994 } 1995 1996 ret = connect(pp->fd, ap->ai.ai_addr, ap->ai.ai_addrlen); 1997 1998 if (ret == -1 && errno != EINPROGRESS) { 1999 xclose(&pp->fd); 2000 continue; 2001 } 2002 2003 connected++; 2004 } 2005 2006 if (connected == 0) { 2007 err = EAI_NONAME; 2008 errmsg = "Could not connect to any host address"; 2009 goto out; 2010 } 2011 2012 ret = poll(pollfds.entries, pollfds.count, 2013 timeout ? ucv_int64_get(timeout) : -1); 2014 2015 if (ret == -1) { 2016 err = errno; 2017 errmsg = "poll()"; 2018 goto out; 2019 } 2020 2021 for (slot = 0, ap = NULL, pp = NULL; slot < pollfds.count; slot++) { 2022 if (pollfds.entries[slot].revents & (POLLIN|POLLOUT)) { 2023 ap = &addresses.entries[slot]; 2024 pp = &pollfds.entries[slot]; 2025 break; 2026 } 2027 } 2028 2029 if (!ap) { 2030 err = ETIMEDOUT; 2031 errmsg = "Connection timed out"; 2032 goto out; 2033 } 2034 2035 if (fcntl(pp->fd, F_SETFL, ap->flags) == -1) { 2036 err = errno; 2037 errmsg = "fcntl(F_SETFL)"; 2038 goto out; 2039 } 2040 2041 out: 2042 for (slot = 0, ret = -1; slot < pollfds.count; slot++) { 2043 if (pp == &pollfds.entries[slot]) 2044 ret = pollfds.entries[slot].fd; 2045 else 2046 xclose(&pollfds.entries[slot].fd); 2047 } 2048 2049 uc_vector_clear(&addresses); 2050 uc_vector_clear(&pollfds); 2051 2052 if (errmsg) 2053 err_return(err, "%s", errmsg); 2054 2055 ok_return(ucv_socket_new(vm, ret)); 2056 } 2057 2058 /** 2059 * Binds a listening network socket to the specified host and service. 2060 * 2061 * This high-level function combines the functionality of 2062 * {@link module:socket#create|create()}, 2063 * {@link module:socket#addrinfo|addrinfo()}, 2064 * {@link module:socket.socket#bind|bind()}, and 2065 * {@link module:socket.socket#listen|listen()} to simplify setting up a 2066 * listening socket with the socket module. 2067 * 2068 * @function module:socket#listen 2069 * 2070 * @param {string|number[]|module:socket.socket.SocketAddress} host 2071 * The host to bind to, can be an IP address, hostname, 2072 * {@link module:socket.socket.SocketAddress|SocketAddress}, or an array value 2073 * returned by {@link module:core#iptoarr|iptoarr()}. 2074 * 2075 * @param {string|number} [service] 2076 * The service to listen on, can be a symbolic service name (such as "http") or 2077 * a port number. Optional if host is specified as 2078 * {@link module:socket.socket.SocketAddress|SocketAddress}. 2079 * 2080 * @param {Object} [hints] 2081 * Optional preferences for the socket. It can contain the following properties: 2082 * - `family`: The preferred address family (`AF_INET` or `AF_INET6`). 2083 * - `socktype`: The socket type (`SOCK_STREAM`, `SOCK_DGRAM`, etc.). 2084 * - `protocol`: The protocol of the created socket. 2085 * - `flags`: Bitwise OR-ed `AI_*` flags to control the resolution behavior. 2086 * 2087 * If no hints are provided, the default socket type preference is set to 2088 * `SOCK_STREAM`. 2089 * 2090 * @param {number} [backlog=128] 2091 * The maximum length of the queue of pending connections. 2092 * 2093 * @returns {module:socket.socket} 2094 * 2095 * @example 2096 * // Listen for incoming TCP connections on port 80 2097 * let server = socket.listen("localhost", 80); 2098 * 2099 * // Listen on IPv6 address only 2100 * let server = socket.listen("machine.local", 8080, { family: socket.AF_INET6 }); 2101 * 2102 * // Listen on a UNIX domain socket 2103 * let server = socket.listen({ path: "/var/run/server.sock" }); 2104 */ 2105 static uc_value_t * 2106 uc_socket_listen(uc_vm_t *vm, size_t nargs) 2107 { 2108 int ret, fd, curr_weight, prev_weight, socktype = 0, protocol = 0; 2109 struct addrinfo *ai_results, *ai_hints, *ai; 2110 uc_value_t *host, *serv, *hints, *backlog; 2111 struct sockaddr_storage ss = { 0 }; 2112 bool v6, lo, ll; 2113 socklen_t slen; 2114 2115 args_get(vm, nargs, NULL, 2116 "host", UC_NULL, true, &host, 2117 "service", UC_NULL, true, &serv, 2118 "hints", UC_OBJECT, true, &hints, 2119 "backlog", UC_INTEGER, true, &backlog); 2120 2121 ai_hints = hints 2122 ? (struct addrinfo *)uv_to_struct(hints, &st_addrinfo) : NULL; 2123 2124 if (host == NULL || ucv_type(host) == UC_STRING) { 2125 char *servstr = (ucv_type(serv) != UC_STRING) 2126 ? ucv_to_string(vm, serv) : NULL; 2127 2128 ret = getaddrinfo(ucv_string_get(host), 2129 servstr ? servstr : ucv_string_get(serv), 2130 ai_hints ? ai_hints : &(struct addrinfo){ 2131 .ai_flags = AI_PASSIVE | AI_ADDRCONFIG, 2132 .ai_socktype = SOCK_STREAM 2133 }, &ai_results); 2134 2135 free(servstr); 2136 2137 if (ret != 0) { 2138 free(ai_hints); 2139 err_return((ret == EAI_SYSTEM) ? errno : ret, 2140 "getaddrinfo()"); 2141 } 2142 2143 for (ai = ai_results, prev_weight = -1; ai != NULL; ai = ai->ai_next) { 2144 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ai->ai_addr; 2145 struct sockaddr_in *s4 = (struct sockaddr_in *)ai->ai_addr; 2146 2147 v6 = (s6->sin6_family == AF_INET6); 2148 ll = v6 2149 ? IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) 2150 : ((ntohl(s4->sin_addr.s_addr) & 0xffff0000) == 0xa9fe0000); 2151 lo = v6 2152 ? IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr) 2153 : ((ntohl(s4->sin_addr.s_addr) & 0xff000000) == 0x7f000000); 2154 2155 curr_weight = (!lo << 2) | (v6 << 1) | (!ll << 0); 2156 2157 if (curr_weight > prev_weight) { 2158 prev_weight = curr_weight; 2159 socktype = ai->ai_socktype; 2160 protocol = ai->ai_protocol; 2161 slen = ai->ai_addrlen; 2162 memcpy(&ss, ai->ai_addr, slen); 2163 } 2164 } 2165 2166 freeaddrinfo(ai_results); 2167 } 2168 else { 2169 if (!uv_to_sockaddr(host, &ss, &slen)) { 2170 free(ai_hints); 2171 return NULL; 2172 } 2173 2174 if (serv) { 2175 uint64_t port = ucv_to_unsigned(serv); 2176 2177 if (port > 65535) 2178 errno = ERANGE; 2179 2180 if (errno != 0) { 2181 free(ai_hints); 2182 err_return(errno, "Invalid port number"); 2183 } 2184 2185 ((struct sockaddr_in *)&ss)->sin_port = htons(port); 2186 } 2187 2188 socktype = ai_hints ? ai_hints->ai_socktype : SOCK_STREAM; 2189 protocol = ai_hints ? ai_hints->ai_protocol : 0; 2190 } 2191 2192 free(ai_hints); 2193 2194 if (ss.ss_family == AF_UNSPEC) 2195 err_return(EAI_NONAME, "Could not resolve host address"); 2196 2197 fd = socket(ss.ss_family, socktype, protocol); 2198 2199 if (fd == -1) 2200 err_return(errno, "socket()"); 2201 2202 ret = bind(fd, (struct sockaddr *)&ss, slen); 2203 2204 if (ret == -1) { 2205 close(fd); 2206 err_return(errno, "bind()"); 2207 } 2208 2209 ret = listen(fd, backlog ? ucv_to_unsigned(backlog) : 128); 2210 2211 if (ret == -1) { 2212 close(fd); 2213 err_return(errno, "listen()"); 2214 } 2215 2216 ok_return(ucv_socket_new(vm, fd)); 2217 } 2218 2219 /** 2220 * Represents a socket handle. 2221 * 2222 * @class module:socket.socket 2223 * @hideconstructor 2224 * 2225 * @borrows module:socket#error as module:socket.socket#error 2226 * 2227 * @see {@link module:socket#create|create()} 2228 * 2229 * @example 2230 * 2231 * const sock = create(…); 2232 * 2233 * sock.getopt(…); 2234 * sock.setopt(…); 2235 * 2236 * sock.connect(…); 2237 * sock.listen(…); 2238 * sock.accept(…); 2239 * sock.bind(…); 2240 * 2241 * sock.send(…); 2242 * sock.recv(…); 2243 * 2244 * sock.shutdown(…); 2245 * 2246 * sock.fileno(); 2247 * sock.peername(); 2248 * sock.sockname(); 2249 * 2250 * sock.close(); 2251 * 2252 * sock.error(); 2253 */ 2254 2255 /** 2256 * Creates a socket and returns its hand 2257 * 2258 * The handle will be connected to the process stdin or stdout, depending on the 2259 * value of the mode argument. 2260 * 2261 * The mode argument may be either "r" to open the process for reading (connect 2262 * to its stdin) or "w" to open the process for writing (connect to its stdout). 2263 * 2264 * The mode character "r" or "w" may be optionally followed by "e" to apply the 2265 * FD_CLOEXEC flag onto the open descriptor. 2266 * 2267 * Returns a process handle referring to the executed process. 2268 * 2269 * Returns `null` if an error occurred. 2270 * 2271 * @function module:fs#popen 2272 * 2273 * @param {string} command 2274 * The command to be executed. 2275 * 2276 * @param {string} [mode="r"] 2277 * The open mode of the process handle. 2278 * 2279 * @returns {?module:fs.proc} 2280 * 2281 * @example 2282 * // Open a process 2283 * const process = popen('command', 'r'); 2284 */ 2285 2286 /** 2287 * Creates a network socket instance. 2288 * 2289 * This function creates a new network socket with the specified domain and 2290 * type, determined by one of the modules `AF_*` and `SOCK_*` constants 2291 * respectively, and returns the resulting socket instance for use in subsequent 2292 * socket operations. 2293 * 2294 * The domain argument specifies the protocol family, such as AF_INET or 2295 * AF_INET6, and defaults to AF_INET if not provided. 2296 * 2297 * The type argument specifies the socket type, such as SOCK_STREAM or 2298 * SOCK_DGRAM, and defaults to SOCK_STREAM if not provided. It may also 2299 * be bitwise OR-ed with SOCK_NONBLOCK to enable non-blocking mode or 2300 * SOCK_CLOEXEC to enable close-on-exec semantics. 2301 * 2302 * The protocol argument may be used to indicate a particular protocol 2303 * to be used with the socket, and it defaults to 0 (automatically 2304 * determined protocol) if not provided. 2305 * 2306 * Returns a socket descriptor representing the newly created socket. 2307 * 2308 * Returns `null` if an error occurred during socket creation. 2309 * 2310 * @function module:socket#create 2311 * 2312 * @param {number} [domain=AF_INET] 2313 * The communication domain for the socket, e.g., AF_INET or AF_INET6. 2314 * 2315 * @param {number} [type=SOCK_STREAM] 2316 * The socket type, e.g., SOCK_STREAM or SOCK_DGRAM. It may also be 2317 * bitwise OR-ed with SOCK_NONBLOCK or SOCK_CLOEXEC. 2318 * 2319 * @param {number} [protocol=0] 2320 * The protocol to be used with the socket. 2321 * 2322 * @returns {?module:socket.socket} 2323 * A socket instance representing the newly created socket. 2324 * 2325 * @example 2326 * // Create a TCP socket 2327 * const tcp_socket = create(AF_INET, SOCK_STREAM); 2328 * 2329 * // Create a nonblocking IPv6 UDP socket 2330 * const udp_socket = create(AF_INET6, SOCK_DGRAM | SOCK_NONBLOCK); 2331 */ 2332 static uc_value_t * 2333 uc_socket_create(uc_vm_t *vm, size_t nargs) 2334 { 2335 uc_value_t *domain, *type, *protocol; 2336 int sockfd, socktype; 2337 2338 args_get(vm, nargs, NULL, 2339 "domain", UC_INTEGER, true, &domain, 2340 "type", UC_INTEGER, true, &type, 2341 "protocol", UC_INTEGER, true, &protocol); 2342 2343 socktype = type ? (int)ucv_int64_get(type) : SOCK_STREAM; 2344 2345 sockfd = socket( 2346 domain ? (int)ucv_int64_get(domain) : AF_INET, 2347 #if defined(__APPLE__) 2348 socktype & ~(SOCK_NONBLOCK|SOCK_CLOEXEC), 2349 #else 2350 socktype, 2351 #endif 2352 protocol ? (int)ucv_int64_get(protocol) : 0); 2353 2354 if (sockfd == -1) 2355 err_return(errno, "socket()"); 2356 2357 #if defined(__APPLE__) 2358 if (socktype & SOCK_NONBLOCK) { 2359 int flags = fcntl(sockfd, F_GETFL); 2360 2361 if (flags == -1) { 2362 close(sockfd); 2363 err_return(errno, "fcntl(F_GETFL)"); 2364 } 2365 2366 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) { 2367 close(sockfd); 2368 err_return(errno, "fcntl(F_SETFL)"); 2369 } 2370 } 2371 2372 if (socktype & SOCK_CLOEXEC) { 2373 if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { 2374 close(sockfd); 2375 err_return(errno, "fcntl(F_SETFD)"); 2376 } 2377 } 2378 #endif 2379 2380 ok_return(ucv_socket_new(vm, sockfd)); 2381 } 2382 2383 /** 2384 * Connects the socket to a remote address. 2385 * 2386 * Attempts to establish a connection to the specified remote address. 2387 * 2388 * Returns `true` if the connection is successfully established. 2389 * Returns `null` if an error occurred during the connection attempt. 2390 * 2391 * @function module:socket.socket#connect 2392 * 2393 * @param {string|module:socket.socket.SocketAddress} address 2394 * The address of the remote endpoint to connect to. 2395 * 2396 * @param {number} port 2397 * The port number of the remote endpoint to connect to. 2398 * 2399 * @returns {?boolean} 2400 */ 2401 static uc_value_t * 2402 uc_socket_inst_connect(uc_vm_t *vm, size_t nargs) 2403 { 2404 struct sockaddr_storage ss; 2405 uc_value_t *addr; 2406 int ret, sockfd; 2407 socklen_t slen; 2408 2409 args_get(vm, nargs, &sockfd, 2410 "address", UC_NULL, false, &addr); 2411 2412 if (!uv_to_sockaddr(addr, &ss, &slen)) 2413 return NULL; 2414 2415 ret = connect(sockfd, (struct sockaddr *)&ss, slen); 2416 2417 if (ret == -1) 2418 err_return(errno, "connect()"); 2419 2420 ok_return(ucv_boolean_new(true)); 2421 } 2422 2423 /** 2424 * Sends data through the socket. 2425 * 2426 * Sends the provided data through the socket handle to the specified remote 2427 * address, if provided. 2428 * 2429 * Returns the number of bytes sent. 2430 * Returns `null` if an error occurred during the send operation. 2431 * 2432 * @function module:socket.socket#send 2433 * 2434 * @param {*} data 2435 * The data to be sent through the socket. String data is sent as-is, any other 2436 * type is implicitly converted to a string first before being sent on the 2437 * socket. 2438 * 2439 * @param {number} [flags] 2440 * Optional flags that modify the behavior of the send operation. 2441 * 2442 * @param {module:socket.socket.SocketAddress|number[]|string} [address] 2443 * The address of the remote endpoint to send the data to. It can be either an 2444 * IP address string, an array returned by {@link module:core#iptoarr|iptoarr()}, 2445 * or an object representing a network address. If not provided, the data is 2446 * sent to the remote endpoint the socket is connected to. 2447 * 2448 * @returns {?number} 2449 * 2450 * @see {@link module:socket#sockaddr|sockaddr()} 2451 * 2452 * @example 2453 * // Send to connected socket 2454 * let tcp_sock = socket.create(socket.AF_INET, socket.SOCK_STREAM); 2455 * tcp_sock.connect("192.168.1.1", 80); 2456 * tcp_sock.send("GET / HTTP/1.0\r\n\r\n"); 2457 * 2458 * // Send a datagram on unconnected socket 2459 * let udp_sock = socket.create(socket.AF_INET, socket.SOCK_DGRAM); 2460 * udp_sock.send("Hello there!", 0, "255.255.255.255:9000"); 2461 * udp_sock.send("Hello there!", 0, { 2462 * family: socket.AF_INET, // optional 2463 * address: "255.255.255.255", 2464 * port: 9000 2465 * }); 2466 */ 2467 static uc_value_t * 2468 uc_socket_inst_send(uc_vm_t *vm, size_t nargs) 2469 { 2470 uc_value_t *data, *flags, *addr; 2471 struct sockaddr_storage ss = { 0 }; 2472 struct sockaddr *sa = NULL; 2473 socklen_t salen = 0; 2474 char *buf = NULL; 2475 ssize_t ret; 2476 int sockfd; 2477 2478 args_get(vm, nargs, &sockfd, 2479 "data", UC_NULL, false, &data, 2480 "flags", UC_INTEGER, true, &flags, 2481 "address", UC_NULL, true, &addr); 2482 2483 if (addr) { 2484 if (!uv_to_sockaddr(addr, &ss, &salen)) 2485 return NULL; 2486 2487 sa = (struct sockaddr *)&ss; 2488 } 2489 2490 if (ucv_type(data) != UC_STRING) 2491 buf = ucv_to_string(vm, data); 2492 2493 ret = sendto(sockfd, 2494 buf ? buf : ucv_string_get(data), 2495 buf ? strlen(buf) : ucv_string_length(data), 2496 (flags ? ucv_int64_get(flags) : 0) | MSG_NOSIGNAL, sa, salen); 2497 2498 free(buf); 2499 2500 if (ret == -1) 2501 err_return(errno, "send()"); 2502 2503 ok_return(ucv_int64_new(ret)); 2504 } 2505 2506 /** 2507 * Receives data from the socket. 2508 * 2509 * Receives data from the socket handle, optionally specifying the maximum 2510 * length of data to receive, flags to modify the receive behavior, and an 2511 * optional address dictionary where the function will place the address from 2512 * which the data was received (for unconnected sockets). 2513 * 2514 * Returns a string containing the received data. 2515 * Returns an empty string if the remote side closed the socket. 2516 * Returns `null` if an error occurred during the receive operation. 2517 * 2518 * @function module:socket.socket#recv 2519 * 2520 * @param {number} [length=4096] 2521 * The maximum number of bytes to receive. 2522 * 2523 * @param {number} [flags] 2524 * Optional flags that modify the behavior of the receive operation. 2525 * 2526 * @param {Object} [address] 2527 * An object where the function will store the address from which the data was 2528 * received. If provided, it will be filled with the details obtained from the 2529 * sockaddr argument of the underlying `recvfrom()` syscall. See the type 2530 * definition of {@link module:socket.socket.SocketAddress|SocketAddress} for 2531 * details on the format. 2532 * 2533 * @returns {?string} 2534 */ 2535 static uc_value_t * 2536 uc_socket_inst_recv(uc_vm_t *vm, size_t nargs) 2537 { 2538 uc_value_t *length, *flags, *addrobj; 2539 struct sockaddr_storage ss = { 0 }; 2540 uc_stringbuf_t *buf; 2541 ssize_t len, ret; 2542 socklen_t sslen; 2543 int sockfd; 2544 2545 args_get(vm, nargs, &sockfd, 2546 "length", UC_INTEGER, true, &length, 2547 "flags", UC_INTEGER, true, &flags, 2548 "address", UC_OBJECT, true, &addrobj); 2549 2550 len = length ? ucv_to_integer(length) : 4096; 2551 2552 if (errno || len <= 0) 2553 err_return(errno, "Invalid length argument"); 2554 2555 buf = strbuf_alloc(len); 2556 2557 if (!buf) 2558 return NULL; 2559 2560 do { 2561 sslen = sizeof(ss); 2562 ret = recvfrom(sockfd, strbuf_data(buf), len, 2563 flags ? ucv_int64_get(flags) : 0, (struct sockaddr *)&ss, &sslen); 2564 } while (ret == -1 && errno == EINTR); 2565 2566 if (ret == -1) { 2567 strbuf_free(buf); 2568 err_return(errno, "recv()"); 2569 } 2570 2571 if (addrobj) 2572 sockaddr_to_uv(&ss, addrobj); 2573 2574 ok_return(strbuf_finish(&buf, ret)); 2575 } 2576 2577 /** 2578 * Binds a socket to a specific address. 2579 * 2580 * This function binds the socket to the specified address. 2581 * 2582 * Returns `true` if the socket is successfully bound. 2583 * 2584 * Returns `null` on error, e.g. when the address is in use. 2585 * 2586 * @function module:socket.socket#bind 2587 * 2588 * @param {string|module:socket.socket.SocketAddress} address 2589 * The IP address to bind the socket to. 2590 * 2591 * @returns {?boolean} 2592 * 2593 * @example 2594 * const sock = socket.create(…); 2595 * const success = sock.bind("192.168.0.1:80"); 2596 * 2597 * if (success) 2598 * print(`Socket bound successfully!\n`); 2599 * else 2600 * print(`Failed to bind socket: ${sock.error()}.\n`); 2601 */ 2602 static uc_value_t * 2603 uc_socket_inst_bind(uc_vm_t *vm, size_t nargs) 2604 { 2605 struct sockaddr_storage ss = { 0 }; 2606 uc_value_t *addr; 2607 socklen_t slen; 2608 int sockfd; 2609 2610 args_get(vm, nargs, &sockfd, 2611 "address", UC_NULL, true, &addr); 2612 2613 if (addr) { 2614 if (!uv_to_sockaddr(addr, &ss, &slen)) 2615 return NULL; 2616 2617 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1) 2618 err_return(errno, "bind()"); 2619 } 2620 else { 2621 #if defined(__linux__) 2622 int sval = 0; 2623 slen = sizeof(sval); 2624 2625 if (getsockopt(sockfd, SOL_SOCKET, SO_DOMAIN, &sval, &slen) == -1) 2626 err_return(errno, "getsockopt()"); 2627 2628 switch (sval) { 2629 case AF_INET6: 2630 ss.ss_family = AF_INET6; 2631 slen = sizeof(struct sockaddr_in6); 2632 break; 2633 2634 case AF_INET: 2635 ss.ss_family = AF_INET; 2636 slen = sizeof(struct sockaddr_in); 2637 break; 2638 2639 default: 2640 err_return(EAFNOSUPPORT, "Unsupported socket address family"); 2641 } 2642 2643 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1) 2644 err_return(errno, "bind()"); 2645 #else 2646 ss.ss_family = AF_INET6; 2647 slen = sizeof(struct sockaddr_in6); 2648 2649 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1) { 2650 if (errno != EAFNOSUPPORT) 2651 err_return(errno, "bind()"); 2652 2653 ss.ss_family = AF_INET; 2654 slen = sizeof(struct sockaddr_in); 2655 2656 if (bind(sockfd, (struct sockaddr *)&ss, slen) == -1) 2657 err_return(errno, "bind()"); 2658 } 2659 #endif 2660 } 2661 2662 ok_return(ucv_boolean_new(true)); 2663 } 2664 2665 /** 2666 * Listen for connections on a socket. 2667 * 2668 * This function marks the socket as a passive socket, that is, as a socket that 2669 * will be used to accept incoming connection requests using `accept()`. 2670 * 2671 * The `backlog` parameter specifies the maximum length to which the queue of 2672 * pending connections may grow. If a connection request arrives when the queue 2673 * is full, the client connection might get refused. 2674 * 2675 * If `backlog` is not provided, it defaults to 128. 2676 * 2677 * Returns `true` if the socket is successfully marked as passive. 2678 * Returns `null` if an error occurred, e.g. when the requested port is in use. 2679 * 2680 * @function module:socket.socket#listen 2681 * 2682 * @param {number} [backlog=128] 2683 * The maximum length of the queue of pending connections. 2684 * 2685 * @returns {?boolean} 2686 * 2687 * @see {@link module:socket.socket#accept|accept()} 2688 * 2689 * @example 2690 * const sock = socket.create(…); 2691 * sock.bind(…); 2692 * 2693 * const success = sock.listen(10); 2694 * if (success) 2695 * print(`Socket is listening for incoming connections!\n`); 2696 * else 2697 * print(`Failed to listen on socket: ${sock.error()}\n`); 2698 */ 2699 static uc_value_t * 2700 uc_socket_inst_listen(uc_vm_t *vm, size_t nargs) 2701 { 2702 uc_value_t *backlog; 2703 int ret, sockfd; 2704 2705 args_get(vm, nargs, &sockfd, 2706 "backlog", UC_INTEGER, true, &backlog); 2707 2708 ret = listen(sockfd, backlog ? ucv_to_unsigned(backlog) : 128); 2709 2710 if (ret == -1) 2711 err_return(errno, "listen()"); 2712 2713 ok_return(ucv_boolean_new(true)); 2714 } 2715 2716 /** 2717 * Accept a connection on a socket. 2718 * 2719 * This function accepts a connection on the socket. It extracts the first 2720 * connection request on the queue of pending connections, creates a new 2721 * connected socket, and returns a new socket handle referring to that socket. 2722 * The newly created socket is not in listening state and has no backlog. 2723 * 2724 * When a optional `address` dictionary is provided, it is populated with the 2725 * remote address details of the peer socket. 2726 * 2727 * The optional `flags` parameter is a bitwise-or-ed number of flags to modify 2728 * the behavior of accepted peer socket. Possible values are: 2729 * - `SOCK_CLOEXEC`: Enable close-on-exec semantics for the new socket. 2730 * - `SOCK_NONBLOCK`: Enable nonblocking mode for the new socket. 2731 * 2732 * Returns a socket handle representing the newly created peer socket of the 2733 * accepted connection. 2734 * 2735 * Returns `null` if an error occurred. 2736 * 2737 * @function module:socket.socket#accept 2738 * 2739 * @param {object} [address] 2740 * An optional dictionary to receive the address details of the peer socket. 2741 * See {@link module:socket.socket.SocketAddress|SocketAddress} for details. 2742 * 2743 * @param {number} [flags] 2744 * Optional flags to modify the behavior of the peer socket. 2745 * 2746 * @returns {?module:socket.socket} 2747 * 2748 * @example 2749 * const sock = socket.create(…); 2750 * sock.bind(…); 2751 * sock.listen(); 2752 * 2753 * const peerAddress = {}; 2754 * const newSocket = sock.accept(peerAddress, socket.SOCK_CLOEXEC); 2755 * if (newSocket) 2756 * print(`Accepted connection from: ${peerAddress}\n`); 2757 * else 2758 * print(`Failed to accept connection: ${sock.error()}\n`); 2759 */ 2760 static uc_value_t * 2761 uc_socket_inst_accept(uc_vm_t *vm, size_t nargs) 2762 { 2763 struct sockaddr_storage ss = { 0 }; 2764 int peerfd, sockfd, sockflags; 2765 uc_value_t *addrobj, *flags; 2766 socklen_t slen; 2767 2768 args_get(vm, nargs, &sockfd, 2769 "address", UC_OBJECT, true, &addrobj, 2770 "flags", UC_INTEGER, true, &flags); 2771 2772 slen = sizeof(ss); 2773 sockflags = flags ? ucv_to_integer(flags) : 0; 2774 2775 #ifdef __APPLE__ 2776 peerfd = accept(sockfd, (struct sockaddr *)&ss, &slen); 2777 2778 if (peerfd == -1) 2779 err_return(errno, "accept()"); 2780 2781 if (sockflags & SOCK_CLOEXEC) { 2782 if (fcntl(peerfd, F_SETFD, FD_CLOEXEC) == -1) { 2783 close(peerfd); 2784 err_return(errno, "fcntl(F_SETFD)"); 2785 } 2786 } 2787 2788 if (sockflags & SOCK_NONBLOCK) { 2789 sockflags = fcntl(peerfd, F_GETFL); 2790 2791 if (sockflags == -1) { 2792 close(peerfd); 2793 err_return(errno, "fcntl(F_GETFL)"); 2794 } 2795 2796 if (fcntl(peerfd, F_SETFL, sockflags | O_NONBLOCK) == -1) { 2797 close(peerfd); 2798 err_return(errno, "fcntl(F_SETFL)"); 2799 } 2800 } 2801 #else 2802 peerfd = accept4(sockfd, (struct sockaddr *)&ss, &slen, sockflags); 2803 2804 if (peerfd == -1) 2805 err_return(errno, "accept4()"); 2806 #endif 2807 2808 if (addrobj) 2809 sockaddr_to_uv(&ss, addrobj); 2810 2811 ok_return(ucv_socket_new(vm, peerfd)); 2812 } 2813 2814 /** 2815 * Shutdown part of a full-duplex connection. 2816 * 2817 * This function shuts down part of the full-duplex connection associated with 2818 * the socket handle. The `how` parameter specifies which half of the connection 2819 * to shut down. It can take one of the following constant values: 2820 * 2821 * - `SHUT_RD`: Disables further receive operations. 2822 * - `SHUT_WR`: Disables further send operations. 2823 * - `SHUT_RDWR`: Disables further send and receive operations. 2824 * 2825 * Returns `true` if the shutdown operation is successful. 2826 * Returns `null` if an error occurred. 2827 * 2828 * @function module:socket.socket#shutdown 2829 * 2830 * @param {number} how 2831 * Specifies which half of the connection to shut down. 2832 * It can be one of the following constant values: `SHUT_RD`, `SHUT_WR`, 2833 * or `SHUT_RDWR`. 2834 * 2835 * @returns {?boolean} 2836 * 2837 * @example 2838 * const sock = socket.create(…); 2839 * sock.connect(…); 2840 * // Perform data exchange… 2841 * 2842 * const success = sock.shutdown(socket.SHUT_WR); 2843 * if (success) 2844 * print(`Send operations on socket shut down successfully.\n`); 2845 * else 2846 * print(`Failed to shut down send operations: ${sock.error()}\n`); 2847 */ 2848 static uc_value_t * 2849 uc_socket_inst_shutdown(uc_vm_t *vm, size_t nargs) 2850 { 2851 uc_value_t *how; 2852 int sockfd, ret; 2853 2854 args_get(vm, nargs, &sockfd, 2855 "how", UC_INTEGER, true, &how); 2856 2857 ret = shutdown(sockfd, ucv_int64_get(how)); 2858 2859 if (ret == -1) 2860 err_return(errno, "shutdown()"); 2861 2862 ok_return(ucv_boolean_new(true)); 2863 } 2864 2865 /** 2866 * Represents a credentials information object returned by 2867 * {@link module:socket.socket#peercred|`peercred()`}. 2868 * 2869 * @typedef {Object} module:socket.socket.PeerCredentials 2870 * @property {number} uid 2871 * The effective user ID the remote socket endpoint. 2872 * 2873 * @property {number} gid 2874 * The effective group ID the remote socket endpoint. 2875 * 2876 * @property {number} pid 2877 * The ID of the process the remote socket endpoint belongs to. 2878 */ 2879 2880 /** 2881 * Retrieves the peer credentials. 2882 * 2883 * This function retrieves the remote uid, gid and pid of a connected UNIX 2884 * domain socket. 2885 * 2886 * Returns the remote credentials if the operation is successful. 2887 * Returns `null` on error. 2888 * 2889 * @function module:socket.socket#peercred 2890 * 2891 * @returns {?module:socket.socket.PeerCredentials} 2892 * 2893 * @example 2894 * const sock = socket.create(socket.AF_UNIX, …); 2895 * sock.connect(…); 2896 * 2897 * const peerCredentials = sock.peercred(); 2898 * if (peerCredentials) 2899 * print(`Peer credentials: ${peerCredentials}\n`); 2900 * else 2901 * print(`Failed to retrieve peer credentials: ${sock.error()}\n`); 2902 */ 2903 static uc_value_t * 2904 uc_socket_inst_peercred(uc_vm_t *vm, size_t nargs) 2905 { 2906 uc_value_t *rv = NULL; 2907 socklen_t optlen; 2908 int ret, sockfd; 2909 2910 args_get(vm, nargs, &sockfd); 2911 2912 #if defined(__linux__) 2913 struct ucred cred; 2914 2915 optlen = sizeof(cred); 2916 ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &optlen); 2917 2918 if (ret == -1) 2919 err_return(errno, "getsockopt()"); 2920 2921 if (optlen != sizeof(cred)) 2922 err_return(EINVAL, "Invalid credentials received"); 2923 2924 rv = ucv_object_new(vm); 2925 2926 ucv_object_add(rv, "uid", ucv_uint64_new(cred.uid)); 2927 ucv_object_add(rv, "gid", ucv_uint64_new(cred.gid)); 2928 ucv_object_add(rv, "pid", ucv_int64_new(cred.pid)); 2929 #elif defined(__APPLE__) 2930 struct xucred cred; 2931 pid_t pid; 2932 2933 optlen = sizeof(cred); 2934 ret = getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &cred, &optlen); 2935 2936 if (ret == -1) 2937 err_return(errno, "getsockopt(LOCAL_PEERCRED)"); 2938 2939 if (optlen != sizeof(cred) || cred.cr_version != XUCRED_VERSION) 2940 err_return(EINVAL, "Invalid credentials received"); 2941 2942 rv = ucv_object_new(vm); 2943 2944 ucv_object_add(rv, "uid", ucv_uint64_new(cred.cr_uid)); 2945 ucv_object_add(rv, "gid", ucv_uint64_new(cred.cr_gid)); 2946 2947 optlen = sizeof(pid); 2948 ret = getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERPID, &pid, &optlen); 2949 2950 if (ret == -1) { 2951 ucv_put(rv); 2952 err_return(errno, "getsockopt(LOCAL_PEERPID)"); 2953 } 2954 2955 ucv_object_add(rv, "pid", ucv_int64_new(pid)); 2956 #else 2957 err_return(ENOSYS, "Operation not supported on this system"); 2958 #endif 2959 2960 return rv; 2961 } 2962 2963 /** 2964 * Retrieves the remote address. 2965 * 2966 * This function retrieves the remote address of a connected socket. 2967 * 2968 * Returns the remote address if the operation is successful. 2969 * Returns `null` on error. 2970 * 2971 * @function module:socket.socket#peername 2972 * 2973 * @returns {?module:socket.socket.SocketAddress} 2974 * 2975 * @see {@link module:socket.socket#sockname|sockname()} 2976 * 2977 * @example 2978 * const sock = socket.create(…); 2979 * sock.connect(…); 2980 * 2981 * const peerAddress = sock.peername(); 2982 * if (peerAddress) 2983 * print(`Connected to ${peerAddress}\n`); 2984 * else 2985 * print(`Failed to retrieve peer address: ${sock.error()}\n`); 2986 */ 2987 static uc_value_t * 2988 uc_socket_inst_peername(uc_vm_t *vm, size_t nargs) 2989 { 2990 struct sockaddr_storage ss = { 0 }; 2991 uc_value_t *addr; 2992 socklen_t sslen; 2993 int sockfd, ret; 2994 2995 args_get(vm, nargs, &sockfd); 2996 2997 sslen = sizeof(ss); 2998 ret = getpeername(sockfd, (struct sockaddr *)&ss, &sslen); 2999 3000 if (ret == -1) 3001 err_return(errno, "getpeername()"); 3002 3003 addr = ucv_object_new(vm); 3004 sockaddr_to_uv(&ss, addr); 3005 3006 ok_return(addr); 3007 } 3008 3009 /** 3010 * Retrieves the local address. 3011 * 3012 * This function retrieves the local address of a bound or connected socket. 3013 * 3014 * Returns the local address if the operation is successful. 3015 * Returns `null` on error. 3016 * 3017 * @function module:socket.socket#sockname 3018 * 3019 * @returns {?module:socket.socket.SocketAddress} 3020 * 3021 * @see {@link module:socket.socket#peername|peername()} 3022 * 3023 * @example 3024 * const sock = socket.create(…); 3025 * sock.connect(…); 3026 * 3027 * const myAddress = sock.sockname(); 3028 * if (myAddress) 3029 * print(`My source IP address is ${myAddress}\n`); 3030 * else 3031 * print(`Failed to retrieve peer address: ${sock.error()}\n`); 3032 */ 3033 static uc_value_t * 3034 uc_socket_inst_sockname(uc_vm_t *vm, size_t nargs) 3035 { 3036 struct sockaddr_storage ss = { 0 }; 3037 uc_value_t *addr; 3038 socklen_t sslen; 3039 int sockfd, ret; 3040 3041 args_get(vm, nargs, &sockfd); 3042 3043 sslen = sizeof(ss); 3044 ret = getsockname(sockfd, (struct sockaddr *)&ss, &sslen); 3045 3046 if (ret == -1) 3047 err_return(errno, "getsockname()"); 3048 3049 addr = ucv_object_new(vm); 3050 sockaddr_to_uv(&ss, addr); 3051 3052 ok_return(addr); 3053 } 3054 3055 /** 3056 * Closes the socket. 3057 * 3058 * This function closes the socket, releasing its resources and terminating its 3059 * associated connections. 3060 * 3061 * Returns `true` if the socket was successfully closed. 3062 * Returns `null` on error. 3063 * 3064 * @function module:socket.socket#close 3065 * 3066 * @returns {?boolean} 3067 * 3068 * @example 3069 * const sock = socket.create(…); 3070 * sock.connect(…); 3071 * // Perform operations with the socket… 3072 * sock.close(); 3073 */ 3074 static uc_value_t * 3075 uc_socket_inst_close(uc_vm_t *vm, size_t nargs) 3076 { 3077 int *sockfd = uc_fn_this("socket"); 3078 3079 if (!sockfd || *sockfd == -1) 3080 err_return(EBADF, "Invalid socket context"); 3081 3082 if (!xclose(sockfd)) 3083 err_return(errno, "close()"); 3084 3085 ok_return(ucv_boolean_new(true)); 3086 } 3087 3088 static void 3089 close_socket(void *ud) 3090 { 3091 int fd = (intptr_t)ud; 3092 3093 if (fd != -1) 3094 close(fd); 3095 } 3096 3097 static const uc_function_list_t socket_fns[] = { 3098 { "connect", uc_socket_inst_connect }, 3099 { "bind", uc_socket_inst_bind }, 3100 { "listen", uc_socket_inst_listen }, 3101 { "accept", uc_socket_inst_accept }, 3102 { "send", uc_socket_inst_send }, 3103 { "recv", uc_socket_inst_recv }, 3104 { "setopt", uc_socket_inst_setopt }, 3105 { "getopt", uc_socket_inst_getopt }, 3106 { "fileno", uc_socket_inst_fileno }, 3107 { "shutdown", uc_socket_inst_shutdown }, 3108 { "peercred", uc_socket_inst_peercred }, 3109 { "peername", uc_socket_inst_peername }, 3110 { "sockname", uc_socket_inst_sockname }, 3111 { "close", uc_socket_inst_close }, 3112 { "error", uc_socket_error }, 3113 }; 3114 3115 static const uc_function_list_t global_fns[] = { 3116 { "sockaddr", uc_socket_sockaddr }, 3117 { "create", uc_socket_create }, 3118 { "nameinfo", uc_socket_nameinfo }, 3119 { "addrinfo", uc_socket_addrinfo }, 3120 { "poll", uc_socket_poll }, 3121 { "connect", uc_socket_connect }, 3122 { "listen", uc_socket_listen }, 3123 { "error", uc_socket_error }, 3124 }; 3125 3126 void uc_module_init(uc_vm_t *vm, uc_value_t *scope) 3127 { 3128 uc_function_list_register(scope, global_fns); 3129 3130 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x)) 3131 3132 /** 3133 * @typedef 3134 * @name Address Families 3135 * @description Constants representing address families and socket domains. 3136 * @property {number} AF_UNSPEC - Unspecified address family. 3137 * @property {number} AF_UNIX - UNIX domain sockets. 3138 * @property {number} AF_INET - IPv4 Internet protocols. 3139 * @property {number} AF_INET6 - IPv6 Internet protocols. 3140 * @property {number} AF_PACKET - Low-level packet interface. 3141 */ 3142 ADD_CONST(AF_UNSPEC); 3143 ADD_CONST(AF_UNIX); 3144 ADD_CONST(AF_INET); 3145 ADD_CONST(AF_INET6); 3146 #if defined(__linux__) 3147 ADD_CONST(AF_PACKET); 3148 #endif 3149 3150 /** 3151 * @typedef 3152 * @name Socket Types 3153 * @description 3154 * The `SOCK_*` type and flag constants are used by 3155 * {@link module:socket#create|create()} to specify the type of socket to 3156 * open. The {@link module:socket.socket#accept|accept()} function 3157 * recognizes the `SOCK_NONBLOCK` and `SOCK_CLOEXEC` flags and applies them 3158 * to accepted peer sockets. 3159 * @property {number} SOCK_STREAM - Provides sequenced, reliable, two-way, connection-based byte streams. 3160 * @property {number} SOCK_DGRAM - Supports datagrams (connectionless, unreliable messages of a fixed maximum length). 3161 * @property {number} SOCK_RAW - Provides raw network protocol access. 3162 * @property {number} SOCK_PACKET - Obsolete and should not be used. 3163 * @property {number} SOCK_NONBLOCK - Enables non-blocking operation. 3164 * @property {number} SOCK_CLOEXEC - Sets the close-on-exec flag on the new file descriptor. 3165 */ 3166 ADD_CONST(SOCK_STREAM); 3167 ADD_CONST(SOCK_DGRAM); 3168 ADD_CONST(SOCK_RAW); 3169 ADD_CONST(SOCK_NONBLOCK); 3170 ADD_CONST(SOCK_CLOEXEC); 3171 #if defined(__linux__) 3172 ADD_CONST(SOCK_PACKET); 3173 #endif 3174 3175 /** 3176 * @typedef 3177 * @name Message Flags 3178 * @description 3179 * The `MSG_*` flag constants are commonly used in conjunction with the 3180 * {@link module:socket.socket#send|send()} and 3181 * {@link module:socket.socket#recv|recv()} functions. 3182 * @property {number} MSG_CONFIRM - Confirm path validity. 3183 * @property {number} MSG_DONTROUTE - Send without using routing tables. 3184 * @property {number} MSG_DONTWAIT - Enables non-blocking operation. 3185 * @property {number} MSG_EOR - End of record. 3186 * @property {number} MSG_MORE - Sender will send more. 3187 * @property {number} MSG_NOSIGNAL - Do not generate SIGPIPE. 3188 * @property {number} MSG_OOB - Process out-of-band data. 3189 * @property {number} MSG_FASTOPEN - Send data in TCP SYN. 3190 * @property {number} MSG_CMSG_CLOEXEC - Sets the close-on-exec flag on the received file descriptor. 3191 * @property {number} MSG_ERRQUEUE - Receive errors from ICMP. 3192 * @property {number} MSG_PEEK - Peeks at incoming messages. 3193 * @property {number} MSG_TRUNC - Report if datagram truncation occurred. 3194 * @property {number} MSG_WAITALL - Wait for full message. 3195 */ 3196 ADD_CONST(MSG_DONTROUTE); 3197 ADD_CONST(MSG_DONTWAIT); 3198 ADD_CONST(MSG_EOR); 3199 ADD_CONST(MSG_NOSIGNAL); 3200 ADD_CONST(MSG_OOB); 3201 ADD_CONST(MSG_PEEK); 3202 ADD_CONST(MSG_TRUNC); 3203 ADD_CONST(MSG_WAITALL); 3204 #if defined(__linux__) 3205 ADD_CONST(MSG_CONFIRM); 3206 ADD_CONST(MSG_MORE); 3207 ADD_CONST(MSG_FASTOPEN); 3208 ADD_CONST(MSG_CMSG_CLOEXEC); 3209 ADD_CONST(MSG_ERRQUEUE); 3210 #endif 3211 3212 /** 3213 * @typedef 3214 * @name IP Protocol Constants 3215 * @description 3216 * The `IPPROTO_IP` constant specifies the IP protocol number and may be 3217 * passed as third argument to {@link module:socket#create|create()} as well 3218 * as *level* argument value to {@link module:socket.socket#getopt|getopt()} 3219 * and {@link module:socket.socket#setopt|setopt()}. 3220 * 3221 * The `IP_*` constants are option names recognized by 3222 * {@link module:socket.socket#getopt|getopt()} 3223 * and {@link module:socket.socket#setopt|setopt()}, in conjunction with 3224 * the `IPPROTO_IP` socket level. 3225 * @property {number} IPPROTO_IP - Dummy protocol for IP. 3226 * @property {number} IP_ADD_MEMBERSHIP - Add an IP group membership. 3227 * @property {number} IP_ADD_SOURCE_MEMBERSHIP - Add an IP group/source membership. 3228 * @property {number} IP_BIND_ADDRESS_NO_PORT - Bind to the device only. 3229 * @property {number} IP_BLOCK_SOURCE - Block IP group/source. 3230 * @property {number} IP_DROP_MEMBERSHIP - Drop an IP group membership. 3231 * @property {number} IP_DROP_SOURCE_MEMBERSHIP - Drop an IP group/source membership. 3232 * @property {number} IP_FREEBIND - Allow binding to an IP address not assigned to a network interface. 3233 * @property {number} IP_HDRINCL - Header is included with data. 3234 * @property {number} IP_MSFILTER - Filter IP multicast source memberships. 3235 * @property {number} IP_MTU - Path MTU discovery. 3236 * @property {number} IP_MTU_DISCOVER - Control Path MTU discovery. 3237 * @property {number} IP_MULTICAST_ALL - Receive all multicast packets. 3238 * @property {number} IP_MULTICAST_IF - Set outgoing interface for multicast packets. 3239 * @property {number} IP_MULTICAST_LOOP - Control multicast packet looping. 3240 * @property {number} IP_MULTICAST_TTL - Set time-to-live for outgoing multicast packets. 3241 * @property {number} IP_NODEFRAG - Don't fragment IP packets. 3242 * @property {number} IP_OPTIONS - Set/get IP options. 3243 * @property {number} IP_PASSSEC - Pass security information. 3244 * @property {number} IP_PKTINFO - Receive packet information. 3245 * @property {number} IP_RECVERR - Receive all ICMP errors. 3246 * @property {number} IP_RECVOPTS - Receive all IP options. 3247 * @property {number} IP_RECVORIGDSTADDR - Receive original destination address of the socket. 3248 * @property {number} IP_RECVTOS - Receive IP TOS. 3249 * @property {number} IP_RECVTTL - Receive IP TTL. 3250 * @property {number} IP_RETOPTS - Set/get IP options. 3251 * @property {number} IP_ROUTER_ALERT - Receive ICMP msgs generated by router. 3252 * @property {number} IP_TOS - IP type of service and precedence. 3253 * @property {number} IP_TRANSPARENT - Transparent proxy support. 3254 * @property {number} IP_TTL - IP time-to-live. 3255 * @property {number} IP_UNBLOCK_SOURCE - Unblock IP group/source. 3256 */ 3257 ADD_CONST(IPPROTO_IP); 3258 ADD_CONST(IP_ADD_MEMBERSHIP); 3259 ADD_CONST(IP_ADD_SOURCE_MEMBERSHIP); 3260 ADD_CONST(IP_BLOCK_SOURCE); 3261 ADD_CONST(IP_DROP_MEMBERSHIP); 3262 ADD_CONST(IP_DROP_SOURCE_MEMBERSHIP); 3263 ADD_CONST(IP_HDRINCL); 3264 ADD_CONST(IP_MSFILTER); 3265 ADD_CONST(IP_MULTICAST_IF); 3266 ADD_CONST(IP_MULTICAST_LOOP); 3267 ADD_CONST(IP_MULTICAST_TTL); 3268 ADD_CONST(IP_OPTIONS); 3269 ADD_CONST(IP_PKTINFO); 3270 ADD_CONST(IP_RECVOPTS); 3271 ADD_CONST(IP_RECVTOS); 3272 ADD_CONST(IP_RECVTTL); 3273 ADD_CONST(IP_RETOPTS); 3274 ADD_CONST(IP_TOS); 3275 ADD_CONST(IP_TTL); 3276 ADD_CONST(IP_UNBLOCK_SOURCE); 3277 #if defined(__linux__) 3278 ADD_CONST(IP_BIND_ADDRESS_NO_PORT); 3279 ADD_CONST(IP_FREEBIND); 3280 ADD_CONST(IP_MTU); 3281 ADD_CONST(IP_MTU_DISCOVER); 3282 ADD_CONST(IP_MULTICAST_ALL); 3283 ADD_CONST(IP_NODEFRAG); 3284 ADD_CONST(IP_PASSSEC); 3285 ADD_CONST(IP_RECVERR); 3286 ADD_CONST(IP_RECVORIGDSTADDR); 3287 ADD_CONST(IP_ROUTER_ALERT); 3288 ADD_CONST(IP_TRANSPARENT); 3289 #endif 3290 3291 /** 3292 * @typedef 3293 * @name Socket Option Constants 3294 * @description 3295 * The `SOL_SOCKET` constant is passed as *level* argument to the 3296 * {@link module:socket.socket#getopt|getopt()} and 3297 * {@link module:socket.socket#setopt|setopt()} functions in order to set 3298 * or retrieve generic socket option values. 3299 * 3300 * The `SO_*` constants are passed as *option* argument in conjunction with 3301 * the `SOL_SOCKET` level to specify the specific option to get or set on 3302 * the socket. 3303 * @property {number} SOL_SOCKET - Socket options at the socket API level. 3304 * @property {number} SO_ACCEPTCONN - Reports whether socket listening is enabled. 3305 * @property {number} SO_ATTACH_BPF - Attach BPF program to socket. 3306 * @property {number} SO_ATTACH_FILTER - Attach a socket filter. 3307 * @property {number} SO_ATTACH_REUSEPORT_CBPF - Attach BPF program for cgroup and skb program reuseport hook. 3308 * @property {number} SO_ATTACH_REUSEPORT_EBPF - Attach eBPF program for cgroup and skb program reuseport hook. 3309 * @property {number} SO_BINDTODEVICE - Bind socket to a specific interface. 3310 * @property {number} SO_BROADCAST - Allow transmission of broadcast messages. 3311 * @property {number} SO_BUSY_POLL - Enable busy polling. 3312 * @property {number} SO_DEBUG - Enable socket debugging. 3313 * @property {number} SO_DETACH_BPF - Detach BPF program from socket. 3314 * @property {number} SO_DETACH_FILTER - Detach a socket filter. 3315 * @property {number} SO_DOMAIN - Retrieves the domain of the socket. 3316 * @property {number} SO_DONTROUTE - Send packets directly without routing. 3317 * @property {number} SO_ERROR - Retrieves and clears the error status for the socket. 3318 * @property {number} SO_INCOMING_CPU - Retrieves the CPU number on which the last packet was received. 3319 * @property {number} SO_INCOMING_NAPI_ID - Retrieves the NAPI ID of the device. 3320 * @property {number} SO_KEEPALIVE - Enable keep-alive packets. 3321 * @property {number} SO_LINGER - Set linger on close. 3322 * @property {number} SO_LOCK_FILTER - Set or get the socket filter lock state. 3323 * @property {number} SO_MARK - Set the mark for packets sent through the socket. 3324 * @property {number} SO_OOBINLINE - Enables out-of-band data to be received in the normal data stream. 3325 * @property {number} SO_PASSCRED - Enable the receiving of SCM_CREDENTIALS control messages. 3326 * @property {number} SO_PASSSEC - Enable the receiving of security context. 3327 * @property {number} SO_PEEK_OFF - Returns the number of bytes in the receive buffer without removing them. 3328 * @property {number} SO_PEERCRED - Retrieves the credentials of the foreign peer. 3329 * @property {number} SO_PEERSEC - Retrieves the security context of the foreign peer. 3330 * @property {number} SO_PRIORITY - Set the protocol-defined priority for all packets. 3331 * @property {number} SO_PROTOCOL - Retrieves the protocol number. 3332 * @property {number} SO_RCVBUF - Set the receive buffer size. 3333 * @property {number} SO_RCVBUFFORCE - Set the receive buffer size forcefully. 3334 * @property {number} SO_RCVLOWAT - Set the minimum number of bytes to process for input operations. 3335 * @property {number} SO_RCVTIMEO - Set the timeout for receiving data. 3336 * @property {number} SO_REUSEADDR - Allow the socket to be bound to an address that is already in use. 3337 * @property {number} SO_REUSEPORT - Enable duplicate address and port bindings. 3338 * @property {number} SO_RXQ_OVFL - Reports if the receive queue has overflown. 3339 * @property {number} SO_SNDBUF - Set the send buffer size. 3340 * @property {number} SO_SNDBUFFORCE - Set the send buffer size forcefully. 3341 * @property {number} SO_SNDLOWAT - Set the minimum number of bytes to process for output operations. 3342 * @property {number} SO_SNDTIMEO - Set the timeout for sending data. 3343 * @property {number} SO_TIMESTAMP - Enable receiving of timestamps. 3344 * @property {number} SO_TIMESTAMPNS - Enable receiving of nanosecond timestamps. 3345 * @property {number} SO_TYPE - Retrieves the type of the socket (e.g., SOCK_STREAM). 3346 */ 3347 ADD_CONST(SOL_SOCKET); 3348 ADD_CONST(SO_ACCEPTCONN); 3349 ADD_CONST(SO_BROADCAST); 3350 ADD_CONST(SO_DEBUG); 3351 ADD_CONST(SO_DONTROUTE); 3352 ADD_CONST(SO_ERROR); 3353 ADD_CONST(SO_KEEPALIVE); 3354 ADD_CONST(SO_LINGER); 3355 ADD_CONST(SO_OOBINLINE); 3356 ADD_CONST(SO_RCVBUF); 3357 ADD_CONST(SO_RCVLOWAT); 3358 ADD_CONST(SO_RCVTIMEO); 3359 ADD_CONST(SO_REUSEADDR); 3360 ADD_CONST(SO_REUSEPORT); 3361 ADD_CONST(SO_SNDBUF); 3362 ADD_CONST(SO_SNDLOWAT); 3363 ADD_CONST(SO_SNDTIMEO); 3364 ADD_CONST(SO_TIMESTAMP); 3365 ADD_CONST(SO_TYPE); 3366 #if defined(__linux__) 3367 ADD_CONST(SO_ATTACH_BPF); 3368 ADD_CONST(SO_ATTACH_FILTER); 3369 ADD_CONST(SO_ATTACH_REUSEPORT_CBPF); 3370 ADD_CONST(SO_ATTACH_REUSEPORT_EBPF); 3371 ADD_CONST(SO_BINDTODEVICE); 3372 ADD_CONST(SO_BUSY_POLL); 3373 ADD_CONST(SO_DETACH_BPF); 3374 ADD_CONST(SO_DETACH_FILTER); 3375 ADD_CONST(SO_DOMAIN); 3376 ADD_CONST(SO_INCOMING_CPU); 3377 ADD_CONST(SO_INCOMING_NAPI_ID); 3378 ADD_CONST(SO_LOCK_FILTER); 3379 ADD_CONST(SO_MARK); 3380 ADD_CONST(SO_PASSCRED); 3381 ADD_CONST(SO_PASSSEC); 3382 ADD_CONST(SO_PEEK_OFF); 3383 ADD_CONST(SO_PEERCRED); 3384 ADD_CONST(SO_PEERSEC); 3385 ADD_CONST(SO_PRIORITY); 3386 ADD_CONST(SO_PROTOCOL); 3387 ADD_CONST(SO_RCVBUFFORCE); 3388 ADD_CONST(SO_RXQ_OVFL); 3389 ADD_CONST(SO_SNDBUFFORCE); 3390 ADD_CONST(SO_TIMESTAMPNS); 3391 #endif 3392 3393 /** 3394 * @typedef 3395 * @name TCP Protocol Constants 3396 * @description 3397 * The `IPPROTO_TCP` constant specifies the TCP protocol number and may be 3398 * passed as third argument to {@link module:socket#create|create()} as well 3399 * as *level* argument value to {@link module:socket.socket#getopt|getopt()} 3400 * and {@link module:socket.socket#setopt|setopt()}. 3401 * 3402 * The `TCP_*` constants are *option* argument values recognized by 3403 * {@link module:socket.socket#getopt|getopt()} 3404 * and {@link module:socket.socket#setopt|setopt()}, in conjunction with 3405 * the `IPPROTO_TCP` socket level. 3406 * @property {number} IPPROTO_TCP - TCP protocol. 3407 * @property {number} TCP_CONGESTION - Set the congestion control algorithm. 3408 * @property {number} TCP_CORK - Delay packet transmission until full-sized packets are available. 3409 * @property {number} TCP_DEFER_ACCEPT - Delay accepting incoming connections until data arrives. 3410 * @property {number} TCP_FASTOPEN - Enable TCP Fast Open. 3411 * @property {number} TCP_FASTOPEN_CONNECT - Perform TFO connect. 3412 * @property {number} TCP_INFO - Retrieve TCP statistics. 3413 * @property {number} TCP_KEEPCNT - Number of keepalive probes. 3414 * @property {number} TCP_KEEPIDLE - Time before keepalive probes begin. 3415 * @property {number} TCP_KEEPINTVL - Interval between keepalive probes. 3416 * @property {number} TCP_LINGER2 - Lifetime of orphaned FIN_WAIT2 state sockets. 3417 * @property {number} TCP_MAXSEG - Maximum segment size. 3418 * @property {number} TCP_NODELAY - Disable Nagle's algorithm. 3419 * @property {number} TCP_QUICKACK - Enable quick ACKs. 3420 * @property {number} TCP_SYNCNT - Number of SYN retransmits. 3421 * @property {number} TCP_USER_TIMEOUT - Set the user timeout. 3422 * @property {number} TCP_WINDOW_CLAMP - Set the maximum window. 3423 */ 3424 ADD_CONST(IPPROTO_TCP); 3425 ADD_CONST(TCP_FASTOPEN); 3426 ADD_CONST(TCP_KEEPCNT); 3427 ADD_CONST(TCP_KEEPINTVL); 3428 ADD_CONST(TCP_MAXSEG); 3429 ADD_CONST(TCP_NODELAY); 3430 #if defined(__linux__) 3431 ADD_CONST(TCP_CONGESTION); 3432 ADD_CONST(TCP_CORK); 3433 ADD_CONST(TCP_DEFER_ACCEPT); 3434 ADD_CONST(TCP_FASTOPEN_CONNECT); 3435 ADD_CONST(TCP_INFO); 3436 ADD_CONST(TCP_KEEPIDLE); 3437 ADD_CONST(TCP_LINGER2); 3438 ADD_CONST(TCP_QUICKACK); 3439 ADD_CONST(TCP_SYNCNT); 3440 ADD_CONST(TCP_USER_TIMEOUT); 3441 ADD_CONST(TCP_WINDOW_CLAMP); 3442 #endif 3443 3444 /** 3445 * @typedef 3446 * @name UDP Protocol Constants 3447 * @description 3448 * The `IPPROTO_UDP` constant specifies the UDP protocol number and may be 3449 * passed as third argument to {@link module:socket#create|create()} as well 3450 * as *level* argument value to {@link module:socket.socket#getopt|getopt()} 3451 * and {@link module:socket.socket#setopt|setopt()}. 3452 * 3453 * The `UDP_*` constants are *option* argument values recognized by 3454 * {@link module:socket.socket#getopt|getopt()} 3455 * and {@link module:socket.socket#setopt|setopt()}, in conjunction with 3456 * the `IPPROTO_UDP` socket level. 3457 * @property {number} IPPROTO_UDP - UDP protocol. 3458 * @property {number} UDP_CORK - Cork data until flush. 3459 */ 3460 ADD_CONST(IPPROTO_UDP); 3461 #if defined(__linux__) 3462 ADD_CONST(UDP_CORK); 3463 #endif 3464 3465 /** 3466 * @typedef 3467 * @name Shutdown Constants 3468 * @description 3469 * The `SHUT_*` constants are passed as argument to the 3470 * {@link module:socket.socket#shutdown|shutdown()} function to specify 3471 * which direction of a full duplex connection to shut down. 3472 * @property {number} SHUT_RD - Disallow further receptions. 3473 * @property {number} SHUT_WR - Disallow further transmissions. 3474 * @property {number} SHUT_RDWR - Disallow further receptions and transmissions. 3475 */ 3476 ADD_CONST(SHUT_RD); 3477 ADD_CONST(SHUT_WR); 3478 ADD_CONST(SHUT_RDWR); 3479 3480 /** 3481 * @typedef 3482 * @name Address Info Flags 3483 * @description 3484 * The `AI_*` flags may be passed as bitwise OR-ed number in the *flags* 3485 * property of the *hints* dictionary argument of 3486 * {@link module:socket#addrinfo|addrinfo()}. 3487 * @property {number} AI_ADDRCONFIG - Address configuration flag. 3488 * @property {number} AI_ALL - Return IPv4 and IPv6 socket addresses. 3489 * @property {number} AI_CANONIDN - Canonicalize using the IDNA standard. 3490 * @property {number} AI_CANONNAME - Fill in the canonical name field. 3491 * @property {number} AI_IDN - Enable IDN encoding. 3492 * @property {number} AI_NUMERICHOST - Prevent hostname resolution. 3493 * @property {number} AI_NUMERICSERV - Prevent service name resolution. 3494 * @property {number} AI_PASSIVE - Use passive socket. 3495 * @property {number} AI_V4MAPPED - Map IPv6 addresses to IPv4-mapped format. 3496 */ 3497 ADD_CONST(AI_ADDRCONFIG); 3498 ADD_CONST(AI_ALL); 3499 ADD_CONST(AI_CANONIDN); 3500 ADD_CONST(AI_CANONNAME); 3501 ADD_CONST(AI_IDN); 3502 ADD_CONST(AI_NUMERICHOST); 3503 ADD_CONST(AI_NUMERICSERV); 3504 ADD_CONST(AI_PASSIVE); 3505 ADD_CONST(AI_V4MAPPED); 3506 3507 /** 3508 * @typedef 3509 * @name Name Info Constants 3510 * @description 3511 * The `NI_*` flags may be passed as bitwise OR-ed number via the *flags* 3512 * argument of {@link module:socket#nameinfo|nameinfo()}. 3513 * @property {number} NI_DGRAM - Datagram socket type. 3514 * @property {number} NI_IDN - Enable IDN encoding. 3515 * @property {number} NI_NAMEREQD - Hostname resolution required. 3516 * @property {number} NI_NOFQDN - Do not force fully qualified domain name. 3517 * @property {number} NI_NUMERICHOST - Return numeric form of the hostname. 3518 * @property {number} NI_NUMERICSERV - Return numeric form of the service name. 3519 */ 3520 ADD_CONST(NI_DGRAM); 3521 ADD_CONST(NI_IDN); 3522 ADD_CONST(NI_MAXHOST); 3523 ADD_CONST(NI_MAXSERV); 3524 ADD_CONST(NI_NAMEREQD); 3525 ADD_CONST(NI_NOFQDN); 3526 ADD_CONST(NI_NUMERICHOST); 3527 ADD_CONST(NI_NUMERICSERV); 3528 3529 /** 3530 * @typedef 3531 * @name Poll Event Constants 3532 * @description 3533 * The following constants represent event types for polling operations and 3534 * are set or returned as part of a 3535 * {@link module:socket.PollSpec|PollSpec} tuple by the 3536 * {@link module:socket#poll|poll()} function. When passed via an argument 3537 * PollSpec to `poll()`, they specify the I/O events to watch for on the 3538 * corresponding handle. When appearing in a PollSpec returned by `poll()`, 3539 * they specify the I/O events that occurred on a watched handle. 3540 * @property {number} POLLIN - Data available to read. 3541 * @property {number} POLLPRI - Priority data available to read. 3542 * @property {number} POLLOUT - Writable data available. 3543 * @property {number} POLLERR - Error condition. 3544 * @property {number} POLLHUP - Hang up. 3545 * @property {number} POLLNVAL - Invalid request. 3546 * @property {number} POLLRDHUP - Peer closed or shutdown writing. 3547 */ 3548 ADD_CONST(POLLIN); 3549 ADD_CONST(POLLPRI); 3550 ADD_CONST(POLLOUT); 3551 ADD_CONST(POLLERR); 3552 ADD_CONST(POLLHUP); 3553 ADD_CONST(POLLNVAL); 3554 #if defined(__linux__) 3555 ADD_CONST(POLLRDHUP); 3556 #endif 3557 3558 uc_type_declare(vm, "socket", socket_fns, close_socket); 3559 } 3560
This page was automatically generated by LXR 0.3.1. • OpenWrt