static JSValue js_os_accept(
JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv
) {
- struct sockaddr * peer; socklen_t ps = sizeof(struct sockaddr);
+ struct sockaddr peer; socklen_t ps = sizeof(struct sockaddr);
char host[40], port[6];
int fd, new;
if ( argc < 1 ) return JS_EXCEPTION;
if ( JS_ToInt32(ctx, &fd, argv[0]) ) return JS_EXCEPTION;
+ // FIXME: use numeric port number (int instead of string)
if ( argc >= 2 ) {
- peer = malloc(ps);
- if ((new = accept(fd, peer, &ps)) != -1) {
- JS_SetPropertyStr(ctx, argv[1], "protocol", JS_NewInt32(ctx, peer->sa_family));
- if ( peer->sa_family != AF_UNIX ) {
- getnameinfo(peer, ps, host, 40, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
+ if ((new = accept(fd, &peer, &ps)) != -1) {
+ JS_SetPropertyStr(ctx, argv[1], "protocol", JS_NewInt32(ctx, peer.sa_family));
+ if ( peer.sa_family != AF_UNIX ) {
+ getnameinfo(&peer, ps, host, 40, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
JS_SetPropertyStr(ctx, argv[1], "host", JS_NewString(ctx, host));
JS_SetPropertyStr(ctx, argv[1], "port", JS_NewString(ctx, port));
}
}
- free(peer);
} else {
new = accept(fd, NULL, 0);
}
typedef struct {
int fd;
- struct sockaddr bind;
- struct sockaddr peer;
+ struct sockaddr_storage bind;
+ struct sockaddr_storage peer;
} SocketData;
static JSValue sock_accept(
SocketData * data = JS_GetOpaque2(ctx, this, socket_cid);
SocketData * newdata = js_mallocz(ctx, sizeof(SocketData));
JSValue new = JS_NewObjectClass(ctx, socket_cid);
- socklen_t ps = sizeof(struct sockaddr);
+ socklen_t ps = sizeof(data->bind);
if ( newdata
- && (newdata->fd = accept(data->fd, &(newdata->peer), &ps)) >= 0
+ && (newdata->fd = accept(
+ data->fd, (struct sockaddr *) &(newdata->peer), &ps
+ )) >= 0
) {
- memcpy(&(newdata->bind), &(data->bind), sizeof(struct sockaddr));
+ memcpy(&(newdata->bind), &(data->bind), sizeof(data->bind));
JS_SetOpaque(new, newdata);
} else {
new = libc_error(ctx);
return new;
}
-static JSValue sock_send(
+static JSValue sock_send( // TODO: optional dstHost, dstPort for UDP
JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv
) {
SocketData * data = JS_GetOpaque2(ctx, this, socket_cid);
uint8_t *buf; size_t len;
- // FIXME: how portable is MSG_NOSIGNAL ? (POSIX.1-2008)
+ // XXX: how portable is MSG_NOSIGNAL ? (POSIX.1-2008)
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])) ) {
else return JS_NewInt32(ctx, len);
}
+// like in quickjs.c
+static void js_array_buffer_free(JSRuntime *rt, void *junk, void *buf) {
+ js_free_rt(rt, buf);
+}
+
static JSValue sock_recv(
JSContext *ctx, JSValueConst this, int argc, JSValueConst *argv, int str
) {
SocketData * data = JS_GetOpaque2(ctx, this, socket_cid);
uint8_t *buf; int len; JSValue jbuf;
+ socklen_t ps = sizeof(data->peer);
- // FIXME: how portable is ioctl/FIONREAD ?
+ // XXX: how portable is ioctl/FIONREAD ?
if ( (JS_ToInt32(ctx, &len, argv[0]) || len <= 0)
&& ioctl(data->fd, FIONREAD, &len)
) return libc_error(ctx);
else if (len == 0)
return JS_NewArrayBufferCopy(ctx, NULL, 0);
else if ( len > 0
- && (buf = malloc(len))
- && ((len = recv(data->fd, buf, len, 0)) >= 0)
+ && (buf = js_malloc(ctx, len))
+ && ((len = recvfrom(data->fd, buf, len, 0,
+ (struct sockaddr *) &(data->peer), &ps)) >= 0)
) {
+ // make sure the buffer is resized after a short read
+ // avoid realloc(p, 0) as recommended by glibc
+ if (len) js_realloc(ctx, buf, len);
+ else { js_free(ctx, buf); buf = NULL; }
+
+ // XXX: what does the opaque field in NewArryBuffer do? Is it important?
if (str) jbuf = JS_NewStringLen(ctx, (char*) buf, len);
- else jbuf = JS_NewArrayBufferCopy(ctx, buf, len);
- free(buf);
+ else jbuf = JS_NewArrayBuffer(ctx, buf, len, js_array_buffer_free, NULL, 0);
return jbuf;
} else {
free(buf);
static JSValue sock_get_addr( JSContext *ctx, JSValueConst this, int magic ) {
SocketData * data = JS_GetOpaque2(ctx, this, socket_cid);
- struct sockaddr * addr = (magic&2) ? &(data->peer) : &(data->bind);
+ struct sockaddr_storage * addr = (magic&2) ? &(data->peer) : &(data->bind);
char host[40];
if ( addr == NULL) return JS_UNDEFINED;
if (magic&1){
- if (addr->sa_family == AF_INET)
+ if (addr->ss_family == AF_INET)
return JS_NewInt32(ctx, ntohs(((struct sockaddr_in *) addr)->sin_port));
- else if (addr->sa_family == AF_INET6)
+ else if (addr->ss_family == AF_INET6)
return JS_NewInt32(ctx, ntohs(((struct sockaddr_in6 *) addr)->sin6_port));
else return JS_UNDEFINED;
}
- if (addr->sa_family == AF_UNIX) {
+ if (addr->ss_family == AF_UNIX) {
return JS_NewString(ctx, ((struct sockaddr_un *) addr)->sun_path);
- } else if (addr->sa_family == AF_INET || addr->sa_family == AF_INET6) {
- if (!getnameinfo(addr, sizeof(struct sockaddr),
+ } else if (addr->ss_family == AF_INET || addr->ss_family == AF_INET6) {
+ if (!getnameinfo((struct sockaddr *) addr, sizeof(*addr),
host, 40, NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV)
) { return JS_NewString(ctx, host);
JS_CGETSET_MAGIC_DEF("localPort", sock_get_addr, NULL, 1),
JS_CGETSET_MAGIC_DEF("peerName", sock_get_addr, NULL, 2),
JS_CGETSET_MAGIC_DEF("peerPort", sock_get_addr, NULL, 3),
+ // JS_CGETSET_DEF("timeout", ) // TODO: send / receive timeout
+ // JS_CFUNC_DEF("reconnect", ) // TODO
};
static JSClassDef socket_class = {
&& (plen < sizeof(addr->sun_path))
&& strncpy(addr->sun_path, path, plen)
&& (data->fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0
- && !( c ? connect(data->fd, &(data->peer), sizeof(*addr))
- : bind(data->fd, &(data->bind), sizeof(*addr))
+ && !( c ?connect(data->fd,(struct sockaddr *) &(data->peer),sizeof(*addr))
+ : bind(data->fd,(struct sockaddr *) &(data->bind),sizeof(*addr))
) && (c || !listen(data->fd, 1))
) {
JS_SetOpaque(new, data);
JS_CFUNC_MAGIC_DEF("tcp6Connect", 2, ip_connect, 3),
JS_CFUNC_MAGIC_DEF("unixListen", 1, unix_bind, 0),
JS_CFUNC_MAGIC_DEF("unixConnect", 1, unix_bind, 1),
+ // JS_CGETSET_DEF("timeout", ) // TODO: connect timeout
};
// static const JSCFunctionListEntry net_obj[] = {