Skip to content

Commit e4da65e

Browse files
committed
windows support
1 parent 29a8f53 commit e4da65e

File tree

5 files changed

+136
-43
lines changed

5 files changed

+136
-43
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ HOST_LIBS=-lm -ldl -lpthread
247247
LIBS=-lm -lpthread
248248
ifndef CONFIG_WIN32
249249
LIBS+=-ldl
250+
else
251+
LIBS+=-lws2_32
250252
endif
251253
LIBS+=$(EXTRA_LIBS)
252254

examples/http_client.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ function must(result) {
1010
}
1111

1212
const sockfd = must(os.socket(os.AF_INET, os.SOCK_STREAM));
13-
await os.connect(sockfd, os.getaddrinfo("bellard.org",'80')[0]);
14-
const httpReq = ["GET / HTTP/1.0", "", ""].join('\r\n')
15-
must(await os.send(sockfd, Uint8Array.from(httpReq, c => c.charCodeAt(0)).buffer) > 0);
13+
const addr = {addr:"0.0.0.0",port:8000} //os.getaddrinfo("bellard.org",'80');
14+
await os.connect(sockfd, addr);
15+
const httpReq = Uint8Array.from("GET / HTTP/1.0\r\n\r\n", c => c.charCodeAt(0))
16+
must(await os.send(sockfd, httpReq.buffer) > 0);
1617
const chunk = new Uint8Array(512);
1718
const recvd = await os.recv(sockfd, chunk.buffer);
1819
console.log([...chunk.slice(0,recvd)].map(c => String.fromCharCode(c)).join(''));

qjs.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
#elif defined(__FreeBSD__)
4040
#include <malloc_np.h>
4141
#endif
42+
#if defined(_WIN32)
43+
#include <winsock2.h>
44+
#include <ws2tcpip.h>
45+
#include <windows.h>
46+
#endif
4247

4348
#include "cutils.h"
4449
#include "quickjs-libc.h"

quickjs-libc.c

Lines changed: 107 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@
3838
#include <sys/stat.h>
3939
#include <dirent.h>
4040
#if defined(_WIN32)
41+
#include <winsock2.h>
42+
#include <ws2tcpip.h>
4143
#include <windows.h>
4244
#include <conio.h>
4345
#include <utime.h>
44-
#include <winsock2.h>
4546
#else
4647
#include <dlfcn.h>
4748
#include <termios.h>
@@ -113,6 +114,9 @@ typedef struct {
113114
struct sockaddr_storage sockaddr; // for sendto()
114115
JSValue resolve;
115116
JSValue reject;
117+
#ifdef _WIN32
118+
WSAEVENT event; // so os_pool can wait on it
119+
#endif
116120
} JSOSSockHandler;
117121

118122
typedef struct {
@@ -1039,6 +1043,18 @@ static ssize_t js_get_errno(ssize_t ret)
10391043
return ret;
10401044
}
10411045

