]> git.plutz.net Git - quickjs_net/commitdiff
overall testing and cleanup, optimisations in listener functions
authorPaul Hänsch <paul@plutz.net>
Wed, 11 Mar 2026 03:10:22 +0000 (04:10 +0100)
committerPaul Hänsch <paul@plutz.net>
Wed, 11 Mar 2026 03:10:22 +0000 (04:10 +0100)
socket.c

index 9c3d58eac0d1702e62f15010bfe57f497fa1852c..12ea8842a82128d957c6f7c710939058012c9f83 100644 (file)
--- a/socket.c
+++ b/socket.c
 #define countof(x) ( sizeof(x) / sizeof(x[0]) )
 #define libc_error(ctx) ( JS_ThrowInternalError(ctx, "%s", strerror(errno)) )
 
+// use struct addrinfo in socket functions
+#define ai_socket(a) ( socket( (a)->ai_family, (a)->ai_socktype, (a)->ai_protocol ) )
+#define ai_bind(s, a) (       bind((s), (a)->ai_addr, (a)->ai_addrlen) )
+#define ai_connect(s, a) ( connect((s), (a)->ai_addr, (a)->ai_addrlen) )
+
 static JSValue js_os_socket( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv) {
   int family, type, protocol, fd;
 
@@ -145,12 +150,10 @@ static JSValue sock_send(  JSContext *ctx, JSValueConst this, int argc, JSValueC
   SocketData * data = JS_GetOpaque2(ctx, this, socket_cid);
   uint8_t *buf; size_t len;
 
-  if ( ! data->peer.sa_family ) {
-    return JS_ThrowInternalError(ctx, "Socket not connected");
-  } else if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) {
-    len = send(data->fd, buf, len, 0);
+  if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) {
+    len = send(data->fd, buf, len, MSG_NOSIGNAL);
   } else if ( (buf = (uint8_t*) JS_ToCStringLen(ctx, &len, argv[0])) ) {
-    len = send(data->fd, buf, len, 0);
+    len = send(data->fd, buf, len, MSG_NOSIGNAL);
     JS_FreeCString(ctx, (char *) buf);
   } else return JS_ThrowTypeError(ctx,
     "expected ArrayBuffer or String"
@@ -164,6 +167,7 @@ static JSValue sock_recv(  JSContext *ctx, JSValueConst this, int argc, JSValueC
   SocketData * data = JS_GetOpaque2(ctx, this, socket_cid);
   uint8_t *buf; int len; JSValue jbuf;
 
+  // FIXME: how portable is ioctl/FIONREAD ?
   if ( (JS_ToInt32(ctx, &len, argv[0]) || len <= 0)
     && ioctl(data->fd, FIONREAD, &len)
   ) return libc_error(ctx);
@@ -209,35 +213,13 @@ static JSClassDef socket_class = {
   "Socket", .finalizer = sock_destroy
 };
 
-
-static int ai_socket(struct addrinfo *address) {
-  return socket(address->ai_family,
-                address->ai_socktype,
-                address->ai_protocol
-               );
-}
-
-static int ai_bind(int sock, struct addrinfo *address) {
-  return bind(sock,
-              address->ai_addr,
-              address->ai_addrlen
-             );
-}
-
-static int ai_connect(int sock, struct addrinfo *address) {
-  return connect(sock,
-                 address->ai_addr,
-                 address->ai_addrlen
-                );
-}
-
-static JSValue udp_listen( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv) {
-  return JS_UNDEFINED;
-}
-static JSValue tcp_listen( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv, int family) {
-  struct addrinfo hints = { .ai_family = family, .ai_socktype = SOCK_STREAM };
-  struct addrinfo * self;
-  const char *host, *port;
+static JSValue ip_listen( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv, int magic) {
+  struct addrinfo hints = {
+    .ai_family = (magic&2) ? AF_INET6 : AF_INET,
+    .ai_socktype = (magic&1) ? SOCK_STREAM : SOCK_DGRAM,
+  };
+  struct addrinfo * self = NULL;
+  const char *host, *port; int gai_err;
   SocketData *data = js_mallocz(ctx, sizeof(*data));
   JSValue new = JS_NewObjectClass(ctx, socket_cid);
 
@@ -245,10 +227,10 @@ static JSValue tcp_listen( JSContext *ctx, JSValueConst this, int argc, JSValueC
   port = JS_ToCString(ctx, argv[1]);
 
   if ( data && (data->fd = -1)
-    && !getaddrinfo( host, port, &hints, &self)
+    && !(gai_err = getaddrinfo( host, port, &hints, &self))
     && (data->fd = ai_socket(self)) >= 0
     && !ai_bind(data->fd, self)
-    && !listen(data->fd, 1)
+    && ( hints.ai_socktype == SOCK_DGRAM || !listen(data->fd, 1))
   ) {
     memcpy(&(data->bind), self->ai_addr, sizeof(struct sockaddr));
     JS_SetOpaque(new, data);
@@ -256,7 +238,8 @@ static JSValue tcp_listen( JSContext *ctx, JSValueConst this, int argc, JSValueC
     JS_FreeValue(ctx, new);
     if (data->fd >= 0) close(data->fd);
     js_free(ctx, data);
-    new = libc_error(ctx);
+    if (!gai_err) new = libc_error(ctx);
+    else new = JS_ThrowInternalError(ctx, "%s", gai_strerror(gai_err));
   }
   freeaddrinfo(self);
   JS_FreeCString(ctx, host); JS_FreeCString(ctx, port);
@@ -283,10 +266,10 @@ static const JSCFunctionListEntry net_funcs[] = {
   JS_PROP_INT32_DEF("AF_INET6",      AF_INET6,      JS_PROP_CONFIGURABLE),
   JS_PROP_INT32_DEF("SOCK_STREAM",   SOCK_STREAM,   JS_PROP_CONFIGURABLE),
   JS_PROP_INT32_DEF("SOCK_DGRAM",    SOCK_DGRAM,    JS_PROP_CONFIGURABLE),
-  JS_PROP_INT32_DEF("SOCK_NONBLOCK", SOCK_NONBLOCK, JS_PROP_CONFIGURABLE),
-  JS_CFUNC_DEF("udpListen",   2, udp_listen),
-  JS_CFUNC_MAGIC_DEF("tcpListen",   2, tcp_listen, AF_INET),
-  JS_CFUNC_MAGIC_DEF("tcp6Listen",  2, tcp_listen, AF_INET6),
+  JS_CFUNC_MAGIC_DEF("udpListen",  2, ip_listen, 0),
+  JS_CFUNC_MAGIC_DEF("tcpListen",  2, ip_listen, 1),
+  JS_CFUNC_MAGIC_DEF("udp6Listen", 2, ip_listen, 2),
+  JS_CFUNC_MAGIC_DEF("tcp6Listen", 2, ip_listen, 3),
   JS_CFUNC_DEF("unixListen",  1, unix_listen),
   JS_CFUNC_DEF("udpConnect",  2, udp_connect),
   JS_CFUNC_DEF("tcpConnect",  2, tcp_connect),