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.

add node:net module

+1129 -66
+26
examples/demo/net.cjs
··· 1 + const net = require('node:net'); 2 + 3 + const httpResponse = `HTTP/1.1 200 OK\r 4 + Content-Type: text/plain\r 5 + \r 6 + Hello, World from net module! 7 + `; 8 + 9 + const server = net.createServer(socket => { 10 + console.log('Client connected'); 11 + 12 + socket.on('data', () => { 13 + socket.write(httpResponse); 14 + socket.end(); 15 + }); 16 + 17 + socket.on('end', () => { 18 + console.log('Client disconnected'); 19 + }); 20 + 21 + socket.on('error', err => { 22 + console.error(`Socket error: ${err.message}`); 23 + }); 24 + }); 25 + 26 + server.listen(3000, () => console.log(`server on http://localhost:3000`));
+3
examples/demo/server.cjs
··· 1 + require('node:http') 2 + .createServer((_req, res) => res.end('ant!')) 3 + .listen(3000);
+10 -8
examples/demo/welcome.js
··· 2 2 3 3 const rows = [ 4 4 ['Feature', 'Description'], 5 - ['Async/Await', 'Full coroutine support with minicoro'], 6 - ['HTTP Server', 'Built-in Ant.serve() with TLS support'], 7 - ['Fetch API', 'HTTP client with TLS via tlsuv'], 8 - ['File System', 'Async/sync fs with ant:fs module'], 9 - ['FFI', 'Native library integration'], 10 - ['Web Locks', 'Navigator.locks API'], 11 - ['TypeScript', 'Built-in type stripping via oxc'], 12 - ['Garbage Collection', 'Mark-copy compacting + Boehm-Demers'], 5 + ['Async/Await', 'Native promises, microtasks, and async functions'], 6 + ['HTTP Server', 'Module-first server runtime with export default { fetch }'], 7 + ['WinterTC APIs', 'Request, Response, Headers, fetch, streams, Blob, FormData'], 8 + ['Fetch API', 'Request/Response/Headers/FormData with streamed bodies'], 9 + ['File System', 'Async and sync filesystem APIs for scripts and tooling'], 10 + ['FFI', 'Call native libraries directly with libffi-backed bindings'], 11 + ['Web Locks', 'Web-standard Navigator.locks coordination primitives'], 12 + ['TypeScript', 'Built-in .ts execution with automatic type stripping'], 13 + ['Compression', 'CompressionStream, DecompressionStream, gzip, deflate, brotli'], 14 + ['Garbage Collection', 'Adaptive generational GC with nursery and major cycles'], 13 15 null, 14 16 [null, 'And more...'] 15 17 ];
+1
include/gc/modules.h
··· 13 13 void gc_mark_readline(ant_t *js, gc_mark_fn mark); 14 14 void gc_mark_process(ant_t *js, gc_mark_fn mark); 15 15 void gc_mark_navigator(ant_t *js, gc_mark_fn mark); 16 + void gc_mark_net(ant_t *js, gc_mark_fn mark); 16 17 void gc_mark_server(ant_t *js, gc_mark_fn mark); 17 18 void gc_mark_events(ant_t *js, gc_mark_fn mark); 18 19 void gc_mark_lmdb(ant_t *js, gc_mark_fn mark);
+12 -2
include/net/connection.h
··· 3 3 4 4 #include <stdbool.h> 5 5 #include <stddef.h> 6 + #include <stdint.h> 6 7 #include <uv.h> 7 8 8 9 typedef struct ant_listener_s ant_listener_t; ··· 16 17 char *buffer; 17 18 size_t buffer_len; 18 19 size_t buffer_cap; 19 - int timeout_secs; 20 + uint64_t timeout_ms; 21 + uint64_t bytes_read; 22 + uint64_t bytes_written; 20 23 int close_handles; 21 24 bool closing; 25 + bool read_paused; 26 + bool read_eof; 27 + bool has_local_addr; 22 28 bool has_remote_addr; 29 + char local_addr[64]; 23 30 char remote_addr[64]; 31 + char local_family[8]; 32 + char remote_family[8]; 33 + int local_port; 24 34 int remote_port; 25 35 struct ant_conn_s *next; 26 36 }; 27 37 28 38 void ant_conn_start(ant_conn_t *conn); 29 39 int ant_conn_accept(ant_conn_t *conn, uv_stream_t *server_stream); 30 - ant_conn_t *ant_conn_create_tcp(ant_listener_t *listener, int timeout_secs); 40 + ant_conn_t *ant_conn_create_tcp(ant_listener_t *listener, uint64_t timeout_ms); 31 41 32 42 #endif
+23 -4
include/net/listener.h
··· 3 3 4 4 #include <stdbool.h> 5 5 #include <stddef.h> 6 + #include <stdint.h> 6 7 #include <uv.h> 7 8 8 9 typedef struct ant_listener_s ant_listener_t; ··· 17 18 typedef struct { 18 19 void (*on_accept)(ant_listener_t *listener, ant_conn_t *conn, void *user_data); 19 20 void (*on_read)(ant_conn_t *conn, ssize_t nread, void *user_data); 21 + void (*on_end)(ant_conn_t *conn, void *user_data); 22 + void (*on_error)(ant_conn_t *conn, int status, void *user_data); 23 + void (*on_timeout)(ant_conn_t *conn, void *user_data); 20 24 void (*on_conn_close)(ant_conn_t *conn, void *user_data); 21 25 void (*on_listener_close)(ant_listener_t *listener, void *user_data); 22 26 } ant_listener_callbacks_t; ··· 27 31 ant_conn_t *connections; 28 32 ant_listener_callbacks_t callbacks; 29 33 void *user_data; 30 - int idle_timeout_secs; 34 + uint64_t idle_timeout_ms; 31 35 int port; 32 36 int backlog; 33 37 bool started; ··· 41 45 const char *hostname, 42 46 int port, 43 47 int backlog, 44 - int idle_timeout_secs, 48 + uint64_t idle_timeout_ms, 45 49 const ant_listener_callbacks_t *callbacks, 46 50 void *user_data 47 51 ); ··· 49 53 void ant_listener_stop(ant_listener_t *listener, bool force); 50 54 void *ant_listener_get_user_data(const ant_listener_t *listener); 51 55 56 + int ant_conn_local_port(const ant_conn_t *conn); 52 57 int ant_listener_port(const ant_listener_t *listener); 53 - int ant_conn_timeout(const ant_conn_t *conn); 54 58 int ant_conn_remote_port(const ant_conn_t *conn); 59 + int ant_conn_set_no_delay(ant_conn_t *conn, bool enable); 60 + int ant_conn_set_keep_alive(ant_conn_t *conn, bool enable, unsigned int delay_secs); 55 61 int ant_conn_write(ant_conn_t *conn, char *data, size_t len, ant_conn_write_cb cb, void *user_data); 56 62 57 63 bool ant_listener_has_connections(const ant_listener_t *listener); 58 64 bool ant_listener_is_closed(const ant_listener_t *listener); 59 65 bool ant_conn_is_closing(const ant_conn_t *conn); 66 + bool ant_conn_has_local_addr(const ant_conn_t *conn); 60 67 bool ant_conn_has_remote_addr(const ant_conn_t *conn); 61 68 62 69 void ant_conn_set_user_data(ant_conn_t *conn, void *user_data); 63 70 void *ant_conn_get_user_data(const ant_conn_t *conn); 64 71 void ant_conn_pause_read(ant_conn_t *conn); 72 + void ant_conn_resume_read(ant_conn_t *conn); 65 73 void ant_conn_close(ant_conn_t *conn); 66 - void ant_conn_set_timeout(ant_conn_t *conn, int timeout_secs); 74 + void ant_conn_shutdown(ant_conn_t *conn); 75 + void ant_conn_ref(ant_conn_t *conn); 76 + void ant_conn_unref(ant_conn_t *conn); 77 + void ant_conn_set_timeout_ms(ant_conn_t *conn, uint64_t timeout_ms); 78 + void ant_conn_consume(ant_conn_t *conn, size_t len); 67 79 68 80 const char *ant_conn_buffer(const ant_conn_t *conn); 81 + const char *ant_conn_local_addr(const ant_conn_t *conn); 69 82 const char *ant_conn_remote_addr(const ant_conn_t *conn); 83 + const char *ant_conn_local_family(const ant_conn_t *conn); 84 + const char *ant_conn_remote_family(const ant_conn_t *conn); 70 85 71 86 size_t ant_conn_buffer_len(const ant_conn_t *conn); 72 87 ant_listener_t *ant_conn_listener(const ant_conn_t *conn); 88 + 89 + uint64_t ant_conn_timeout_ms(const ant_conn_t *conn); 90 + uint64_t ant_conn_bytes_read(const ant_conn_t *conn); 91 + uint64_t ant_conn_bytes_written(const ant_conn_t *conn); 73 92 74 93 #endif
+1
src/gc/objects.c
··· 446 446 gc_mark_readline(js, gc_mark_value); 447 447 gc_mark_process(js, gc_mark_value); 448 448 gc_mark_navigator(js, gc_mark_value); 449 + gc_mark_net(js, gc_mark_value); 449 450 gc_mark_server(js, gc_mark_value); 450 451 gc_mark_events(js, gc_mark_value); 451 452 gc_mark_lmdb(js, gc_mark_value);
+862 -22
src/modules/net.c
··· 1 - // stub: minimal node:net implementation (isIP, isIPv4, isIPv6) 2 - // just enough for vite to resolve the module and validate hostnames 1 + #include <compat.h> // IWYU pragma: keep 3 2 3 + #include <stdbool.h> 4 + #include <stdint.h> 5 + #include <stdlib.h> 4 6 #include <string.h> 5 7 6 8 #ifdef _WIN32 ··· 11 13 #endif 12 14 13 15 #include "ant.h" 14 - #include "internal.h" // IWYU pragma: keep 16 + #include "ptr.h" 17 + #include "errors.h" 18 + #include "internal.h" 19 + 20 + #include "gc/modules.h" 21 + #include "net/listener.h" 22 + #include "silver/engine.h" 23 + 24 + #include "modules/buffer.h" 25 + #include "modules/events.h" 26 + #include "modules/net.h" 27 + #include "modules/symbol.h" 28 + 29 + typedef struct net_server_s net_server_t; 30 + typedef struct net_socket_s net_socket_t; 31 + 32 + struct net_socket_s { 33 + ant_t *js; 34 + ant_value_t obj; 35 + ant_conn_t *conn; 36 + net_server_t *server; 37 + ant_value_t encoding; 38 + struct net_socket_s *next_active; 39 + struct net_socket_s *next_in_server; 40 + bool allow_half_open; 41 + bool destroyed; 42 + bool had_error; 43 + }; 44 + 45 + struct net_server_s { 46 + ant_t *js; 47 + ant_value_t obj; 48 + ant_listener_t listener; 49 + net_socket_t *sockets; 50 + struct net_server_s *next_active; 51 + char *host; 52 + int port; 53 + int backlog; 54 + int max_connections; 55 + bool listening; 56 + bool closing; 57 + bool allow_half_open; 58 + bool pause_on_connect; 59 + bool no_delay; 60 + bool keep_alive; 61 + unsigned int keep_alive_initial_delay_secs; 62 + }; 63 + 64 + static ant_value_t g_net_server_proto = 0; 65 + static ant_value_t g_net_socket_proto = 0; 66 + static ant_value_t g_net_server_ctor = 0; 67 + static ant_value_t g_net_socket_ctor = 0; 68 + 69 + static net_server_t *g_active_servers = NULL; 70 + static net_socket_t *g_active_sockets = NULL; 71 + 72 + static bool g_default_auto_select_family = true; 73 + static double g_default_auto_select_family_attempt_timeout = 250.0; 74 + 75 + enum { 76 + NET_SERVER_NATIVE_TAG = 0x4e455453u, 77 + NET_SOCKET_NATIVE_TAG = 0x4e45544bu, 78 + }; 79 + 80 + static net_server_t *net_server_data(ant_value_t value) { 81 + if (!js_check_native_tag(value, NET_SERVER_NATIVE_TAG)) return NULL; 82 + return (net_server_t *)js_get_native_ptr(value); 83 + } 84 + 85 + static net_socket_t *net_socket_data(ant_value_t value) { 86 + if (!js_check_native_tag(value, NET_SOCKET_NATIVE_TAG)) return NULL; 87 + return (net_socket_t *)js_get_native_ptr(value); 88 + } 89 + 90 + static void net_add_active_server(net_server_t *server) { 91 + server->next_active = g_active_servers; 92 + g_active_servers = server; 93 + } 94 + 95 + static void net_remove_active_server(net_server_t *server) { 96 + net_server_t **it = NULL; 97 + for (it = &g_active_servers; *it; it = &(*it)->next_active) { 98 + if (*it == server) { 99 + *it = server->next_active; 100 + server->next_active = NULL; 101 + return; 102 + }} 103 + } 104 + 105 + static void net_add_active_socket(net_socket_t *socket) { 106 + socket->next_active = g_active_sockets; 107 + g_active_sockets = socket; 108 + } 109 + 110 + static void net_remove_active_socket(net_socket_t *socket) { 111 + net_socket_t **it = NULL; 112 + for (it = &g_active_sockets; *it; it = &(*it)->next_active) { 113 + if (*it == socket) { 114 + *it = socket->next_active; 115 + socket->next_active = NULL; 116 + return; 117 + }} 118 + } 119 + 120 + static ant_value_t net_call_value( 121 + ant_t *js, 122 + ant_value_t fn, 123 + ant_value_t this_val, 124 + ant_value_t *args, 125 + int nargs 126 + ) { 127 + ant_value_t saved_this = js->this_val; 128 + ant_value_t result = js_mkundef(); 129 + 130 + js->this_val = this_val; 131 + if (vtype(fn) == T_CFUNC) 132 + result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(fn))(js, args, nargs); 133 + else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false); 134 + js->this_val = saved_this; 135 + return result; 136 + } 137 + 138 + static ant_value_t net_call_method( 139 + ant_t *js, 140 + ant_value_t target, 141 + const char *name, 142 + ant_value_t *args, 143 + int nargs 144 + ) { 145 + ant_value_t fn = js_get(js, target, name); 146 + if (!is_callable(fn)) return js_mkundef(); 147 + return net_call_value(js, fn, target, args, nargs); 148 + } 149 + 150 + static void net_emit(ant_t *js, ant_value_t target, const char *event, ant_value_t *args, int nargs) { 151 + ant_value_t emit_args[8] = {0}; 152 + int i = 0; 153 + 154 + if (nargs > 7) nargs = 7; 155 + emit_args[0] = js_mkstr(js, event, strlen(event)); 156 + for (i = 0; i < nargs; i++) emit_args[i + 1] = args[i]; 157 + net_call_method(js, target, "emit", emit_args, nargs + 1); 158 + } 159 + 160 + static ant_value_t net_make_buffer_chunk(ant_t *js, const char *data, size_t len) { 161 + ArrayBufferData *ab = create_array_buffer_data(len); 162 + if (!ab) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 163 + if (len > 0 && data) memcpy(ab->data, data, len); 164 + return create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, len, "Buffer"); 165 + } 166 + 167 + static void net_socket_sync_state(net_socket_t *socket) { 168 + ant_value_t obj = 0; 169 + const char *ready_state = "open"; 15 170 16 - static ant_value_t net_isIP(ant_t *js, ant_value_t *args, int nargs) { 17 - if (nargs < 1) return js_mknum(0); 18 - size_t len; 19 - const char *host = js_getstr(js, args[0], &len); 20 - if (!host) return js_mknum(0); 171 + if (!socket) return; 172 + obj = socket->obj; 173 + if (!is_object_type(obj)) return; 174 + 175 + if (socket->destroyed) ready_state = "closed"; 176 + js_set(socket->js, obj, "destroyed", js_bool(socket->destroyed)); 177 + js_set(socket->js, obj, "pending", js_bool(socket->conn == NULL && !socket->destroyed)); 178 + js_set(socket->js, obj, "connecting", js_false); 179 + js_set(socket->js, obj, "readyState", js_mkstr(socket->js, ready_state, strlen(ready_state))); 180 + js_set(socket->js, obj, "bytesRead", js_mknum((double)(socket->conn ? ant_conn_bytes_read(socket->conn) : 0))); 181 + js_set(socket->js, obj, "bytesWritten", js_mknum((double)(socket->conn ? ant_conn_bytes_written(socket->conn) : 0))); 182 + js_set(socket->js, obj, "timeout", js_mknum((double)(socket->conn ? ant_conn_timeout_ms(socket->conn) : 0))); 183 + } 184 + 185 + static void net_server_sync_state(net_server_t *server) { 186 + if (!server || !is_object_type(server->obj)) return; 187 + js_set(server->js, server->obj, "listening", js_bool(server->listening)); 188 + js_set(server->js, server->obj, "maxConnections", js_mknum((double)server->max_connections)); 189 + js_set(server->js, server->obj, "dropMaxConnection", js_false); 190 + } 191 + 192 + static int net_server_socket_count(net_server_t *server) { 193 + int count = 0; 194 + net_socket_t *socket = NULL; 195 + 196 + for (socket = server ? server->sockets : NULL; socket; socket = socket->next_in_server) 197 + count++; 198 + return count; 199 + } 200 + 201 + static void net_server_maybe_finish_close(net_server_t *server) { 202 + if (!server || !server->closing) return; 203 + if (!ant_listener_is_closed(&server->listener)) return; 204 + if (server->sockets) return; 205 + 206 + server->closing = false; 207 + server->listening = false; 208 + net_server_sync_state(server); 209 + net_emit(server->js, server->obj, "close", NULL, 0); 210 + net_remove_active_server(server); 211 + } 212 + 213 + static void net_socket_detach(net_socket_t *socket) { 214 + if (!socket) return; 215 + 216 + if (socket->server) { 217 + net_socket_t **it = NULL; 218 + for (it = &socket->server->sockets; *it; it = &(*it)->next_in_server) { 219 + if (*it == socket) { 220 + *it = socket->next_in_server; 221 + break; 222 + } 223 + } 224 + socket->next_in_server = NULL; 225 + } 21 226 227 + net_remove_active_socket(socket); 228 + if (is_object_type(socket->obj)) { 229 + js_set_native_ptr(socket->obj, NULL); 230 + js_set_native_tag(socket->obj, 0); 231 + } 232 + net_server_maybe_finish_close(socket->server); 233 + free(socket); 234 + } 235 + 236 + static void net_socket_emit_error(net_socket_t *socket, const char *message) { 237 + ant_value_t arg = js_mkerr_typed(socket->js, JS_ERR_TYPE, "%s", message); 238 + socket->had_error = true; 239 + net_emit(socket->js, socket->obj, "error", &arg, 1); 240 + } 241 + 242 + static net_socket_t *net_socket_create(ant_t *js, bool allow_half_open) { 243 + ant_value_t obj = js_mkobj(js); 244 + ant_value_t proto = js_instance_proto_from_new_target(js, g_net_socket_proto); 245 + net_socket_t *socket = calloc(1, sizeof(*socket)); 246 + 247 + if (!socket) return NULL; 248 + if (is_object_type(proto)) js_set_proto_init(obj, proto); 249 + 250 + socket->js = js; 251 + socket->obj = obj; 252 + socket->encoding = js_mkundef(); 253 + socket->allow_half_open = allow_half_open; 254 + 255 + js_set_native_ptr(obj, socket); 256 + js_set_native_tag(obj, NET_SOCKET_NATIVE_TAG); 257 + js_set(js, obj, "remoteAddress", js_mkundef()); 258 + js_set(js, obj, "remotePort", js_mkundef()); 259 + js_set(js, obj, "remoteFamily", js_mkundef()); 260 + js_set(js, obj, "localAddress", js_mkundef()); 261 + js_set(js, obj, "localPort", js_mkundef()); 262 + js_set(js, obj, "localFamily", js_mkundef()); 263 + net_socket_sync_state(socket); 264 + 265 + return socket; 266 + } 267 + 268 + static void net_socket_attach_conn(net_socket_t *socket, ant_conn_t *conn) { 269 + if (!socket || !conn) return; 270 + 271 + socket->conn = conn; 272 + ant_conn_set_user_data(conn, socket); 273 + if (ant_conn_has_remote_addr(conn)) { 274 + js_set(socket->js, socket->obj, "remoteAddress", js_mkstr(socket->js, ant_conn_remote_addr(conn), strlen(ant_conn_remote_addr(conn)))); 275 + js_set(socket->js, socket->obj, "remotePort", js_mknum(ant_conn_remote_port(conn))); 276 + js_set(socket->js, socket->obj, "remoteFamily", js_mkstr(socket->js, ant_conn_remote_family(conn), strlen(ant_conn_remote_family(conn)))); 277 + } 278 + if (ant_conn_has_local_addr(conn)) { 279 + js_set(socket->js, socket->obj, "localAddress", js_mkstr(socket->js, ant_conn_local_addr(conn), strlen(ant_conn_local_addr(conn)))); 280 + js_set(socket->js, socket->obj, "localPort", js_mknum(ant_conn_local_port(conn))); 281 + js_set(socket->js, socket->obj, "localFamily", js_mkstr(socket->js, ant_conn_local_family(conn), strlen(ant_conn_local_family(conn)))); 282 + } 283 + net_socket_sync_state(socket); 284 + } 285 + 286 + static net_server_t *net_server_create(ant_t *js) { 287 + ant_value_t obj = js_mkobj(js); 288 + ant_value_t proto = js_instance_proto_from_new_target(js, g_net_server_proto); 289 + net_server_t *server = calloc(1, sizeof(*server)); 290 + 291 + if (!server) return NULL; 292 + if (is_object_type(proto)) js_set_proto_init(obj, proto); 293 + 294 + server->js = js; 295 + server->obj = obj; 296 + server->host = strdup("0.0.0.0"); 297 + server->backlog = 511; 298 + if (!server->host) { 299 + free(server); 300 + return NULL; 301 + } 302 + 303 + js_set_native_ptr(obj, server); 304 + js_set_native_tag(obj, NET_SERVER_NATIVE_TAG); 305 + net_server_sync_state(server); 306 + return server; 307 + } 308 + 309 + static ant_value_t net_not_implemented(ant_t *js, const char *what) { 310 + return js_mkerr_typed(js, JS_ERR_TYPE, "%s is not implemented yet", what); 311 + } 312 + 313 + static ant_value_t net_isIP(ant_t *js, ant_value_t *args, int nargs) { 314 + size_t len = 0; 315 + const char *host = NULL; 22 316 struct in_addr addr4; 23 317 struct in6_addr addr6; 24 318 319 + if (nargs < 1) return js_mknum(0); 320 + host = js_getstr(js, args[0], &len); 321 + if (!host) return js_mknum(0); 322 + 25 323 if (inet_pton(AF_INET, host, &addr4) == 1) return js_mknum(4); 26 324 if (inet_pton(AF_INET6, host, &addr6) == 1) return js_mknum(6); 27 325 return js_mknum(0); 28 326 } 29 327 30 328 static ant_value_t net_isIPv4(ant_t *js, ant_value_t *args, int nargs) { 31 - if (nargs < 1) return js_false; 32 - size_t len; 33 - const char *host = js_getstr(js, args[0], &len); 34 - if (!host) return js_false; 329 + if (js_getnum(net_isIP(js, args, nargs)) == 4.0) return js_true; 330 + return js_false; 331 + } 332 + 333 + static ant_value_t net_isIPv6(ant_t *js, ant_value_t *args, int nargs) { 334 + if (js_getnum(net_isIP(js, args, nargs)) == 6.0) return js_true; 335 + return js_false; 336 + } 337 + 338 + static void net_server_apply_options(ant_t *js, net_server_t *server, ant_value_t options) { 339 + ant_value_t value = 0; 340 + 341 + if (!server || vtype(options) != T_OBJ) return; 342 + 343 + value = js_get(js, options, "allowHalfOpen"); 344 + if (vtype(value) != T_UNDEF) server->allow_half_open = js_truthy(js, value); 345 + 346 + value = js_get(js, options, "pauseOnConnect"); 347 + if (vtype(value) != T_UNDEF) server->pause_on_connect = js_truthy(js, value); 348 + 349 + value = js_get(js, options, "noDelay"); 350 + if (vtype(value) != T_UNDEF) server->no_delay = js_truthy(js, value); 351 + 352 + value = js_get(js, options, "keepAlive"); 353 + if (vtype(value) != T_UNDEF) server->keep_alive = js_truthy(js, value); 354 + 355 + value = js_get(js, options, "keepAliveInitialDelay"); 356 + if (vtype(value) == T_NUM && js_getnum(value) > 0) 357 + server->keep_alive_initial_delay_secs = (unsigned int)(js_getnum(value) / 1000.0); 358 + 359 + value = js_get(js, options, "backlog"); 360 + if (vtype(value) == T_NUM && js_getnum(value) > 0) 361 + server->backlog = (int)js_getnum(value); 362 + } 363 + 364 + static void net_socket_on_read(ant_conn_t *conn, ssize_t nread, void *user_data) { 365 + net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 366 + const char *buffer = NULL; 367 + ant_value_t chunk = 0; 368 + size_t total = 0; 369 + size_t offset = 0; 370 + 371 + if (!socket || !conn || nread <= 0) return; 372 + 373 + total = ant_conn_buffer_len(conn); 374 + if ((size_t)nread > total) return; 375 + offset = total - (size_t)nread; 376 + buffer = ant_conn_buffer(conn) + offset; 35 377 36 - struct in_addr addr; 37 - return inet_pton(AF_INET, host, &addr) == 1 ? js_true : js_false; 378 + if (vtype(socket->encoding) == T_STR) 379 + chunk = js_mkstr(socket->js, buffer, (size_t)nread); 380 + else chunk = net_make_buffer_chunk(socket->js, buffer, (size_t)nread); 381 + 382 + ant_conn_consume(conn, total); 383 + net_socket_sync_state(socket); 384 + net_emit(socket->js, socket->obj, "data", &chunk, 1); 38 385 } 39 386 40 - static ant_value_t net_isIPv6(ant_t *js, ant_value_t *args, int nargs) { 41 - if (nargs < 1) return js_false; 42 - size_t len; 43 - const char *host = js_getstr(js, args[0], &len); 44 - if (!host) return js_false; 387 + static void net_socket_on_end(ant_conn_t *conn, void *user_data) { 388 + net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 45 389 46 - struct in6_addr addr; 47 - return inet_pton(AF_INET6, host, &addr) == 1 ? js_true : js_false; 390 + if (!socket) return; 391 + net_emit(socket->js, socket->obj, "end", NULL, 0); 392 + if (!socket->allow_half_open && socket->conn) ant_conn_shutdown(socket->conn); 393 + } 394 + 395 + static void net_socket_on_error(ant_conn_t *conn, int status, void *user_data) { 396 + net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 397 + 398 + if (!socket) return; 399 + socket->had_error = true; { 400 + ant_value_t err = js_mkerr_typed(socket->js, JS_ERR_TYPE, "%s", uv_strerror(status)); 401 + net_emit(socket->js, socket->obj, "error", &err, 1); 402 + } 403 + } 404 + 405 + static void net_socket_on_timeout(ant_conn_t *conn, void *user_data) { 406 + net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 407 + if (!socket) return; 408 + net_emit(socket->js, socket->obj, "timeout", NULL, 0); 409 + } 410 + 411 + static void net_server_on_conn_close(ant_conn_t *conn, void *user_data) { 412 + net_socket_t *socket = (net_socket_t *)ant_conn_get_user_data(conn); 413 + ant_value_t arg = 0; 414 + 415 + if (!socket) return; 416 + arg = js_bool(socket->had_error); 417 + socket->conn = NULL; 418 + socket->destroyed = true; 419 + net_socket_sync_state(socket); 420 + net_emit(socket->js, socket->obj, "close", &arg, 1); 421 + ant_conn_set_user_data(conn, NULL); 422 + net_socket_detach(socket); 423 + } 424 + 425 + static void net_server_on_listener_close(ant_listener_t *listener, void *user_data) { 426 + net_server_maybe_finish_close((net_server_t *)user_data); 427 + } 428 + 429 + static void net_server_on_accept(ant_listener_t *listener, ant_conn_t *conn, void *user_data) { 430 + net_server_t *server = (net_server_t *)user_data; 431 + net_socket_t *socket = NULL; 432 + ant_value_t arg = 0; 433 + 434 + if (!server || !conn) return; 435 + 436 + if (server->max_connections > 0 && net_server_socket_count(server) >= server->max_connections) { 437 + ant_conn_close(conn); 438 + return; 439 + } 440 + 441 + socket = net_socket_create(server->js, server->allow_half_open); 442 + if (!socket) { 443 + ant_conn_close(conn); 444 + return; 445 + } 446 + 447 + socket->server = server; 448 + socket->next_in_server = server->sockets; 449 + server->sockets = socket; 450 + net_add_active_socket(socket); 451 + net_socket_attach_conn(socket, conn); 452 + 453 + if (server->no_delay) ant_conn_set_no_delay(conn, true); 454 + if (server->keep_alive) 455 + ant_conn_set_keep_alive(conn, true, server->keep_alive_initial_delay_secs); 456 + if (server->pause_on_connect) ant_conn_pause_read(conn); 457 + 458 + arg = socket->obj; 459 + net_emit(server->js, server->obj, "connection", &arg, 1); 460 + } 461 + 462 + static bool net_server_parse_host(const char *input, const char **out) { 463 + if (!input || !*input) { 464 + *out = "0.0.0.0"; 465 + return true; 466 + } 467 + if (strcmp(input, "localhost") == 0) { 468 + *out = "127.0.0.1"; 469 + return true; 470 + } 471 + *out = input; 472 + return true; 473 + } 474 + 475 + static ant_value_t js_net_socket_ctor(ant_t *js, ant_value_t *args, int nargs) { 476 + net_socket_t *socket = NULL; 477 + bool allow_half_open = false; 478 + 479 + if (nargs > 0 && vtype(args[0]) == T_OBJ) { 480 + ant_value_t value = js_get(js, args[0], "allowHalfOpen"); 481 + allow_half_open = js_truthy(js, value); 482 + } 483 + 484 + socket = net_socket_create(js, allow_half_open); 485 + if (!socket) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 486 + return socket->obj; 487 + } 488 + 489 + static ant_value_t js_net_socket_address(ant_t *js, ant_value_t *args, int nargs) { 490 + net_socket_t *socket = net_socket_data(js_getthis(js)); 491 + ant_value_t out = js_mkobj(js); 492 + 493 + if (!socket || !socket->conn || !ant_conn_has_local_addr(socket->conn)) return out; 494 + js_set(js, out, "address", js_mkstr(js, ant_conn_local_addr(socket->conn), strlen(ant_conn_local_addr(socket->conn)))); 495 + js_set(js, out, "port", js_mknum(ant_conn_local_port(socket->conn))); 496 + js_set(js, out, "family", js_mkstr(js, ant_conn_local_family(socket->conn), strlen(ant_conn_local_family(socket->conn)))); 497 + return out; 498 + } 499 + 500 + static ant_value_t js_net_socket_pause(ant_t *js, ant_value_t *args, int nargs) { 501 + net_socket_t *socket = net_socket_data(js_getthis(js)); 502 + if (socket && socket->conn) ant_conn_pause_read(socket->conn); 503 + return js_getthis(js); 504 + } 505 + 506 + static ant_value_t js_net_socket_resume(ant_t *js, ant_value_t *args, int nargs) { 507 + net_socket_t *socket = net_socket_data(js_getthis(js)); 508 + if (socket && socket->conn) ant_conn_resume_read(socket->conn); 509 + return js_getthis(js); 510 + } 511 + 512 + static ant_value_t js_net_socket_setEncoding(ant_t *js, ant_value_t *args, int nargs) { 513 + net_socket_t *socket = net_socket_data(js_getthis(js)); 514 + if (!socket) return js_getthis(js); 515 + socket->encoding = nargs > 0 && vtype(args[0]) != T_UNDEF ? js_tostring_val(js, args[0]) : js_mkundef(); 516 + return js_getthis(js); 517 + } 518 + 519 + static ant_value_t js_net_socket_setTimeout(ant_t *js, ant_value_t *args, int nargs) { 520 + net_socket_t *socket = net_socket_data(js_getthis(js)); 521 + double timeout = 0; 522 + ant_value_t once_args[2] = {0}; 523 + 524 + if (!socket) return js_getthis(js); 525 + if (nargs > 0 && vtype(args[0]) == T_NUM) timeout = js_getnum(args[0]); 526 + if (socket->conn) ant_conn_set_timeout_ms(socket->conn, timeout > 0 ? (uint64_t)timeout : 0); 527 + net_socket_sync_state(socket); 528 + 529 + if (nargs > 1 && is_callable(args[1])) { 530 + once_args[0] = js_mkstr(js, "timeout", 7); 531 + once_args[1] = args[1]; 532 + net_call_method(js, socket->obj, "once", once_args, 2); 533 + } 534 + 535 + return js_getthis(js); 536 + } 537 + 538 + static ant_value_t js_net_socket_setNoDelay(ant_t *js, ant_value_t *args, int nargs) { 539 + net_socket_t *socket = net_socket_data(js_getthis(js)); 540 + bool enable = nargs == 0 || js_truthy(js, args[0]); 541 + if (socket && socket->conn) ant_conn_set_no_delay(socket->conn, enable); 542 + return js_getthis(js); 543 + } 544 + 545 + static ant_value_t js_net_socket_setKeepAlive(ant_t *js, ant_value_t *args, int nargs) { 546 + net_socket_t *socket = net_socket_data(js_getthis(js)); 547 + bool enable = nargs > 0 && js_truthy(js, args[0]); 548 + unsigned int delay = nargs > 1 && vtype(args[1]) == T_NUM ? (unsigned int)(js_getnum(args[1]) / 1000.0) : 0; 549 + if (socket && socket->conn) ant_conn_set_keep_alive(socket->conn, enable, delay); 550 + return js_getthis(js); 551 + } 552 + 553 + static ant_value_t js_net_socket_ref(ant_t *js, ant_value_t *args, int nargs) { 554 + net_socket_t *socket = net_socket_data(js_getthis(js)); 555 + if (socket && socket->conn) ant_conn_ref(socket->conn); 556 + return js_getthis(js); 557 + } 558 + 559 + static ant_value_t js_net_socket_unref(ant_t *js, ant_value_t *args, int nargs) { 560 + net_socket_t *socket = net_socket_data(js_getthis(js)); 561 + if (socket && socket->conn) ant_conn_unref(socket->conn); 562 + return js_getthis(js); 563 + } 564 + 565 + static ant_value_t js_net_socket_write(ant_t *js, ant_value_t *args, int nargs) { 566 + net_socket_t *socket = net_socket_data(js_getthis(js)); 567 + const uint8_t *bytes = NULL; 568 + size_t len = 0; 569 + char *copy = NULL; 570 + 571 + if (!socket || !socket->conn) return js_false; 572 + if (nargs < 1) return js_true; 573 + 574 + if (!buffer_source_get_bytes(js, args[0], &bytes, &len)) { 575 + size_t slen = 0; 576 + const char *str = js_getstr(js, js_tostring_val(js, args[0]), &slen); 577 + if (!str) return js_false; 578 + bytes = (const uint8_t *)str; 579 + len = slen; 580 + } 581 + 582 + copy = malloc(len); 583 + if (!copy) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 584 + if (len > 0) memcpy(copy, bytes, len); 585 + 586 + if (ant_conn_write(socket->conn, copy, len, NULL, NULL) != 0) { 587 + free(copy); 588 + return js_false; 589 + } 590 + 591 + net_socket_sync_state(socket); 592 + if (nargs > 2 && is_callable(args[2])) net_call_value(js, args[2], js_mkundef(), NULL, 0); 593 + return js_true; 594 + } 595 + 596 + static ant_value_t js_net_socket_end(ant_t *js, ant_value_t *args, int nargs) { 597 + net_socket_t *socket = net_socket_data(js_getthis(js)); 598 + ant_value_t result = js_getthis(js); 599 + 600 + if (!socket || !socket->conn) return result; 601 + if (nargs > 0 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) 602 + js_net_socket_write(js, args, nargs); 603 + ant_conn_shutdown(socket->conn); 604 + if (nargs > 2 && is_callable(args[2])) net_call_value(js, args[2], js_mkundef(), NULL, 0); 605 + return result; 606 + } 607 + 608 + static ant_value_t js_net_socket_destroy(ant_t *js, ant_value_t *args, int nargs) { 609 + net_socket_t *socket = net_socket_data(js_getthis(js)); 610 + if (!socket) return js_getthis(js); 611 + 612 + if (nargs > 0 && vtype(args[0]) != T_UNDEF && vtype(args[0]) != T_NULL) { 613 + ant_value_t err = args[0]; 614 + socket->had_error = true; 615 + net_emit(js, socket->obj, "error", &err, 1); 616 + } 617 + 618 + if (socket->conn) ant_conn_close(socket->conn); 619 + return js_getthis(js); 620 + } 621 + 622 + static ant_value_t js_net_socket_connect(ant_t *js, ant_value_t *args, int nargs) { 623 + return net_not_implemented(js, "net.Socket.connect"); 624 + } 625 + 626 + static ant_value_t js_net_server_ctor(ant_t *js, ant_value_t *args, int nargs) { 627 + net_server_t *server = net_server_create(js); 628 + ant_value_t on_args[2] = {0}; 629 + 630 + if (!server) return js_mkerr_typed(js, JS_ERR_TYPE, "Out of memory"); 631 + if (nargs > 0 && vtype(args[0]) == T_OBJ) net_server_apply_options(js, server, args[0]); 632 + if (nargs > 0 && is_callable(args[0])) { 633 + on_args[0] = js_mkstr(js, "connection", 10); 634 + on_args[1] = args[0]; 635 + net_call_method(js, server->obj, "on", on_args, 2); 636 + } else if (nargs > 1 && is_callable(args[1])) { 637 + on_args[0] = js_mkstr(js, "connection", 10); 638 + on_args[1] = args[1]; 639 + net_call_method(js, server->obj, "on", on_args, 2); 640 + } 641 + 642 + return server->obj; 643 + } 644 + 645 + static ant_value_t js_net_server_listen(ant_t *js, ant_value_t *args, int nargs) { 646 + net_server_t *server = net_server_data(js_getthis(js)); 647 + ant_listener_callbacks_t callbacks = {0}; 648 + const char *host = "0.0.0.0"; 649 + ant_value_t cb = js_mkundef(); 650 + int port = 0; 651 + int backlog = 511; 652 + int rc = 0; 653 + 654 + if (!server) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid net.Server"); 655 + if (server->listening) return js_mkerr_typed(js, JS_ERR_TYPE, "Server is already listening"); 656 + 657 + if (nargs > 0 && vtype(args[0]) == T_NUM) { 658 + port = (int)js_getnum(args[0]); 659 + if (nargs > 1 && vtype(args[1]) == T_STR) { 660 + size_t len = 0; 661 + host = js_getstr(js, args[1], &len); 662 + } 663 + if (nargs > 2 && vtype(args[2]) == T_NUM) backlog = (int)js_getnum(args[2]); 664 + if (nargs > 3 && is_callable(args[3])) cb = args[3]; 665 + else if (nargs > 2 && is_callable(args[2])) cb = args[2]; 666 + else if (nargs > 1 && is_callable(args[1])) cb = args[1]; 667 + } else if (nargs > 0 && vtype(args[0]) == T_OBJ) { 668 + ant_value_t value = js_get(js, args[0], "path"); 669 + if (vtype(value) != T_UNDEF) return net_not_implemented(js, "IPC server listen"); 670 + 671 + value = js_get(js, args[0], "port"); 672 + if (vtype(value) == T_NUM) port = (int)js_getnum(value); 673 + value = js_get(js, args[0], "host"); 674 + if (vtype(value) == T_STR) { 675 + size_t len = 0; 676 + host = js_getstr(js, value, &len); 677 + } 678 + value = js_get(js, args[0], "backlog"); 679 + if (vtype(value) == T_NUM) backlog = (int)js_getnum(value); 680 + if (nargs > 1 && is_callable(args[1])) cb = args[1]; 681 + } else if (nargs > 0 && vtype(args[0]) == T_STR) { 682 + return net_not_implemented(js, "IPC server listen"); 683 + } else if (nargs > 0 && is_callable(args[0])) { 684 + cb = args[0]; 685 + } 686 + 687 + net_server_parse_host(host, &host); 688 + free(server->host); 689 + server->host = strdup(host ? host : "0.0.0.0"); 690 + server->port = port; 691 + server->backlog = backlog > 0 ? backlog : server->backlog; 692 + 693 + callbacks.on_accept = net_server_on_accept; 694 + callbacks.on_read = net_socket_on_read; 695 + callbacks.on_end = net_socket_on_end; 696 + callbacks.on_error = net_socket_on_error; 697 + callbacks.on_timeout = net_socket_on_timeout; 698 + callbacks.on_conn_close = net_server_on_conn_close; 699 + callbacks.on_listener_close = net_server_on_listener_close; 700 + 701 + rc = ant_listener_listen_tcp( 702 + &server->listener, 703 + uv_default_loop(), 704 + server->host, 705 + port, 706 + server->backlog, 707 + 0, 708 + &callbacks, 709 + server 710 + ); 711 + if (rc != 0) return js_mkerr_typed(js, JS_ERR_TYPE, "%s", uv_strerror(rc)); 712 + 713 + server->port = ant_listener_port(&server->listener); 714 + server->listening = true; 715 + server->closing = false; 716 + net_server_sync_state(server); 717 + net_add_active_server(server); 718 + 719 + if (is_callable(cb)) net_call_value(js, cb, js_mkundef(), NULL, 0); 720 + net_emit(js, server->obj, "listening", NULL, 0); 721 + return js_getthis(js); 722 + } 723 + 724 + static ant_value_t js_net_server_close(ant_t *js, ant_value_t *args, int nargs) { 725 + net_server_t *server = net_server_data(js_getthis(js)); 726 + ant_value_t once_args[2] = {0}; 727 + 728 + if (!server) return js_getthis(js); 729 + 730 + if (nargs > 0 && is_callable(args[0])) { 731 + once_args[0] = js_mkstr(js, "close", 5); 732 + once_args[1] = args[0]; 733 + net_call_method(js, server->obj, "once", once_args, 2); 734 + } 735 + 736 + if (!server->listening && !server->closing) { 737 + if (nargs > 0 && is_callable(args[0])) { 738 + ant_value_t err = js_mkerr_typed(js, JS_ERR_TYPE, "Server is not running"); 739 + net_call_value(js, args[0], js_mkundef(), &err, 1); 740 + } 741 + return js_getthis(js); 742 + } 743 + 744 + server->closing = true; 745 + ant_listener_stop(&server->listener, false); 746 + net_server_maybe_finish_close(server); 747 + return js_getthis(js); 748 + } 749 + 750 + static ant_value_t js_net_server_address(ant_t *js, ant_value_t *args, int nargs) { 751 + net_server_t *server = net_server_data(js_getthis(js)); 752 + ant_value_t out = js_mknull(); 753 + if (!server || !server->listening) return out; 754 + 755 + out = js_mkobj(js); 756 + js_set(js, out, "port", js_mknum(server->port)); 757 + js_set(js, out, "family", js_mkstr(js, "IPv4", 4)); 758 + js_set(js, out, "address", js_mkstr(js, server->host, strlen(server->host))); 759 + return out; 760 + } 761 + 762 + static ant_value_t js_net_server_getConnections(ant_t *js, ant_value_t *args, int nargs) { 763 + net_server_t *server = net_server_data(js_getthis(js)); 764 + ant_value_t cb = nargs > 0 ? args[0] : js_mkundef(); 765 + ant_value_t argv[2] = { js_mknull(), js_mknum((double)net_server_socket_count(server)) }; 766 + 767 + if (is_callable(cb)) net_call_value(js, cb, js_mkundef(), argv, 2); 768 + return js_getthis(js); 769 + } 770 + 771 + static ant_value_t js_net_server_ref(ant_t *js, ant_value_t *args, int nargs) { 772 + net_server_t *server = net_server_data(js_getthis(js)); 773 + if (server && !uv_is_closing((uv_handle_t *)&server->listener.handle)) 774 + uv_ref((uv_handle_t *)&server->listener.handle); 775 + return js_getthis(js); 776 + } 777 + 778 + static ant_value_t js_net_server_unref(ant_t *js, ant_value_t *args, int nargs) { 779 + net_server_t *server = net_server_data(js_getthis(js)); 780 + if (server && !uv_is_closing((uv_handle_t *)&server->listener.handle)) 781 + uv_unref((uv_handle_t *)&server->listener.handle); 782 + return js_getthis(js); 783 + } 784 + 785 + static ant_value_t js_net_createServer(ant_t *js, ant_value_t *args, int nargs) { 786 + return js_net_server_ctor(js, args, nargs); 787 + } 788 + 789 + static ant_value_t js_net_createConnection(ant_t *js, ant_value_t *args, int nargs) { 790 + return net_not_implemented(js, "net.createConnection"); 791 + } 792 + 793 + static ant_value_t js_net_connect(ant_t *js, ant_value_t *args, int nargs) { 794 + return js_net_createConnection(js, args, nargs); 795 + } 796 + 797 + static ant_value_t js_net_getDefaultAutoSelectFamily(ant_t *js, ant_value_t *args, int nargs) { 798 + return js_bool(g_default_auto_select_family); 799 + } 800 + 801 + static ant_value_t js_net_setDefaultAutoSelectFamily(ant_t *js, ant_value_t *args, int nargs) { 802 + if (nargs > 0) g_default_auto_select_family = js_truthy(js, args[0]); 803 + return js_mkundef(); 804 + } 805 + 806 + static ant_value_t js_net_getDefaultAutoSelectFamilyAttemptTimeout(ant_t *js, ant_value_t *args, int nargs) { 807 + return js_mknum(g_default_auto_select_family_attempt_timeout); 808 + } 809 + 810 + static ant_value_t js_net_setDefaultAutoSelectFamilyAttemptTimeout(ant_t *js, ant_value_t *args, int nargs) { 811 + if (nargs > 0 && vtype(args[0]) == T_NUM) { 812 + double value = js_getnum(args[0]); 813 + if (value > 0 && value < 10) value = 10; 814 + if (value > 0) g_default_auto_select_family_attempt_timeout = value; 815 + } 816 + return js_mkundef(); 817 + } 818 + 819 + static void net_init_constructors(ant_t *js) { 820 + ant_value_t events = 0; 821 + ant_value_t ee_ctor = 0; 822 + ant_value_t ee_proto = 0; 823 + 824 + if (g_net_server_ctor && g_net_socket_ctor) return; 825 + 826 + events = events_library(js); 827 + ee_ctor = js_get(js, events, "EventEmitter"); 828 + ee_proto = js_get(js, ee_ctor, "prototype"); 829 + 830 + g_net_socket_proto = js_mkobj(js); 831 + js_set_proto_init(g_net_socket_proto, ee_proto); 832 + js_set(js, g_net_socket_proto, "address", js_mkfun(js_net_socket_address)); 833 + js_set(js, g_net_socket_proto, "pause", js_mkfun(js_net_socket_pause)); 834 + js_set(js, g_net_socket_proto, "resume", js_mkfun(js_net_socket_resume)); 835 + js_set(js, g_net_socket_proto, "setEncoding", js_mkfun(js_net_socket_setEncoding)); 836 + js_set(js, g_net_socket_proto, "setTimeout", js_mkfun(js_net_socket_setTimeout)); 837 + js_set(js, g_net_socket_proto, "setNoDelay", js_mkfun(js_net_socket_setNoDelay)); 838 + js_set(js, g_net_socket_proto, "setKeepAlive", js_mkfun(js_net_socket_setKeepAlive)); 839 + js_set(js, g_net_socket_proto, "write", js_mkfun(js_net_socket_write)); 840 + js_set(js, g_net_socket_proto, "end", js_mkfun(js_net_socket_end)); 841 + js_set(js, g_net_socket_proto, "destroy", js_mkfun(js_net_socket_destroy)); 842 + js_set(js, g_net_socket_proto, "connect", js_mkfun(js_net_socket_connect)); 843 + js_set(js, g_net_socket_proto, "ref", js_mkfun(js_net_socket_ref)); 844 + js_set(js, g_net_socket_proto, "unref", js_mkfun(js_net_socket_unref)); 845 + js_set_sym(js, g_net_socket_proto, get_toStringTag_sym(), js_mkstr(js, "Socket", 6)); 846 + g_net_socket_ctor = js_make_ctor(js, js_net_socket_ctor, g_net_socket_proto, "Socket", 6); 847 + 848 + g_net_server_proto = js_mkobj(js); 849 + js_set_proto_init(g_net_server_proto, ee_proto); 850 + js_set(js, g_net_server_proto, "listen", js_mkfun(js_net_server_listen)); 851 + js_set(js, g_net_server_proto, "close", js_mkfun(js_net_server_close)); 852 + js_set(js, g_net_server_proto, "address", js_mkfun(js_net_server_address)); 853 + js_set(js, g_net_server_proto, "getConnections", js_mkfun(js_net_server_getConnections)); 854 + js_set(js, g_net_server_proto, "ref", js_mkfun(js_net_server_ref)); 855 + js_set(js, g_net_server_proto, "unref", js_mkfun(js_net_server_unref)); 856 + js_set_sym(js, g_net_server_proto, get_toStringTag_sym(), js_mkstr(js, "Server", 6)); 857 + g_net_server_ctor = js_make_ctor(js, js_net_server_ctor, g_net_server_proto, "Server", 6); 48 858 } 49 859 50 860 ant_value_t net_library(ant_t *js) { 51 861 ant_value_t lib = js_mkobj(js); 52 862 863 + net_init_constructors(js); 864 + 865 + js_set(js, lib, "Server", g_net_server_ctor); 866 + js_set(js, lib, "Socket", g_net_socket_ctor); 867 + js_set(js, lib, "createServer", js_mkfun(js_net_createServer)); 868 + js_set(js, lib, "createConnection", js_mkfun(js_net_createConnection)); 869 + js_set(js, lib, "connect", js_mkfun(js_net_connect)); 53 870 js_set(js, lib, "isIP", js_mkfun(net_isIP)); 54 871 js_set(js, lib, "isIPv4", js_mkfun(net_isIPv4)); 55 872 js_set(js, lib, "isIPv6", js_mkfun(net_isIPv6)); 873 + js_set(js, lib, "getDefaultAutoSelectFamily", js_mkfun(js_net_getDefaultAutoSelectFamily)); 874 + js_set(js, lib, "setDefaultAutoSelectFamily", js_mkfun(js_net_setDefaultAutoSelectFamily)); 875 + js_set(js, lib, "getDefaultAutoSelectFamilyAttemptTimeout", js_mkfun(js_net_getDefaultAutoSelectFamilyAttemptTimeout)); 876 + js_set(js, lib, "setDefaultAutoSelectFamilyAttemptTimeout", js_mkfun(js_net_setDefaultAutoSelectFamilyAttemptTimeout)); 877 + js_set(js, lib, "default", lib); 878 + js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "net", 3)); 879 + return lib; 880 + } 881 + 882 + void gc_mark_net(ant_t *js, gc_mark_fn mark) { 883 + net_server_t *server = NULL; 884 + net_socket_t *socket = NULL; 56 885 57 - return lib; 886 + if (g_net_server_proto) mark(js, g_net_server_proto); 887 + if (g_net_socket_proto) mark(js, g_net_socket_proto); 888 + if (g_net_server_ctor) mark(js, g_net_server_ctor); 889 + if (g_net_socket_ctor) mark(js, g_net_socket_ctor); 890 + 891 + for (server = g_active_servers; server; server = server->next_active) 892 + mark(js, server->obj); 893 + 894 + for (socket = g_active_sockets; socket; socket = socket->next_active) { 895 + mark(js, socket->obj); 896 + if (vtype(socket->encoding) != T_UNDEF) mark(js, socket->encoding); 897 + } 58 898 }
+8 -3
src/modules/server.c
··· 625 625 if (!req || !req->conn) return js_mkundef(); 626 626 627 627 timeout = (int)js_getnum(args[1]); 628 - ant_conn_set_timeout(req->conn, timeout); 628 + ant_conn_set_timeout_ms(req->conn, (uint64_t)timeout * 1000ULL); 629 + 629 630 return js_mkundef(); 630 631 } 631 632 ··· 726 727 ant_conn_pause_read(conn); 727 728 server_process_client_request(conn, &parsed); 728 729 } 730 + } 731 + 732 + static void server_on_end(ant_conn_t *conn, void *user_data) { 733 + if (conn) ant_conn_close(conn); 729 734 } 730 735 731 736 static void server_on_conn_close(ant_conn_t *conn, void *user_data) { ··· 899 904 server->sigterm_handle.data = server; 900 905 901 906 callbacks.on_read = server_on_read; 907 + callbacks.on_end = server_on_end; 902 908 callbacks.on_conn_close = server_on_conn_close; 903 909 callbacks.on_listener_close = server_on_listener_close; 904 910 905 911 rc = ant_listener_listen_tcp( 906 912 &server->listener, server->loop, 907 913 server->hostname, server->port, 908 - 128, server->idle_timeout_secs, &callbacks, server 914 + 128, (uint64_t)server->idle_timeout_secs * 1000ULL, &callbacks, server 909 915 ); 910 916 911 917 if (rc != 0) { ··· 915 921 } 916 922 917 923 server->port = ant_listener_port(&server->listener); 918 - 919 924 uv_signal_start(&server->sigint_handle, server_signal_cb, SIGINT); 920 925 uv_signal_start(&server->sigterm_handle, server_signal_cb, SIGTERM); 921 926
-2
src/modules/v8.c
··· 1 - // stub: functional where possible 2 - 3 1 #include <math.h> 4 2 #include <stdint.h> 5 3 #include <stdlib.h>
+180 -22
src/net/connection.c
··· 18 18 void *user_data; 19 19 } ant_conn_write_req_t; 20 20 21 + typedef struct { 22 + uv_shutdown_t req; 23 + } ant_conn_shutdown_req_t; 24 + 21 25 static void ant_conn_restart_timer(ant_conn_t *conn); 22 26 static void ant_conn_close_cb(uv_handle_t *handle); 23 27 ··· 32 36 }} 33 37 } 34 38 35 - static bool ant_conn_store_peer_addr(ant_conn_t *conn) { 39 + static bool ant_conn_store_addr( 40 + uv_tcp_t *handle, 41 + int (*get_name)(const uv_tcp_t *, struct sockaddr *, int *), 42 + char *out_addr, 43 + size_t out_addr_len, 44 + char *out_family, 45 + size_t out_family_len, 46 + int *out_port, 47 + bool *out_has_addr 48 + ) { 36 49 struct sockaddr_storage addr; 37 50 int len = sizeof(addr); 38 51 39 - if (uv_tcp_getpeername(&conn->handle, (struct sockaddr *)&addr, &len) != 0) return false; 52 + if (get_name(handle, (struct sockaddr *)&addr, &len) != 0) return false; 40 53 if (addr.ss_family == AF_INET) { 41 54 struct sockaddr_in *in = (struct sockaddr_in *)&addr; 42 - uv_ip4_name(in, conn->remote_addr, sizeof(conn->remote_addr)); 43 - conn->remote_port = ntohs(in->sin_port); 44 - conn->has_remote_addr = true; 55 + uv_ip4_name(in, out_addr, out_addr_len); 56 + memcpy(out_family, "IPv4", out_family_len < 5 ? out_family_len : 5); 57 + *out_port = ntohs(in->sin_port); 58 + *out_has_addr = true; 45 59 return true; 46 60 } 61 + 47 62 if (addr.ss_family == AF_INET6) { 48 63 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; 49 - uv_ip6_name(in6, conn->remote_addr, sizeof(conn->remote_addr)); 50 - conn->remote_port = ntohs(in6->sin6_port); 51 - conn->has_remote_addr = true; 64 + uv_ip6_name(in6, out_addr, out_addr_len); 65 + memcpy(out_family, "IPv6", out_family_len < 5 ? out_family_len : 5); 66 + *out_port = ntohs(in6->sin6_port); 67 + *out_has_addr = true; 52 68 return true; 53 69 } 70 + 54 71 return false; 55 72 } 56 73 74 + static bool ant_conn_store_peer_addr(ant_conn_t *conn) { 75 + return ant_conn_store_addr( 76 + &conn->handle, 77 + (int (*)(const uv_tcp_t *, struct sockaddr *, int *))uv_tcp_getpeername, 78 + conn->remote_addr, 79 + sizeof(conn->remote_addr), 80 + conn->remote_family, 81 + sizeof(conn->remote_family), 82 + &conn->remote_port, 83 + &conn->has_remote_addr 84 + ); 85 + } 86 + 87 + static bool ant_conn_store_local_addr(ant_conn_t *conn) { 88 + return ant_conn_store_addr( 89 + &conn->handle, 90 + (int (*)(const uv_tcp_t *, struct sockaddr *, int *))uv_tcp_getsockname, 91 + conn->local_addr, 92 + sizeof(conn->local_addr), 93 + conn->local_family, 94 + sizeof(conn->local_family), 95 + &conn->local_port, 96 + &conn->has_local_addr 97 + ); 98 + } 99 + 57 100 static void ant_conn_timeout_cb(uv_timer_t *handle) { 58 101 ant_conn_t *conn = (ant_conn_t *)handle->data; 102 + ant_listener_t *listener = conn ? conn->listener : NULL; 103 + 104 + if (!conn) return; 105 + if (listener && listener->callbacks.on_timeout) { 106 + listener->callbacks.on_timeout(conn, listener->user_data); 107 + return; 108 + } 109 + 59 110 ant_conn_close(conn); 60 111 } 61 112 62 113 static void ant_conn_restart_timer(ant_conn_t *conn) { 63 - uint64_t timeout_ms = 0; 64 - 65 114 if (!conn || conn->closing) return; 66 115 uv_timer_stop(&conn->timer); 67 - if (conn->timeout_secs <= 0) return; 68 - 69 - timeout_ms = (uint64_t)conn->timeout_secs * 1000ULL; 70 - uv_timer_start(&conn->timer, ant_conn_timeout_cb, timeout_ms, 0); 116 + if (conn->timeout_ms == 0) return; 117 + uv_timer_start(&conn->timer, ant_conn_timeout_cb, conn->timeout_ms, 0); 71 118 } 72 119 73 120 static void ant_conn_alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { ··· 103 150 static void ant_conn_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { 104 151 ant_conn_t *conn = (ant_conn_t *)stream->data; 105 152 ant_listener_t *listener = conn ? conn->listener : NULL; 106 - (void)buf; 107 - 108 153 if (!conn || !listener) return; 154 + 109 155 if (nread < 0) { 156 + if (nread == UV_EOF) { 157 + conn->read_eof = true; 158 + uv_read_stop((uv_stream_t *)&conn->handle); 159 + if (listener->callbacks.on_end) 160 + listener->callbacks.on_end(conn, listener->user_data); 161 + return; 162 + } 163 + 164 + if (listener->callbacks.on_error) listener->callbacks.on_error( 165 + conn, (int)nread, listener->user_data 166 + ); 167 + 110 168 ant_conn_close(conn); 111 169 return; 112 170 } 171 + 113 172 if (nread == 0) return; 114 173 174 + conn->bytes_read += (uint64_t)nread; 115 175 conn->buffer_len += (size_t)nread; 116 176 ant_conn_restart_timer(conn); 117 177 ··· 122 182 static void ant_conn_write_cb_impl(uv_write_t *req, int status) { 123 183 ant_conn_write_req_t *wr = (ant_conn_write_req_t *)req; 124 184 185 + if (status >= 0 && wr->conn) 186 + wr->conn->bytes_written += (uint64_t)wr->buf.len; 125 187 if (wr->cb) wr->cb(wr->conn, status, wr->user_data); 188 + 126 189 free(wr->buf.base); 127 190 free(wr); 128 191 } 129 192 193 + static void ant_conn_shutdown_cb(uv_shutdown_t *req, int status) { 194 + ant_conn_shutdown_req_t *shutdown_req = (ant_conn_shutdown_req_t *)req; 195 + free(shutdown_req); 196 + } 197 + 130 198 static void ant_conn_close_cb(uv_handle_t *handle) { 131 199 ant_conn_t *conn = (ant_conn_t *)handle->data; 132 200 ant_listener_t *listener = conn ? conn->listener : NULL; ··· 142 210 free(conn); 143 211 } 144 212 145 - ant_conn_t *ant_conn_create_tcp(ant_listener_t *listener, int timeout_secs) { 213 + ant_conn_t *ant_conn_create_tcp(ant_listener_t *listener, uint64_t timeout_ms) { 146 214 ant_conn_t *conn = NULL; 147 215 148 216 if (!listener || !listener->loop) return NULL; ··· 151 219 if (!conn) return NULL; 152 220 153 221 conn->listener = listener; 154 - conn->timeout_secs = timeout_secs; 222 + conn->timeout_ms = timeout_ms; 155 223 conn->buffer_cap = ANT_CONN_READ_BUFFER_SIZE; 156 224 conn->buffer = malloc(conn->buffer_cap); 157 225 if (!conn->buffer) { ··· 173 241 return UV_ECONNABORTED; 174 242 175 243 ant_conn_store_peer_addr(conn); 244 + ant_conn_store_local_addr(conn); 176 245 conn->next = conn->listener->connections; 177 246 conn->listener->connections = conn; 178 247 return 0; ··· 180 249 181 250 void ant_conn_start(ant_conn_t *conn) { 182 251 if (!conn || conn->closing) return; 252 + conn->read_paused = false; 183 253 ant_conn_restart_timer(conn); 184 254 uv_read_start((uv_stream_t *)&conn->handle, ant_conn_alloc_cb, ant_conn_read_cb); 185 255 } ··· 204 274 return conn ? conn->buffer_len : 0; 205 275 } 206 276 207 - void ant_conn_set_timeout(ant_conn_t *conn, int timeout_secs) { 277 + void ant_conn_set_timeout_ms(ant_conn_t *conn, uint64_t timeout_ms) { 208 278 if (!conn) return; 209 - conn->timeout_secs = timeout_secs < 0 ? 0 : timeout_secs; 279 + conn->timeout_ms = timeout_ms; 210 280 ant_conn_restart_timer(conn); 211 281 } 212 282 213 - int ant_conn_timeout(const ant_conn_t *conn) { 214 - return conn ? conn->timeout_secs : 0; 283 + uint64_t ant_conn_timeout_ms(const ant_conn_t *conn) { 284 + return conn ? conn->timeout_ms : 0; 215 285 } 216 286 217 287 bool ant_conn_is_closing(const ant_conn_t *conn) { 218 288 return !conn || conn->closing; 219 289 } 220 290 291 + bool ant_conn_has_local_addr(const ant_conn_t *conn) { 292 + return conn && conn->has_local_addr; 293 + } 294 + 221 295 bool ant_conn_has_remote_addr(const ant_conn_t *conn) { 222 296 return conn && conn->has_remote_addr; 223 297 } 224 298 299 + const char *ant_conn_local_addr(const ant_conn_t *conn) { 300 + return conn ? conn->local_addr : NULL; 301 + } 302 + 225 303 const char *ant_conn_remote_addr(const ant_conn_t *conn) { 226 304 return conn ? conn->remote_addr : NULL; 227 305 } 228 306 307 + const char *ant_conn_local_family(const ant_conn_t *conn) { 308 + return conn ? conn->local_family : NULL; 309 + } 310 + 311 + const char *ant_conn_remote_family(const ant_conn_t *conn) { 312 + return conn ? conn->remote_family : NULL; 313 + } 314 + 315 + int ant_conn_local_port(const ant_conn_t *conn) { 316 + return conn ? conn->local_port : 0; 317 + } 318 + 229 319 int ant_conn_remote_port(const ant_conn_t *conn) { 230 320 return conn ? conn->remote_port : 0; 231 321 } 232 322 233 323 void ant_conn_pause_read(ant_conn_t *conn) { 234 324 if (!conn || conn->closing) return; 325 + conn->read_paused = true; 235 326 uv_read_stop((uv_stream_t *)&conn->handle); 236 327 } 237 328 329 + void ant_conn_resume_read(ant_conn_t *conn) { 330 + if (!conn || conn->closing || conn->read_eof || !conn->read_paused) return; 331 + conn->read_paused = false; 332 + ant_conn_restart_timer(conn); 333 + uv_read_start((uv_stream_t *)&conn->handle, ant_conn_alloc_cb, ant_conn_read_cb); 334 + } 335 + 336 + void ant_conn_shutdown(ant_conn_t *conn) { 337 + ant_conn_shutdown_req_t *req = NULL; 338 + int rc = 0; 339 + 340 + if (!conn || conn->closing) return; 341 + 342 + req = calloc(1, sizeof(*req)); 343 + if (!req) { 344 + ant_conn_close(conn); 345 + return; 346 + } 347 + 348 + rc = uv_shutdown(&req->req, (uv_stream_t *)&conn->handle, ant_conn_shutdown_cb); 349 + if (rc != 0) { 350 + free(req); 351 + ant_conn_close(conn); 352 + } 353 + } 354 + 355 + void ant_conn_ref(ant_conn_t *conn) { 356 + if (!conn) return; 357 + if (!uv_is_closing((uv_handle_t *)&conn->handle)) uv_ref((uv_handle_t *)&conn->handle); 358 + if (!uv_is_closing((uv_handle_t *)&conn->timer)) uv_ref((uv_handle_t *)&conn->timer); 359 + } 360 + 361 + void ant_conn_unref(ant_conn_t *conn) { 362 + if (!conn) return; 363 + if (!uv_is_closing((uv_handle_t *)&conn->handle)) uv_unref((uv_handle_t *)&conn->handle); 364 + if (!uv_is_closing((uv_handle_t *)&conn->timer)) uv_unref((uv_handle_t *)&conn->timer); 365 + } 366 + 367 + int ant_conn_set_no_delay(ant_conn_t *conn, bool enable) { 368 + if (!conn || conn->closing) return UV_EINVAL; 369 + return uv_tcp_nodelay(&conn->handle, enable ? 1 : 0); 370 + } 371 + 372 + int ant_conn_set_keep_alive(ant_conn_t *conn, bool enable, unsigned int delay_secs) { 373 + if (!conn || conn->closing) return UV_EINVAL; 374 + return uv_tcp_keepalive(&conn->handle, enable ? 1 : 0, delay_secs); 375 + } 376 + 377 + void ant_conn_consume(ant_conn_t *conn, size_t len) { 378 + if (!conn || conn->buffer_len == 0 || len == 0) return; 379 + if (len >= conn->buffer_len) { 380 + conn->buffer_len = 0; 381 + return; 382 + } 383 + 384 + memmove(conn->buffer, conn->buffer + len, conn->buffer_len - len); 385 + conn->buffer_len -= len; 386 + } 387 + 238 388 void ant_conn_close(ant_conn_t *conn) { 239 389 if (!conn || conn->closing) return; 240 390 conn->closing = true; ··· 284 434 285 435 return 0; 286 436 } 437 + 438 + uint64_t ant_conn_bytes_read(const ant_conn_t *conn) { 439 + return conn ? conn->bytes_read : 0; 440 + } 441 + 442 + uint64_t ant_conn_bytes_written(const ant_conn_t *conn) { 443 + return conn ? conn->bytes_written : 0; 444 + }
+3 -3
src/net/listener.c
··· 22 22 23 23 if (status < 0 || !listener || listener->closing) return; 24 24 25 - conn = ant_conn_create_tcp(listener, listener->idle_timeout_secs); 25 + conn = ant_conn_create_tcp(listener, listener->idle_timeout_ms); 26 26 if (!conn) return; 27 27 28 28 if (ant_conn_accept(conn, server_stream) != 0) { ··· 42 42 const char *hostname, 43 43 int port, 44 44 int backlog, 45 - int idle_timeout_secs, 45 + uint64_t idle_timeout_ms, 46 46 const ant_listener_callbacks_t *callbacks, 47 47 void *user_data 48 48 ) { ··· 55 55 56 56 listener->loop = loop; 57 57 listener->user_data = user_data; 58 - listener->idle_timeout_secs = idle_timeout_secs; 58 + listener->idle_timeout_ms = idle_timeout_ms; 59 59 listener->port = port; 60 60 listener->backlog = backlog > 0 ? backlog : 128; 61 61 if (callbacks) listener->callbacks = *callbacks;