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 {
@@ -249,7 +253,7 @@ static int JS_ToSockaddrStruct(JSContext *ctx, JSValue addr,
249253static JSValue JS_ToSockaddrObj (JSContext * ctx , struct sockaddr_storage * sockaddr )
250254{
251255 JSValue obj , prop ;
252- char ip_str [INET_ADDRSTRLEN ];
256+ char ip_str [INET6_ADDRSTRLEN ]; // max(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)
253257 const char * ip_ptr ;
254258 struct sockaddr_in * sockaddr4 = (struct sockaddr_in * )sockaddr ;
255259 struct sockaddr_in6 * sockaddr6 = (struct sockaddr_in6 * )sockaddr ;
@@ -268,7 +272,9 @@ static JSValue JS_ToSockaddrObj(JSContext *ctx, struct sockaddr_storage *sockadd
268272
269273 void * sin_addr = sockaddr -> ss_family == AF_INET ? (void * )& sockaddr4 -> sin_addr :
270274 sockaddr -> ss_family == AF_INET6 ? (void * )& sockaddr6 -> sin6_addr : NULL ;
271- ip_ptr = inet_ntop (AF_INET , sin_addr , ip_str , sizeof (ip_str ));
275+ size_t sin_len = sockaddr -> ss_family == AF_INET ? INET_ADDRSTRLEN :
276+ sockaddr -> ss_family == AF_INET6 ? INET6_ADDRSTRLEN : 0 ;
277+ ip_ptr = inet_ntop (sockaddr -> ss_family , sin_addr , ip_str , sin_len );
272278 prop = ip_ptr ? JS_NewString (ctx , ip_ptr ) : JS_NULL ;
273279 JS_DefinePropertyValueStr (ctx , obj , "addr" , prop , JS_PROP_C_W_E );
274280 return obj ;
@@ -1039,6 +1045,18 @@ static ssize_t js_get_errno(ssize_t ret)
10391045 return ret ;
10401046}
10411047
1048+ static ssize_t js_get_sockerrno (ssize_t ret )
1049+ {
1050+ #if defined(_WIN32 )
1051+ if (ret == -1 || ret == INVALID_SOCKET )
1052+ ret = - WSAGetLastError ();
1053+ #else
1054+ if (ret == -1 )
1055+ ret = - errno ;
1056+ #endif
1057+ return ret ;
1058+ }
1059+
10421060static JSValue js_std_strerror (JSContext * ctx , JSValueConst this_val ,
10431061 int argc , JSValueConst * argv )
10441062{
@@ -1785,11 +1803,6 @@ static int js_std_init(JSContext *ctx, JSModuleDef *m)
17851803{
17861804 JSValue proto ;
17871805
1788- #if defined(_WIN32 )
1789- WSADATA wsa_data ;
1790- WSAStartup (0x0202 , & wsa_data );
1791- #endif
1792-
17931806 /* FILE class */
17941807 /* the class ID is created once */
17951808 JS_NewClassID (& js_std_file_class_id );
@@ -2517,28 +2530,41 @@ static int handle_posted_message(JSContext *ctx, JSWorkerMessageHandler *port)
25172530
25182531static void handle_socket_message (JSContext * ctx , JSOSSockHandler * sh )
25192532{
2533+ #ifdef _WIN32
2534+ WSANETWORKEVENTS netEvents ;
2535+ WSAEnumNetworkEvents (sh -> sockfd , sh -> event , & netEvents );
2536+ #endif
2537+
25202538 int err = 0 ;
25212539 struct sockaddr_storage sockaddr ;
25222540 socklen_t addr_len = sizeof (sockaddr );
2523- socklen_t len = sizeof ( err );
2541+
25242542 if (sh -> magic == MAGIC_SOCKET_RECV ) {
2525- err = js_get_errno (recv (sh -> sockfd , sh -> buffer , sh -> length , 0 ));
2543+ err = js_get_sockerrno (recv (sh -> sockfd , ( char * ) sh -> buffer , sh -> length , 0 ));
25262544 } else if (sh -> magic == MAGIC_SOCKET_SEND ) {
2527- err = js_get_errno (send (sh -> sockfd , sh -> buffer , sh -> length , 0 ));
2545+ err = js_get_sockerrno (send (sh -> sockfd , ( char * ) sh -> buffer , sh -> length , 0 ));
25282546 } 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 ));
2547+ err = js_get_sockerrno (recvfrom (sh -> sockfd , ( char * ) sh -> buffer , sh -> length , 0 , (struct sockaddr * )& sockaddr , & addr_len ));
25302548 } 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 ));
2549+ err = js_get_sockerrno (sendto (sh -> sockfd , ( char * ) sh -> buffer , sh -> length , 0 , (const struct sockaddr * )& sh -> sockaddr , addr_len ));
25322550 } else if (sh -> magic == MAGIC_SOCKET_CONNECT ) {
2533- err = getsockopt (sh -> sockfd , SOL_SOCKET , SO_ERROR , & err , & len ) ? - errno : - err ;
2551+ #ifdef _WIN32
2552+ err = 0 ;
2553+ #else
2554+ socklen_t len = sizeof (err );
2555+ err = getsockopt (sh -> sockfd , SOL_SOCKET , SO_ERROR , (char * ) & err , & len ) ? - errno : - err ;
2556+ #endif
25342557 } else if (sh -> magic == MAGIC_SOCKET_ACCEPT ) {
2535- err = js_get_errno (accept (sh -> sockfd , (struct sockaddr * )& sockaddr , & addr_len ));
2558+ err = js_get_sockerrno (accept (sh -> sockfd , (struct sockaddr * )& sockaddr , & addr_len ));
25362559 }
25372560
2538-
2561+ #ifdef _WIN32
2562+ if (err == - WSAEWOULDBLOCK )
2563+ return ;
2564+ #else
25392565 if (err == - EAGAIN || err == - EWOULDBLOCK )
25402566 return ;
2541-
2567+ #endif
25422568 JSValue promiseval = JS_UNDEFINED ;
25432569 if (sh -> magic == MAGIC_SOCKET_ACCEPT ) {
25442570 promiseval = JS_NewArray (ctx );
@@ -2589,8 +2615,10 @@ static int js_os_poll(JSContext *ctx)
25892615
25902616 /* XXX: handle signals if useful */
25912617
2592- if (list_empty (& ts -> os_rw_handlers ) && list_empty (& ts -> os_timers ) &&
2593- list_empty (& ts -> port_list )) {
2618+ if (list_empty (& ts -> os_rw_handlers ) &&
2619+ list_empty (& ts -> os_timers ) &&
2620+ list_empty (& ts -> port_list ) &&
2621+ list_empty (& ts -> os_sock_handlers )) {
25942622 return -1 ; /* no more events */
25952623 }
25962624
@@ -2620,13 +2648,21 @@ static int js_os_poll(JSContext *ctx)
26202648 count = 0 ;
26212649 list_for_each (el , & ts -> os_rw_handlers ) {
26222650 rh = list_entry (el , JSOSRWHandler , link );
2623- if (rh -> fd == 0 && !JS_IsNull (rh -> rw_func [ 0 ] )) {
2651+ if (rh -> fd == 0 && !JS_IsNull (rh -> r_func )) {
26242652 handles [count ++ ] = (HANDLE )_get_osfhandle (rh -> fd ); // stdin
26252653 if (count == (int )countof (handles ))
26262654 break ;
26272655 }
26282656 }
26292657
2658+ list_for_each (el , & ts -> os_sock_handlers ) {
2659+ JSOSSockHandler * sh = list_entry (el , JSOSSockHandler , link );
2660+ //TODO: socket readability don't seems to be a winsock event => trigger manually
2661+ handles [count ++ ] = sh -> event ;
2662+ if (count == (int )countof (handles ))
2663+ break ;
2664+ }
2665+
26302666 list_for_each (el , & ts -> port_list ) {
26312667 JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
26322668 if (JS_IsNull (port -> on_message_func ))
@@ -2642,16 +2678,26 @@ static int js_os_poll(JSContext *ctx)
26422678 timeout = min_delay ;
26432679 ret = WaitForMultipleObjects (count , handles , FALSE, timeout );
26442680
2681+ // why iterate on every list instead of just handles[ret] ?
26452682 if (ret < count ) {
26462683 list_for_each (el , & ts -> os_rw_handlers ) {
26472684 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 ] );
2685+ if (rh -> fd == 0 && !JS_IsNull (rh -> r_func )) {
2686+ call_handler (ctx , rh -> r_func );
26502687 /* must stop because the list may have been modified */
26512688 goto done ;
26522689 }
26532690 }
26542691
2692+ list_for_each (el , & ts -> os_sock_handlers ) {
2693+ JSOSSockHandler * sh = list_entry (el , JSOSSockHandler , link );
2694+ if (sh -> event == handles [ret ]) {
2695+ handle_socket_message (ctx , sh );
2696+ WSAResetEvent (sh -> event ); // WSACloseEvent(sh->event);
2697+ goto done ;
2698+ }
2699+ }
2700+
26552701 list_for_each (el , & ts -> port_list ) {
26562702 JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
26572703 if (!JS_IsNull (port -> on_message_func )) {
@@ -3613,7 +3659,7 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
36133659static JSValue js_os_socket (JSContext * ctx , JSValueConst this_val ,
36143660 int argc , JSValueConst * argv )
36153661{
3616- int domain , type , protocol = 0 , ret ;
3662+ int domain , type , protocol = 0 ;
36173663
36183664 if (JS_ToInt32 (ctx , & domain , argv [0 ]))
36193665 return JS_EXCEPTION ;
@@ -3622,11 +3668,19 @@ static JSValue js_os_socket(JSContext *ctx, JSValueConst this_val,
36223668 if (argc >= 3 && JS_ToInt32 (ctx , & protocol , argv [2 ]))
36233669 return JS_EXCEPTION ;
36243670
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 );
3671+ int socketfd = socket (domain , type , protocol );
3672+ int ret = js_get_sockerrno (socketfd );
3673+ if (ret < 0 )
3674+ return JS_NewInt32 (ctx , ret );
3675+ #if defined(_WIN32 )
3676+ u_long mode = 1 ;
3677+ ret = ioctlsocket (ret , FIONBIO , & mode );
3678+ #else
3679+ ret = fcntl (ret , F_SETFL , fcntl (ret , F_GETFL , 0 ) | O_NONBLOCK );
3680+ #endif
3681+ if (ret < 0 )
3682+ return JS_NewInt32 (ctx , ret );
3683+ return JS_NewInt32 (ctx , socketfd );
36303684}
36313685
36323686static JSValue js_os_get_setsockopt (JSContext * ctx , JSValueConst this_val ,
@@ -3647,9 +3701,9 @@ static JSValue js_os_get_setsockopt(JSContext *ctx, JSValueConst this_val,
36473701 optlen = buflen ;
36483702
36493703 if (magic == 0 )
3650- ret = js_get_errno (getsockopt (sock , SOL_SOCKET , optname , optval , & optlen ));
3704+ ret = js_get_sockerrno (getsockopt (sock , SOL_SOCKET , optname , ( char * ) optval , & optlen ));
36513705 else
3652- ret = js_get_errno (setsockopt (sock , SOL_SOCKET , optname , & optval , optlen ));
3706+ ret = js_get_sockerrno (setsockopt (sock , SOL_SOCKET , optname , ( char * ) optval , optlen ));
36533707 return JS_NewInt32 (ctx , ret );
36543708}
36553709
@@ -3670,7 +3724,7 @@ static JSValue js_os_getaddrinfo(JSContext *ctx, JSValueConst this_val,
36703724 if (!service )
36713725 goto fail ;
36723726
3673- ret = js_get_errno (getaddrinfo (node , service , NULL , & ai ));
3727+ ret = js_get_sockerrno (getaddrinfo (node , service , NULL , & ai ));
36743728 if (ret )
36753729 goto fail ;
36763730
@@ -3703,7 +3757,7 @@ static JSValue js_os_bind(JSContext *ctx, JSValueConst this_val,
37033757 return JS_EXCEPTION ;
37043758 socklen_t addr_len = sockaddr .ss_family == AF_INET ? sizeof (struct sockaddr_in ) :
37053759 sockaddr .ss_family == AF_INET6 ? sizeof (struct sockaddr_in6 ) : 0 ;
3706- ret = js_get_errno (bind (sockfd , (struct sockaddr * )& sockaddr , addr_len ));
3760+ ret = js_get_sockerrno (bind (sockfd , (struct sockaddr * )& sockaddr , addr_len ));
37073761 return JS_NewInt32 (ctx , ret );
37083762}
37093763
@@ -3717,7 +3771,7 @@ static JSValue js_os_listen(JSContext *ctx, JSValueConst this_val,
37173771 if (argc >= 2 && JS_ToInt32 (ctx , & backlog , argv [1 ]))
37183772 return JS_EXCEPTION ;
37193773
3720- ret = js_get_errno (listen (sockfd , backlog ));
3774+ ret = js_get_sockerrno (listen (sockfd , backlog ));
37213775 return JS_NewInt32 (ctx , ret );
37223776}
37233777
@@ -3737,10 +3791,14 @@ static JSValue js_os_connect_accept(JSContext *ctx, JSValueConst this_val,
37373791 }
37383792 socklen_t addr_len = sockaddr .ss_family == AF_INET ? sizeof (struct sockaddr_in ) :
37393793 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" );
3794+ sockret = js_get_sockerrno (connect (sockfd , (struct sockaddr * )& sockaddr , addr_len ));
3795+ #if defined(_WIN32 )
3796+ if (sockret != - WSAEWOULDBLOCK )
3797+ #else
3798+ if (sockret != - EINPROGRESS )
3799+ #endif
3800+ {
3801+ JS_ThrowTypeError (ctx , "connect failed (%i)" , sockret );
37443802 return JS_EXCEPTION ;
37453803 }
37463804 }
@@ -3757,10 +3815,13 @@ static JSValue js_os_connect_accept(JSContext *ctx, JSValueConst this_val,
37573815 sh -> magic = magic ;
37583816 sh -> resolve = JS_DupValue (ctx , resolving_funcs [0 ]);
37593817 sh -> reject = JS_DupValue (ctx , resolving_funcs [1 ]);
3818+ #if defined(_WIN32 )
3819+ sh -> event = WSACreateEvent ();
3820+ WSAEventSelect (sh -> sockfd , sh -> event , magic == MAGIC_SOCKET_CONNECT ? FD_CONNECT : FD_ACCEPT );
3821+ #endif
37603822 list_add_tail (& sh -> link , & ts -> os_sock_handlers );
37613823 JS_FreeValue (ctx , resolving_funcs [0 ]);
37623824 JS_FreeValue (ctx , resolving_funcs [1 ]);
3763-
37643825 return promise ;
37653826}
37663827
@@ -3804,7 +3865,11 @@ static JSValue js_os_recv_send(JSContext *ctx, JSValueConst this_val,
38043865 }
38053866 sh -> length = length ;
38063867 }
3807-
3868+ #if defined(_WIN32 )
3869+ sh -> event = WSACreateEvent ();
3870+ int flags = (magic == MAGIC_SOCKET_SENDTO || magic == MAGIC_SOCKET_SEND ) ? FD_WRITE : FD_READ ;
3871+ WSAEventSelect (sh -> sockfd , sh -> event , flags );
3872+ #endif
38083873 sh -> bufval = JS_DupValue (ctx , argv [bufArgvIdx ]);
38093874 sh -> resolve = JS_DupValue (ctx , resolving_funcs [0 ]);
38103875 sh -> reject = JS_DupValue (ctx , resolving_funcs [1 ]);
@@ -3831,7 +3896,7 @@ static JSValue js_os_shutdown(JSContext *ctx, JSValueConst this_val,
38313896 if (JS_ToInt32 (ctx , & how , argv [1 ]))
38323897 return JS_EXCEPTION ;
38333898
3834- ret = js_get_errno (shutdown (sockfd , how ));
3899+ ret = js_get_sockerrno (shutdown (sockfd , how ));
38353900 return JS_NewInt32 (ctx , ret );
38363901}
38373902
@@ -4389,14 +4454,18 @@ static const JSCFunctionListEntry js_os_funcs[] = {
43894454 OS_FLAG (SOCK_STREAM ),
43904455 OS_FLAG (SOCK_DGRAM ),
43914456 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 ),
43944457 OS_FLAG (SO_REUSEADDR ),
43954458 OS_FLAG (SO_RCVBUF ),
43964459 OS_FLAG (SO_ERROR ),
4460+ #if defined(_WIN32 )
4461+ JS_PROP_INT32_DEF ("SHUT_RD" , SD_RECEIVE , JS_PROP_CONFIGURABLE ),
4462+ JS_PROP_INT32_DEF ("SHUT_WR" , SD_SEND , JS_PROP_CONFIGURABLE ),
4463+ JS_PROP_INT32_DEF ("SHUT_RDWR" , SD_BOTH , JS_PROP_CONFIGURABLE ),
4464+ #else
43974465 OS_FLAG (SHUT_RD ),
43984466 OS_FLAG (SHUT_WR ),
43994467 OS_FLAG (SHUT_RDWR ),
4468+ #endif
44004469};
44014470
44024471static int js_os_init (JSContext * ctx , JSModuleDef * m )
0 commit comments