38
38
#include <sys/stat.h>
39
39
#include <dirent.h>
40
40
#if defined(_WIN32 )
41
+ #include <winsock2.h>
42
+ #include <ws2tcpip.h>
41
43
#include <windows.h>
42
44
#include <conio.h>
43
45
#include <utime.h>
44
- #include <winsock2.h>
45
46
#else
46
47
#include <dlfcn.h>
47
48
#include <termios.h>
@@ -113,6 +114,9 @@ typedef struct {
113
114
struct sockaddr_storage sockaddr ; // for sendto()
114
115
JSValue resolve ;
115
116
JSValue reject ;
117
+ #ifdef _WIN32
118
+ WSAEVENT event ; // so os_pool can wait on it
119
+ #endif
116
120
} JSOSSockHandler ;
117
121
118
122
typedef struct {
@@ -1039,6 +1043,18 @@ static ssize_t js_get_errno(ssize_t ret)
1039
1043
return ret ;
1040
1044
}
1041
1045
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
+
1042
1058
static JSValue js_std_strerror (JSContext * ctx , JSValueConst this_val ,
1043
1059
int argc , JSValueConst * argv )
1044
1060
{
@@ -1785,11 +1801,6 @@ static int js_std_init(JSContext *ctx, JSModuleDef *m)
1785
1801
{
1786
1802
JSValue proto ;
1787
1803
1788
- #if defined(_WIN32 )
1789
- WSADATA wsa_data ;
1790
- WSAStartup (0x0202 , & wsa_data );
1791
- #endif
1792
-
1793
1804
/* FILE class */
1794
1805
/* the class ID is created once */
1795
1806
JS_NewClassID (& js_std_file_class_id );
@@ -2517,28 +2528,41 @@ static int handle_posted_message(JSContext *ctx, JSWorkerMessageHandler *port)
2517
2528
2518
2529
static void handle_socket_message (JSContext * ctx , JSOSSockHandler * sh )
2519
2530
{
2531
+ #ifdef _WIN32
2532
+ WSANETWORKEVENTS netEvents ;
2533
+ WSAEnumNetworkEvents (sh -> sockfd , sh -> event , & netEvents );
2534
+ #endif
2535
+
2520
2536
int err = 0 ;
2521
2537
struct sockaddr_storage sockaddr ;
2522
2538
socklen_t addr_len = sizeof (sockaddr );
2523
- socklen_t len = sizeof ( err );
2539
+
2524
2540
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 ));
2526
2542
} 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 ));
2528
2544
} 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 ));
2530
2546
} 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 ));
2532
2548
} 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
2534
2555
} 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 ));
2536
2557
}
2537
2558
2538
-
2559
+ #ifdef _WIN32
2560
+ if (err == - WSAEWOULDBLOCK )
2561
+ return ;
2562
+ #else
2539
2563
if (err == - EAGAIN || err == - EWOULDBLOCK )
2540
2564
return ;
2541
-
2565
+ #endif
2542
2566
JSValue promiseval = JS_UNDEFINED ;
2543
2567
if (sh -> magic == MAGIC_SOCKET_ACCEPT ) {
2544
2568
promiseval = JS_NewArray (ctx );
@@ -2589,8 +2613,10 @@ static int js_os_poll(JSContext *ctx)
2589
2613
2590
2614
/* XXX: handle signals if useful */
2591
2615
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 )) {
2594
2620
return -1 ; /* no more events */
2595
2621
}
2596
2622
@@ -2620,13 +2646,21 @@ static int js_os_poll(JSContext *ctx)
2620
2646
count = 0 ;
2621
2647
list_for_each (el , & ts -> os_rw_handlers ) {
2622
2648
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 )) {
2624
2650
handles [count ++ ] = (HANDLE )_get_osfhandle (rh -> fd ); // stdin
2625
2651
if (count == (int )countof (handles ))
2626
2652
break ;
2627
2653
}
2628
2654
}
2629
2655
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
+
2630
2664
list_for_each (el , & ts -> port_list ) {
2631
2665
JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
2632
2666
if (JS_IsNull (port -> on_message_func ))
@@ -2642,16 +2676,26 @@ static int js_os_poll(JSContext *ctx)
2642
2676
timeout = min_delay ;
2643
2677
ret = WaitForMultipleObjects (count , handles , FALSE, timeout );
2644
2678
2679
+ // why iterate on every list instead of just handles[ret] ?
2645
2680
if (ret < count ) {
2646
2681
list_for_each (el , & ts -> os_rw_handlers ) {
2647
2682
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 );
2650
2685
/* must stop because the list may have been modified */
2651
2686
goto done ;
2652
2687
}
2653
2688
}
2654
2689
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
+
2655
2699
list_for_each (el , & ts -> port_list ) {
2656
2700
JSWorkerMessageHandler * port = list_entry (el , JSWorkerMessageHandler , link );
2657
2701
if (!JS_IsNull (port -> on_message_func )) {
@@ -3613,7 +3657,7 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
3613
3657
static JSValue js_os_socket (JSContext * ctx , JSValueConst this_val ,
3614
3658
int argc , JSValueConst * argv )
3615
3659
{
3616
- int domain , type , protocol = 0 , ret ;
3660
+ int domain , type , protocol = 0 ;
3617
3661
3618
3662
if (JS_ToInt32 (ctx , & domain , argv [0 ]))
3619
3663
return JS_EXCEPTION ;
@@ -3622,11 +3666,19 @@ static JSValue js_os_socket(JSContext *ctx, JSValueConst this_val,
3622
3666
if (argc >= 3 && JS_ToInt32 (ctx , & protocol , argv [2 ]))
3623
3667
return JS_EXCEPTION ;
3624
3668
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 );
3630
3682
}
3631
3683
3632
3684
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,
3647
3699
optlen = buflen ;
3648
3700
3649
3701
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 ));
3651
3703
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 ));
3653
3705
return JS_NewInt32 (ctx , ret );
3654
3706
}
3655
3707
@@ -3670,7 +3722,7 @@ static JSValue js_os_getaddrinfo(JSContext *ctx, JSValueConst this_val,
3670
3722
if (!service )
3671
3723
goto fail ;
3672
3724
3673
- ret = js_get_errno (getaddrinfo (node , service , NULL , & ai ));
3725
+ ret = js_get_sockerrno (getaddrinfo (node , service , NULL , & ai ));
3674
3726
if (ret )
3675
3727
goto fail ;
3676
3728
@@ -3703,7 +3755,7 @@ static JSValue js_os_bind(JSContext *ctx, JSValueConst this_val,
3703
3755
return JS_EXCEPTION ;
3704
3756
socklen_t addr_len = sockaddr .ss_family == AF_INET ? sizeof (struct sockaddr_in ) :
3705
3757
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 ));
3707
3759
return JS_NewInt32 (ctx , ret );
3708
3760
}
3709
3761
@@ -3717,7 +3769,7 @@ static JSValue js_os_listen(JSContext *ctx, JSValueConst this_val,
3717
3769
if (argc >= 2 && JS_ToInt32 (ctx , & backlog , argv [1 ]))
3718
3770
return JS_EXCEPTION ;
3719
3771
3720
- ret = js_get_errno (listen (sockfd , backlog ));
3772
+ ret = js_get_sockerrno (listen (sockfd , backlog ));
3721
3773
return JS_NewInt32 (ctx , ret );
3722
3774
}
3723
3775
@@ -3737,10 +3789,14 @@ static JSValue js_os_connect_accept(JSContext *ctx, JSValueConst this_val,
3737
3789
}
3738
3790
socklen_t addr_len = sockaddr .ss_family == AF_INET ? sizeof (struct sockaddr_in ) :
3739
3791
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 );
3744
3800
return JS_EXCEPTION ;
3745
3801
}
3746
3802
}
@@ -3757,10 +3813,13 @@ static JSValue js_os_connect_accept(JSContext *ctx, JSValueConst this_val,
3757
3813
sh -> magic = magic ;
3758
3814
sh -> resolve = JS_DupValue (ctx , resolving_funcs [0 ]);
3759
3815
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
3760
3820
list_add_tail (& sh -> link , & ts -> os_sock_handlers );
3761
3821
JS_FreeValue (ctx , resolving_funcs [0 ]);
3762
3822
JS_FreeValue (ctx , resolving_funcs [1 ]);
3763
-
3764
3823
return promise ;
3765
3824
}
3766
3825
@@ -3804,7 +3863,11 @@ static JSValue js_os_recv_send(JSContext *ctx, JSValueConst this_val,
3804
3863
}
3805
3864
sh -> length = length ;
3806
3865
}
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
3808
3871
sh -> bufval = JS_DupValue (ctx , argv [bufArgvIdx ]);
3809
3872
sh -> resolve = JS_DupValue (ctx , resolving_funcs [0 ]);
3810
3873
sh -> reject = JS_DupValue (ctx , resolving_funcs [1 ]);
@@ -3831,7 +3894,7 @@ static JSValue js_os_shutdown(JSContext *ctx, JSValueConst this_val,
3831
3894
if (JS_ToInt32 (ctx , & how , argv [1 ]))
3832
3895
return JS_EXCEPTION ;
3833
3896
3834
- ret = js_get_errno (shutdown (sockfd , how ));
3897
+ ret = js_get_sockerrno (shutdown (sockfd , how ));
3835
3898
return JS_NewInt32 (ctx , ret );
3836
3899
}
3837
3900
@@ -4389,14 +4452,18 @@ static const JSCFunctionListEntry js_os_funcs[] = {
4389
4452
OS_FLAG (SOCK_STREAM ),
4390
4453
OS_FLAG (SOCK_DGRAM ),
4391
4454
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 ),
4394
4455
OS_FLAG (SO_REUSEADDR ),
4395
4456
OS_FLAG (SO_RCVBUF ),
4396
4457
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
4397
4463
OS_FLAG (SHUT_RD ),
4398
4464
OS_FLAG (SHUT_WR ),
4399
4465
OS_FLAG (SHUT_RDWR ),
4466
+ #endif
4400
4467
};
4401
4468
4402
4469
static int js_os_init (JSContext * ctx , JSModuleDef * m )
0 commit comments