turn into a cell package
This commit is contained in:
620
net/socket.c
Normal file
620
net/socket.c
Normal file
@@ -0,0 +1,620 @@
|
||||
#include "cell.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#define close closesocket
|
||||
#define SHUT_RD SD_RECEIVE
|
||||
#define SHUT_WR SD_SEND
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#ifndef AF_UNIX
|
||||
#define AF_UNIX 1
|
||||
#endif
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Helper to convert JS value to file descriptor
|
||||
static int js2fd(JSContext *ctx, JSValueConst val)
|
||||
{
|
||||
int fd;
|
||||
if (JS_ToInt32(ctx, &fd, val) < 0) {
|
||||
JS_ThrowTypeError(ctx, "Expected file descriptor number");
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
// SOCKET FUNCTIONS
|
||||
|
||||
JSC_CCALL(socket_getaddrinfo,
|
||||
const char *node = NULL;
|
||||
const char *service = NULL;
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if (!JS_IsNull(argv[0]) && !JS_IsNull(argv[0]))
|
||||
node = JS_ToCString(js, argv[0]);
|
||||
|
||||
if (!JS_IsNull(argv[1]) && !JS_IsNull(argv[1]))
|
||||
service = JS_ToCString(js, argv[1]);
|
||||
|
||||
// Parse optional hints object
|
||||
if (argc > 2 && JS_IsObject(argv[2])) {
|
||||
JSValue val;
|
||||
|
||||
val = JS_GetPropertyStr(js, argv[2], "family");
|
||||
if (!JS_IsNull(val)) {
|
||||
const char *family = JS_ToCString(js, val);
|
||||
if (strcmp(family, "AF_INET") == 0) hints.ai_family = AF_INET;
|
||||
else if (strcmp(family, "AF_INET6") == 0) hints.ai_family = AF_INET6;
|
||||
JS_FreeCString(js, family);
|
||||
}
|
||||
JS_FreeValue(js, val);
|
||||
|
||||
val = JS_GetPropertyStr(js, argv[2], "socktype");
|
||||
if (!JS_IsNull(val)) {
|
||||
const char *socktype = JS_ToCString(js, val);
|
||||
if (strcmp(socktype, "SOCK_STREAM") == 0) hints.ai_socktype = SOCK_STREAM;
|
||||
else if (strcmp(socktype, "SOCK_DGRAM") == 0) hints.ai_socktype = SOCK_DGRAM;
|
||||
JS_FreeCString(js, socktype);
|
||||
}
|
||||
JS_FreeValue(js, val);
|
||||
|
||||
val = JS_GetPropertyStr(js, argv[2], "flags");
|
||||
if (!JS_IsNull(val)) {
|
||||
hints.ai_flags = js2number(js, val);
|
||||
}
|
||||
JS_FreeValue(js, val);
|
||||
|
||||
val = JS_GetPropertyStr(js, argv[2], "passive");
|
||||
if (JS_ToBool(js, val)) {
|
||||
hints.ai_flags |= AI_PASSIVE;
|
||||
}
|
||||
JS_FreeValue(js, val);
|
||||
}
|
||||
|
||||
int status = getaddrinfo(node, service, &hints, &res);
|
||||
|
||||
if (node) JS_FreeCString(js, node);
|
||||
if (service) JS_FreeCString(js, service);
|
||||
|
||||
if (status != 0) {
|
||||
return JS_ThrowReferenceError(js, "getaddrinfo error: %s", gai_strerror(status));
|
||||
}
|
||||
|
||||
// Convert linked list to JS array
|
||||
ret = JS_NewArray(js);
|
||||
int idx = 0;
|
||||
for (struct addrinfo *p = res; p != NULL; p = p->ai_next) {
|
||||
JSValue info = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, info, "family", JS_NewInt32(js, p->ai_family));
|
||||
JS_SetPropertyStr(js, info, "socktype", JS_NewInt32(js, p->ai_socktype));
|
||||
JS_SetPropertyStr(js, info, "protocol", JS_NewInt32(js, p->ai_protocol));
|
||||
|
||||
// Convert address to string
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
void *addr;
|
||||
if (p->ai_family == AF_INET) {
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
addr = &(ipv4->sin_addr);
|
||||
} else {
|
||||
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
addr = &(ipv6->sin6_addr);
|
||||
}
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
JS_SetPropertyStr(js, info, "address", JS_NewString(js, ipstr));
|
||||
|
||||
// Store the addrinfo for later use
|
||||
struct addrinfo *copy = malloc(sizeof(struct addrinfo));
|
||||
memcpy(copy, p, sizeof(struct addrinfo));
|
||||
copy->ai_addr = malloc(p->ai_addrlen);
|
||||
memcpy(copy->ai_addr, p->ai_addr, p->ai_addrlen);
|
||||
copy->ai_next = NULL;
|
||||
if (p->ai_canonname) {
|
||||
copy->ai_canonname = strdup(p->ai_canonname);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_socket,
|
||||
int domain = AF_INET;
|
||||
int type = SOCK_STREAM;
|
||||
int protocol = 0;
|
||||
|
||||
// Parse domain
|
||||
if (JS_IsString(argv[0])) {
|
||||
const char *domain_str = JS_ToCString(js, argv[0]);
|
||||
if (strcmp(domain_str, "AF_INET") == 0) domain = AF_INET;
|
||||
else if (strcmp(domain_str, "AF_INET6") == 0) domain = AF_INET6;
|
||||
else if (strcmp(domain_str, "AF_UNIX") == 0) domain = AF_UNIX;
|
||||
JS_FreeCString(js, domain_str);
|
||||
} else if (JS_IsNumber(argv[0])) {
|
||||
domain = js2number(js, argv[0]);
|
||||
}
|
||||
|
||||
// Parse type
|
||||
if (argc > 1) {
|
||||
if (JS_IsString(argv[1])) {
|
||||
const char *type_str = JS_ToCString(js, argv[1]);
|
||||
if (strcmp(type_str, "SOCK_STREAM") == 0) type = SOCK_STREAM;
|
||||
else if (strcmp(type_str, "SOCK_DGRAM") == 0) type = SOCK_DGRAM;
|
||||
JS_FreeCString(js, type_str);
|
||||
} else if (JS_IsNumber(argv[1])) {
|
||||
type = js2number(js, argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse protocol
|
||||
if (argc > 2) {
|
||||
protocol = js2number(js, argv[2]);
|
||||
}
|
||||
|
||||
int sockfd = socket(domain, type, protocol);
|
||||
if (sockfd < 0) {
|
||||
return JS_ThrowReferenceError(js, "socket failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return JS_NewInt32(js, sockfd);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_bind,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
// 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"));
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (inet_pton(AF_INET, addr_str, &addr.sin_addr) <= 0) {
|
||||
JS_FreeCString(js, addr_str);
|
||||
return JS_ThrowReferenceError(js, "Invalid address");
|
||||
}
|
||||
JS_FreeCString(js, addr_str);
|
||||
|
||||
if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "bind failed: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_connect,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
// 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"));
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (inet_pton(AF_INET, addr_str, &addr.sin_addr) <= 0) {
|
||||
JS_FreeCString(js, addr_str);
|
||||
return JS_ThrowReferenceError(js, "Invalid address");
|
||||
}
|
||||
JS_FreeCString(js, addr_str);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "connect failed: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_listen,
|
||||
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(sockfd, backlog) < 0) {
|
||||
return JS_ThrowReferenceError(js, "listen failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_accept,
|
||||
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(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", JS_NewInt32(js, new_sockfd));
|
||||
|
||||
// Get peer address info
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
int port;
|
||||
if (their_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&their_addr;
|
||||
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||
port = ntohs(s->sin_port);
|
||||
} else {
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&their_addr;
|
||||
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||
port = ntohs(s->sin6_port);
|
||||
}
|
||||
|
||||
JSValue addr_info = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, addr_info, "address", JS_NewString(js, ipstr));
|
||||
JS_SetPropertyStr(js, addr_info, "port", JS_NewInt32(js, port));
|
||||
JS_SetPropertyStr(js, ret, "address", addr_info);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_send,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len;
|
||||
ssize_t sent;
|
||||
int flags = 0;
|
||||
|
||||
if (argc > 2) {
|
||||
flags = js2number(js, argv[2]);
|
||||
}
|
||||
|
||||
if (JS_IsString(argv[1])) {
|
||||
const char *data = JS_ToCStringLen(js, &len, argv[1]);
|
||||
sent = send(sockfd, data, len, flags);
|
||||
JS_FreeCString(js, data);
|
||||
} else {
|
||||
unsigned char *data = js_get_blob_data(js, &len, argv[1]);
|
||||
if (data == -1)
|
||||
return JS_EXCEPTION;
|
||||
|
||||
if (len == 0)
|
||||
return JS_ThrowReferenceError(js, "No data to send");
|
||||
|
||||
sent = send(sockfd, (const char *)data, len, flags);
|
||||
}
|
||||
|
||||
if (sent < 0) {
|
||||
return JS_ThrowReferenceError(js, "send failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return JS_NewInt64(js, sent);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_recv,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len = 4096;
|
||||
if (argc > 1) {
|
||||
len = js2number(js, argv[1]);
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
if (argc > 2) {
|
||||
flags = js2number(js, argv[2]);
|
||||
}
|
||||
|
||||
void *buf = malloc(len);
|
||||
if (!buf) {
|
||||
return JS_ThrowReferenceError(js, "malloc failed");
|
||||
}
|
||||
|
||||
ssize_t received = recv(sockfd, buf, len, flags);
|
||||
if (received < 0) {
|
||||
free(buf);
|
||||
return JS_ThrowReferenceError(js, "recv failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
ret = js_new_blob_stoned_copy(js, buf, received);
|
||||
free(buf);
|
||||
return ret;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_sendto,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len;
|
||||
ssize_t sent;
|
||||
int flags = 0;
|
||||
|
||||
if (argc > 3) {
|
||||
flags = js2number(js, argv[3]);
|
||||
}
|
||||
|
||||
// Get destination address
|
||||
struct sockaddr *to_addr;
|
||||
socklen_t to_len;
|
||||
|
||||
// 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"));
|
||||
|
||||
static struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (inet_pton(AF_INET, addr_str, &addr.sin_addr) <= 0) {
|
||||
JS_FreeCString(js, addr_str);
|
||||
return JS_ThrowReferenceError(js, "Invalid address");
|
||||
}
|
||||
JS_FreeCString(js, addr_str);
|
||||
|
||||
to_addr = (struct sockaddr *)&addr;
|
||||
to_len = sizeof(addr);
|
||||
}
|
||||
|
||||
if (JS_IsString(argv[1])) {
|
||||
const char *data = JS_ToCStringLen(js, &len, argv[1]);
|
||||
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]);
|
||||
if (data == (unsigned char *)-1) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (len == 0) {
|
||||
return JS_ThrowReferenceError(js, "No data to send");
|
||||
}
|
||||
sent = sendto(sockfd, (const char *)data, len, flags, to_addr, to_len);
|
||||
}
|
||||
|
||||
if (sent < 0) {
|
||||
return JS_ThrowReferenceError(js, "sendto failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return JS_NewInt64(js, sent);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_recvfrom,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
size_t len = 4096;
|
||||
if (argc > 1) {
|
||||
len = js2number(js, argv[1]);
|
||||
}
|
||||
|
||||
int flags = 0;
|
||||
if (argc > 2) {
|
||||
flags = js2number(js, argv[2]);
|
||||
}
|
||||
|
||||
void *buf = malloc(len);
|
||||
if (!buf) {
|
||||
return JS_ThrowReferenceError(js, "malloc failed");
|
||||
}
|
||||
|
||||
struct sockaddr_storage from_addr;
|
||||
socklen_t from_len = sizeof from_addr;
|
||||
|
||||
ssize_t received = recvfrom(sockfd, buf, len, flags,
|
||||
(struct sockaddr *)&from_addr, &from_len);
|
||||
if (received < 0) {
|
||||
free(buf);
|
||||
return JS_ThrowReferenceError(js, "recvfrom failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
ret = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, ret, "data", js_new_blob_stoned_copy(js, buf, received));
|
||||
free(buf);
|
||||
|
||||
// Get source address info
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
int port;
|
||||
if (from_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&from_addr;
|
||||
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||
port = ntohs(s->sin_port);
|
||||
} else {
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&from_addr;
|
||||
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||
port = ntohs(s->sin6_port);
|
||||
}
|
||||
|
||||
JSValue addr_info = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, addr_info, "address", JS_NewString(js, ipstr));
|
||||
JS_SetPropertyStr(js, addr_info, "port", JS_NewInt32(js, port));
|
||||
JS_SetPropertyStr(js, ret, "address", addr_info);
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_shutdown,
|
||||
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(sockfd, how) < 0) {
|
||||
return JS_ThrowReferenceError(js, "shutdown failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_getpeername,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof addr;
|
||||
|
||||
if (getpeername(sockfd, (struct sockaddr *)&addr, &len) < 0) {
|
||||
return JS_ThrowReferenceError(js, "getpeername failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
int port;
|
||||
if (addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
|
||||
port = ntohs(s->sin_port);
|
||||
} else {
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
||||
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
|
||||
port = ntohs(s->sin6_port);
|
||||
}
|
||||
|
||||
ret = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, ret, "address", JS_NewString(js, ipstr));
|
||||
JS_SetPropertyStr(js, ret, "port", JS_NewInt32(js, port));
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_gethostname,
|
||||
char hostname[256];
|
||||
if (gethostname(hostname, sizeof(hostname)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "gethostname failed: %s", strerror(errno));
|
||||
}
|
||||
return JS_NewString(js, hostname);
|
||||
)
|
||||
|
||||
|
||||
JSC_CCALL(socket_gai_strerror,
|
||||
int errcode = js2number(js, argv[0]);
|
||||
return JS_NewString(js, gai_strerror(errcode));
|
||||
)
|
||||
|
||||
JSC_CCALL(socket_setsockopt,
|
||||
int sockfd = js2fd(js, argv[0]);
|
||||
if (sockfd < 0) return JS_EXCEPTION;
|
||||
|
||||
int level = SOL_SOCKET;
|
||||
int optname = 0;
|
||||
|
||||
// Parse level
|
||||
if (JS_IsString(argv[1])) {
|
||||
const char *level_str = JS_ToCString(js, argv[1]);
|
||||
if (strcmp(level_str, "SOL_SOCKET") == 0) level = SOL_SOCKET;
|
||||
else if (strcmp(level_str, "IPPROTO_TCP") == 0) level = IPPROTO_TCP;
|
||||
else if (strcmp(level_str, "IPPROTO_IP") == 0) level = IPPROTO_IP;
|
||||
else if (strcmp(level_str, "IPPROTO_IPV6") == 0) level = IPPROTO_IPV6;
|
||||
JS_FreeCString(js, level_str);
|
||||
} else {
|
||||
level = js2number(js, argv[1]);
|
||||
}
|
||||
|
||||
// Parse option name
|
||||
if (JS_IsString(argv[2])) {
|
||||
const char *opt_str = JS_ToCString(js, argv[2]);
|
||||
if (strcmp(opt_str, "SO_REUSEADDR") == 0) optname = SO_REUSEADDR;
|
||||
else if (strcmp(opt_str, "SO_KEEPALIVE") == 0) optname = SO_KEEPALIVE;
|
||||
else if (strcmp(opt_str, "SO_BROADCAST") == 0) optname = SO_BROADCAST;
|
||||
JS_FreeCString(js, opt_str);
|
||||
} else {
|
||||
optname = js2number(js, argv[2]);
|
||||
}
|
||||
|
||||
// Parse option value
|
||||
if (JS_IsBool(argv[3])) {
|
||||
int optval = JS_ToBool(js, argv[3]);
|
||||
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(sockfd, level, optname, &optval, sizeof(optval)) < 0) {
|
||||
return JS_ThrowReferenceError(js, "setsockopt failed: %s", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
return JS_ThrowTypeError(js, "Invalid option value");
|
||||
}
|
||||
|
||||
return JS_NULL;
|
||||
)
|
||||
|
||||
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_NULL;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_socket_funcs[] = {
|
||||
MIST_FUNC_DEF(socket, getaddrinfo, 3),
|
||||
MIST_FUNC_DEF(socket, socket, 3),
|
||||
MIST_FUNC_DEF(socket, bind, 2),
|
||||
MIST_FUNC_DEF(socket, connect, 2),
|
||||
MIST_FUNC_DEF(socket, listen, 2),
|
||||
MIST_FUNC_DEF(socket, accept, 1),
|
||||
MIST_FUNC_DEF(socket, send, 3),
|
||||
MIST_FUNC_DEF(socket, recv, 3),
|
||||
MIST_FUNC_DEF(socket, sendto, 4),
|
||||
MIST_FUNC_DEF(socket, recvfrom, 3),
|
||||
MIST_FUNC_DEF(socket, shutdown, 2),
|
||||
MIST_FUNC_DEF(socket, getpeername, 1),
|
||||
MIST_FUNC_DEF(socket, gethostname, 0),
|
||||
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) {
|
||||
JSValue mod = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js, mod, js_socket_funcs, countof(js_socket_funcs));
|
||||
|
||||
// Add constants
|
||||
JS_SetPropertyStr(js, mod, "AF_UNSPEC", JS_NewInt32(js, AF_UNSPEC));
|
||||
JS_SetPropertyStr(js, mod, "AF_INET", JS_NewInt32(js, AF_INET));
|
||||
JS_SetPropertyStr(js, mod, "AF_INET6", JS_NewInt32(js, AF_INET6));
|
||||
JS_SetPropertyStr(js, mod, "AF_UNIX", JS_NewInt32(js, AF_UNIX));
|
||||
|
||||
JS_SetPropertyStr(js, mod, "SOCK_STREAM", JS_NewInt32(js, SOCK_STREAM));
|
||||
JS_SetPropertyStr(js, mod, "SOCK_DGRAM", JS_NewInt32(js, SOCK_DGRAM));
|
||||
|
||||
JS_SetPropertyStr(js, mod, "AI_PASSIVE", JS_NewInt32(js, AI_PASSIVE));
|
||||
|
||||
JS_SetPropertyStr(js, mod, "SHUT_RD", JS_NewInt32(js, SHUT_RD));
|
||||
JS_SetPropertyStr(js, mod, "SHUT_WR", JS_NewInt32(js, SHUT_WR));
|
||||
JS_SetPropertyStr(js, mod, "SHUT_RDWR", JS_NewInt32(js, SHUT_RDWR));
|
||||
|
||||
JS_SetPropertyStr(js, mod, "SOL_SOCKET", JS_NewInt32(js, SOL_SOCKET));
|
||||
JS_SetPropertyStr(js, mod, "SO_REUSEADDR", JS_NewInt32(js, SO_REUSEADDR));
|
||||
|
||||
return mod;
|
||||
}
|
||||
Reference in New Issue
Block a user