fix sockets
This commit is contained in:
@@ -13,104 +13,15 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Socket wrapper structure
|
||||
typedef struct {
|
||||
int sockfd;
|
||||
} SocketWrapper;
|
||||
|
||||
// Addrinfo wrapper structure
|
||||
typedef struct {
|
||||
struct addrinfo *info;
|
||||
} AddrinfoWrapper;
|
||||
|
||||
// Free function for socket
|
||||
static void Socket_free(JSRuntime *rt, SocketWrapper *sw)
|
||||
// Helper to convert JS value to file descriptor
|
||||
static int js2fd(JSContext *ctx, JSValueConst val)
|
||||
{
|
||||
if (sw->sockfd >= 0) {
|
||||
close(sw->sockfd);
|
||||
int fd;
|
||||
if (JS_ToInt32(ctx, &fd, val) < 0) {
|
||||
JS_ThrowTypeError(ctx, "Expected file descriptor number");
|
||||
return -1;
|
||||
}
|
||||
js_free_rt(rt, sw);
|
||||
}
|
||||
|
||||
// Free function for addrinfo
|
||||
static void Addrinfo_free(JSRuntime *rt, AddrinfoWrapper *aw)
|
||||
{
|
||||
if (aw->info) {
|
||||
freeaddrinfo(aw->info);
|
||||
}
|
||||
js_free_rt(rt, aw);
|
||||
}
|
||||
|
||||
// Class definitions
|
||||
static JSClassID js_socket_class_id;
|
||||
static JSClassID js_addrinfo_class_id;
|
||||
|
||||
static JSClassDef js_socket_class = {
|
||||
"Socket",
|
||||
.finalizer = (JSClassFinalizer *)Socket_free,
|
||||
};
|
||||
|
||||
static JSClassDef js_addrinfo_class = {
|
||||
"Addrinfo",
|
||||
.finalizer = (JSClassFinalizer *)Addrinfo_free,
|
||||
};
|
||||
|
||||
// Helper to convert JS value to SocketWrapper
|
||||
static SocketWrapper *js2socket(JSContext *ctx, JSValueConst obj)
|
||||
{
|
||||
SocketWrapper *sw = JS_GetOpaque2(ctx, obj, js_socket_class_id);
|
||||
if (!sw) {
|
||||
JS_ThrowTypeError(ctx, "Expected socket object");
|
||||
return NULL;
|
||||
}
|
||||
return sw;
|
||||
}
|
||||
|
||||
// Helper to convert JS value to AddrinfoWrapper
|
||||
static AddrinfoWrapper *js2addrinfo(JSContext *ctx, JSValueConst obj)
|
||||
{
|
||||
AddrinfoWrapper *aw = JS_GetOpaque2(ctx, obj, js_addrinfo_class_id);
|
||||
if (!aw) {
|
||||
JS_ThrowTypeError(ctx, "Expected addrinfo object");
|
||||
return NULL;
|
||||
}
|
||||
return aw;
|
||||
}
|
||||
|
||||
// Helper to create JS SocketWrapper object
|
||||
static JSValue socket2js(JSContext *ctx, int sockfd)
|
||||
{
|
||||
SocketWrapper *sw = js_mallocz(ctx, sizeof(SocketWrapper));
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
|
||||
sw->sockfd = sockfd;
|
||||
|
||||
JSValue obj = JS_NewObjectClass(ctx, js_socket_class_id);
|
||||
if (JS_IsException(obj)) {
|
||||
js_free(ctx, sw);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_SetOpaque(obj, sw);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Helper to create JS AddrinfoWrapper object
|
||||
static JSValue addrinfo2js(JSContext *ctx, struct addrinfo *info)
|
||||
{
|
||||
AddrinfoWrapper *aw = js_mallocz(ctx, sizeof(AddrinfoWrapper));
|
||||
if (!aw) return JS_EXCEPTION;
|
||||
|
||||
aw->info = info;
|
||||
|
||||
JSValue obj = JS_NewObjectClass(ctx, js_addrinfo_class_id);
|
||||
if (JS_IsException(obj)) {
|
||||
js_free(ctx, aw);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_SetOpaque(obj, aw);
|
||||
return obj;
|
||||
return fd;
|
||||
}
|
||||
|
||||
// SOCKET FUNCTIONS
|
||||
@@ -206,7 +117,9 @@ JSC_CCALL(socket_getaddrinfo,
|
||||
copy->ai_canonname = strdup(p->ai_canonname);
|
||||
}
|
||||
|
||||
JS_SetPropertyStr(js, info, "_addrinfo", addrinfo2js(js, copy));
|
||||
// Store the addrinfo pointer as an internal property
|
||||
// We'll need to handle this differently since we can't wrap it
|
||||
// For now, we'll skip storing the raw addrinfo
|
||||
JS_SetPropertyUint32(js, ret, idx++, info);
|
||||
}
|
||||
|
||||
@@ -251,15 +164,15 @@ JSC_CCALL(socket_socket,
|
||||
return JS_ThrowReferenceError(js, "socket failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return socket2js(js, sockfd);
|
||||
return JS_NewInt32(js, sockfd);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_bind,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
AddrinfoWrapper *aw = js2addrinfo(js, JS_GetPropertyStr(js, argv[1], "_addrinfo"));
|
||||
if (!aw) {
|
||||
// For now, we'll only support manual address parsing
|
||||
{
|
||||
// Try to parse address and port manually
|
||||
const char *addr_str = JS_ToCString(js, JS_GetPropertyStr(js, argv[1], "address"));
|
||||
int port = js2number(js, JS_GetPropertyStr(js, argv[1], "port"));
|
||||
@@ -274,11 +187,7 @@ JSC_CCALL(socket_bind,
|
||||
}
|
||||
JS_FreeCString(js, addr_str);
|
||||
|
||||
if (bind(sw->sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "bind failed: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
if (bind(sw->sockfd, aw->info->ai_addr, aw->info->ai_addrlen) < 0) {
|
||||
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "bind failed: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
@@ -287,11 +196,11 @@ JSC_CCALL(socket_bind,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_connect,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
AddrinfoWrapper *aw = js2addrinfo(js, JS_GetPropertyStr(js, argv[1], "_addrinfo"));
|
||||
if (!aw) {
|
||||
// For now, we'll only support manual address parsing
|
||||
{
|
||||
// Try to parse address and port manually
|
||||
const char *addr_str = JS_ToCString(js, JS_GetPropertyStr(js, argv[1], "address"));
|
||||
int port = js2number(js, JS_GetPropertyStr(js, argv[1], "port"));
|
||||
@@ -306,11 +215,7 @@ JSC_CCALL(socket_connect,
|
||||
}
|
||||
JS_FreeCString(js, addr_str);
|
||||
|
||||
if (connect(sw->sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "connect failed: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
if (connect(sw->sockfd, aw->info->ai_addr, aw->info->ai_addrlen) < 0) {
|
||||
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "connect failed: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
@@ -319,15 +224,15 @@ JSC_CCALL(socket_connect,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_listen,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
int backlog = 10;
|
||||
if (argc > 1) {
|
||||
backlog = js2number(js, argv[1]);
|
||||
}
|
||||
|
||||
if (listen(sw->sockfd, backlog) < 0) {
|
||||
if (listen(sockfd, backlog) < 0) {
|
||||
return JS_ThrowReferenceError(js, "listen failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
@@ -335,19 +240,19 @@ JSC_CCALL(socket_listen,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_accept,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
struct sockaddr_storage their_addr;
|
||||
socklen_t addr_size = sizeof their_addr;
|
||||
|
||||
int new_sockfd = accept(sw->sockfd, (struct sockaddr *)&their_addr, &addr_size);
|
||||
int new_sockfd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size);
|
||||
if (new_sockfd < 0) {
|
||||
return JS_ThrowReferenceError(js, "accept failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
ret = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, ret, "socket", socket2js(js, new_sockfd));
|
||||
JS_SetPropertyStr(js, ret, "socket", JS_NewInt32(js, new_sockfd));
|
||||
|
||||
// Get peer address info
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
@@ -369,8 +274,8 @@ JSC_CCALL(socket_accept,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_send,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len;
|
||||
ssize_t sent;
|
||||
@@ -382,11 +287,11 @@ JSC_CCALL(socket_send,
|
||||
|
||||
if (JS_IsString(argv[1])) {
|
||||
const char *data = JS_ToCStringLen(js, &len, argv[1]);
|
||||
sent = send(sw->sockfd, data, len, flags);
|
||||
sent = send(sockfd, data, len, flags);
|
||||
JS_FreeCString(js, data);
|
||||
} else {
|
||||
unsigned char *data = js_get_blob_data(js, &len, argv[1]);
|
||||
sent = send(sw->sockfd, data, len, flags);
|
||||
sent = send(sockfd, data, len, flags);
|
||||
}
|
||||
|
||||
if (sent < 0) {
|
||||
@@ -397,8 +302,8 @@ JSC_CCALL(socket_send,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_recv,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len = 4096;
|
||||
if (argc > 1) {
|
||||
@@ -415,7 +320,7 @@ JSC_CCALL(socket_recv,
|
||||
return JS_ThrowReferenceError(js, "malloc failed");
|
||||
}
|
||||
|
||||
ssize_t received = recv(sw->sockfd, buf, len, flags);
|
||||
ssize_t received = recv(sockfd, buf, len, flags);
|
||||
if (received < 0) {
|
||||
free(buf);
|
||||
return JS_ThrowReferenceError(js, "recv failed: %s", strerror(errno));
|
||||
@@ -427,8 +332,8 @@ JSC_CCALL(socket_recv,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_sendto,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len;
|
||||
ssize_t sent;
|
||||
@@ -439,11 +344,11 @@ JSC_CCALL(socket_sendto,
|
||||
}
|
||||
|
||||
// Get destination address
|
||||
AddrinfoWrapper *aw = js2addrinfo(js, JS_GetPropertyStr(js, argv[2], "_addrinfo"));
|
||||
struct sockaddr *to_addr;
|
||||
socklen_t to_len;
|
||||
|
||||
if (!aw) {
|
||||
// For now, we'll only support manual address parsing
|
||||
{
|
||||
// Try to parse address and port manually
|
||||
const char *addr_str = JS_ToCString(js, JS_GetPropertyStr(js, argv[2], "address"));
|
||||
int port = js2number(js, JS_GetPropertyStr(js, argv[2], "port"));
|
||||
@@ -460,18 +365,15 @@ JSC_CCALL(socket_sendto,
|
||||
|
||||
to_addr = (struct sockaddr *)&addr;
|
||||
to_len = sizeof(addr);
|
||||
} else {
|
||||
to_addr = aw->info->ai_addr;
|
||||
to_len = aw->info->ai_addrlen;
|
||||
}
|
||||
|
||||
if (JS_IsString(argv[1])) {
|
||||
const char *data = JS_ToCStringLen(js, &len, argv[1]);
|
||||
sent = sendto(sw->sockfd, data, len, flags, to_addr, to_len);
|
||||
sent = sendto(sockfd, data, len, flags, to_addr, to_len);
|
||||
JS_FreeCString(js, data);
|
||||
} else {
|
||||
unsigned char *data = js_get_blob_data(js, &len, argv[1]);
|
||||
sent = sendto(sw->sockfd, data, len, flags, to_addr, to_len);
|
||||
sent = sendto(sockfd, data, len, flags, to_addr, to_len);
|
||||
}
|
||||
|
||||
if (sent < 0) {
|
||||
@@ -482,8 +384,8 @@ JSC_CCALL(socket_sendto,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_recvfrom,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len = 4096;
|
||||
if (argc > 1) {
|
||||
@@ -503,7 +405,7 @@ JSC_CCALL(socket_recvfrom,
|
||||
struct sockaddr_storage from_addr;
|
||||
socklen_t from_len = sizeof from_addr;
|
||||
|
||||
ssize_t received = recvfrom(sw->sockfd, buf, len, flags,
|
||||
ssize_t received = recvfrom(sockfd, buf, len, flags,
|
||||
(struct sockaddr *)&from_addr, &from_len);
|
||||
if (received < 0) {
|
||||
free(buf);
|
||||
@@ -534,15 +436,15 @@ JSC_CCALL(socket_recvfrom,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_shutdown,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
int how = SHUT_RDWR;
|
||||
if (argc > 1) {
|
||||
how = js2number(js, argv[1]);
|
||||
}
|
||||
|
||||
if (shutdown(sw->sockfd, how) < 0) {
|
||||
if (shutdown(sockfd, how) < 0) {
|
||||
return JS_ThrowReferenceError(js, "shutdown failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
@@ -550,13 +452,13 @@ JSC_CCALL(socket_shutdown,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_getpeername,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof addr;
|
||||
|
||||
if (getpeername(sw->sockfd, (struct sockaddr *)&addr, &len) < 0) {
|
||||
if (getpeername(sockfd, (struct sockaddr *)&addr, &len) < 0) {
|
||||
return JS_ThrowReferenceError(js, "getpeername failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
@@ -585,19 +487,6 @@ JSC_CCALL(socket_gethostname,
|
||||
return JS_NewString(js, hostname);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_freeaddrinfo,
|
||||
AddrinfoWrapper *aw = js2addrinfo(js, argv[0]);
|
||||
if (!aw) return JS_EXCEPTION;
|
||||
|
||||
if (aw->info) {
|
||||
if (aw->info->ai_addr) free(aw->info->ai_addr);
|
||||
if (aw->info->ai_canonname) free(aw->info->ai_canonname);
|
||||
free(aw->info);
|
||||
aw->info = NULL;
|
||||
}
|
||||
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_gai_strerror,
|
||||
int errcode = js2number(js, argv[0]);
|
||||
@@ -605,8 +494,8 @@ JSC_CCALL(socket_gai_strerror,
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_setsockopt,
|
||||
SocketWrapper *sw = js2socket(js, argv[0]);
|
||||
if (!sw) return JS_EXCEPTION;
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
int level = SOL_SOCKET;
|
||||
int optname = 0;
|
||||
@@ -637,12 +526,12 @@ JSC_CCALL(socket_setsockopt,
|
||||
// Parse option value
|
||||
if (JS_IsBool(argv[3])) {
|
||||
int optval = JS_ToBool(js, argv[3]);
|
||||
if (setsockopt(sw->sockfd, level, optname, &optval, sizeof(optval)) < 0) {
|
||||
if (setsockopt(sockfd, level, optname, &optval, sizeof(optval)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "setsockopt failed: %s", strerror(errno));
|
||||
}
|
||||
} else if (JS_IsNumber(argv[3])) {
|
||||
int optval = js2number(js, argv[3]);
|
||||
if (setsockopt(sw->sockfd, level, optname, &optval, sizeof(optval)) < 0) {
|
||||
if (setsockopt(sockfd, level, optname, &optval, sizeof(optval)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "setsockopt failed: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
@@ -652,6 +541,16 @@ JSC_CCALL(socket_setsockopt,
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_close,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
if (close(sockfd) != 0)
|
||||
return JS_ThrowReferenceError(js, "close failed: %s", strerror(errno));
|
||||
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_socket_funcs[] = {
|
||||
MIST_FUNC_DEF(socket, getaddrinfo, 3),
|
||||
MIST_FUNC_DEF(socket, socket, 3),
|
||||
@@ -666,26 +565,12 @@ static const JSCFunctionListEntry js_socket_funcs[] = {
|
||||
MIST_FUNC_DEF(socket, shutdown, 2),
|
||||
MIST_FUNC_DEF(socket, getpeername, 1),
|
||||
MIST_FUNC_DEF(socket, gethostname, 0),
|
||||
MIST_FUNC_DEF(socket, freeaddrinfo, 1),
|
||||
MIST_FUNC_DEF(socket, gai_strerror, 1),
|
||||
MIST_FUNC_DEF(socket, setsockopt, 4),
|
||||
MIST_FUNC_DEF(socket, close, 1),
|
||||
};
|
||||
|
||||
JSValue js_socket_use(JSContext *js) {
|
||||
// Initialize the socket class
|
||||
JS_NewClassID(&js_socket_class_id);
|
||||
JS_NewClass(JS_GetRuntime(js), js_socket_class_id, &js_socket_class);
|
||||
|
||||
JSValue proto = JS_NewObject(js);
|
||||
JS_SetClassProto(js, js_socket_class_id, proto);
|
||||
|
||||
// Initialize the addrinfo class
|
||||
JS_NewClassID(&js_addrinfo_class_id);
|
||||
JS_NewClass(JS_GetRuntime(js), js_addrinfo_class_id, &js_addrinfo_class);
|
||||
|
||||
JSValue addrinfo_proto = JS_NewObject(js);
|
||||
JS_SetClassProto(js, js_addrinfo_class_id, addrinfo_proto);
|
||||
|
||||
JSValue mod = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js, mod, js_socket_funcs, countof(js_socket_funcs));
|
||||
|
||||
@@ -708,4 +593,4 @@ JSValue js_socket_use(JSContext *js) {
|
||||
JS_SetPropertyStr(js, mod, "SO_REUSEADDR", JS_NewInt32(js, SO_REUSEADDR));
|
||||
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user