#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;
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"
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);
"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);
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);
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);
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),