MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1065 lines 37 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <stdbool.h> 4#include <stdint.h> 5#include <stdlib.h> 6#include <string.h> 7 8#ifdef _WIN32 9#include <winsock2.h> 10#include <ws2tcpip.h> 11#else 12#include <arpa/inet.h> 13#endif 14 15#include "ant.h" 16#include "ptr.h" 17#include "errors.h" 18#include "internal.h" 19 20#include "gc/roots.h" 21#include "gc/modules.h" 22#include "net/listener.h" 23#include "silver/engine.h" 24 25#include "modules/buffer.h" 26#include "modules/events.h" 27#include "modules/net.h" 28#include "modules/symbol.h" 29 30typedef struct net_server_s net_server_t; 31typedef struct net_socket_s net_socket_t; 32 33typedef struct net_listen_args_s net_listen_args_t; 34typedef struct net_write_args_s net_write_args_t; 35 36struct net_socket_s { 37 ant_t *js; 38 ant_value_t obj; 39 ant_conn_t *conn; 40 net_server_t *server; 41 ant_value_t encoding; 42 struct net_socket_s *next_active; 43 struct net_socket_s *next_in_server; 44 bool allow_half_open; 45 bool destroyed; 46 bool had_error; 47}; 48 49struct net_server_s { 50 ant_t *js; 51 ant_value_t obj; 52 ant_listener_t listener; 53 net_socket_t *sockets; 54 struct net_server_s *next_active; 55 char *host; 56 char *path; 57 int port; 58 int backlog; 59 int max_connections; 60 bool listening; 61 bool closing; 62 bool allow_half_open; 63 bool pause_on_connect; 64 bool no_delay; 65 bool keep_alive; 66 unsigned int keep_alive_initial_delay_secs; 67}; 68 69struct net_listen_args_s { 70 const char *host; 71 const char *path; 72 int port; 73 int backlog; 74 ant_value_t callback; 75 ant_value_t error; 76}; 77 78struct net_write_args_s { 79 const uint8_t *bytes; 80 size_t len; 81 ant_value_t callback; 82 ant_value_t error; 83}; 84 85static ant_value_t g_net_server_proto = 0; 86static ant_value_t g_net_socket_proto = 0; 87static ant_value_t g_net_server_ctor = 0; 88static ant_value_t g_net_socket_ctor = 0; 89 90static net_server_t *g_active_servers = NULL; 91static net_socket_t *g_active_sockets = NULL; 92 93static bool g_default_auto_select_family = true; 94static double g_default_auto_select_family_attempt_timeout = 250.0; 95 96enum { 97 NET_SERVER_NATIVE_TAG = 0x4e455453u, // NETS 98 NET_SOCKET_NATIVE_TAG = 0x4e45544bu, // NETK 99}; 100 101static ant_value_t net_not_implemented(ant_t *js, const char *what); 102 103static net_server_t *net_server_data(ant_value_t value) { 104 if (!js_check_native_tag(value, NET_SERVER_NATIVE_TAG)) return NULL; 105 return (net_server_t *)js_get_native_ptr(value); 106} 107 108static net_socket_t *net_socket_data(ant_value_t value) { 109 if (!js_check_native_tag(value, NET_SOCKET_NATIVE_TAG)) return NULL; 110 return (net_socket_t *)js_get_native_ptr(value); 111} 112 113static void net_add_active_server(net_server_t *server) { 114 server->next_active = g_active_servers; 115 g_active_servers = server; 116} 117 118static void net_remove_active_server(net_server_t *server) { 119 net_server_t **it = NULL; 120 for (it = &g_active_servers; *it; it = &(*it)->next_active) { 121 if (*it == server) { 122 *it = server->next_active; 123 server->next_active = NULL; 124 return; 125 }} 126} 127 128static void net_add_active_socket(net_socket_t *socket) { 129 socket->next_active = g_active_sockets; 130 g_active_sockets = socket; 131} 132 133static void net_remove_active_socket(net_socket_t *socket) { 134 net_socket_t **it = NULL; 135 for (it = &g_active_sockets; *it; it = &(*it)->next_active) { 136 if (*it == socket) { 137 *it = socket->next_active; 138 socket->next_active = NULL; 139 return; 140 }} 141} 142 143static ant_value_t net_call_value( 144 ant_t *js, 145 ant_value_t fn, 146 ant_value_t this_val, 147 ant_value_t *args, 148 int nargs 149) { 150 ant_value_t saved_this = js->this_val; 151 ant_value_t result = js_mkundef(); 152 153 js->this_val = this_val; 154 if (vtype(fn) == T_CFUNC) result = js_as_cfunc(fn)(js, args, nargs); 155 else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false); 156 js->this_val = saved_this; 157 return result; 158} 159 160static bool net_emit(ant_t *js, ant_value_t target, const char *event, ant_value_t *args, int nargs) { 161 return eventemitter_emit_args(js, target, event, args, nargs); 162} 163 164static bool net_add_listener( 165 ant_t *js, 166 ant_value_t target, 167 const char *event, 168 ant_value_t listener, 169 bool once 170) { 171 return eventemitter_add_listener(js, target, event, listener, once); 172} 173 174static net_server_t *net_require_server(ant_t *js, ant_value_t this_val) { 175 net_server_t *server = net_server_data(this_val); 176 if (!server) { 177 js->thrown_exists = true; 178 js->thrown_value = js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.Server"); 179 return NULL; 180 } 181 return server; 182} 183 184static net_socket_t *net_require_socket(ant_t *js, ant_value_t this_val) { 185 net_socket_t *socket = net_socket_data(this_val); 186 if (!socket) { 187 js->thrown_exists = true; 188 js->thrown_value = js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.Socket"); 189 return NULL; 190 } 191 return socket; 192} 193 194static bool net_parse_write_args(ant_t *js, ant_value_t *args, int nargs, net_write_args_t *out) { 195 ant_value_t value = 0; 196 197 if (!out) return false; 198 memset(out, 0, sizeof(*out)); 199 out->callback = js_mkundef(); 200 out->error = js_mkundef(); 201 202 if (nargs < 1 || vtype(args[0]) == T_UNDEF || vtype(args[0]) == T_NULL) return true; 203 value = args[0]; 204 205 if (!buffer_source_get_bytes(js, value, &out->bytes, &out->len)) { 206 size_t slen = 0; 207 ant_value_t str_val = js_tostring_val(js, value); 208 const char *str = NULL; 209 210 if (is_err(str_val)) { 211 out->error = str_val; 212 return false; 213 } 214 215 str = js_getstr(js, str_val, &slen); 216 if (!str) { 217 out->error = js_mkerr_typed(js, JS_ERR_TYPE, "Invalid socket write data"); 218 return false; 219 } 220 221 out->bytes = (const uint8_t *)str; 222 out->len = slen; 223 } 224 225 if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; 226 else if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; 227 return true; 228} 229 230static bool net_parse_listen_args(ant_t *js, ant_value_t *args, int nargs, net_listen_args_t *out) { 231 if (!out) return false; 232 233 memset(out, 0, sizeof(*out)); 234 out->host = "0.0.0.0"; 235 out->backlog = 511; 236 out->callback = js_mkundef(); 237 out->error = js_mkundef(); 238 239 if (nargs == 0) return true; 240 241 if (vtype(args[0]) == T_NUM) { 242 out->port = (int)js_getnum(args[0]); 243 if (nargs > 1 && vtype(args[1]) == T_STR) { 244 size_t len = 0; 245 out->host = js_getstr(js, args[1], &len); 246 } 247 if (nargs > 2 && vtype(args[2]) == T_NUM) out->backlog = (int)js_getnum(args[2]); 248 if (nargs > 3 && is_callable(args[3])) out->callback = args[3]; 249 else if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; 250 else if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; 251 return true; 252 } 253 254 if (vtype(args[0]) == T_OBJ) { 255 ant_value_t value = js_get(js, args[0], "path"); 256 if (vtype(value) == T_STR) { 257 out->path = js_getstr(js, value, NULL); 258 } 259 260 value = js_get(js, args[0], "port"); 261 if (vtype(value) == T_NUM) out->port = (int)js_getnum(value); 262 value = js_get(js, args[0], "host"); 263 if (vtype(value) == T_STR) { 264 size_t len = 0; 265 out->host = js_getstr(js, value, &len); 266 } 267 268 value = js_get(js, args[0], "backlog"); 269 if (vtype(value) == T_NUM) out->backlog = (int)js_getnum(value); 270 if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; 271 272 return true; 273 } 274 275 if (vtype(args[0]) == T_STR) { 276 out->path = js_getstr(js, args[0], NULL); 277 if (nargs > 1 && vtype(args[1]) == T_NUM) out->backlog = (int)js_getnum(args[1]); 278 if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; 279 else if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; 280 return true; 281 } 282 283 if (is_callable(args[0])) { 284 out->callback = args[0]; 285 return true; 286 } 287 288 return true; 289} 290 291static ant_value_t net_make_buffer_chunk(ant_t *js, const char *data, size_t len) { 292 ArrayBufferData *ab = create_array_buffer_data(len); 293 if (!ab) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 294 if (len > 0 && data) memcpy(ab->data, data, len); 295 return create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, len, "Buffer"); 296} 297 298static void net_socket_sync_state(net_socket_t *socket) { 299 ant_value_t obj = 0; 300 const char *ready_state = "open"; 301 302 if (!socket) return; 303 obj = socket->obj; 304 if (!is_object_type(obj)) return; 305 306 if (socket->destroyed) ready_state = "closed"; 307 js_set(socket->js, obj, "destroyed", js_bool(socket->destroyed)); 308 js_set(socket->js, obj, "pending", js_bool(socket->conn == NULL && !socket->destroyed)); 309 js_set(socket->js, obj, "connecting", js_false); 310 js_set(socket->js, obj, "readyState", js_mkstr(socket->js, ready_state, strlen(ready_state))); 311 js_set(socket->js, obj, "bytesRead", js_mknum((double)(socket->conn ? ant_conn_bytes_read(socket->conn) : 0))); 312 js_set(socket->js, obj, "bytesWritten", js_mknum((double)(socket->conn ? ant_conn_bytes_written(socket->conn) : 0))); 313 js_set(socket->js, obj, "timeout", js_mknum((double)(socket->conn ? ant_conn_timeout_ms(socket->conn) : 0))); 314} 315 316static void net_server_sync_state(net_server_t *server) { 317 if (!server || !is_object_type(server->obj)) return; 318 js_set(server->js, server->obj, "listening", js_bool(server->listening)); 319 js_set(server->js, server->obj, "maxConnections", js_mknum((double)server->max_connections)); 320 js_set(server->js, server->obj, "dropMaxConnection", js_false); 321} 322 323static int net_server_socket_count(net_server_t *server) { 324 int count = 0; 325 net_socket_t *socket = NULL; 326 327 for (socket = server ? server->sockets : NULL; socket; socket = socket->next_in_server) 328 count++; 329 return count; 330} 331 332static void net_server_maybe_finish_close(net_server_t *server) { 333 if (!server || !server->closing) return; 334 if (!ant_listener_is_closed(&server->listener)) return; 335 if (server->sockets) return; 336 337 server->closing = false; 338 server->listening = false; 339 net_server_sync_state(server); 340 net_emit(server->js, server->obj, "close", NULL, 0); 341 net_remove_active_server(server); 342} 343 344static void net_socket_detach(net_socket_t *socket) { 345 if (!socket) return; 346 347 if (socket->server) { 348 net_socket_t **it = NULL; 349 for (it = &socket->server->sockets; *it; it = &(*it)->next_in_server) { 350 if (*it == socket) { 351 *it = socket->next_in_server; 352 break; 353 } 354 } 355 socket->next_in_server = NULL; 356 } 357 358 net_remove_active_socket(socket); 359 if (is_object_type(socket->obj)) { 360 js_set_native_ptr(socket->obj, NULL); 361 js_set_native_tag(socket->obj, 0); 362 } 363 net_server_maybe_finish_close(socket->server); 364 free(socket); 365} 366 367static void net_socket_emit_error(net_socket_t *socket, const char *message) { 368 ant_value_t arg = js_mkerr_typed(socket->js, JS_ERR_TYPE, "%s", message); 369 socket->had_error = true; 370 net_emit(socket->js, socket->obj, "error", &arg, 1); 371} 372 373static net_socket_t *net_socket_create(ant_t *js, bool allow_half_open) { 374 ant_value_t obj = js_mkobj(js); 375 ant_value_t proto = js_instance_proto_from_new_target(js, g_net_socket_proto); 376 net_socket_t *socket = calloc(1, sizeof(*socket)); 377 378 if (!socket) return NULL; 379 if (is_object_type(proto)) js_set_proto_init(obj, proto); 380 381 socket->js = js; 382 socket->obj = obj; 383 socket->encoding = js_mkundef(); 384 socket->allow_half_open = allow_half_open; 385 386 js_set_native_ptr(obj, socket); 387 js_set_native_tag(obj, NET_SOCKET_NATIVE_TAG); 388 js_set(js, obj, "remoteAddress", js_mkundef()); 389 js_set(js, obj, "remotePort", js_mkundef()); 390 js_set(js, obj, "remoteFamily", js_mkundef()); 391 js_set(js, obj, "localAddress", js_mkundef()); 392 js_set(js, obj, "localPort", js_mkundef()); 393 js_set(js, obj, "localFamily", js_mkundef()); 394 net_socket_sync_state(socket); 395 396 return socket; 397} 398 399static void net_socket_attach_conn(net_socket_t *socket, ant_conn_t *conn) { 400 if (!socket || !conn) return; 401 402 socket->conn = conn; 403 ant_conn_set_user_data(conn, socket); 404 if (ant_conn_has_remote_addr(conn)) { 405 js_set(socket->js, socket->obj, "remoteAddress", js_mkstr(socket->js, ant_conn_remote_addr(conn), strlen(ant_conn_remote_addr(conn)))); 406 js_set(socket->js, socket->obj, "remotePort", js_mknum(ant_conn_remote_port(conn))); 407 js_set(socket->js, socket->obj, "remoteFamily", js_mkstr(socket->js, ant_conn_remote_family(conn), strlen(ant_conn_remote_family(conn)))); 408 } 409 if (ant_conn_has_local_addr(conn)) { 410 js_set(socket->js, socket->obj, "localAddress", js_mkstr(socket->js, ant_conn_local_addr(conn), strlen(ant_conn_local_addr(conn)))); 411 js_set(socket->js, socket->obj, "localPort", js_mknum(ant_conn_local_port(conn))); 412 js_set(socket->js, socket->obj, "localFamily", js_mkstr(socket->js, ant_conn_local_family(conn), strlen(ant_conn_local_family(conn)))); 413 } 414 net_socket_sync_state(socket); 415} 416 417static net_server_t *net_server_create(ant_t *js) { 418 ant_value_t obj = js_mkobj(js); 419 ant_value_t proto = js_instance_proto_from_new_target(js, g_net_server_proto); 420 net_server_t *server = calloc(1, sizeof(*server)); 421 422 if (!server) return NULL; 423 if (is_object_type(proto)) js_set_proto_init(obj, proto); 424 425 server->js = js; 426 server->obj = obj; 427 server->host = strdup("0.0.0.0"); 428 server->backlog = 511; 429 if (!server->host) { 430 free(server); 431 return NULL; 432 } 433 434 js_set_native_ptr(obj, server); 435 js_set_native_tag(obj, NET_SERVER_NATIVE_TAG); 436 net_server_sync_state(server); 437 return server; 438} 439 440static ant_value_t net_not_implemented(ant_t *js, const char *what) { 441 return js_mkerr_typed(js, JS_ERR_TYPE, "%s is not implemented yet", what); 442} 443 444static ant_value_t net_isIP(ant_t *js, ant_value_t *args, int nargs) { 445 size_t len = 0; 446 const char *host = NULL; 447 struct in_addr addr4; 448 struct in6_addr addr6; 449 450 if (nargs < 1) return js_mknum(0); 451 host = js_getstr(js, args[0], &len); 452 if (!host) return js_mknum(0); 453 454 if (inet_pton(AF_INET, host, &addr4) == 1) return js_mknum(4); 455 if (inet_pton(AF_INET6, host, &addr6) == 1) return js_mknum(6); 456 return js_mknum(0); 457} 458 459static ant_value_t net_isIPv4(ant_t *js, ant_value_t *args, int nargs) { 460 if (js_getnum(net_isIP(js, args, nargs)) == 4.0) return js_true; 461 return js_false; 462} 463 464static ant_value_t net_isIPv6(ant_t *js, ant_value_t *args, int nargs) { 465 if (js_getnum(net_isIP(js, args, nargs)) == 6.0) return js_true; 466 return js_false; 467} 468 469static void net_server_apply_options(ant_t *js, net_server_t *server, ant_value_t options) { 470 ant_value_t value = 0; 471 472 if (!server || vtype(options) != T_OBJ) return; 473 474 value = js_get(js, options, "allowHalfOpen"); 475 if (vtype(value) != T_UNDEF) server->allow_half_open = js_truthy(js, value); 476 477 value = js_get(js, options, "pauseOnConnect"); 478 if (vtype(value) != T_UNDEF) server->pause_on_connect = js_truthy(js, value); 479 480 value = js_get(js, options, "noDelay"); 481 if (vtype(value) != T_UNDEF) server->no_delay = js_truthy(js, value); 482 483 value = js_get(js, options, "keepAlive"); 484 if (vtype(value) != T_UNDEF) server->keep_alive = js_truthy(js, value); 485 486 value = js_get(js, options, "keepAliveInitialDelay"); 487 if (vtype(value) == T_NUM && js_getnum(value) > 0) 488 server->keep_alive_initial_delay_secs = (unsigned int)(js_getnum(value) / 1000.0); 489 490 value = js_get(js, options, "backlog"); 491 if (vtype(value) == T_NUM && js_getnum(value) > 0) 492 server->backlog = (int)js_getnum(value); 493} 494 495static void net_socket_on_read(ant_conn_t *conn, ssize_t nread, void *user_data) { 496 net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 497 const char *buffer = NULL; 498 ant_value_t chunk = 0; 499 size_t total = 0; 500 size_t offset = 0; 501 502 if (!socket || !conn || nread <= 0) return; 503 504 total = ant_conn_buffer_len(conn); 505 if ((size_t)nread > total) return; 506 offset = total - (size_t)nread; 507 buffer = ant_conn_buffer(conn) + offset; 508 509 if (vtype(socket->encoding) == T_STR) 510 chunk = js_mkstr(socket->js, buffer, (size_t)nread); 511 else chunk = net_make_buffer_chunk(socket->js, buffer, (size_t)nread); 512 513 ant_conn_consume(conn, total); 514 net_socket_sync_state(socket); 515 net_emit(socket->js, socket->obj, "data", &chunk, 1); 516} 517 518static void net_socket_on_end(ant_conn_t *conn, void *user_data) { 519 net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 520 521 if (!socket) return; 522 net_emit(socket->js, socket->obj, "end", NULL, 0); 523 if (!socket->allow_half_open && socket->conn) ant_conn_shutdown(socket->conn); 524} 525 526static void net_socket_on_error(ant_conn_t *conn, int status, void *user_data) { 527 net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 528 529 if (!socket) return; 530 socket->had_error = true; { 531 ant_value_t err = js_mkerr_typed(socket->js, JS_ERR_TYPE, "%s", uv_strerror(status)); 532 net_emit(socket->js, socket->obj, "error", &err, 1); 533 } 534} 535 536static void net_socket_on_timeout(ant_conn_t *conn, void *user_data) { 537 net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 538 if (!socket) return; 539 net_emit(socket->js, socket->obj, "timeout", NULL, 0); 540} 541 542static void net_server_on_conn_close(ant_conn_t *conn, void *user_data) { 543 net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 544 ant_value_t arg = 0; 545 546 if (!socket) return; 547 arg = js_bool(socket->had_error); 548 socket->conn = NULL; 549 socket->destroyed = true; 550 net_socket_sync_state(socket); 551 net_emit(socket->js, socket->obj, "close", &arg, 1); 552 ant_conn_set_user_data(conn, NULL); 553 net_socket_detach(socket); 554} 555 556static void net_server_on_listener_close(ant_listener_t *listener, void *user_data) { 557 net_server_maybe_finish_close((net_server_t *)user_data); 558} 559 560static void net_server_on_accept(ant_listener_t *listener, ant_conn_t *conn, void *user_data) { 561 net_server_t *server = (net_server_t *)user_data; 562 net_socket_t *socket = NULL; 563 ant_value_t arg = 0; 564 565 if (!server || !conn) return; 566 567 if (server->max_connections > 0 && net_server_socket_count(server) >= server->max_connections) { 568 ant_conn_close(conn); 569 return; 570 } 571 572 socket = net_socket_create(server->js, server->allow_half_open); 573 if (!socket) { 574 ant_conn_close(conn); 575 return; 576 } 577 578 socket->server = server; 579 socket->next_in_server = server->sockets; 580 server->sockets = socket; 581 net_add_active_socket(socket); 582 net_socket_attach_conn(socket, conn); 583 584 if (server->no_delay) ant_conn_set_no_delay(conn, true); 585 if (server->keep_alive) 586 ant_conn_set_keep_alive(conn, true, server->keep_alive_initial_delay_secs); 587 if (server->pause_on_connect) ant_conn_pause_read(conn); 588 589 arg = socket->obj; 590 net_emit(server->js, server->obj, "connection", &arg, 1); 591} 592 593static bool net_server_parse_host(const char *input, const char **out) { 594 if (!input || !*input) { 595 *out = "0.0.0.0"; 596 return true; 597 } 598 *out = input; 599 return true; 600} 601 602static ant_value_t js_net_socket_ctor(ant_t *js, ant_value_t *args, int nargs) { 603 net_socket_t *socket = NULL; 604 bool allow_half_open = false; 605 606 if (nargs > 0 && vtype(args[0]) == T_OBJ) { 607 ant_value_t value = js_get(js, args[0], "allowHalfOpen"); 608 allow_half_open = js_truthy(js, value); 609 } 610 611 socket = net_socket_create(js, allow_half_open); 612 if (!socket) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 613 return socket->obj; 614} 615 616static ant_value_t js_net_socket_address(ant_t *js, ant_value_t *args, int nargs) { 617 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 618 ant_value_t out = js_mkobj(js); 619 620 if (!socket) return js->thrown_value; 621 if (!socket || !socket->conn || !ant_conn_has_local_addr(socket->conn)) return out; 622 js_set(js, out, "address", js_mkstr(js, ant_conn_local_addr(socket->conn), strlen(ant_conn_local_addr(socket->conn)))); 623 js_set(js, out, "port", js_mknum(ant_conn_local_port(socket->conn))); 624 js_set(js, out, "family", js_mkstr(js, ant_conn_local_family(socket->conn), strlen(ant_conn_local_family(socket->conn)))); 625 return out; 626} 627 628static ant_value_t js_net_socket_pause(ant_t *js, ant_value_t *args, int nargs) { 629 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 630 if (!socket) return js->thrown_value; 631 if (socket && socket->conn) ant_conn_pause_read(socket->conn); 632 return js_getthis(js); 633} 634 635static ant_value_t js_net_socket_resume(ant_t *js, ant_value_t *args, int nargs) { 636 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 637 if (!socket) return js->thrown_value; 638 if (socket && socket->conn) ant_conn_resume_read(socket->conn); 639 return js_getthis(js); 640} 641 642static ant_value_t js_net_socket_setEncoding(ant_t *js, ant_value_t *args, int nargs) { 643 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 644 if (!socket) return js->thrown_value; 645 socket->encoding = nargs > 0 && vtype(args[0]) != T_UNDEF ? js_tostring_val(js, args[0]) : js_mkundef(); 646 return js_getthis(js); 647} 648 649static ant_value_t js_net_socket_setTimeout(ant_t *js, ant_value_t *args, int nargs) { 650 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 651 double timeout = 0; 652 653 if (!socket) return js->thrown_value; 654 if (nargs > 0 && vtype(args[0]) == T_NUM) timeout = js_getnum(args[0]); 655 if (socket->conn) ant_conn_set_timeout_ms(socket->conn, timeout > 0 ? (uint64_t)timeout : 0); 656 net_socket_sync_state(socket); 657 658 if (nargs > 1 && is_callable(args[1])) 659 net_add_listener(js, socket->obj, "timeout", args[1], true); 660 661 return js_getthis(js); 662} 663 664static ant_value_t js_net_socket_setNoDelay(ant_t *js, ant_value_t *args, int nargs) { 665 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 666 bool enable = nargs == 0 || js_truthy(js, args[0]); 667 if (!socket) return js->thrown_value; 668 if (socket && socket->conn) ant_conn_set_no_delay(socket->conn, enable); 669 return js_getthis(js); 670} 671 672static ant_value_t js_net_socket_setKeepAlive(ant_t *js, ant_value_t *args, int nargs) { 673 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 674 bool enable = nargs > 0 && js_truthy(js, args[0]); 675 unsigned int delay = nargs > 1 && vtype(args[1]) == T_NUM ? (unsigned int)(js_getnum(args[1]) / 1000.0) : 0; 676 if (!socket) return js->thrown_value; 677 if (socket && socket->conn) ant_conn_set_keep_alive(socket->conn, enable, delay); 678 return js_getthis(js); 679} 680 681static ant_value_t js_net_socket_ref(ant_t *js, ant_value_t *args, int nargs) { 682 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 683 if (!socket) return js->thrown_value; 684 if (socket && socket->conn) ant_conn_ref(socket->conn); 685 return js_getthis(js); 686} 687 688static ant_value_t js_net_socket_unref(ant_t *js, ant_value_t *args, int nargs) { 689 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 690 if (!socket) return js->thrown_value; 691 if (socket && socket->conn) ant_conn_unref(socket->conn); 692 return js_getthis(js); 693} 694 695static ant_value_t js_net_socket_write(ant_t *js, ant_value_t *args, int nargs) { 696 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 697 net_write_args_t parsed; 698 char *copy = NULL; 699 700 if (!socket) return js->thrown_value; 701 if (!socket->conn) return js_false; 702 if (!net_parse_write_args(js, args, nargs, &parsed)) return parsed.error; 703 if (parsed.len == 0) return js_true; 704 705 copy = malloc(parsed.len); 706 if (!copy) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 707 708 memcpy(copy, parsed.bytes, parsed.len); 709 if (ant_conn_write(socket->conn, copy, parsed.len, NULL, NULL) != 0) return js_false; 710 711 GC_ROOT_SAVE(root_mark, js); 712 GC_ROOT_PIN(js, parsed.callback); 713 net_socket_sync_state(socket); 714 715 if (is_callable(parsed.callback)) net_call_value(js, parsed.callback, js_mkundef(), NULL, 0); 716 GC_ROOT_RESTORE(js, root_mark); 717 718 return js_true; 719} 720 721static ant_value_t js_net_socket_end(ant_t *js, ant_value_t *args, int nargs) { 722 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 723 net_write_args_t parsed; 724 ant_value_t result = js_getthis(js); 725 726 if (!socket) return js->thrown_value; 727 if (!socket->conn) return result; 728 if (!net_parse_write_args(js, args, nargs, &parsed)) return parsed.error; 729 730 GC_ROOT_SAVE(root_mark, js); 731 GC_ROOT_PIN(js, parsed.callback); 732 733 if (parsed.len > 0) { 734 ant_value_t write_result = js_net_socket_write(js, args, nargs); 735 if (is_err(write_result)) { 736 GC_ROOT_RESTORE(js, root_mark); 737 return write_result; 738 }} 739 740 ant_conn_shutdown(socket->conn); 741 if (is_callable(parsed.callback)) net_call_value(js, parsed.callback, js_mkundef(), NULL, 0); 742 GC_ROOT_RESTORE(js, root_mark); 743 744 return result; 745} 746 747static ant_value_t js_net_socket_destroy(ant_t *js, ant_value_t *args, int nargs) { 748 net_socket_t *socket = net_require_socket(js, js_getthis(js)); 749 if (!socket) return js->thrown_value; 750 751 if (nargs > 0 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) { 752 ant_value_t err = args[0]; 753 socket->had_error = true; 754 net_emit(js, socket->obj, "error", &err, 1); 755 } 756 757 if (socket->conn) ant_conn_close(socket->conn); 758 return js_getthis(js); 759} 760 761static ant_value_t js_net_socket_connect(ant_t *js, ant_value_t *args, int nargs) { 762 return net_not_implemented(js, "net.Socket.connect"); 763} 764 765static ant_value_t js_net_server_ctor(ant_t *js, ant_value_t *args, int nargs) { 766 net_server_t *server = net_server_create(js); 767 768 if (!server) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 769 if (nargs > 0 && vtype(args[0]) == T_OBJ) net_server_apply_options(js, server, args[0]); 770 if (nargs > 0 && is_callable(args[0])) net_add_listener(js, server->obj, "connection", args[0], false); 771 else if (nargs > 1 && is_callable(args[1])) net_add_listener(js, server->obj, "connection", args[1], false); 772 773 return server->obj; 774} 775 776static ant_value_t net_server_bind_listener( 777 ant_t *js, 778 net_server_t *server, 779 const net_listen_args_t *parsed, 780 const ant_listener_callbacks_t *callbacks 781) { 782 uv_loop_t *loop = uv_default_loop(); 783 int rc = 0; 784 785 if (parsed->path) { 786 server->path = strdup(parsed->path); 787 if (!server->path) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 788 789 rc = ant_listener_listen_pipe( 790 &server->listener, loop, server->path, 791 server->backlog, 0, callbacks, server 792 ); 793 } else { 794 const char *host = parsed->host; 795 net_server_parse_host(host, &host); 796 797 free(server->host); 798 server->host = strdup(host ? host : "0.0.0.0"); 799 if (!server->host) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 800 801 rc = ant_listener_listen_tcp( 802 &server->listener, loop, server->host, parsed->port, 803 server->backlog, 0, callbacks, server 804 ); 805 } 806 807 if (rc != 0) return js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(rc)); 808 return js_mkundef(); 809} 810 811static ant_value_t js_net_server_listen(ant_t *js, ant_value_t *args, int nargs) { 812 net_server_t *server = net_require_server(js, js_getthis(js)); 813 ant_listener_callbacks_t callbacks = {0}; 814 net_listen_args_t parsed; 815 816 if (!server) return js->thrown_value; 817 if (server->listening) return js_mkerr_typed(js, JS_ERR_TYPE, "Server is already listening"); 818 if (!net_parse_listen_args(js, args, nargs, &parsed)) return parsed.error; 819 820 free(server->path); 821 server->path = NULL; 822 server->port = parsed.port; 823 server->backlog = parsed.backlog > 0 ? parsed.backlog : server->backlog; 824 825 callbacks.on_accept = net_server_on_accept; 826 callbacks.on_read = net_socket_on_read; 827 callbacks.on_end = net_socket_on_end; 828 callbacks.on_error = net_socket_on_error; 829 callbacks.on_timeout = net_socket_on_timeout; 830 callbacks.on_conn_close = net_server_on_conn_close; 831 callbacks.on_listener_close = net_server_on_listener_close; 832 833 GC_ROOT_SAVE(root_mark, js); 834 GC_ROOT_PIN(js, parsed.callback); 835 836 ant_value_t bind_result = net_server_bind_listener(js, server, &parsed, &callbacks); 837 if (is_err(bind_result)) { 838 GC_ROOT_RESTORE(js, root_mark); 839 return bind_result; 840 } 841 842 server->port = ant_listener_port(&server->listener); 843 server->listening = true; 844 server->closing = false; 845 net_server_sync_state(server); 846 net_add_active_server(server); 847 848 if (is_callable(parsed.callback)) net_call_value(js, parsed.callback, js_mkundef(), NULL, 0); 849 net_emit(js, server->obj, "listening", NULL, 0); 850 GC_ROOT_RESTORE(js, root_mark); 851 852 return js_getthis(js); 853} 854 855static ant_value_t js_net_server_close(ant_t *js, ant_value_t *args, int nargs) { 856 net_server_t *server = net_require_server(js, js_getthis(js)); 857 858 if (!server) return js->thrown_value; 859 if (nargs > 0 && is_callable(args[0])) net_add_listener(js, server->obj, "close", args[0], true); 860 861 if (!server->listening && !server->closing) { 862 if (nargs > 0 && is_callable(args[0])) { 863 ant_value_t err = js_mkerr_typed(js, JS_ERR_TYPE, "Server is not running"); 864 net_call_value(js, args[0], js_mkundef(), &err, 1); 865 } 866 return js_getthis(js); 867 } 868 869 server->closing = true; 870 ant_listener_stop(&server->listener, false); 871 net_server_maybe_finish_close(server); 872 return js_getthis(js); 873} 874 875static ant_value_t js_net_server_address(ant_t *js, ant_value_t *args, int nargs) { 876 net_server_t *server = net_require_server(js, js_getthis(js)); 877 ant_value_t out = js_mknull(); 878 879 if (!server) return js->thrown_value; 880 if (!server || !server->listening) return out; 881 if (server->path) return js_mkstr(js, server->path, strlen(server->path)); 882 883 struct sockaddr_storage saddr; 884 int saddr_len = sizeof(saddr); 885 886 if (uv_tcp_getsockname(&server->listener.handle.tcp, (struct sockaddr *)&saddr, &saddr_len) == 0) { 887 char addr_str[INET6_ADDRSTRLEN] = {0}; 888 const char *family = "IPv4"; 889 int port = server->port; 890 891 if (saddr.ss_family == AF_INET) { 892 struct sockaddr_in *sa = (struct sockaddr_in *)&saddr; 893 inet_ntop(AF_INET, &sa->sin_addr, addr_str, sizeof(addr_str)); 894 port = ntohs(sa->sin_port); 895 } else if (saddr.ss_family == AF_INET6) { 896 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&saddr; 897 inet_ntop(AF_INET6, &sa6->sin6_addr, addr_str, sizeof(addr_str)); 898 port = ntohs(sa6->sin6_port); 899 family = "IPv6"; 900 } 901 902 out = js_mkobj(js); 903 js_set(js, out, "port", js_mknum((double)port)); 904 js_set(js, out, "family", js_mkstr(js, family, strlen(family))); 905 js_set(js, out, "address", js_mkstr(js, addr_str, strlen(addr_str))); 906 907 return out; 908 } 909 910 struct in6_addr addr6; 911 out = js_mkobj(js); 912 js_set(js, out, "port", js_mknum(server->port)); 913 914 if (server->host && inet_pton(AF_INET6, server->host, &addr6) == 1) { 915 char normalized[INET6_ADDRSTRLEN]; 916 inet_ntop(AF_INET6, &addr6, normalized, sizeof(normalized)); 917 js_set(js, out, "family", js_mkstr(js, "IPv6", 4)); 918 js_set(js, out, "address", js_mkstr(js, normalized, strlen(normalized))); 919 } else { 920 const char *h = server->host ? server->host : "0.0.0.0"; 921 js_set(js, out, "family", js_mkstr(js, "IPv4", 4)); 922 js_set(js, out, "address", js_mkstr(js, h, strlen(h))); 923 } 924 925 return out; 926} 927 928static ant_value_t js_net_server_getConnections(ant_t *js, ant_value_t *args, int nargs) { 929 net_server_t *server = net_require_server(js, js_getthis(js)); 930 ant_value_t cb = nargs > 0 ? args[0] : js_mkundef(); 931 ant_value_t argv[2] = { js_mknull(), js_mknum((double)net_server_socket_count(server)) }; 932 933 if (!server) return js->thrown_value; 934 if (is_callable(cb)) net_call_value(js, cb, js_mkundef(), argv, 2); 935 return js_getthis(js); 936} 937 938static ant_value_t js_net_server_ref(ant_t *js, ant_value_t *args, int nargs) { 939 net_server_t *server = net_require_server(js, js_getthis(js)); 940 if (!server) return js->thrown_value; 941 if (server) ant_listener_ref(&server->listener); 942 return js_getthis(js); 943} 944 945static ant_value_t js_net_server_unref(ant_t *js, ant_value_t *args, int nargs) { 946 net_server_t *server = net_require_server(js, js_getthis(js)); 947 if (!server) return js->thrown_value; 948 if (server) ant_listener_unref(&server->listener); 949 return js_getthis(js); 950} 951 952static ant_value_t js_net_createServer(ant_t *js, ant_value_t *args, int nargs) { 953 return js_net_server_ctor(js, args, nargs); 954} 955 956static ant_value_t js_net_createConnection(ant_t *js, ant_value_t *args, int nargs) { 957 return net_not_implemented(js, "net.createConnection"); 958} 959 960static ant_value_t js_net_connect(ant_t *js, ant_value_t *args, int nargs) { 961 return js_net_createConnection(js, args, nargs); 962} 963 964static ant_value_t js_net_getDefaultAutoSelectFamily(ant_t *js, ant_value_t *args, int nargs) { 965 return js_bool(g_default_auto_select_family); 966} 967 968static ant_value_t js_net_setDefaultAutoSelectFamily(ant_t *js, ant_value_t *args, int nargs) { 969 if (nargs > 0) g_default_auto_select_family = js_truthy(js, args[0]); 970 return js_mkundef(); 971} 972 973static ant_value_t js_net_getDefaultAutoSelectFamilyAttemptTimeout(ant_t *js, ant_value_t *args, int nargs) { 974 return js_mknum(g_default_auto_select_family_attempt_timeout); 975} 976 977static ant_value_t js_net_setDefaultAutoSelectFamilyAttemptTimeout(ant_t *js, ant_value_t *args, int nargs) { 978 if (nargs > 0 && vtype(args[0]) == T_NUM) { 979 double value = js_getnum(args[0]); 980 if (value > 0 && value < 10) value = 10; 981 if (value > 0) g_default_auto_select_family_attempt_timeout = value; 982 } 983 return js_mkundef(); 984} 985 986static void net_init_constructors(ant_t *js) { 987 ant_value_t events = 0; 988 ant_value_t ee_ctor = 0; 989 ant_value_t ee_proto = 0; 990 991 if (g_net_server_ctor && g_net_socket_ctor) return; 992 993 events = events_library(js); 994 ee_ctor = js_get(js, events, "EventEmitter"); 995 ee_proto = js_get(js, ee_ctor, "prototype"); 996 997 g_net_socket_proto = js_mkobj(js); 998 js_set_proto_init(g_net_socket_proto, ee_proto); 999 js_set(js, g_net_socket_proto, "address", js_mkfun(js_net_socket_address)); 1000 js_set(js, g_net_socket_proto, "pause", js_mkfun(js_net_socket_pause)); 1001 js_set(js, g_net_socket_proto, "resume", js_mkfun(js_net_socket_resume)); 1002 js_set(js, g_net_socket_proto, "setEncoding", js_mkfun(js_net_socket_setEncoding)); 1003 js_set(js, g_net_socket_proto, "setTimeout", js_mkfun(js_net_socket_setTimeout)); 1004 js_set(js, g_net_socket_proto, "setNoDelay", js_mkfun(js_net_socket_setNoDelay)); 1005 js_set(js, g_net_socket_proto, "setKeepAlive", js_mkfun(js_net_socket_setKeepAlive)); 1006 js_set(js, g_net_socket_proto, "write", js_mkfun(js_net_socket_write)); 1007 js_set(js, g_net_socket_proto, "end", js_mkfun(js_net_socket_end)); 1008 js_set(js, g_net_socket_proto, "destroy", js_mkfun(js_net_socket_destroy)); 1009 js_set(js, g_net_socket_proto, "connect", js_mkfun(js_net_socket_connect)); 1010 js_set(js, g_net_socket_proto, "ref", js_mkfun(js_net_socket_ref)); 1011 js_set(js, g_net_socket_proto, "unref", js_mkfun(js_net_socket_unref)); 1012 js_set_sym(js, g_net_socket_proto, get_toStringTag_sym(), js_mkstr(js, "Socket", 6)); 1013 g_net_socket_ctor = js_make_ctor(js, js_net_socket_ctor, g_net_socket_proto, "Socket", 6); 1014 1015 g_net_server_proto = js_mkobj(js); 1016 js_set_proto_init(g_net_server_proto, ee_proto); 1017 js_set(js, g_net_server_proto, "listen", js_mkfun(js_net_server_listen)); 1018 js_set(js, g_net_server_proto, "close", js_mkfun(js_net_server_close)); 1019 js_set(js, g_net_server_proto, "address", js_mkfun(js_net_server_address)); 1020 js_set(js, g_net_server_proto, "getConnections", js_mkfun(js_net_server_getConnections)); 1021 js_set(js, g_net_server_proto, "ref", js_mkfun(js_net_server_ref)); 1022 js_set(js, g_net_server_proto, "unref", js_mkfun(js_net_server_unref)); 1023 js_set_sym(js, g_net_server_proto, get_toStringTag_sym(), js_mkstr(js, "Server", 6)); 1024 g_net_server_ctor = js_make_ctor(js, js_net_server_ctor, g_net_server_proto, "Server", 6); 1025} 1026 1027ant_value_t net_library(ant_t *js) { 1028 ant_value_t lib = js_mkobj(js); 1029 1030 net_init_constructors(js); 1031 js_set(js, lib, "Server", g_net_server_ctor); 1032 js_set(js, lib, "Socket", g_net_socket_ctor); 1033 js_set(js, lib, "createServer", js_mkfun(js_net_createServer)); 1034 js_set(js, lib, "createConnection", js_mkfun(js_net_createConnection)); 1035 js_set(js, lib, "connect", js_mkfun(js_net_connect)); 1036 js_set(js, lib, "isIP", js_mkfun(net_isIP)); 1037 js_set(js, lib, "isIPv4", js_mkfun(net_isIPv4)); 1038 js_set(js, lib, "isIPv6", js_mkfun(net_isIPv6)); 1039 js_set(js, lib, "getDefaultAutoSelectFamily", js_mkfun(js_net_getDefaultAutoSelectFamily)); 1040 js_set(js, lib, "setDefaultAutoSelectFamily", js_mkfun(js_net_setDefaultAutoSelectFamily)); 1041 js_set(js, lib, "getDefaultAutoSelectFamilyAttemptTimeout", js_mkfun(js_net_getDefaultAutoSelectFamilyAttemptTimeout)); 1042 js_set(js, lib, "setDefaultAutoSelectFamilyAttemptTimeout", js_mkfun(js_net_setDefaultAutoSelectFamilyAttemptTimeout)); 1043 js_set(js, lib, "default", lib); 1044 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "net", 3)); 1045 1046 return lib; 1047} 1048 1049void gc_mark_net(ant_t *js, gc_mark_fn mark) { 1050 net_server_t *server = NULL; 1051 net_socket_t *socket = NULL; 1052 1053 if (g_net_server_proto) mark(js, g_net_server_proto); 1054 if (g_net_socket_proto) mark(js, g_net_socket_proto); 1055 if (g_net_server_ctor) mark(js, g_net_server_ctor); 1056 if (g_net_socket_ctor) mark(js, g_net_socket_ctor); 1057 1058 for (server = g_active_servers; server; server = server->next_active) 1059 mark(js, server->obj); 1060 1061 for (socket = g_active_sockets; socket; socket = socket->next_active) { 1062 mark(js, socket->obj); 1063 if (vtype(socket->encoding) != T_UNDEF) mark(js, socket->encoding); 1064 } 1065}