1046+
static ssize_t js_get_sockerrno(ssize_t ret)
1047+
{
1048+
#if defined(_WIN32)
1049+
if (ret == -1 || ret == INVALID_SOCKET)
1050+
ret = -WSAGetLastError();
1051+
#else
1052+
if (ret == -1)
1053+
ret = -errno;
1054+
#endif
1055+
return ret;
1056+
}
1057+
10421058
static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,
10431059
int argc, JSValueConst *argv)
10441060
{
@@ -1785,11 +1801,6 @@ static int js_std_init(JSContext *ctx, JSModuleDef *m)
17851801
{
17861802
JSValue proto;
17871803

1788-
#if defined(_WIN32)
1789-
WSADATA wsa_data;
1790-
WSAStartup(0x0202, &wsa_data);
1791-
#endif
1792-
17931804
/* FILE class */
17941805
/* the class ID is created once */
17951806
JS_NewClassID(&js_std_file_class_id);
@@ -2517,28 +2528,41 @@ static int handle_posted_message(JSContext *ctx, JSWorkerMessageHandler *port)
25172528

25182529
static void handle_socket_message(JSContext *ctx, JSOSSockHandler *sh)
25192530
{
2531+
#ifdef _WIN32
2532+
WSANETWORKEVENTS netEvents;
2533+
WSAEnumNetworkEvents(sh->sockfd, sh->event, &netEvents);
2534+
#endif
2535+
25202536
int err = 0;
25212537
struct sockaddr_storage sockaddr;
25222538
socklen_t addr_len = sizeof(sockaddr);
2523-
socklen_t len = sizeof(err);
2539+
25242540
if (sh->magic == MAGIC_SOCKET_RECV) {
2525-
err = js_get_errno(recv(sh->sockfd, sh->buffer, sh->length, 0));
2541+
err = js_get_sockerrno(recv(sh->sockfd, (char*) sh->buffer, sh->length, 0));
25262542
} else if (sh->magic == MAGIC_SOCKET_SEND) {
2527-
err = js_get_errno(send(sh->sockfd, sh->buffer, sh->length, 0));
2543+
err = js_get_sockerrno(send(sh->sockfd, (char*) sh->buffer, sh->length, 0));
25282544
} else if (sh->magic == MAGIC_SOCKET_RECVFROM) {
2529-
err = js_get_errno(recvfrom(sh->sockfd, sh->buffer, sh->length, 0, (struct sockaddr *)&sockaddr, &addr_len));
2545+
err = js_get_sockerrno(recvfrom(sh->sockfd, (char*) sh->buffer, sh->length, 0, (struct sockaddr *)&sockaddr, &addr_len));
25302546
} else if (sh->magic == MAGIC_SOCKET_SENDTO) {
2531-
err = js_get_errno(sendto(sh->sockfd, sh->buffer, sh->length, 0, (const struct sockaddr *)&sh->sockaddr, addr_len));
2547+
err = js_get_sockerrno(sendto(sh->sockfd, (char*) sh->buffer, sh->length, 0, (const struct sockaddr *)&sh->sockaddr, addr_len));
25322548
} else if (sh->magic == MAGIC_SOCKET_CONNECT) {
2533-
err = getsockopt(sh->sockfd, SOL_SOCKET, SO_ERROR, &err, &len) ? -errno : -err;
2549+
#ifdef _WIN32
2550+
err = 0;
2551+
#else
2552+
socklen_t len = sizeof(err);
2553+
err = getsockopt(sh->sockfd, SOL_SOCKET, SO_ERROR, (char*) &err, &len) ? -errno : -err;
2554+
#endif
25342555
} else if (sh->magic == MAGIC_SOCKET_ACCEPT) {
2535-
err = js_get_errno(accept(sh->sockfd, (struct sockaddr *)&sockaddr, &addr_len));
2556+
err = js_get_sockerrno(accept(sh->sockfd, (struct sockaddr *)&sockaddr, &addr_len));
25362557
}
25372558

2538-
2559+
#ifdef _WIN32
2560+
if (err == -WSAEWOULDBLOCK)
2561+
return;
2562+
#else
25392563
if (err == -EAGAIN || err == -EWOULDBLOCK)
25402564
return;
2541-
2565+
#endif
25422566
JSValue promiseval = JS_UNDEFINED;
25432567
if (sh->magic == MAGIC_SOCKET_ACCEPT) {
25442568
promiseval = JS_NewArray(ctx);
@@ -2589,8 +2613,10 @@ static int js_os_poll(JSContext *ctx)
25892613

25902614
/* XXX: handle signals if useful */
25912615

2592-
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
2593-
list_empty(&ts->port_list)) {
2616+
if (list_empty(&ts->os_rw_handlers) &&
2617+
list_empty(&ts->os_timers) &&
2618+
list_empty(&ts->port_list) &&
2619+
list_empty(&ts->os_sock_handlers)) {
25942620
return -1; /* no more events */
25952621
}
25962622

@@ -2620,13 +2646,21 @@ static int js_os_poll(JSContext *ctx)
26202646
count = 0;
26212647
list_for_each(el, &ts->os_rw_handlers) {
26222648
rh = list_entry(el, JSOSRWHandler, link);
2623-
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
2649+
if (rh->fd == 0 && !JS_IsNull(rh->r_func)) {
26242650
handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
26252651
if (count == (int)countof(handles))
26262652
break;
26272653
}
26282654
}
26292655

2656+
list_for_each(el, &ts->os_sock_handlers) {
2657+
JSOSSockHandler *sh = list_entry(el, JSOSSockHandler, link);
2658+
//TODO: socket readability don't seems to be a winsock event => trigger manually
2659+
handles[count++] = sh->event;
2660+
if (count == (int)countof(handles))
2661+
break;
2662+
}
2663+
26302664
list_for_each(el, &ts->port_list) {
26312665
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
26322666
if (JS_IsNull(port->on_message_func))
@@ -2642,16 +2676,26 @@ static int js_os_poll(JSContext *ctx)
26422676
timeout = min_delay;
26432677
ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
26442678

2679+
// why iterate on every list instead of just handles[ret] ?
26452680
if (ret < count) {
26462681
list_for_each(el, &ts->os_rw_handlers) {
26472682
rh = list_entry(el, JSOSRWHandler, link);
2648-
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
2649-
call_handler(ctx, rh->rw_func[0]);
2683+
if (rh->fd == 0 && !JS_IsNull(rh->r_func)) {
2684+
call_handler(ctx, rh->r_func);
26502685
/* must stop because the list may have been modified */
26512686
goto done;
26522687
}
26532688
}
26542689

2690+
list_for_each(el, &ts->os_sock_handlers) {
2691+
JSOSSockHandler *sh = list_entry(el, JSOSSockHandler, link);
2692+
if (sh->event == handles[ret]) {
2693+
handle_socket_message(ctx, sh);
2694+
WSAResetEvent(sh->event); // WSACloseEvent(sh->event);
2695+
goto done;
2696+
}
2697+
}
2698+
26552699
list_for_each(el, &ts->port_list) {
26562700
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
26572701
if (!JS_IsNull(port->on_message_func)) {
@@ -3613,7 +3657,7 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
36133657
static JSValue js_os_socket(JSContext *ctx, JSValueConst this_val,
36143658
int argc, JSValueConst *argv)
36153659
{
3616-
int domain, type, protocol = 0, ret;
3660+
int domain, type, protocol = 0;
36173661

36183662
if (JS_ToInt32(ctx, &domain, argv[0]))
36193663
return JS_EXCEPTION;
@@ -3622,11 +3666,19 @@ static JSValue js_os_socket(JSContext *ctx, JSValueConst this_val,
36223666
if (argc >= 3 && JS_ToInt32(ctx, &protocol, argv[2]))
36233667
return JS_EXCEPTION;
36243668

3625-
ret = js_get_errno(socket(domain, type, protocol));
3626-
3627-
if (ret >= 0 && !(type & SOCK_NONBLOCK)) // JS flag `os.SOCK_BLOCKING`
3628-
fcntl(ret, F_SETFL, fcntl(ret, F_GETFL, 0) | O_NONBLOCK);
3629-
return JS_NewInt32(ctx, ret);
3669+
int socketfd = socket(domain, type, protocol);
3670+
int ret = js_get_sockerrno(socketfd);
3671+
if (ret < 0)
3672+
return JS_NewInt32(ctx, ret);
3673+
#if defined(_WIN32)
3674+
u_long mode = 1;
3675+
ret = ioctlsocket(ret, FIONBIO, &mode);
3676+
#else
3677+
ret = fcntl(ret, F_SETFL, fcntl(ret, F_GETFL, 0) | O_NONBLOCK);
3678+
#endif
3679+
if (ret < 0)
3680+
return JS_NewInt32(ctx, ret);
3681+
return JS_NewInt32(ctx, socketfd);
36303682
}
36313683

36323684
static JSValue js_os_get_setsockopt(JSContext *ctx, JSValueConst this_val,
@@ -3647,9 +3699,9 @@ static JSValue js_os_get_setsockopt(JSContext *ctx, JSValueConst this_val,
36473699
optlen = buflen;
36483700

36493701
if (magic == 0)
3650-
ret = js_get_errno(getsockopt(sock, SOL_SOCKET, optname, optval, &optlen));
3702+
ret = js_get_sockerrno(getsockopt(sock, SOL_SOCKET, optname, (char*)optval, &optlen));
36513703
else
3652-
ret = js_get_errno(setsockopt(sock, SOL_SOCKET, optname, &optval, optlen));
3704+
ret = js_get_sockerrno(setsockopt(sock, SOL_SOCKET, optname, (char*)optval, optlen));
36533705
return JS_NewInt32(ctx, ret);
36543706
}
36553707

@@ -3670,7 +3722,7 @@ static JSValue js_os_getaddrinfo(JSContext *ctx, JSValueConst this_val,
36703722
if (!service)
36713723
goto fail;
36723724

3673-
ret = js_get_errno(getaddrinfo(node, service, NULL, &ai));
3725+
ret = js_get_sockerrno(getaddrinfo(node, service, NULL, &ai));
36743726
if (ret)
36753727
goto fail;
36763728

@@ -3703,7 +3755,7 @@ static JSValue js_os_bind(JSContext *ctx, JSValueConst this_val,
37033755
return JS_EXCEPTION;
37043756
socklen_t addr_len = sockaddr.ss_family == AF_INET ? sizeof(struct sockaddr_in) :
37053757
sockaddr.ss_family == AF_INET6 ? sizeof(struct sockaddr_in6) : 0;
3706-
ret = js_get_errno(bind(sockfd, (struct sockaddr *)&sockaddr, addr_len));
3758+
ret = js_get_sockerrno(bind(sockfd, (struct sockaddr *)&sockaddr, addr_len));
37073759
return JS_NewInt32(ctx, ret);
37083760
}
37093761

@@ -3717,7 +3769,7 @@ static JSValue js_os_listen(JSContext *ctx, JSValueConst this_val,
37173769
if (argc >= 2 && JS_ToInt32(ctx, &backlog, argv[1]))
37183770
return JS_EXCEPTION;
37193771

3720-
ret = js_get_errno(listen(sockfd, backlog));
3772+
ret = js_get_sockerrno(listen(sockfd, backlog));
37213773
return JS_NewInt32(ctx, ret);
37223774
}
37233775

@@ -3737,10 +3789,14 @@ static JSValue js_os_connect_accept(JSContext *ctx, JSValueConst this_val,
37373789
}
37383790
socklen_t addr_len = sockaddr.ss_family == AF_INET ? sizeof(struct sockaddr_in) :
37393791
sockaddr.ss_family == AF_INET6 ? sizeof(struct sockaddr_in6) : 0;
3740-
3741-
sockret = js_get_errno(connect(sockfd, (struct sockaddr *)&sockaddr, addr_len));
3742-
if (sockret != 0 && sockret != -EINPROGRESS) {
3743-
JS_ThrowTypeError(ctx, "connect failed");
3792+
sockret = js_get_sockerrno(connect(sockfd, (struct sockaddr *)&sockaddr, addr_len));
3793+
#if defined(_WIN32)
3794+
if (sockret != -WSAEWOULDBLOCK)
3795+
#else
3796+
if (sockret != -EINPROGRESS)
3797+
#endif
3798+
{
3799+
JS_ThrowTypeError(ctx, "connect failed (%i)", sockret);
37443800
return JS_EXCEPTION;
37453801
}
37463802
}
@@ -3757,10 +3813,13 @@ static JSValue js_os_connect_accept(JSContext *ctx, JSValueConst this_val,
37573813
sh->magic = magic;
37583814
sh->resolve = JS_DupValue(ctx, resolving_funcs[0]);
37593815
sh->reject = JS_DupValue(ctx, resolving_funcs[1]);
3816+
#if defined(_WIN32)
3817+
sh->event = WSACreateEvent();
3818+
WSAEventSelect(sh->sockfd, sh->event, magic == MAGIC_SOCKET_CONNECT ? FD_CONNECT : FD_ACCEPT);
3819+
#endif
37603820
list_add_tail(&sh->link, &ts->os_sock_handlers);
37613821
JS_FreeValue(ctx, resolving_funcs[0]);
37623822
JS_FreeValue(ctx, resolving_funcs[1]);
3763-
37643823
return promise;
37653824
}
37663825

@@ -3804,7 +3863,11 @@ static JSValue js_os_recv_send(JSContext *ctx, JSValueConst this_val,
38043863
}
38053864
sh->length = length;
38063865
}
3807-
3866+
#if defined(_WIN32)
3867+
sh->event = WSACreateEvent();
3868+
int flags = (magic == MAGIC_SOCKET_SENDTO || magic == MAGIC_SOCKET_SEND) ? FD_WRITE : FD_READ;
3869+
WSAEventSelect(sh->sockfd, sh->event, flags);
3870+
#endif
38083871
sh->bufval = JS_DupValue(ctx, argv[bufArgvIdx]);
38093872
sh->resolve = JS_DupValue(ctx, resolving_funcs[0]);
38103873
sh->reject = JS_DupValue(ctx, resolving_funcs[1]);
@@ -3831,7 +3894,7 @@ static JSValue js_os_shutdown(JSContext *ctx, JSValueConst this_val,
38313894
if (JS_ToInt32(ctx, &how, argv[1]))
38323895
return JS_EXCEPTION;
38333896

3834-
ret = js_get_errno(shutdown(sockfd, how));
3897+
ret = js_get_sockerrno(shutdown(sockfd, how));
38353898
return JS_NewInt32(ctx, ret);
38363899
}
38373900

@@ -4389,14 +4452,18 @@ static const JSCFunctionListEntry js_os_funcs[] = {
43894452
OS_FLAG(SOCK_STREAM),
43904453
OS_FLAG(SOCK_DGRAM),
43914454
OS_FLAG(SOCK_RAW),
4392-
// SOCK_NONBLOCK is set by default so reuse it value for our imaginary nemsis
4393-
JS_PROP_INT32_DEF("SOCK_BLOCK", SOCK_NONBLOCK, JS_PROP_CONFIGURABLE ),
43944455
OS_FLAG(SO_REUSEADDR),
43954456
OS_FLAG(SO_RCVBUF),
43964457
OS_FLAG(SO_ERROR),
4458+
#if defined(_WIN32)
4459+
JS_PROP_INT32_DEF("SHUT_RD", SD_RECEIVE, JS_PROP_CONFIGURABLE),
4460+
JS_PROP_INT32_DEF("SHUT_WR", SD_SEND, JS_PROP_CONFIGURABLE),
4461+
JS_PROP_INT32_DEF("SHUT_RDWR", SD_BOTH, JS_PROP_CONFIGURABLE),
4462+
#else
43974463
OS_FLAG(SHUT_RD),
43984464
OS_FLAG(SHUT_WR),
43994465
OS_FLAG(SHUT_RDWR),
4466+
#endif
44004467
};
44014468

44024469
static int js_os_init(JSContext *ctx, JSModuleDef *m)

0 commit comments

Comments
 (0)