--- sbbs/src/sbbs3/js_socket.c 2018/04/24 16:41:23 1.1 +++ sbbs/src/sbbs3/js_socket.c 2018/04/24 16:43:42 1.1.1.2 @@ -2,13 +2,13 @@ /* Synchronet JavaScript "Socket" Object */ -/* $Id: js_socket.c,v 1.1 2018/04/24 16:41:23 root Exp $ */ +/* $Id: js_socket.c,v 1.1.1.2 2018/04/24 16:43:42 root Exp $ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -36,6 +36,7 @@ ****************************************************************************/ #include "sbbs.h" +#include "js_request.h" #ifdef JAVASCRIPT @@ -49,6 +50,7 @@ typedef struct BOOL network_byte_order; int last_error; int type; + SOCKADDR_IN remote_addr; } private_t; @@ -96,6 +98,7 @@ static JSBool js_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { private_t* p; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -105,6 +108,7 @@ js_close(JSContext *cx, JSObject *obj, u if(p->sock==INVALID_SOCKET) return(JS_TRUE); + rc=JS_SUSPENDREQUEST(cx); close_socket(p->sock); p->last_error = ERROR_VALUE; @@ -113,6 +117,7 @@ js_close(JSContext *cx, JSObject *obj, u p->sock = INVALID_SOCKET; p->is_connected = FALSE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -123,6 +128,7 @@ static ushort js_port(JSContext* cx, jsv JSString* str; int32 i=0; struct servent* serv; + jsrefcount rc; if(JSVAL_IS_NUMBER(val)) { JS_ValueToInt32(cx,val,&i); @@ -133,7 +139,9 @@ static ushort js_port(JSContext* cx, jsv cp = JS_GetStringBytes(str); if(isdigit(*cp)) return((ushort)strtol(cp,NULL,0)); + rc=JS_SUSPENDREQUEST(cx); serv = getservbyname(cp,type==SOCK_STREAM ? "tcp":"udp"); + JS_RESUMEREQUEST(cx, rc); if(serv!=NULL) return(htons(serv->s_port)); } @@ -173,9 +181,10 @@ static JSBool js_bind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { ulong ip=0; - SOCKADDR_IN addr; private_t* p; ushort port=0; + SOCKADDR_IN addr; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -192,15 +201,18 @@ js_bind(JSContext *cx, JSObject *obj, ui && (ip=inet_addr(JS_GetStringBytes(JS_ValueToString(cx,argv[1]))))!=INADDR_NONE) addr.sin_addr.s_addr = ip; + rc=JS_SUSPENDREQUEST(cx); if(bind(p->sock, (struct sockaddr *) &addr, sizeof(addr))!=0) { p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "bind failed with error %d",ERROR_VALUE); *rval = JSVAL_FALSE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } dbprintf(FALSE, p, "bound to port %u",port); *rval = JSVAL_TRUE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -209,24 +221,28 @@ js_listen(JSContext *cx, JSObject *obj, { private_t* p; int32 backlog=1; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); return(JS_FALSE); } - if(argc) + if(argc && argv[0]!=JSVAL_VOID) backlog = JS_ValueToInt32(cx,argv[0],&backlog); + rc=JS_SUSPENDREQUEST(cx); if(listen(p->sock, backlog)!=0) { p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "listen failed with error %d",ERROR_VALUE); *rval = JSVAL_FALSE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } dbprintf(FALSE, p, "listening, backlog=%d",backlog); *rval = JSVAL_TRUE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -237,24 +253,32 @@ js_accept(JSContext *cx, JSObject *obj, private_t* new_p; JSObject* sockobj; SOCKET new_socket; + socklen_t addrlen; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); return(JS_FALSE); } - if((new_socket=accept_socket(p->sock,NULL,NULL))==INVALID_SOCKET) { + addrlen=sizeof(p->remote_addr); + + rc=JS_SUSPENDREQUEST(cx); + if((new_socket=accept_socket(p->sock,(struct sockaddr *)&(p->remote_addr),&addrlen))==INVALID_SOCKET) { p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "accept failed with error %d",ERROR_VALUE); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } if((sockobj=js_CreateSocketObject(cx, obj, "new_socket", new_socket))==NULL) { closesocket(new_socket); + JS_RESUMEREQUEST(cx, rc); JS_ReportError(cx,"Error creating new socket object"); return(JS_TRUE); } if((new_p=(private_t*)JS_GetPrivate(cx,sockobj))==NULL) { + JS_RESUMEREQUEST(cx, rc); JS_ReportError(cx,getprivate_failure,WHERE); return(JS_FALSE); } @@ -267,6 +291,7 @@ js_accept(JSContext *cx, JSObject *obj, dbprintf(FALSE, p, "accepted connection"); *rval = OBJECT_TO_JSVAL(sockobj); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -279,9 +304,10 @@ js_connect(JSContext *cx, JSObject *obj, ushort port; JSString* str; private_t* p; - SOCKADDR_IN addr; fd_set socket_set; struct timeval tv = {0, 0}; + jsrefcount rc; + char* cstr; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -289,14 +315,18 @@ js_connect(JSContext *cx, JSObject *obj, } str = JS_ValueToString(cx, argv[0]); - dbprintf(FALSE, p, "resolving hostname: %s", JS_GetStringBytes(str)); + cstr = JS_GetStringBytes(str); + rc=JS_SUSPENDREQUEST(cx); + dbprintf(FALSE, p, "resolving hostname: %s", cstr); if((ip_addr=resolve_ip(JS_GetStringBytes(str)))==INADDR_NONE) { p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "resolve_ip failed with error %d",ERROR_VALUE); *rval = JSVAL_FALSE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } + JS_RESUMEREQUEST(cx, rc); port = js_port(cx,argv[1],p->type); tv.tv_sec = 10; /* default time-out */ @@ -304,19 +334,20 @@ js_connect(JSContext *cx, JSObject *obj, if(argc>2) /* time-out value specified */ js_timeval(cx,argv[2],&tv); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "connecting to port %u at %s", port, JS_GetStringBytes(str)); - memset(&addr,0,sizeof(addr)); - addr.sin_addr.s_addr = ip_addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); + memset(&(p->remote_addr),0,sizeof(p->remote_addr)); + p->remote_addr.sin_addr.s_addr = ip_addr; + p->remote_addr.sin_family = AF_INET; + p->remote_addr.sin_port = htons(port); /* always set to nonblocking here */ val=1; ioctlsocket(p->sock,FIONBIO,&val); - result=connect(p->sock, (struct sockaddr *)&addr, sizeof(addr)); - + result=connect(p->sock, (struct sockaddr *)&(p->remote_addr), sizeof(p->remote_addr)); + if(result==SOCKET_ERROR && (ERROR_VALUE==EWOULDBLOCK || ERROR_VALUE==EINPROGRESS)) { FD_ZERO(&socket_set); @@ -332,12 +363,14 @@ js_connect(JSContext *cx, JSObject *obj, p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "connect failed with error %d",ERROR_VALUE); *rval = JSVAL_FALSE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } p->is_connected = TRUE; *rval = JSVAL_TRUE; dbprintf(FALSE, p, "connected to port %u at %s", port, JS_GetStringBytes(str)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -349,6 +382,7 @@ js_send(JSContext *cx, JSObject *obj, ui int len; JSString* str; private_t* p; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -361,6 +395,7 @@ js_send(JSContext *cx, JSObject *obj, ui cp = JS_GetStringBytes(str); len = JS_GetStringLength(str); + rc=JS_SUSPENDREQUEST(cx); if(sendsocket(p->sock,cp,len)==len) { dbprintf(FALSE, p, "sent %u bytes",len); *rval = JSVAL_TRUE; @@ -368,6 +403,7 @@ js_send(JSContext *cx, JSObject *obj, ui p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "send of %u bytes failed",len); } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -383,6 +419,8 @@ js_sendto(JSContext *cx, JSObject *obj, JSString* ip_str; private_t* p; SOCKADDR_IN addr; + jsrefcount rc; + char* cstr; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -398,16 +436,21 @@ js_sendto(JSContext *cx, JSObject *obj, /* address */ ip_str = JS_ValueToString(cx, argv[1]); + cstr = JS_GetStringBytes(ip_str); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "resolving hostname: %s", JS_GetStringBytes(ip_str)); - if((ip_addr=resolve_ip(JS_GetStringBytes(ip_str)))==INADDR_NONE) { + if((ip_addr=resolve_ip(cstr))==INADDR_NONE) { p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "resolve_ip failed with error %d",ERROR_VALUE); *rval = JSVAL_FALSE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } /* port */ + JS_RESUMEREQUEST(cx, rc); port = js_port(cx,argv[2],p->type); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "sending %d bytes to port %u at %s" ,len, port, JS_GetStringBytes(ip_str)); @@ -424,6 +467,7 @@ js_sendto(JSContext *cx, JSObject *obj, p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "send of %u bytes failed",len); } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -437,6 +481,7 @@ js_sendfile(JSContext *cx, JSObject *obj int file; JSString* str; private_t* p; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -451,8 +496,11 @@ js_sendfile(JSContext *cx, JSObject *obj return(JS_FALSE); } - if((file=nopen(fname,O_RDONLY|O_BINARY))==-1) + rc=JS_SUSPENDREQUEST(cx); + if((file=nopen(fname,O_RDONLY|O_BINARY))==-1) { + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); + } #if 0 len=filelength(file); @@ -478,6 +526,7 @@ js_sendfile(JSContext *cx, JSObject *obj free(buf); #else len = sendfilesocket(p->sock, file, NULL, 0); + close(file); if(len > 0) { dbprintf(FALSE, p, "sent %u bytes",len); *rval = JSVAL_TRUE; @@ -487,6 +536,7 @@ js_sendfile(JSContext *cx, JSObject *obj } #endif + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -500,6 +550,7 @@ js_sendbin(JSContext *cx, JSObject *obj, size_t wr=0; size_t size=sizeof(DWORD); private_t* p; + jsrefcount rc; *rval = JSVAL_FALSE; @@ -508,10 +559,12 @@ js_sendbin(JSContext *cx, JSObject *obj, return(JS_FALSE); } - JS_ValueToInt32(cx,argv[0],&val); - if(argc>1) + if(argv[0]!=JSVAL_VOID) + JS_ValueToInt32(cx,argv[0],&val); + if(argc>1 && argv[1]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[1],(int32*)&size); + rc=JS_SUSPENDREQUEST(cx); switch(size) { case sizeof(BYTE): b = (BYTE)val; @@ -542,6 +595,7 @@ js_sendbin(JSContext *cx, JSObject *obj, dbprintf(TRUE, p, "send of %u bytes (binary) failed",size); } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -552,6 +606,7 @@ js_recv(JSContext *cx, JSObject *obj, ui char* buf; int32 len=512; JSString* str; + jsrefcount rc; private_t* p; @@ -560,7 +615,7 @@ js_recv(JSContext *cx, JSObject *obj, ui return(JS_FALSE); } - if(argc) + if(argc && argv[0]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[0],&len); if((buf=(char*)alloca(len+1))==NULL) { @@ -568,7 +623,9 @@ js_recv(JSContext *cx, JSObject *obj, ui return(JS_FALSE); } + rc=JS_SUSPENDREQUEST(cx); len = recv(p->sock,buf,len,0); + JS_RESUMEREQUEST(cx, rc); if(len<0) { p->last_error=ERROR_VALUE; *rval = JSVAL_NULL; @@ -581,7 +638,9 @@ js_recv(JSContext *cx, JSObject *obj, ui return(JS_FALSE); *rval = STRING_TO_JSVAL(str); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "received %u bytes",len); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -604,6 +663,7 @@ js_recvfrom(JSContext *cx, JSObject *obj JSObject* retobj; SOCKADDR_IN addr; socklen_t addrlen; + jsrefcount rc; private_t* p; @@ -619,7 +679,7 @@ js_recvfrom(JSContext *cx, JSObject *obj binary=JSVAL_TO_BOOLEAN(argv[n]); if(binary) len=sizeof(DWORD); - } else + } else if(argv[n]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[n],&len); } @@ -627,6 +687,7 @@ js_recvfrom(JSContext *cx, JSObject *obj if(binary) { /* Binary/Integer Data */ + rc=JS_SUSPENDREQUEST(cx); switch(len) { case sizeof(BYTE): if((rd=recvfrom(p->sock,&b,len,0,(SOCKADDR*)&addr,&addrlen))==len) @@ -639,15 +700,20 @@ js_recvfrom(JSContext *cx, JSObject *obj data_val = INT_TO_JSVAL(w); } break; + default: case sizeof(DWORD): if((rd=recvfrom(p->sock,(BYTE*)&l,len,0,(SOCKADDR*)&addr,&addrlen))==len) { if(p->network_byte_order) l=ntohl(l); + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,l,&data_val); + rc=JS_SUSPENDREQUEST(cx); } break; } + JS_RESUMEREQUEST(cx, rc); + if(rd!=len) { p->last_error=ERROR_VALUE; return(JS_TRUE); @@ -660,7 +726,9 @@ js_recvfrom(JSContext *cx, JSObject *obj return(JS_FALSE); } + rc=JS_SUSPENDREQUEST(cx); len = recvfrom(p->sock,buf,len,0,(SOCKADDR*)&addr,&addrlen); + JS_RESUMEREQUEST(cx, rc); if(len<0) { p->last_error=ERROR_VALUE; return(JS_TRUE); @@ -701,7 +769,9 @@ js_recvfrom(JSContext *cx, JSObject *obj *rval = OBJECT_TO_JSVAL(retobj); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "received %u bytes from %s:%s",len,ip_addr,port); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -713,6 +783,7 @@ js_peek(JSContext *cx, JSObject *obj, ui char* buf; int32 len=512; JSString* str; + jsrefcount rc; private_t* p; @@ -721,14 +792,16 @@ js_peek(JSContext *cx, JSObject *obj, ui return(JS_FALSE); } - if(argc) + if(argc && argv[0]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[0],&len); if((buf=(char*)alloca(len+1))==NULL) { JS_ReportError(cx,"Error allocating %u bytes",len+1); return(JS_FALSE); } + rc=JS_SUSPENDREQUEST(cx); len = recv(p->sock,buf,len,MSG_PEEK); + JS_RESUMEREQUEST(cx, rc); if(len<0) { p->last_error=ERROR_VALUE; *rval = JSVAL_NULL; @@ -741,8 +814,10 @@ js_peek(JSContext *cx, JSObject *obj, ui return(JS_FALSE); *rval = STRING_TO_JSVAL(str); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "received %u bytes, lasterror=%d" ,len,ERROR_VALUE); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -759,13 +834,14 @@ js_recvline(JSContext *cx, JSObject *obj int32 timeout=30; /* seconds */ JSString* str; private_t* p; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); return(JS_FALSE); } - if(argc) + if(argc && argv[0]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[0],&len); if((buf=(char*)alloca(len+1))==NULL) { @@ -773,14 +849,20 @@ js_recvline(JSContext *cx, JSObject *obj return(JS_FALSE); } - if(argc>1) - JS_ValueToInt32(cx,argv[1],(int32*)&timeout); + if(argc>1 && argv[1]!=JSVAL_VOID) + JS_ValueToInt32(cx,argv[1],&timeout); start=time(NULL); + rc=JS_SUSPENDREQUEST(cx); for(i=0;isock,&rd,NULL,1000)) { p->last_error=ERROR_VALUE; + if(i==0) { + *rval = JSVAL_NULL; + JS_RESUMEREQUEST(cx, rc); + return(JS_TRUE); /* socket closed */ + } break; /* disconnected */ } @@ -788,6 +870,7 @@ js_recvline(JSContext *cx, JSObject *obj if(time(NULL)-start>timeout) { dbprintf(FALSE, p, "recvline timeout (received: %d)",i); *rval = JSVAL_NULL; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); /* time-out */ } continue; /* no data */ @@ -808,13 +891,16 @@ js_recvline(JSContext *cx, JSObject *obj else buf[i]=0; + JS_RESUMEREQUEST(cx, rc); str = JS_NewStringCopyZ(cx, buf); if(str==NULL) return(JS_FALSE); *rval = STRING_TO_JSVAL(str); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "received %u bytes (recvline) lasterror=%d" ,i,ERROR_VALUE); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -828,6 +914,7 @@ js_recvbin(JSContext *cx, JSObject *obj, int size=sizeof(DWORD); int rd=0; private_t* p; + jsrefcount rc; *rval = INT_TO_JSVAL(-1); @@ -836,9 +923,10 @@ js_recvbin(JSContext *cx, JSObject *obj, return(JS_FALSE); } - if(argc) + if(argc && argv[0]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[0],(int32*)&size); + rc=JS_SUSPENDREQUEST(cx); switch(size) { case sizeof(BYTE): if((rd=recv(p->sock,&b,size,0))==size) @@ -855,7 +943,9 @@ js_recvbin(JSContext *cx, JSObject *obj, if((rd=recv(p->sock,(BYTE*)&l,size,0))==size) { if(p->network_byte_order) l=ntohl(l); + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,l,rval); + rc=JS_SUSPENDREQUEST(cx); } break; } @@ -863,6 +953,7 @@ js_recvbin(JSContext *cx, JSObject *obj, if(rd!=size) p->last_error=ERROR_VALUE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -877,6 +968,7 @@ js_getsockopt(JSContext *cx, JSObject *o LINGER linger; void* vp=&val; socklen_t len=sizeof(val); + jsrefcount rc; *rval = INT_TO_JSVAL(-1); @@ -885,8 +977,11 @@ js_getsockopt(JSContext *cx, JSObject *o return(JS_FALSE); } - if((opt = getSocketOptionByName(JS_GetStringBytes(JS_ValueToString(cx,argv[0])),&level)) == -1) + rc=JS_SUSPENDREQUEST(cx); + if((opt = getSocketOptionByName(JS_GetStringBytes(JS_ValueToString(cx,argv[0])),&level)) == -1) { + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); + } if(opt == SO_LINGER) { vp=&linger; @@ -899,13 +994,16 @@ js_getsockopt(JSContext *cx, JSObject *o else val = 0; } + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,val,rval); + rc=JS_SUSPENDREQUEST(cx); } else { p->last_error=ERROR_VALUE; dbprintf(TRUE, p, "error %d getting option %d" ,ERROR_VALUE,opt); } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -920,15 +1018,20 @@ js_setsockopt(JSContext *cx, JSObject *o LINGER linger; void* vp=&val; socklen_t len=sizeof(val); - + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); return(JS_FALSE); } + rc=JS_SUSPENDREQUEST(cx); opt = getSocketOptionByName(JS_GetStringBytes(JS_ValueToString(cx,argv[0])),&level); - JS_ValueToInt32(cx,argv[1],&val); + if(argv[1]!=JSVAL_VOID) { + JS_RESUMEREQUEST(cx, rc); + JS_ValueToInt32(cx,argv[1],&val); + rc=JS_SUSPENDREQUEST(cx); + } if(opt == SO_LINGER) { if(val) { @@ -945,29 +1048,37 @@ js_setsockopt(JSContext *cx, JSObject *o setsockopt(p->sock, level, opt, vp, len)==0); p->last_error=ERROR_VALUE; + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_ioctlsocket(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - int32 cmd; + int32 cmd=0; int32 arg=0; private_t* p; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); return(JS_FALSE); } - JS_ValueToInt32(cx,argv[0],&cmd); - if(argc>1) + if(argv[0]!=JSVAL_VOID) + JS_ValueToInt32(cx,argv[0],&cmd); + if(argc>1 && argv[1]!=JSVAL_VOID) JS_ValueToInt32(cx,argv[1],&arg); - if(ioctlsocket(p->sock,cmd,(ulong*)&arg)==0) + rc=JS_SUSPENDREQUEST(cx); + if(ioctlsocket(p->sock,cmd,(ulong*)&arg)==0) { + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,arg,rval); - else + } + else { *rval = INT_TO_JSVAL(-1); + JS_RESUMEREQUEST(cx, rc); + } p->last_error=ERROR_VALUE; @@ -985,6 +1096,7 @@ js_poll(JSContext *cx, JSObject *obj, ui uintN argn; int result; struct timeval tv = {0, 0}; + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { JS_ReportError(cx,getprivate_failure,WHERE); @@ -1004,6 +1116,7 @@ js_poll(JSContext *cx, JSObject *obj, ui js_timeval(cx,argv[argn],&tv); } + rc=JS_SUSPENDREQUEST(cx); FD_ZERO(&socket_set); FD_SET(p->sock,&socket_set); if(poll_for_write) @@ -1019,6 +1132,7 @@ js_poll(JSContext *cx, JSObject *obj, ui ,result,p->last_error); *rval = INT_TO_JSVAL(result); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -1047,7 +1161,7 @@ enum { static char* socket_prop_desc[] = { "error status for the last socket operation that failed - READ ONLY" ,"true if socket is in a connected state - READ ONLY" - ,"true if socket can accept written data - READ ONLY" + ,"true if socket can accept written data - Setting to false will shutdown the write end of the socket." ,"true if data is waiting to be read from socket - READ ONLY" ,"number of bytes waiting to be read - READ ONLY" ,"enable debug logging" @@ -1069,15 +1183,19 @@ static JSBool js_socket_set(JSContext *c { jsint tiny; private_t* p; + jsrefcount rc; + BOOL b; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { - JS_ReportError(cx,getprivate_failure,WHERE); - return(JS_FALSE); + // Prototype access + return(JS_TRUE); } tiny = JSVAL_TO_INT(id); + rc=JS_SUSPENDREQUEST(cx); dbprintf(FALSE, p, "setting property %d",tiny); + JS_RESUMEREQUEST(cx, rc); switch(tiny) { case SOCK_PROP_DEBUG: @@ -1085,17 +1203,25 @@ static JSBool js_socket_set(JSContext *c break; case SOCK_PROP_DESCRIPTOR: JS_ValueToInt32(cx,*vp,(int32*)&(p->sock)); + p->is_connected=TRUE; break; case SOCK_PROP_LAST_ERROR: JS_ValueToInt32(cx,*vp,(int32*)&(p->last_error)); break; case SOCK_PROP_NONBLOCKING: JS_ValueToBoolean(cx,*vp,&(p->nonblocking)); + rc=JS_SUSPENDREQUEST(cx); ioctlsocket(p->sock,FIONBIO,(ulong*)&(p->nonblocking)); + JS_RESUMEREQUEST(cx, rc); break; case SOCK_PROP_NETWORK_ORDER: JS_ValueToBoolean(cx,*vp,&(p->network_byte_order)); break; + case SOCK_PROP_IS_WRITEABLE: + JS_ValueToBoolean(cx,*vp,&b); + if(!b) + shutdown(p->sock,SHUT_WR); + break; } return(JS_TRUE); @@ -1108,17 +1234,19 @@ static JSBool js_socket_get(JSContext *c BOOL rd; BOOL wr; private_t* p; - socklen_t addr_len; - SOCKADDR_IN addr; JSString* js_str; + SOCKADDR_IN addr; + socklen_t len=sizeof(addr); + jsrefcount rc; if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { - JS_ReportError(cx,getprivate_failure,WHERE); - return(JS_FALSE); + // Protoype access + return(JS_TRUE); } tiny = JSVAL_TO_INT(id); + rc=JS_SUSPENDREQUEST(cx); #if 0 /* just too much */ dbprintf(FALSE, p, "getting property %d",tiny); #endif @@ -1128,7 +1256,7 @@ static JSBool js_socket_get(JSContext *c *vp = INT_TO_JSVAL(p->last_error); break; case SOCK_PROP_IS_CONNECTED: - if(!p->is_connected && !p->external) + if(!p->is_connected) *vp = JSVAL_FALSE; else *vp = BOOLEAN_TO_JSVAL(socket_check(p->sock,NULL,NULL,0)); @@ -1143,8 +1271,11 @@ static JSBool js_socket_get(JSContext *c break; case SOCK_PROP_NREAD: cnt=0; - if(ioctlsocket(p->sock, FIONREAD, &cnt)==0) + if(ioctlsocket(p->sock, FIONREAD, &cnt)==0) { + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,cnt,vp); + rc=JS_SUSPENDREQUEST(cx); + } else *vp = JSVAL_ZERO; break; @@ -1158,42 +1289,48 @@ static JSBool js_socket_get(JSContext *c *vp = BOOLEAN_TO_JSVAL(p->nonblocking); break; case SOCK_PROP_LOCAL_IP: - addr_len = sizeof(addr); - if(getsockname(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { - p->last_error=ERROR_VALUE; - *vp = JSVAL_VOID; - } else { + if(p->sock != INVALID_SOCKET) { + if(getsockname(p->sock, (struct sockaddr *)&addr,&len)!=0) + return(JS_FALSE); + JS_RESUMEREQUEST(cx, rc); if((js_str=JS_NewStringCopyZ(cx,inet_ntoa(addr.sin_addr)))==NULL) return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); + rc=JS_SUSPENDREQUEST(cx); } + else + *vp=JSVAL_VOID; break; case SOCK_PROP_LOCAL_PORT: - addr_len = sizeof(addr); - if(getsockname(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { - p->last_error=ERROR_VALUE; - *vp = JSVAL_ZERO; - } else + if(p->sock != INVALID_SOCKET) { + if(getsockname(p->sock, (struct sockaddr *)&addr,&len)!=0) + return(JS_FALSE); + JS_RESUMEREQUEST(cx, rc); + if((js_str=JS_NewStringCopyZ(cx,inet_ntoa(addr.sin_addr)))==NULL) + return(JS_FALSE); + *vp = INT_TO_JSVAL(ntohs(addr.sin_port)); + rc=JS_SUSPENDREQUEST(cx); + } + else + *vp=JSVAL_VOID; break; case SOCK_PROP_REMOTE_IP: - addr_len = sizeof(addr); - if(getpeername(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { - p->last_error=ERROR_VALUE; - *vp = JSVAL_VOID; - } else { - if((js_str=JS_NewStringCopyZ(cx,inet_ntoa(addr.sin_addr)))==NULL) + if(p->is_connected) { + JS_RESUMEREQUEST(cx, rc); + if((js_str=JS_NewStringCopyZ(cx,inet_ntoa(p->remote_addr.sin_addr)))==NULL) return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); + rc=JS_SUSPENDREQUEST(cx); } + else + *vp=JSVAL_VOID; break; case SOCK_PROP_REMOTE_PORT: - addr_len = sizeof(addr); - if(getpeername(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { - p->last_error=ERROR_VALUE; - *vp = JSVAL_ZERO; - } else - *vp = INT_TO_JSVAL(ntohs(addr.sin_port)); + if(p->is_connected) + *vp = INT_TO_JSVAL(ntohs(p->remote_addr.sin_port)); + else + *vp=JSVAL_VOID; break; case SOCK_PROP_TYPE: *vp = INT_TO_JSVAL(p->type); @@ -1204,6 +1341,7 @@ static JSBool js_socket_get(JSContext *c } + JS_RESUMEREQUEST(cx, rc); return(TRUE); } @@ -1215,8 +1353,8 @@ static jsSyncPropertySpec js_socket_prop { "error" ,SOCK_PROP_LAST_ERROR ,SOCK_PROP_FLAGS, 311 }, { "last_error" ,SOCK_PROP_LAST_ERROR ,JSPROP_READONLY, 310 }, /* alias */ { "is_connected" ,SOCK_PROP_IS_CONNECTED ,SOCK_PROP_FLAGS, 310 }, - { "is_writeable" ,SOCK_PROP_IS_WRITEABLE ,SOCK_PROP_FLAGS, 311 }, - { "is_writable" ,SOCK_PROP_IS_WRITEABLE ,JSPROP_READONLY, 312 }, /* alias */ + { "is_writeable" ,SOCK_PROP_IS_WRITEABLE ,JSPROP_ENUMERATE, 311 }, + { "is_writable" ,SOCK_PROP_IS_WRITEABLE ,JSPROP_ENUMERATE, 312 }, /* alias */ { "data_waiting" ,SOCK_PROP_DATA_WAITING ,SOCK_PROP_FLAGS, 310 }, { "nread" ,SOCK_PROP_NREAD ,SOCK_PROP_FLAGS, 310 }, { "debug" ,SOCK_PROP_DEBUG ,JSPROP_ENUMERATE, 310 }, @@ -1231,19 +1369,6 @@ static jsSyncPropertySpec js_socket_prop {0} }; -static JSClass js_socket_class = { - "Socket" /* name */ - ,JSCLASS_HAS_PRIVATE /* flags */ - ,JS_PropertyStub /* addProperty */ - ,JS_PropertyStub /* delProperty */ - ,js_socket_get /* getProperty */ - ,js_socket_set /* setProperty */ - ,JS_EnumerateStub /* enumerate */ - ,JS_ResolveStub /* resolve */ - ,JS_ConvertStub /* convert */ - ,js_finalize_socket /* finalize */ -}; - static jsSyncMethodSpec js_socket_functions[] = { {"close", js_close, 0, JSTYPE_VOID, "" ,JSDOCSTR("close (shutdown) the socket immediately") @@ -1333,6 +1458,34 @@ static jsSyncMethodSpec js_socket_functi {0} }; +static JSBool js_socket_resolve(JSContext *cx, JSObject *obj, jsval id) +{ + char* name=NULL; + + if(id != JSVAL_NULL) + name=JS_GetStringBytes(JSVAL_TO_STRING(id)); + + return(js_SyncResolve(cx, obj, name, js_socket_properties, js_socket_functions, NULL, 0)); +} + +static JSBool js_socket_enumerate(JSContext *cx, JSObject *obj) +{ + return(js_socket_resolve(cx, obj, JSVAL_NULL)); +} + +static JSClass js_socket_class = { + "Socket" /* name */ + ,JSCLASS_HAS_PRIVATE /* flags */ + ,JS_PropertyStub /* addProperty */ + ,JS_PropertyStub /* delProperty */ + ,js_socket_get /* getProperty */ + ,js_socket_set /* setProperty */ + ,js_socket_enumerate /* enumerate */ + ,js_socket_resolve /* resolve */ + ,JS_ConvertStub /* convert */ + ,js_finalize_socket /* finalize */ +}; + static BOOL js_DefineSocketOptionsArray(JSContext *cx, JSObject *obj, int type) { size_t i; @@ -1395,19 +1548,9 @@ js_socket_constructor(JSContext *cx, JSO return(JS_FALSE); } - if(!js_DefineSyncProperties(cx, obj, js_socket_properties)) { - JS_ReportError(cx,"js_DefineSyncProperties failed"); - return(JS_FALSE); - } - if(!js_DefineSocketOptionsArray(cx, obj, type)) return(JS_FALSE); - if(!js_DefineSyncMethods(cx, obj, js_socket_functions, FALSE)) { - JS_ReportError(cx,"js_DefineSyncMethods failed"); - return(JS_FALSE); - } - #ifdef BUILD_JSDOCS js_DescribeSyncObject(cx,obj,"Class used for TCP/IP socket communications",310); js_DescribeSyncConstructor(cx,obj,"To create a new Socket object: " @@ -1450,9 +1593,6 @@ JSObject* DLLCALL js_CreateSocketObject( if(obj==NULL) return(NULL); - if(!js_DefineSyncProperties(cx, obj, js_socket_properties)) - return(NULL); - len = sizeof(type); getsockopt(sock,SOL_SOCKET,SO_TYPE,(void*)&type,&len); @@ -1467,14 +1607,15 @@ JSObject* DLLCALL js_CreateSocketObject( p->external = TRUE; p->network_byte_order = TRUE; + len=sizeof(p->remote_addr); + if(getpeername(p->sock, (struct sockaddr *)&p->remote_addr,&len)==0) + p->is_connected=TRUE; + if(!JS_SetPrivate(cx, obj, p)) { dbprintf(TRUE, p, "JS_SetPrivate failed"); return(NULL); } - if (!js_DefineSyncMethods(cx, obj, js_socket_functions, FALSE)) - return(NULL); - dbprintf(FALSE, p, "object created"); return(obj);