Something went wrong. Try again.
MIRROR: javascript for 🐜's, a tiny runtime with big ambitions ant.themackabu.dev
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287#include <compat.h> // IWYU pragma: keep
#include <stdbool.h>#include <stdint.h>#include <stdlib.h>#include <string.h>
#ifdef _WIN32#include <winsock2.h>#include <ws2tcpip.h>#else#include <arpa/inet.h>#endif
#include "ant.h"#include "cfunc.h"#include "list.h"#include "ptr.h"#include "errors.h"#include "internal.h"
#include "gc/roots.h"#include "gc/modules.h"#include "net/connection.h"#include "net/listener.h"#include "sandbox/policy.h"#include "silver/call.h"
#include "modules/buffer.h"#include "modules/events.h"#include "modules/net.h"#include "modules/stream.h"#include "modules/timer.h"
typedef struct net_listen_args_s net_listen_args_t;typedef struct net_connect_args_s net_connect_args_t;typedef struct net_write_args_s net_write_args_t;
struct net_socket_s { ant_t *js; ant_value_t obj; ant_conn_t *conn; ant_listener_t client_listener; net_server_t *server; net_socket_t *next; net_socket_t **pprev; struct net_socket_s *next_in_server; bool allow_half_open; bool string_encoding; bool destroyed; bool connecting; bool had_error;};
struct net_server_s { ant_t *js; ant_value_t obj; ant_listener_t listener; net_socket_t *sockets; net_server_t *next; net_server_t **pprev; char *host; char *path; int port; int backlog; int max_connections; bool listening; bool closing; bool allow_half_open; bool pause_on_connect; bool no_delay; bool keep_alive; unsigned int keep_alive_initial_delay_secs;};
struct net_listen_args_s { const char *host; const char *path; int port; int backlog; ant_value_t callback; ant_value_t error;};
struct net_connect_args_s { const char *host; const char *path; int port; uint64_t timeout_ms; bool allow_half_open; bool no_delay; bool keep_alive; unsigned int keep_alive_initial_delay_secs; ant_value_t callback; ant_value_t error;};
struct net_write_args_s { const uint8_t *bytes; size_t len; ant_value_t callback; ant_value_t error;};
static constexpr uint32_t NET_SERVER_NATIVE_TAG = Ant_NativeTag("NETS");static constexpr uint32_t NET_SOCKET_NATIVE_TAG = Ant_NativeTag("NETK");
static net_server_t *net_server_data(ant_value_t value) { return (net_server_t *)js_get_native(value, NET_SERVER_NATIVE_TAG);}
static net_socket_t *net_socket_data(ant_value_t value) { return (net_socket_t *)js_get_native(value, NET_SOCKET_NATIVE_TAG);}
static void net_add_active_server(net_server_t *server) { Ant_List_Insert(&server->js->net_servers, server);}
static void net_remove_active_server(net_server_t *server) { Ant_List_Remove(server);}
static void net_add_active_socket(net_socket_t *socket) { if (socket) Ant_List_Insert(&socket->js->net_sockets, socket);}
static void net_remove_active_socket(net_socket_t *socket) { Ant_List_Remove(socket);}
static bool net_emit(ant_t *js, ant_value_t target, const char *event, ant_value_t *args, int nargs) { return eventemitter_emit_args(js, target, event, args, nargs);}
static bool net_add_listener( ant_t *js, ant_value_t target, const char *event, ant_value_t listener, bool once) { return eventemitter_add_listener(js, target, event, listener, once);}
static net_server_t *net_require_server(ant_t *js, ant_value_t this_val) { net_server_t *server = net_server_data(this_val); if (!server) { js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.Server"); return NULL; } return server;}
static net_socket_t *net_require_socket(ant_t *js, ant_value_t this_val) { net_socket_t *socket = net_socket_data(this_val); if (!socket) { js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.Socket"); return NULL; } return socket;}
static bool net_parse_write_args(ant_native_params_t, net_write_args_t *out) { ant_value_t value = 0;
if (!out) return false; memset(out, 0, sizeof(*out)); out->callback = js_mkundef(); out->error = js_mkundef();
if (nargs < 1 || vtype(args[0]) == kTypeUndefined || vtype(args[0]) == kTypeNull) return true; value = args[0];
if (!buffer_source_get_bytes(js, value, &out->bytes, &out->len)) { size_t slen = 0; ant_value_t str_val = js_tostring_val(js, value); const char *str = NULL;
if (is_err(str_val)) { out->error = str_val; return false; }
str = js_getstr(js, str_val, &slen); if (!str) { out->error = js_mkerr_typed(js, JS_ERR_TYPE, "Invalid socket write data"); return false; }
out->bytes = (const uint8_t *)str; out->len = slen; }
if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; else if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; return true;}
static bool net_parse_listen_args(ant_native_params_t, net_listen_args_t *out) { if (!out) return false; memset(out, 0, sizeof(*out)); out->host = "0.0.0.0"; out->backlog = 511; out->callback = js_mkundef(); out->error = js_mkundef();
if (nargs == 0) return true;
if (vtype(args[0]) == kTypeNumber) { out->port = (int)js_getnum(args[0]); if (nargs > 1 && vtype(args[1]) == kTypeString) { size_t len = 0; out->host = js_getstr(js, args[1], &len); } if (nargs > 2 && vtype(args[2]) == kTypeNumber) out->backlog = (int)js_getnum(args[2]); if (nargs > 3 && is_callable(args[3])) out->callback = args[3]; else if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; else if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; return true; }
if (vtype(args[0]) == kTypeObject) { ant_value_t value = js_get(js, args[0], "path"); if (vtype(value) == kTypeString) { out->path = js_getstr(js, value, NULL); }
value = js_get(js, args[0], "port"); if (vtype(value) == kTypeNumber) out->port = (int)js_getnum(value); value = js_get(js, args[0], "host"); if (vtype(value) == kTypeString) { size_t len = 0; out->host = js_getstr(js, value, &len); } value = js_get(js, args[0], "backlog"); if (vtype(value) == kTypeNumber) out->backlog = (int)js_getnum(value); if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; return true; }
if (vtype(args[0]) == kTypeString) { out->path = js_getstr(js, args[0], NULL); if (nargs > 1 && vtype(args[1]) == kTypeNumber) out->backlog = (int)js_getnum(args[1]); if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; else if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; return true; }
if (is_callable(args[0])) { out->callback = args[0]; return true; }
return true;}
static bool net_take_string(ant_t *js, const char *name, ant_value_t value, const char **slot, net_connect_args_t *out) { ant_value_t nul = Ant_Error_CheckNoNullBytes(js, name, value); if (is_err(nul)) { out->error = nul; return false; } *slot = js_getstr(js, value, NULL); return true;}
static bool net_parse_connect_args(ant_native_params_t, net_connect_args_t *out) { ant_value_t value = 0;
if (!out) return false; memset(out, 0, sizeof(*out)); out->host = "localhost"; out->callback = js_mkundef(); out->error = js_mkundef(); out->no_delay = true;
if (nargs == 0) { out->error = js_mkerr_typed(js, JS_ERR_TYPE, "net.connect requires options, port, or path"); return false; }
if (vtype(args[0]) == kTypeNumber) { out->port = (int)js_getnum(args[0]); if (nargs > 1 && vtype(args[1]) == kTypeString && !net_take_string(js, "host", args[1], &out->host, out)) return false; if (nargs > 2 && is_callable(args[2])) out->callback = args[2]; else if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; return true; }
if (vtype(args[0]) == kTypeString) { if (!net_take_string(js, "path", args[0], &out->path, out)) return false; if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; return true; }
if (vtype(args[0]) == kTypeObject) { value = js_get(js, args[0], "path"); if (vtype(value) == kTypeString && !net_take_string(js, "path", value, &out->path, out)) return false;
value = js_get(js, args[0], "socketPath"); if (!out->path && vtype(value) == kTypeString && !net_take_string(js, "path", value, &out->path, out)) return false;
value = js_get(js, args[0], "port"); if (vtype(value) == kTypeNumber) out->port = (int)js_getnum(value);
value = js_get(js, args[0], "host"); if (vtype(value) == kTypeString && !net_take_string(js, "host", value, &out->host, out)) return false;
value = js_get(js, args[0], "hostname"); if (vtype(value) == kTypeString && !net_take_string(js, "hostname", value, &out->host, out)) return false;
value = js_get(js, args[0], "allowHalfOpen"); if (vtype(value) != kTypeUndefined) out->allow_half_open = js_truthy(js, value);
value = js_get(js, args[0], "timeout"); if (vtype(value) == kTypeNumber && js_getnum(value) > 0) out->timeout_ms = (uint64_t)js_getnum(value);
value = js_get(js, args[0], "noDelay"); if (vtype(value) != kTypeUndefined) out->no_delay = js_truthy(js, value);
value = js_get(js, args[0], "keepAlive"); if (vtype(value) != kTypeUndefined) out->keep_alive = js_truthy(js, value);
value = js_get(js, args[0], "keepAliveInitialDelay"); if (vtype(value) == kTypeNumber && js_getnum(value) > 0) out->keep_alive_initial_delay_secs = (unsigned int)(js_getnum(value) / 1000.0);
if (nargs > 1 && is_callable(args[1])) out->callback = args[1]; return true; }
if (is_callable(args[0])) { out->callback = args[0]; return true; }
out->error = js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.connect options"); return false;}
static ant_value_t net_make_buffer_chunk(ant_t *js, const char *data, size_t len) { ArrayBufferData *ab = create_array_buffer_data(js, len); if (!ab) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); if (len > 0 && data) memcpy(ab->data, data, len); return create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, len, js->builtins.buffer_proto);}
static void net_socket_sync_state(net_socket_t *socket) { ant_value_t obj = 0; const char *ready_state = "open";
if (!socket) return; obj = socket->obj; if (!is_object_type(obj)) return;
if (socket->destroyed) ready_state = "closed"; else if (socket->connecting) ready_state = "opening"; js_set(socket->js, obj, "destroyed", js_bool(socket->destroyed)); js_set(socket->js, obj, "pending", js_bool(socket->connecting || (socket->conn == NULL && !socket->destroyed))); js_set(socket->js, obj, "connecting", js_bool(socket->connecting)); js_set(socket->js, obj, "readyState", js_mkstr(socket->js, ready_state, strlen(ready_state))); js_set(socket->js, obj, "bytesRead", js_mknum((double)(socket->conn ? ant_conn_bytes_read(socket->conn) : 0))); js_set(socket->js, obj, "bytesWritten", js_mknum((double)(socket->conn ? ant_conn_bytes_written(socket->conn) : 0))); js_set(socket->js, obj, "timeout", js_mknum((double)(socket->conn ? ant_conn_timeout_ms(socket->conn) : 0)));}
static void net_server_sync_state(net_server_t *server) { if (!server || !is_object_type(server->obj)) return; js_set(server->js, server->obj, "listening", js_bool(server->listening)); js_set(server->js, server->obj, "maxConnections", js_mknum((double)server->max_connections)); js_set(server->js, server->obj, "dropMaxConnection", js_false);}
static int net_server_socket_count(net_server_t *server) { int count = 0; net_socket_t *socket = NULL;
for (socket = server ? server->sockets : NULL; socket; socket = socket->next_in_server) count++; return count;}
static void net_server_maybe_finish_close(net_server_t *server) { if (!server || !server->closing) return; if (!ant_listener_is_closed(&server->listener)) return; if (server->sockets) return;
server->closing = false; server->listening = false; net_server_sync_state(server); net_emit(server->js, server->obj, "close", NULL, 0); net_remove_active_server(server);}
static void net_socket_unlink(net_socket_t *socket) { net_server_t *server = socket->server;
if (server) { net_socket_t **it = NULL; for (it = &socket->server->sockets; *it; it = &(*it)->next_in_server) if (*it == socket) { *it = socket->next_in_server; break; } socket->next_in_server = NULL; socket->server = NULL; }
net_remove_active_socket(socket); net_server_maybe_finish_close(server);}
static void net_server_finalize(ant_t *js, ant_object_t *obj) { ant_value_t value = js_obj_from_ptr(obj); net_server_t *server = net_server_data(value); if (!server) return; js_clear_native(value, NET_SERVER_NATIVE_TAG); server->obj = js_mkundef(); if (server->listener.started && !ant_listener_is_closed(&server->listener)) return; for (net_socket_t *socket = server->sockets; socket; socket = socket->next_in_server) socket->server = NULL; Ant_List_Remove(server); free(server->host); free(server->path); free(server);}
static void net_socket_finalize(ant_t *js, ant_object_t *obj) { net_socket_t *socket = net_socket_data(js_obj_from_ptr(obj)); if (!socket || socket->conn) return; net_socket_unlink(socket); js_clear_native(js_obj_from_ptr(obj), NET_SOCKET_NATIVE_TAG); free(socket);}
static ant_value_t net_socket_emit_connect_error(ant_params_t) { ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); ant_value_t socket_obj = is_object_type(state) ? js_get(js, state, "socket") : js_mkundef(); ant_value_t status_val = is_object_type(state) ? js_get(js, state, "status") : js_mknum(UV_EIO); net_socket_t *socket = net_socket_data(socket_obj); int status = vtype(status_val) == kTypeNumber ? (int)js_getnum(status_val) : UV_EIO; ant_value_t err = 0; if (!socket) return js_mkundef();
socket->connecting = false; socket->had_error = true; net_socket_sync_state(socket); err = Ant_Error_Create(js, JS_ERR_TYPE, uv_strerror(status)); net_emit(js, socket->obj, "error", &err, 1); if (socket->conn) ant_conn_close(socket->conn);
return js_mkundef();}
static void net_socket_schedule_connect_error(ant_t *js, net_socket_t *socket, int status) { ant_value_t state = Ant_Object_CreateBare(js); js_set(js, state, "socket", socket->obj); js_set(js, state, "status", js_mknum((double)status)); queue_microtask(js, js_heavy_mkfun(js, net_socket_emit_connect_error, state));}
static net_socket_t *net_socket_create(ant_t *js, bool allow_half_open, ant_value_t new_target) { ant_value_t obj = Ant_Object_CreateBare(js); ant_value_t proto = js_instance_proto_from_new_target(js, js->builtins.net_socket_proto, new_target); net_socket_t *socket = calloc(1, sizeof(*socket));
if (!socket) return NULL; if (is_object_type(proto)) js_set_proto_init(obj, proto);
socket->js = js; socket->obj = obj; socket->allow_half_open = allow_half_open;
js_set_native(obj, socket, NET_SOCKET_NATIVE_TAG); js_set_finalizer(obj, net_socket_finalize); stream_init_duplex_object(js, obj, js_mkundef()); js_set(js, obj, "remoteAddress", js_mkundef()); js_set(js, obj, "remotePort", js_mkundef()); js_set(js, obj, "remoteFamily", js_mkundef()); js_set(js, obj, "localAddress", js_mkundef()); js_set(js, obj, "localPort", js_mkundef()); js_set(js, obj, "localFamily", js_mkundef()); net_socket_sync_state(socket); return socket;}
static void net_socket_attach_conn(net_socket_t *socket, ant_conn_t *conn) { if (!socket || !conn) return;
socket->conn = conn; ant_conn_set_user_data(conn, socket); if (ant_conn_has_remote_addr(conn)) { js_set(socket->js, socket->obj, "remoteAddress", js_mkstr(socket->js, ant_conn_remote_addr(conn), strlen(ant_conn_remote_addr(conn)))); js_set(socket->js, socket->obj, "remotePort", js_mknum(ant_conn_remote_port(conn))); js_set(socket->js, socket->obj, "remoteFamily", js_mkstr(socket->js, ant_conn_remote_family(conn), strlen(ant_conn_remote_family(conn)))); } if (ant_conn_has_local_addr(conn)) { js_set(socket->js, socket->obj, "localAddress", js_mkstr(socket->js, ant_conn_local_addr(conn), strlen(ant_conn_local_addr(conn)))); js_set(socket->js, socket->obj, "localPort", js_mknum(ant_conn_local_port(conn))); js_set(socket->js, socket->obj, "localFamily", js_mkstr(socket->js, ant_conn_local_family(conn), strlen(ant_conn_local_family(conn)))); } net_socket_sync_state(socket);}
static net_server_t *net_server_create(ant_t *js, ant_value_t new_target) { ant_value_t obj = Ant_Object_CreateBare(js); ant_value_t proto = js_instance_proto_from_new_target(js, js->builtins.net_server_proto, new_target); net_server_t *server = calloc(1, sizeof(*server));
if (!server) return NULL; if (is_object_type(proto)) js_set_proto_init(obj, proto);
server->js = js; server->obj = obj; server->host = strdup("0.0.0.0"); server->backlog = 511; if (!server->host) { free(server); return NULL; }
js_set_native(obj, server, NET_SERVER_NATIVE_TAG); js_set_finalizer(obj, net_server_finalize); net_server_sync_state(server); return server;}
static ant_value_t net_isIP(ant_params_t) { size_t len = 0; const char *host = NULL; struct in_addr addr4; struct in6_addr addr6;
if (nargs < 1) return js_mknum(0); host = js_getstr(js, args[0], &len); if (!host) return js_mknum(0);
if (inet_pton(AF_INET, host, &addr4) == 1) return js_mknum(4); if (inet_pton(AF_INET6, host, &addr6) == 1) return js_mknum(6); return js_mknum(0);}
static ant_value_t net_isIPv4(ant_params_t) { if (js_getnum(net_isIP(js, args, nargs, js_mkundef())) == 4.0) return js_true; return js_false;}
static ant_value_t net_isIPv6(ant_params_t) { if (js_getnum(net_isIP(js, args, nargs, js_mkundef())) == 6.0) return js_true; return js_false;}
static void net_server_apply_options(ant_t *js, net_server_t *server, ant_value_t options) { ant_value_t value = 0;
if (!server || vtype(options) != kTypeObject) return;
value = js_get(js, options, "allowHalfOpen"); if (vtype(value) != kTypeUndefined) server->allow_half_open = js_truthy(js, value);
value = js_get(js, options, "pauseOnConnect"); if (vtype(value) != kTypeUndefined) server->pause_on_connect = js_truthy(js, value);
value = js_get(js, options, "noDelay"); if (vtype(value) != kTypeUndefined) server->no_delay = js_truthy(js, value);
value = js_get(js, options, "keepAlive"); if (vtype(value) != kTypeUndefined) server->keep_alive = js_truthy(js, value);
value = js_get(js, options, "keepAliveInitialDelay"); if (vtype(value) == kTypeNumber && js_getnum(value) > 0) server->keep_alive_initial_delay_secs = (unsigned int)(js_getnum(value) / 1000.0);
value = js_get(js, options, "backlog"); if (vtype(value) == kTypeNumber && js_getnum(value) > 0) server->backlog = (int)js_getnum(value);}
static void net_socket_on_read(ant_conn_t *conn, ssize_t nread, void *user_data) { net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); const char *buffer = NULL; ant_value_t chunk = 0; size_t total = 0; size_t offset = 0;
if (!socket || !conn || nread <= 0) return;
total = ant_conn_buffer_len(conn); if ((size_t)nread > total) return; offset = total - (size_t)nread; buffer = ant_conn_buffer(conn) + offset;
if (socket->string_encoding) chunk = js_mkstr(socket->js, buffer, (size_t)nread); else chunk = net_make_buffer_chunk(socket->js, buffer, (size_t)nread);
if (is_err(chunk)) { GC_ROOT_SAVE(root_mark, socket->js); chunk = js_take_thrown(socket->js, chunk);
GC_ROOT_PIN(socket->js, chunk); socket->had_error = true;
net_emit(socket->js, socket->obj, "error", &chunk, 1); GC_ROOT_RESTORE(socket->js, root_mark); ant_conn_close(conn);
return; }
ant_conn_consume(conn, total); net_socket_sync_state(socket); net_emit(socket->js, socket->obj, "data", &chunk, 1);}
static void net_socket_on_end(ant_conn_t *conn, void *user_data) { net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn);
if (!socket) return; net_emit(socket->js, socket->obj, "end", NULL, 0); if (!socket->allow_half_open && socket->conn) ant_conn_shutdown(socket->conn);}
static void net_socket_on_error(ant_conn_t *conn, int status, void *user_data) { net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn);
if (!socket) return; socket->had_error = true; { ant_value_t err = Ant_Error_Create(socket->js, JS_ERR_TYPE, uv_strerror(status)); net_emit(socket->js, socket->obj, "error", &err, 1); }}
static void net_socket_on_timeout(ant_conn_t *conn, void *user_data) { net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); if (!socket) return; net_emit(socket->js, socket->obj, "timeout", NULL, 0);}
static void net_server_on_conn_close(ant_conn_t *conn, void *user_data) { net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); ant_value_t arg = 0;
if (!socket) return; arg = js_bool(socket->had_error); socket->conn = NULL; socket->destroyed = true; net_socket_sync_state(socket); net_emit(socket->js, socket->obj, "close", &arg, 1); ant_conn_set_user_data(conn, NULL); net_socket_unlink(socket);}
static void net_socket_on_connect(ant_conn_t *conn, int status, void *user_data) { net_socket_t *socket = (net_socket_t *)user_data;
if (!socket) return; socket->connecting = false;
if (status != 0) { socket->had_error = true; net_socket_sync_state(socket); net_socket_on_error(conn, status, user_data); if (conn) ant_conn_close(conn); return; }
net_socket_attach_conn(socket, conn); ant_conn_start(conn); net_emit(socket->js, socket->obj, "connect", NULL, 0);}
static void net_server_on_listener_close(ant_listener_t *listener, void *user_data) { net_server_maybe_finish_close((net_server_t *)user_data);}
static void net_server_on_accept(ant_listener_t *listener, ant_conn_t *conn, void *user_data) { net_server_t *server = (net_server_t *)user_data; net_socket_t *socket = NULL; ant_value_t arg = 0;
if (!server || !conn) return;
if (server->max_connections > 0 && net_server_socket_count(server) >= server->max_connections) { ant_conn_close(conn); return; }
socket = net_socket_create(server->js, server->allow_half_open, js_mkundef()); if (!socket) { ant_conn_close(conn); return; }
socket->server = server; socket->next_in_server = server->sockets; server->sockets = socket; net_add_active_socket(socket); net_socket_attach_conn(socket, conn);
if (server->no_delay) ant_conn_set_no_delay(conn, true); if (server->keep_alive) ant_conn_set_keep_alive(conn, true, server->keep_alive_initial_delay_secs); if (server->pause_on_connect) ant_conn_pause_read(conn);
arg = socket->obj; net_emit(server->js, server->obj, "connection", &arg, 1);}
static bool net_server_parse_host(const char *input, const char **out) { if (!input || !*input) { *out = "0.0.0.0"; return true; } *out = input; return true;}
static ant_value_t js_net_socket_ctor(ant_params_t) { net_socket_t *socket = NULL; bool allow_half_open = false;
if (nargs > 0 && vtype(args[0]) == kTypeObject) { ant_value_t value = js_get(js, args[0], "allowHalfOpen"); allow_half_open = js_truthy(js, value); }
socket = net_socket_create(js, allow_half_open, call_new_target); if (!socket) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); return socket->obj;}
static ant_value_t js_net_socket_address(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); ant_value_t out = Ant_Object_CreateBare(js);
if (!socket) return Ant_Exception_Current(js); if (!socket || !socket->conn || !ant_conn_has_local_addr(socket->conn)) return out;
js_set(js, out, "address", js_mkstr(js, ant_conn_local_addr(socket->conn), strlen(ant_conn_local_addr(socket->conn)))); js_set(js, out, "port", js_mknum(ant_conn_local_port(socket->conn))); js_set(js, out, "family", js_mkstr(js, ant_conn_local_family(socket->conn), strlen(ant_conn_local_family(socket->conn))));
return out;}
static ant_value_t js_net_socket_pause(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); if (!socket) return Ant_Exception_Current(js); if (socket && socket->conn) ant_conn_pause_read(socket->conn); return js_getthis(js);}
static ant_value_t js_net_socket_resume(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); if (!socket) return Ant_Exception_Current(js); if (socket && socket->conn) ant_conn_resume_read(socket->conn); return js_getthis(js);}
static ant_value_t js_net_socket_setEncoding(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); if (!socket) return Ant_Exception_Current(js); socket->string_encoding = nargs > 0 && vtype(args[0]) != kTypeUndefined; return js_getthis(js);}
static ant_value_t js_net_socket_setTimeout(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); double timeout = 0;
if (!socket) return Ant_Exception_Current(js); if (nargs > 0 && vtype(args[0]) == kTypeNumber) timeout = js_getnum(args[0]); if (socket->conn) ant_conn_set_timeout_ms(socket->conn, timeout > 0 ? (uint64_t)timeout : 0); net_socket_sync_state(socket);
if (nargs > 1 && is_callable(args[1])) net_add_listener(js, socket->obj, "timeout", args[1], true);
return js_getthis(js);}
static ant_value_t js_net_socket_setNoDelay(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); bool enable = nargs == 0 || js_truthy(js, args[0]); if (!socket) return Ant_Exception_Current(js); if (socket && socket->conn) ant_conn_set_no_delay(socket->conn, enable); return js_getthis(js);}
static ant_value_t js_net_socket_setKeepAlive(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); bool enable = nargs > 0 && js_truthy(js, args[0]); unsigned int delay = nargs > 1 && vtype(args[1]) == kTypeNumber ? (unsigned int)(js_getnum(args[1]) / 1000.0) : 0; if (!socket) return Ant_Exception_Current(js); if (socket && socket->conn) ant_conn_set_keep_alive(socket->conn, enable, delay); return js_getthis(js);}
static ant_value_t js_net_socket_ref(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); if (!socket) return Ant_Exception_Current(js); if (socket && socket->conn) ant_conn_ref(socket->conn); return js_getthis(js);}
static ant_value_t js_net_socket_unref(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); if (!socket) return Ant_Exception_Current(js); if (socket && socket->conn) ant_conn_unref(socket->conn); return js_getthis(js);}
static ant_value_t js_net_socket_write(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); net_write_args_t parsed; char *copy = NULL;
if (!socket) return Ant_Exception_Current(js); if (!socket->conn) return js_false; if (!net_parse_write_args(js, args, nargs, &parsed)) return parsed.error; if (parsed.len == 0) return js_true;
copy = malloc(parsed.len); if (!copy) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); memcpy(copy, parsed.bytes, parsed.len); if (ant_conn_write(socket->conn, copy, parsed.len, NULL, NULL) != 0) return js_false;
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, parsed.callback); net_socket_sync_state(socket); if (is_callable(parsed.callback)) sv_call_value(js, parsed.callback, js_mkundef(), NULL, 0); GC_ROOT_RESTORE(js, root_mark); return js_true;}
static ant_value_t js_net_socket_end(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); net_write_args_t parsed; ant_value_t result = js_getthis(js);
if (!socket) return Ant_Exception_Current(js); if (!socket->conn) return result; if (!net_parse_write_args(js, args, nargs, &parsed)) return parsed.error; GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, parsed.callback); if (parsed.len > 0) { ant_value_t write_result = js_net_socket_write(js, args, nargs, js_mkundef()); if (is_err(write_result)) { GC_ROOT_RESTORE(js, root_mark); return write_result; }} ant_conn_shutdown(socket->conn); if (is_callable(parsed.callback)) sv_call_value(js, parsed.callback, js_mkundef(), NULL, 0); GC_ROOT_RESTORE(js, root_mark); return result;}
static ant_value_t js_net_socket_destroy(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); if (!socket) return Ant_Exception_Current(js); if (socket->destroyed) return js_getthis(js);
if (nargs > 0 && vtype(args[0]) != kTypeUndefined && vtype(args[0]) != kTypeNull) { ant_value_t err = args[0]; socket->had_error = true; net_emit(js, socket->obj, "error", &err, 1); }
socket->destroyed = true; socket->connecting = false; net_socket_sync_state(socket); if (socket->conn && !ant_conn_is_closing(socket->conn)) ant_conn_close(socket->conn); return js_getthis(js);}
static ant_value_t net_socket_connect_parsed(ant_t *js, net_socket_t *socket, const net_connect_args_t *parsed) { ant_conn_t *conn = NULL; int rc = 0;
if (!socket || !parsed) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.Socket"); if (socket->conn || socket->connecting) return js_mkerr_typed(js, JS_ERR_TYPE, "Socket is already connected or connecting");
memset(&socket->client_listener, 0, sizeof(socket->client_listener)); socket->client_listener.loop = js->loop; socket->client_listener.user_data = socket; socket->client_listener.callbacks.on_read = net_socket_on_read; socket->client_listener.callbacks.on_end = net_socket_on_end; socket->client_listener.callbacks.on_error = net_socket_on_error; socket->client_listener.callbacks.on_timeout = net_socket_on_timeout; socket->client_listener.callbacks.on_conn_close = net_server_on_conn_close; socket->client_listener.idle_timeout_ms = parsed->timeout_ms;
conn = parsed->path ? ant_conn_create_pipe(&socket->client_listener, parsed->timeout_ms) : ant_conn_create_tcp(&socket->client_listener, parsed->timeout_ms); if (!conn) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory");
socket->conn = conn; socket->connecting = true; socket->destroyed = false; socket->had_error = false; ant_conn_set_user_data(conn, socket); net_add_active_socket(socket); net_socket_sync_state(socket);
if (is_callable(parsed->callback)) net_add_listener(js, socket->obj, "connect", parsed->callback, true);
if (parsed->no_delay) ant_conn_set_no_delay(conn, true); if (parsed->keep_alive) ant_conn_set_keep_alive(conn, true, parsed->keep_alive_initial_delay_secs);
if (parsed->path) rc = ant_conn_connect_pipe(conn, parsed->path, net_socket_on_connect, socket); else rc = ant_conn_connect_tcp(conn, parsed->host ? parsed->host : "localhost", parsed->port, net_socket_on_connect, socket);
if (rc != 0) { socket->connecting = false; socket->had_error = true; net_socket_sync_state(socket); net_socket_schedule_connect_error(js, socket, rc); }
return socket->obj;}
static ant_value_t js_net_socket_connect(ant_params_t) { net_socket_t *socket = net_require_socket(js, js_getthis(js)); net_connect_args_t parsed;
if (!socket) return Ant_Exception_Current(js); if (!net_parse_connect_args(js, args, nargs, &parsed)) return parsed.error; return net_socket_connect_parsed(js, socket, &parsed);}
static ant_value_t js_net_server_ctor(ant_params_t) { net_server_t *server = net_server_create(js, call_new_target);
if (!server) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); if (nargs > 0 && vtype(args[0]) == kTypeObject) net_server_apply_options(js, server, args[0]); if (nargs > 0 && is_callable(args[0])) net_add_listener(js, server->obj, "connection", args[0], false); else if (nargs > 1 && is_callable(args[1])) net_add_listener(js, server->obj, "connection", args[1], false);
return server->obj;}
static ant_value_t net_server_bind_listener( ant_t *js, net_server_t *server, const net_listen_args_t *parsed, const ant_listener_callbacks_t *callbacks) { uv_loop_t *loop = js->loop; int rc = 0;
if (parsed->path) { server->path = strdup(parsed->path); if (!server->path) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); rc = ant_listener_listen_pipe( &server->listener, loop, server->path, server->backlog, 0, callbacks, server ); } else { const char *host = parsed->host; net_server_parse_host(host, &host); free(server->host); server->host = strdup(host ? host : "0.0.0.0"); if (!server->host) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); rc = ant_listener_listen_tcp( &server->listener, loop, server->host, parsed->port, server->backlog, 0, callbacks, server ); }
if (rc != 0) return js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(rc)); return js_mkundef();}
static ant_value_t net_server_emit_listening(ant_params_t) { ant_value_t obj = js_get_slot(js->current_func, SLOT_DATA); net_server_t *server = net_server_data(obj); if (server && server->listening) net_emit(js, obj, "listening", NULL, 0); return js_mkundef();}
static ant_value_t js_net_server_listen(ant_params_t) { net_server_t *server = net_require_server(js, js_getthis(js)); ant_listener_callbacks_t callbacks = {0}; net_listen_args_t parsed;
if (!server) return Ant_Exception_Current(js); if (server->listening) return js_mkerr_typed(js, JS_ERR_TYPE, "Server is already listening"); if (!net_parse_listen_args(js, args, nargs, &parsed)) return parsed.error; if (!parsed.path && parsed.port == 0 && ant_sandbox_policy_forward_restricted()) return js_mkerr_typed( js, JS_ERR_TYPE | JS_ERR_NO_STACK, "sandbox listen on port 0 is not supported; use a fixed port with --forward <port>" ); if (!parsed.path && !ant_sandbox_policy_port_forwarded(parsed.port)) return js_mkerr_typed( js, JS_ERR_TYPE | JS_ERR_NO_STACK, "sandbox listen on port %d requires --forward %d or --forward <host>:%d", parsed.port, parsed.port, parsed.port );
free(server->path); server->path = NULL; server->port = parsed.port; server->backlog = parsed.backlog > 0 ? parsed.backlog : server->backlog;
callbacks.on_accept = net_server_on_accept; callbacks.on_read = net_socket_on_read; callbacks.on_end = net_socket_on_end; callbacks.on_error = net_socket_on_error; callbacks.on_timeout = net_socket_on_timeout; callbacks.on_conn_close = net_server_on_conn_close; callbacks.on_listener_close = net_server_on_listener_close;
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, parsed.callback); ant_value_t bind_result = net_server_bind_listener(js, server, &parsed, &callbacks); if (is_err(bind_result)) { GC_ROOT_RESTORE(js, root_mark); return bind_result; }
server->port = ant_listener_port(&server->listener); server->listening = true; server->closing = false; net_server_sync_state(server); net_add_active_server(server);
if (is_callable(parsed.callback)) net_add_listener(js, server->obj, "listening", parsed.callback, true); ant_value_t emit = js_make_data_cfunc(js, server->obj, net_server_emit_listening); if (!is_err(emit)) queue_next_tick(js, emit); GC_ROOT_RESTORE(js, root_mark); return js_getthis(js);}
static ant_value_t js_net_server_close(ant_params_t) { net_server_t *server = net_require_server(js, js_getthis(js));
if (!server) return Ant_Exception_Current(js); if (nargs > 0 && is_callable(args[0])) net_add_listener(js, server->obj, "close", args[0], true);
if (!server->listening && !server->closing) { if (nargs > 0 && is_callable(args[0])) { ant_value_t err = Ant_Error_Create(js, JS_ERR_TYPE, "Server is not running"); sv_call_value(js, args[0], js_mkundef(), &err, 1); } return js_getthis(js); }
server->closing = true; ant_listener_stop(&server->listener, false); net_server_maybe_finish_close(server); return js_getthis(js);}
static ant_value_t js_net_server_address(ant_params_t) { net_server_t *server = net_require_server(js, js_getthis(js)); ant_value_t out = js_mknull(); if (!server) return Ant_Exception_Current(js); if (!server || !server->listening) return out; if (server->path) return js_mkstr(js, server->path, strlen(server->path));
struct sockaddr_storage saddr; int saddr_len = sizeof(saddr); if (uv_tcp_getsockname(&server->listener.handle.tcp, (struct sockaddr *)&saddr, &saddr_len) == 0) { char addr_str[INET6_ADDRSTRLEN] = {0}; const char *family = "IPv4"; int port = server->port;
if (saddr.ss_family == AF_INET) { struct sockaddr_in *sa = (struct sockaddr_in *)&saddr; inet_ntop(AF_INET, &sa->sin_addr, addr_str, sizeof(addr_str)); port = ntohs(sa->sin_port); } else if (saddr.ss_family == AF_INET6) { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&saddr; inet_ntop(AF_INET6, &sa6->sin6_addr, addr_str, sizeof(addr_str)); port = ntohs(sa6->sin6_port); family = "IPv6"; }
out = Ant_Object_CreateBare(js); js_set(js, out, "port", js_mknum((double)port)); js_set(js, out, "family", js_mkstr(js, family, strlen(family))); js_set(js, out, "address", js_mkstr(js, addr_str, strlen(addr_str))); return out; }
struct in6_addr addr6; out = Ant_Object_CreateBare(js); js_set(js, out, "port", js_mknum(server->port)); if (server->host && inet_pton(AF_INET6, server->host, &addr6) == 1) { char normalized[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &addr6, normalized, sizeof(normalized)); js_set(js, out, "family", js_mkstr(js, "IPv6", 4)); js_set(js, out, "address", js_mkstr(js, normalized, strlen(normalized))); } else { const char *h = server->host ? server->host : "0.0.0.0"; js_set(js, out, "family", js_mkstr(js, "IPv4", 4)); js_set(js, out, "address", js_mkstr(js, h, strlen(h))); } return out;}
static ant_value_t js_net_server_getConnections(ant_params_t) { net_server_t *server = net_require_server(js, js_getthis(js)); ant_value_t cb = nargs > 0 ? args[0] : js_mkundef(); ant_value_t argv[2] = { js_mknull(), js_mknum((double)net_server_socket_count(server)) };
if (!server) return Ant_Exception_Current(js); if (is_callable(cb)) sv_call_value(js, cb, js_mkundef(), argv, 2); return js_getthis(js);}
static ant_value_t js_net_server_ref(ant_params_t) { net_server_t *server = net_require_server(js, js_getthis(js)); if (!server) return Ant_Exception_Current(js); if (server) ant_listener_ref(&server->listener); return js_getthis(js);}
static ant_value_t js_net_server_unref(ant_params_t) { net_server_t *server = net_require_server(js, js_getthis(js)); if (!server) return Ant_Exception_Current(js); if (server) ant_listener_unref(&server->listener); return js_getthis(js);}
static ant_value_t js_net_createServer(ant_params_t) { return js_net_server_ctor(js, args, nargs, js_mkundef());}
static ant_value_t js_net_createConnection(ant_params_t) { net_connect_args_t parsed; net_socket_t *socket = NULL;
if (!net_parse_connect_args(js, args, nargs, &parsed)) return parsed.error; socket = net_socket_create(js, parsed.allow_half_open, js_mkundef()); if (!socket) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory");
return net_socket_connect_parsed(js, socket, &parsed);}
static ant_value_t js_net_connect(ant_params_t) { return js_net_createConnection(js, args, nargs, js_mkundef());}
static ant_value_t js_net_getDefaultAutoSelectFamily(ant_params_t) { return js_bool(js->defaults.net_auto_select_family);}
static ant_value_t js_net_setDefaultAutoSelectFamily(ant_params_t) { if (nargs > 0) js->defaults.net_auto_select_family = js_truthy(js, args[0]); return js_mkundef();}
static ant_value_t js_net_getDefaultAutoSelectFamilyAttemptTimeout(ant_params_t) { return js_mknum(js->defaults.net_auto_select_family_timeout);}
static ant_value_t js_net_setDefaultAutoSelectFamilyAttemptTimeout(ant_params_t) { if (nargs > 0 && vtype(args[0]) == kTypeNumber) { double value = js_getnum(args[0]); if (value > 0 && value < 10) value = 10; if (value > 0) js->defaults.net_auto_select_family_timeout = value; } return js_mkundef();}
static void net_init_constructors(ant_t *js) { ant_value_t events = 0; ant_value_t ee_ctor = 0; ant_value_t ee_proto = 0; ant_value_t duplex_proto = 0;
if (js->builtins.net_server_ctor && js->builtins.net_socket_ctor) return;
events = events_library(js); ee_ctor = js_get(js, events, "EventEmitter"); ee_proto = js_get(js, ee_ctor, "prototype"); duplex_proto = stream_duplex_prototype(js);
js->builtins.net_socket_proto = Ant_Object_CreateBare(js); js_set_proto_init(js->builtins.net_socket_proto, is_object_type(duplex_proto) ? duplex_proto : ee_proto); js_set(js, js->builtins.net_socket_proto, "address", Ant_Function_Create(js_net_socket_address)); js_set(js, js->builtins.net_socket_proto, "pause", Ant_Function_Create(js_net_socket_pause)); js_set(js, js->builtins.net_socket_proto, "resume", Ant_Function_Create(js_net_socket_resume)); js_set(js, js->builtins.net_socket_proto, "setEncoding", Ant_Function_Create(js_net_socket_setEncoding)); js_set(js, js->builtins.net_socket_proto, "setTimeout", Ant_Function_CreateWithArity(js_net_socket_setTimeout, 2)); js_set(js, js->builtins.net_socket_proto, "setNoDelay", Ant_Function_CreateWithArity(js_net_socket_setNoDelay, 1)); js_set(js, js->builtins.net_socket_proto, "setKeepAlive", Ant_Function_CreateWithArity(js_net_socket_setKeepAlive, 2)); js_set(js, js->builtins.net_socket_proto, "write", Ant_Function_Create(js_net_socket_write)); js_set(js, js->builtins.net_socket_proto, "end", Ant_Function_CreateWithArity(js_net_socket_end, 3)); js_set(js, js->builtins.net_socket_proto, "destroy", Ant_Function_Create(js_net_socket_destroy)); js_set(js, js->builtins.net_socket_proto, "connect", Ant_Function_Create(js_net_socket_connect)); js_set(js, js->builtins.net_socket_proto, "ref", Ant_Function_Create(js_net_socket_ref)); js_set(js, js->builtins.net_socket_proto, "unref", Ant_Function_Create(js_net_socket_unref)); js_set_tostringtag(js, js->builtins.net_socket_proto, js_mkstr(js, "Socket", 6)); js->builtins.net_socket_ctor = Ant_Function_CreateConstructor(js, js_net_socket_ctor, js->builtins.net_socket_proto, "Socket", 1);
js->builtins.net_server_proto = Ant_Object_CreateBare(js); js_set_proto_init(js->builtins.net_server_proto, ee_proto); js_set(js, js->builtins.net_server_proto, "listen", Ant_Function_Create(js_net_server_listen)); js_set(js, js->builtins.net_server_proto, "close", Ant_Function_CreateWithArity(js_net_server_close, 1)); js_set(js, js->builtins.net_server_proto, "address", Ant_Function_Create(js_net_server_address)); js_set(js, js->builtins.net_server_proto, "getConnections", Ant_Function_CreateWithArity(js_net_server_getConnections, 1)); js_set(js, js->builtins.net_server_proto, "ref", Ant_Function_Create(js_net_server_ref)); js_set(js, js->builtins.net_server_proto, "unref", Ant_Function_Create(js_net_server_unref)); js_set_tostringtag(js, js->builtins.net_server_proto, js_mkstr(js, "Server", 6)); js->builtins.net_server_ctor = Ant_Function_CreateConstructor(js, js_net_server_ctor, js->builtins.net_server_proto, "Server", 2);}
ant_value_t net_library(ant_t *js) { ant_value_t lib = Ant_Object_CreateBare(js);
net_init_constructors(js); js_set(js, lib, "Server", js->builtins.net_server_ctor); js_set(js, lib, "Socket", js->builtins.net_socket_ctor); js_set(js, lib, "createServer", Ant_Function_CreateWithArity(js_net_createServer, 2)); js_set(js, lib, "createConnection", Ant_Function_Create(js_net_createConnection)); js_set(js, lib, "connect", Ant_Function_Create(js_net_connect)); js_set(js, lib, "isIP", Ant_Function_CreateWithArity(net_isIP, 1)); js_set(js, lib, "isIPv4", Ant_Function_CreateWithArity(net_isIPv4, 1)); js_set(js, lib, "isIPv6", Ant_Function_CreateWithArity(net_isIPv6, 1)); js_set(js, lib, "getDefaultAutoSelectFamily", Ant_Function_Create(js_net_getDefaultAutoSelectFamily)); js_set(js, lib, "setDefaultAutoSelectFamily", Ant_Function_CreateWithArity(js_net_setDefaultAutoSelectFamily, 1)); js_set(js, lib, "getDefaultAutoSelectFamilyAttemptTimeout", Ant_Function_Create(js_net_getDefaultAutoSelectFamilyAttemptTimeout)); js_set(js, lib, "setDefaultAutoSelectFamilyAttemptTimeout", Ant_Function_CreateWithArity(js_net_setDefaultAutoSelectFamilyAttemptTimeout, 1)); js_set(js, lib, "default", lib); js_set_tostringtag(js, lib, js_mkstr(js, "net", 3)); return lib;}
void cleanup_net_module(ant_t *js) { for (net_socket_t *socket = js->net_sockets; socket; socket = socket->next) if (socket->conn && !ant_conn_is_closing(socket->conn)) ant_conn_close(socket->conn);
for (net_server_t *server = js->net_servers; server; server = server->next) { server->closing = true; ant_listener_stop(&server->listener, true); }}
void gc_mark_net(ant_t *js, gc_mark_fn mark) { net_server_t *server = NULL; net_socket_t *socket = NULL;
for (server = js->net_servers; server; server = server->next) mark(js, server->obj); for (socket = js->net_sockets; socket; socket = socket->next) mark(js, socket->obj);}