From bd5fce10b559c6ca630cd1a2fdbc3d979fae6b3e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Thu, 12 Mar 2026 15:12:52 +0100 Subject: [PATCH] allow selection destination for udp send --- socket.c | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/socket.c b/socket.c index 80d9cd9..2b5c9ff 100644 --- a/socket.c +++ b/socket.c @@ -133,6 +133,7 @@ static JSClassID socket_cid; typedef struct { int fd; + int type; struct sockaddr_storage bind; struct sockaddr_storage peer; } SocketData; @@ -160,18 +161,43 @@ static JSValue sock_accept( return new; } -static JSValue sock_send( // TODO: optional dstHost, dstPort for UDP +static JSValue sock_send( JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv ) { SocketData * data = JS_GetOpaque2(ctx, this, socket_cid); uint8_t *buf; size_t len; + const char *host, *port; int gai_err; + struct addrinfo hints = { .ai_family = data->bind.ss_family, .ai_socktype = data->type }; + struct addrinfo * dest; struct sockaddr * to; + + // destHost and destPort may be given for UDP sockets + if (data->type == SOCK_DGRAM && argc >= 3) { + host = JS_ToCString(ctx, argv[1]); + port = JS_ToCString(ctx, argv[2]); + if (! (gai_err = getaddrinfo(host, port, &hints, &dest))) + memcpy(&(data->peer), dest->ai_addr, dest->ai_addrlen); + JS_FreeCString(ctx, host); JS_FreeCString(ctx, port); + freeaddrinfo(dest); + if (gai_err) return libc_error(ctx); + to = (struct sockaddr *) &(data->peer); + + // otherwise use default peer address + } else if (data->type == SOCK_DGRAM) { + to = (struct sockaddr *) &(data->peer); - // XXX: how portable is MSG_NOSIGNAL ? (POSIX.1-2008) + // destination should not be given for SOCK_STREAM sockets + } else to = NULL; + + + // Read Argument either as ArrayBuffer or String if ( (buf = JS_GetArrayBuffer(ctx, &len, argv[0])) ) { - len = send(data->fd, buf, len, MSG_NOSIGNAL); + // XXX: how portable is MSG_NOSIGNAL ? (POSIX.1-2008) + len = sendto(data->fd, buf, len, MSG_NOSIGNAL, to, to ? sizeof(*to) : 0); + } else if ( (buf = (uint8_t*) JS_ToCStringLen(ctx, &len, argv[0])) ) { - len = send(data->fd, buf, len, MSG_NOSIGNAL); + len = sendto(data->fd, buf, len, MSG_NOSIGNAL, to, to ? sizeof(*to) : 0); JS_FreeCString(ctx, (char *) buf); + } else return JS_ThrowTypeError(ctx, "expected ArrayBuffer or String" ); @@ -180,7 +206,7 @@ static JSValue sock_send( // TODO: optional dstHost, dstPort for UDP else return JS_NewInt32(ctx, len); } -// like in quickjs.c +// like in quickjs.c, needed for direct ArrayBuffer in sock_recv() static void js_array_buffer_free(JSRuntime *rt, void *junk, void *buf) { js_free_rt(rt, buf); } @@ -192,15 +218,18 @@ static JSValue sock_recv( uint8_t *buf; int len; JSValue jbuf; socklen_t ps = sizeof(data->peer); + // see how much data is queued up if no length argument was given // XXX: how portable is ioctl/FIONREAD ? if ( (JS_ToInt32(ctx, &len, argv[0]) || len <= 0) && ioctl(data->fd, FIONREAD, &len) ) return libc_error(ctx); + // return immediately if 0 data was requested (and queue is empty) if (len == 0 && str) return JS_NewStringLen(ctx, NULL, 0); else if (len == 0) return JS_NewArrayBufferCopy(ctx, NULL, 0); + else if ( len > 0 && (buf = js_malloc(ctx, len)) && ((len = recvfrom(data->fd, buf, len, 0, @@ -215,8 +244,9 @@ static JSValue sock_recv( if (str) jbuf = JS_NewStringLen(ctx, (char*) buf, len); else jbuf = JS_NewArrayBuffer(ctx, buf, len, js_array_buffer_free, NULL, 0); return jbuf; + } else { - free(buf); + js_free(ctx, buf); return libc_error(ctx); } } @@ -301,6 +331,7 @@ static JSValue ip_listen( && !ai_bind(data->fd, self) && ( hints.ai_socktype == SOCK_DGRAM || !listen(data->fd, 1)) ) { + data->type = self->ai_socktype; memcpy(&(data->bind), self->ai_addr, sizeof(struct sockaddr)); JS_SetOpaque(new, data); } else { @@ -337,6 +368,7 @@ static JSValue ip_connect( && (data->fd = ai_socket(peer)) >= 0 && !ai_connect(data->fd, peer) ) { + data->type = peer->ai_socktype; memcpy(&(data->peer), peer->ai_addr, sizeof(struct sockaddr)); JS_SetOpaque(new, data); } else { @@ -373,6 +405,7 @@ static JSValue unix_bind( : bind(data->fd,(struct sockaddr *) &(data->bind),sizeof(*addr)) ) && (c || !listen(data->fd, 1)) ) { + data->type = SOCK_STREAM; JS_SetOpaque(new, data); } else { if (data && data->fd >= 0) close(data->fd); -- 2.39.5