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
118122typedef 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+
10421058static 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
25182529static 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,
36133657static 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
36323684static 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
44024469static int js_os_init (JSContext * ctx , JSModuleDef * m )
0 commit comments