typedef struct {
int fd;
+ int type;
struct sockaddr_storage bind;
struct sockaddr_storage peer;
} SocketData;
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"
);
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);
}
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,
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);
}
}
&& !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 {
&& (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 {
: 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);