From 5bd2a8dd2d22e650dfcc21df72a725449fd86d01 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Wed, 18 Mar 2026 02:55:03 +0100 Subject: [PATCH] async accept and recv functions --- socket.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/socket.c b/socket.c index cedd511..72c3f58 100644 --- a/socket.c +++ b/socket.c @@ -9,10 +9,17 @@ #include #include #include +#include #define countof(x) ( sizeof(x) / sizeof(x[0]) ) #define libc_error(ctx) ( JS_ThrowInternalError(ctx, "%s", strerror(errno)) ) +static JSValue js_os_fork( + JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv +) { + return JS_NewInt32(ctx, fork()); +} + static JSValue js_os_socket( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv ) { @@ -115,6 +122,7 @@ static const JSCFunctionListEntry os_socket_funcs[] = { JS_CFUNC_DEF("socket", 3, js_os_socket), JS_CFUNC_DEF("listen", 1, js_os_listen), JS_CFUNC_DEF("accept", 1, js_os_accept), + JS_CFUNC_DEF("fork", 0, js_os_fork), JS_CFUNC_MAGIC_DEF("bind", 2, js_os_bind, 0), JS_CFUNC_MAGIC_DEF("connect", 2, js_os_bind, 1), // JS_CFUNC_DEF("send", 2, js_os_send), // would be same as os.write @@ -185,6 +193,16 @@ static JSValue js_sock_get_connected( JSContext *ctx, JSValueConst this ) { return JS_NewBool(ctx, data->connected); } +struct sock_async { + JSContext * ctx; + JSValue this; + JSValue flflrjct[2]; // fullfill / reject + JSValue (*func)(JSContext *, JSValueConst, int, JSValueConst *); + JSValue (*mfunc)(JSContext *, JSValueConst, int, JSValueConst *, int); + int magic; +}; + + static JSValue js_sock_accept( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv ) { @@ -213,6 +231,7 @@ static JSValue js_sock_accept( else return libc_error(ctx); } } + static JSValue js_sock_send( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv ) { @@ -242,7 +261,11 @@ static JSValue js_sock_send( } else to = NULL; // Read Argument either as ArrayBuffer or String - if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) { + if ( JS_IsUndefined(argv[0]) ) { + len = sendto(data->fd, NULL, 0, flags, to, + to ? sizeof(struct sockaddr_storage) : 0 + ); + } else if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) { len = sendto(data->fd, buf, len, flags, to, to ? sizeof(struct sockaddr_storage) : 0 ); @@ -348,18 +371,72 @@ static JSValue js_sock_close( if ( close(data->fd) ) return libc_error(ctx); else return JS_UNDEFINED; } + static void sock_destroy(JSRuntime *rt, JSValue this){ SocketData *data = JS_GetOpaque(this, socket_cid); // close(data->fd); // do not do what a c programmer wouldn't do js_free_rt(rt, data); }; +static void *js_run_async(void *async) { + struct sock_async as = * (struct sock_async*) async; + JSValue ret; + + if (as.func) { + ret = as.func(as.ctx, as.this, 0, &JS_UNDEFINED); + } else if (as.mfunc) { + ret = as.mfunc(as.ctx, as.this, 0, &JS_UNDEFINED, as.magic); + } else ret = JS_ThrowReferenceError(as.ctx, "js_run_async invalid"); + + if (JS_IsException(ret)) { + JS_Call(as.ctx, as.flflrjct[1], as.this, 1, &ret); + } else { + JS_Call(as.ctx, as.flflrjct[0], as.this, 1, &ret); + } + JS_FreeValue(as.ctx, as.flflrjct[0]); + JS_FreeValue(as.ctx, as.flflrjct[1]); + free(async); + return NULL; +} + +static JSValue js_sock_async( + JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv, int mgc +) { + JSValue promise; pthread_t thread; pthread_attr_t ta; + struct sock_async * a = malloc(sizeof(struct sock_async)); + memset(a, 0, sizeof(struct sock_async)); + a->ctx = ctx; a->this = this; + + switch (mgc) { + case 1: a->func = js_sock_accept; break; + case 2: a->mfunc = js_sock_recv; a->magic = 0; break; + case 3: a->mfunc = js_sock_recv; a->magic = 1; break; + } + + promise = JS_NewPromiseCapability(ctx, a->flflrjct); + if (JS_IsException(promise)) { + JS_FreeValue(ctx, a->flflrjct[0]); + JS_FreeValue(ctx, a->flflrjct[1]); + free(a); + } else { + pthread_attr_init(&ta); + pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED); + pthread_create(&thread, &ta, js_run_async, a); + pthread_attr_destroy(&ta); + } + + return promise; +} + static const JSCFunctionListEntry socket_ptype[] = { JS_CFUNC_DEF("accept", 0, js_sock_accept), + JS_CFUNC_MAGIC_DEF("acceptAsync", 0, js_sock_async, 1), JS_CFUNC_DEF("send", 1, js_sock_send), JS_CFUNC_DEF("close", 0, js_sock_close), JS_CFUNC_MAGIC_DEF("recv", 0, js_sock_recv, 0), JS_CFUNC_MAGIC_DEF("recvString", 0, js_sock_recv, 1), + JS_CFUNC_MAGIC_DEF("recvAsync", 0, js_sock_async, 2), + JS_CFUNC_MAGIC_DEF("recvStringAsync", 0, js_sock_async, 3), JS_CGETSET_MAGIC_DEF("localName", js_sock_get_addr, NULL, 0), JS_CGETSET_MAGIC_DEF("localPort", js_sock_get_addr, NULL, 1), JS_CGETSET_MAGIC_DEF("peerName", js_sock_get_addr, NULL, 2), @@ -577,6 +654,7 @@ static const JSCFunctionListEntry net_funcs[] = { // JS_CGETSET_DEF("timeout", net_get_timeout, net_set_timeout), JS_CFUNC_DEF("setTimeout", 1, net_set_timeout), JS_CFUNC_DEF("getTimeout", 1, net_get_timeout), + JS_CFUNC_DEF("fork", 0, js_os_fork), }; static int sock_modinit(JSContext *ctx, JSModuleDef *mod ) { -- 2.39.5