5252#include <netinet/in.h>
5353#include <netinet/ip.h>
5454#include <arpa/inet.h>
55+ #include <poll.h>
5556#define __USE_XOPEN2K // for addrinfo
5657#include <netdb.h>
5758
@@ -1618,6 +1619,9 @@ static const JSCFunctionListEntry js_std_error_props[] = {
16181619 DEF (EPERM ),
16191620 DEF (EPIPE ),
16201621 DEF (EBADF ),
1622+ DEF (EAGAIN ),
1623+ DEF (EINPROGRESS ),
1624+ DEF (EWOULDBLOCK ),
16211625#undef DEF
16221626};
16231627
@@ -2401,7 +2405,7 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
24012405
24022406#if defined(_WIN32 )
24032407
2404- static int js_os_poll (JSContext * ctx )
2408+ static int js_os_event_poll (JSContext * ctx )
24052409{
24062410 JSRuntime * rt = JS_GetRuntime (ctx );
24072411 JSThreadState * ts = JS_GetRuntimeOpaque (rt );
@@ -2496,7 +2500,7 @@ static int js_os_poll(JSContext *ctx)
24962500
24972501#else
24982502
2499- static int js_os_poll (JSContext * ctx )
2503+ static int js_os_event_poll (JSContext * ctx )
25002504{
25012505 JSRuntime * rt = JS_GetRuntime (ctx );
25022506 JSThreadState * ts = JS_GetRuntimeOpaque (rt );
@@ -3410,7 +3414,7 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
34103414
34113415#endif /* !_WIN32 */
34123416
3413- static int JS_toSockaddrStruct (JSContext * ctx , JSValue addr ,
3417+ static int JS_ToSockaddrStruct (JSContext * ctx , JSValue addr ,
34143418 struct sockaddr_in * sockaddr )
34153419{
34163420 JSValue val ;
@@ -3438,13 +3442,13 @@ static int JS_toSockaddrStruct(JSContext *ctx, JSValue addr,
34383442 val = JS_GetPropertyStr (ctx , addr , "port" );
34393443 ret = JS_ToUint32 (ctx , & port , val );
34403444 JS_FreeValue (ctx , val );
3441- if (ret )
3445+ if (ret )
34423446 return -1 ;
34433447 sockaddr -> sin_port = htons (port );
34443448 return 0 ;
34453449}
34463450
3447- static JSValue js_toSockaddrObj (JSContext * ctx , struct sockaddr_in * sockaddr )
3451+ static JSValue JS_ToSockaddrObj (JSContext * ctx , struct sockaddr_in * sockaddr )
34483452{
34493453 JSValue obj , prop ;
34503454 char ip_str [INET_ADDRSTRLEN ];
@@ -3481,7 +3485,10 @@ static JSValue js_os_socket(JSContext *ctx, JSValueConst this_val,
34813485 return JS_EXCEPTION ;
34823486 if (argc >= 3 && JS_ToInt32 (ctx , & protocol , argv [2 ]))
34833487 return JS_EXCEPTION ;
3484- ret = js_get_errno (socket (domain , type , protocol ));
3488+ ret = js_get_errno (socket (domain , type & ~SOCK_NONBLOCK , protocol ));
3489+ if (ret >=0 && (type & SOCK_NONBLOCK )) {
3490+ fcntl (ret , F_SETFL , fcntl (ret , F_GETFL , 0 ) | O_NONBLOCK );
3491+ }
34853492 return JS_NewInt32 (ctx , ret );
34863493}
34873494
@@ -3526,13 +3533,13 @@ static JSValue js_os_getaddrinfo(JSContext *ctx, JSValueConst this_val,
35263533 goto fail ;
35273534
35283535 ret = js_get_errno (getaddrinfo (node , service , NULL , & ai ));
3529- if (ret )
3536+ if (ret )
35303537 goto fail ;
35313538
35323539 obj = JS_NewArray (ctx );
35333540 for (objLen = 0 , it = ai ; it ; it = it -> ai_next ) {
35343541 for (len = 0 ; len < it -> ai_addrlen ; len ++ ) {
3535- addrObj = js_toSockaddrObj (ctx ,(struct sockaddr_in * )& it -> ai_addr [len ]);
3542+ addrObj = JS_ToSockaddrObj (ctx ,(struct sockaddr_in * )& it -> ai_addr [len ]);
35363543 JS_SetPropertyUint32 (ctx ,obj ,objLen ++ ,addrObj );
35373544 }
35383545 }
@@ -3554,7 +3561,7 @@ static JSValue js_os_bind(JSContext *ctx, JSValueConst this_val,
35543561
35553562 if (JS_ToInt32 (ctx , & sockfd , argv [0 ]))
35563563 return JS_EXCEPTION ;
3557- if (JS_toSockaddrStruct (ctx , argv [1 ], & saddr ))
3564+ if (JS_ToSockaddrStruct (ctx , argv [1 ], & saddr ))
35583565 return JS_EXCEPTION ;
35593566 ret = js_get_errno (bind (sockfd , (struct sockaddr * )& saddr , sizeof (saddr )));
35603567 return JS_NewInt32 (ctx , ret );
@@ -3586,7 +3593,7 @@ static JSValue js_os_accept(JSContext *ctx, JSValueConst this_val,
35863593 return JS_EXCEPTION ;
35873594 ret = js_get_errno (accept (sockfd , (struct sockaddr * )& client_addr , & addr_len ));
35883595
3589- sockaddr_obj = js_toSockaddrObj (ctx , & client_addr );
3596+ sockaddr_obj = JS_ToSockaddrObj (ctx , & client_addr );
35903597 if (JS_IsException (sockaddr_obj ))
35913598 return sockaddr_obj ; // shall we return ?
35923599
@@ -3598,6 +3605,7 @@ static JSValue js_os_accept(JSContext *ctx, JSValueConst this_val,
35983605 JS_DefinePropertyValueUint32 (ctx , arr , 1 , sockaddr_obj , JS_PROP_C_W_E );
35993606 return arr ;
36003607}
3608+
36013609static JSValue js_os_connect (JSContext * ctx , JSValueConst this_val ,
36023610 int argc , JSValueConst * argv )
36033611{
@@ -3608,14 +3616,80 @@ static JSValue js_os_connect(JSContext *ctx, JSValueConst this_val,
36083616 if (JS_ToInt32 (ctx , & sockfd , argv [0 ]))
36093617 return JS_EXCEPTION ;
36103618
3611- if (JS_toSockaddrStruct (ctx , argv [1 ], & client_addr ) < 0 )
3619+ if (JS_ToSockaddrStruct (ctx , argv [1 ], & client_addr ) < 0 )
36123620 return JS_EXCEPTION ;
36133621
36143622 ret = js_get_errno (connect (sockfd , (struct sockaddr * )& client_addr , client_len ));
36153623
36163624 return JS_NewInt32 (ctx , ret );
36173625}
36183626
3627+
3628+ static JSValue js_os_poll (JSContext * ctx , JSValueConst this_val ,
3629+ int argc , JSValueConst * argv )
3630+ {
3631+ JSValue val , prop ;
3632+ struct pollfd pfds [32 ] = {}; // XXX: use js_mallocz() ?
3633+ uint32_t i , nbfd , events ;
3634+ int ret , timeoutms = -1 ; // infinite timeout by default
3635+
3636+ val = JS_GetPropertyStr (ctx , argv [0 ], "length" );
3637+ if (JS_IsException (val ))
3638+ return JS_EXCEPTION ;
3639+ ret = JS_ToUint32 (ctx , & nbfd , val );
3640+ JS_FreeValue (ctx , val );
3641+ if (ret )
3642+ return JS_EXCEPTION ;
3643+ if (nbfd > sizeof (pfds )/sizeof (* pfds ))
3644+ return JS_EXCEPTION ;
3645+
3646+ for (i = 0 ; i < nbfd ; i ++ ) {
3647+ val = JS_GetPropertyUint32 (ctx , argv [0 ], i );
3648+ if (JS_IsException (val )) {
3649+ return JS_EXCEPTION ;
3650+ }
3651+ prop = JS_GetPropertyStr (ctx , val , "fd" );
3652+ if (JS_IsException (prop )) {
3653+ JS_FreeValue (ctx , val );
3654+ return JS_EXCEPTION ;
3655+ }
3656+ ret = JS_ToInt32 (ctx , & pfds [i ].fd , prop );
3657+ JS_FreeValue (ctx , prop );
3658+ if (ret ) {
3659+ JS_FreeValue (ctx , val );
3660+ return JS_EXCEPTION ;
3661+ }
3662+ prop = JS_GetPropertyStr (ctx , val , "events" );
3663+ if (JS_IsException (prop )) {
3664+ return JS_EXCEPTION ;
3665+ }
3666+ ret = JS_ToUint32 (ctx , & events , prop );
3667+ JS_FreeValue (ctx , prop );
3668+ if (ret ) {
3669+ JS_FreeValue (ctx , val );
3670+ return JS_EXCEPTION ;
3671+ }
3672+ pfds [i ].events = events ;
3673+ JS_FreeValue (ctx , val );
3674+ }
3675+
3676+ if (argc >= 2 && JS_ToInt32 (ctx , & timeoutms , argv [1 ]))
3677+ return JS_EXCEPTION ;
3678+
3679+ if (poll (pfds , nbfd , timeoutms ) <= 0 )
3680+ return JS_EXCEPTION ;
3681+
3682+ val = JS_NewArray (ctx );
3683+ if (JS_IsException (val ))
3684+ return val ;
3685+
3686+ for (i = 0 ; i < nbfd ; i ++ ) {
3687+ JS_DefinePropertyValueUint32 (ctx , val , i , JS_NewInt32 (ctx , pfds [i ].revents ), JS_PROP_C_W_E );
3688+ }
3689+
3690+ return val ;
3691+ }
3692+
36193693static JSValue js_os_recv_send (JSContext * ctx , JSValueConst this_val ,
36203694 int argc , JSValueConst * argv , int magic )
36213695{
@@ -3634,35 +3708,49 @@ static JSValue js_os_recv_send(JSContext *ctx, JSValueConst this_val,
36343708 buf = JS_GetArrayBuffer (ctx , & size , argv [1 ]);
36353709 if (!buf )
36363710 return JS_EXCEPTION ;
3637- if (JS_ToIndex (ctx , & len , argv [2 ]))
3711+ if (argc <= 2 )
3712+ len = size ;
3713+ else if (JS_ToIndex (ctx , & len , argv [2 ]))
36383714 return JS_EXCEPTION ;
36393715 if (len > size )
36403716 return JS_ThrowRangeError (ctx , "recv/send array buffer overflow" );
3641- if ((magic == 2 || magic == 3 ) && JS_toSockaddrStruct (ctx , argv [1 ], & saddr ))
3717+ if ((magic == 2 || magic == 3 ) && JS_ToSockaddrStruct (ctx , argv [1 ], & saddr ))
36423718 return JS_EXCEPTION ;
3643-
36443719 if (magic == 0 )
3645- ret = js_get_errno (send (fd , buf , len , 0 ));
3646- if (magic == 1 )
36473720 ret = js_get_errno (recv (fd , buf , len , 0 ));
3648- if (magic == 2 )
3649- ret = js_get_errno (sendto (fd , buf , len , 0 , ( const struct sockaddr * ) & saddr , saddrlen ));
3650- if (magic == 3 ) { // recvfrom returns recvLen + sockaddrRecvFrom
3721+ if (magic == 1 )
3722+ ret = js_get_errno (send (fd , buf , len , 0 ));
3723+ if (magic == 2 ) { // recvfrom returns recvLen + sockaddrRecvFrom
36513724 ret = js_get_errno (recvfrom (fd , buf , len , 0 , (struct sockaddr * )& saddr , & saddrlen ));
3652- addr = js_toSockaddrObj (ctx , & saddr );
3725+ addr = JS_ToSockaddrObj (ctx , & saddr );
36533726 if (JS_IsException (addr ))
36543727 return addr ; // shall we return ?
36553728 addr_ret = JS_NewArray (ctx );
36563729 if (JS_IsException (addr_ret ))
36573730 return addr_ret ;
3658- JS_DefinePropertyValueUint32 (ctx , addr_ret , 0 , addr , JS_PROP_C_W_E );
3659- JS_DefinePropertyValueUint32 (ctx , addr_ret , 1 , JS_NewInt64 (ctx , ret ),
3660- JS_PROP_C_W_E );
3731+ JS_DefinePropertyValueUint32 (ctx , addr_ret , 0 , JS_NewInt64 (ctx , ret ), JS_PROP_C_W_E );
3732+ JS_DefinePropertyValueUint32 (ctx , addr_ret , 1 , addr , JS_PROP_C_W_E );
36613733 return addr_ret ;
36623734 }
3735+ if (magic == 3 )
3736+ ret = js_get_errno (sendto (fd , buf , len , 0 , (const struct sockaddr * )& saddr , saddrlen ));
36633737 return JS_NewInt64 (ctx , ret );
36643738}
36653739
3740+ static JSValue js_os_shutdown (JSContext * ctx , JSValueConst this_val ,
3741+ int argc , JSValueConst * argv )
3742+ {
3743+ int sockfd , how , ret ;
3744+
3745+ if (JS_ToInt32 (ctx , & sockfd , argv [0 ]))
3746+ return JS_EXCEPTION ;
3747+ if (JS_ToInt32 (ctx , & how , argv [1 ]))
3748+ return JS_EXCEPTION ;
3749+
3750+ ret = js_get_errno (shutdown (sockfd , how ));
3751+ return JS_NewInt32 (ctx , ret );
3752+ }
3753+
36663754#ifdef USE_WORKER
36673755
36683756/* Worker */
@@ -4204,25 +4292,38 @@ static const JSCFunctionListEntry js_os_funcs[] = {
42044292 JS_CFUNC_MAGIC_DEF ("setsockopt" , 3 , js_os_get_setsockopt , 1 ),
42054293 JS_CFUNC_DEF ("getaddrinfo" , 2 , js_os_getaddrinfo ),
42064294 JS_CFUNC_DEF ("bind" , 2 , js_os_bind ),
4295+ JS_CFUNC_DEF ("poll" , 2 , js_os_poll ),
42074296 JS_CFUNC_DEF ("listen" , 1 , js_os_listen ),
42084297 JS_CFUNC_DEF ("accept" , 1 , js_os_accept ),
42094298 JS_CFUNC_DEF ("connect" , 1 , js_os_connect ),
4210- JS_CFUNC_MAGIC_DEF ("recv" , 4 , js_os_recv_send , 0 ),
4211- JS_CFUNC_MAGIC_DEF ("send" , 4 , js_os_recv_send , 1 ),
4299+ JS_CFUNC_MAGIC_DEF ("recv" , 3 , js_os_recv_send , 0 ),
4300+ JS_CFUNC_MAGIC_DEF ("send" , 3 , js_os_recv_send , 1 ),
42124301 JS_CFUNC_MAGIC_DEF ("recvfrom" , 4 , js_os_recv_send , 2 ),
42134302 JS_CFUNC_MAGIC_DEF ("sendto" , 4 , js_os_recv_send , 3 ),
4303+ JS_CFUNC_DEF ("shutdown" , 2 , js_os_shutdown ),
42144304 OS_FLAG (AF_INET ),
42154305 OS_FLAG (AF_INET6 ),
42164306 OS_FLAG (SOCK_STREAM ),
42174307 OS_FLAG (SOCK_DGRAM ),
42184308 OS_FLAG (SOCK_RAW ),
4309+ OS_FLAG (SOCK_NONBLOCK ),
42194310 OS_FLAG (SO_REUSEADDR ),
42204311 OS_FLAG (SO_RCVBUF ),
4312+ OS_FLAG (SO_ERROR ),
4313+ OS_FLAG (SHUT_RD ),
4314+ OS_FLAG (SHUT_WR ),
4315+ OS_FLAG (SHUT_RDWR ),
4316+ OS_FLAG (POLLIN ),
4317+ OS_FLAG (POLLPRI ),
4318+ OS_FLAG (POLLOUT ),
4319+ OS_FLAG (POLLERR ),
4320+ OS_FLAG (POLLHUP ),
4321+ OS_FLAG (POLLNVAL ),
42214322};
42224323
42234324static int js_os_init (JSContext * ctx , JSModuleDef * m )
42244325{
4225- os_poll_func = js_os_poll ;
4326+ os_poll_func = js_os_event_poll ;
42264327
42274328#ifdef USE_WORKER
42284329 {
0 commit comments