]> git.plutz.net Git - quickjs_net/commitdiff
async accept and recv functions
authorPaul Hänsch <paul@plutz.net>
Wed, 18 Mar 2026 01:55:03 +0000 (02:55 +0100)
committerPaul Hänsch <paul@plutz.net>
Wed, 18 Mar 2026 01:55:03 +0000 (02:55 +0100)
socket.c

index cedd5119fc55de87b3207e83f7359d7b8e4eba71..72c3f58b53a03284e2985a07c43e501e206ac3ec 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -9,10 +9,17 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <pthread.h>
 
 #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 ) {