|
|
1.1 ! root 1: /* js_socket.c */ ! 2: ! 3: /* Synchronet JavaScript "Socket" Object */ ! 4: ! 5: /* $Id: js_socket.c,v 1.118 2006/12/28 02:43:48 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include "sbbs.h" ! 39: ! 40: #ifdef JAVASCRIPT ! 41: ! 42: typedef struct ! 43: { ! 44: SOCKET sock; ! 45: BOOL external; /* externally created, don't close */ ! 46: BOOL debug; ! 47: BOOL nonblocking; ! 48: BOOL is_connected; ! 49: BOOL network_byte_order; ! 50: int last_error; ! 51: int type; ! 52: ! 53: } private_t; ! 54: ! 55: static const char* getprivate_failure = "line %d %s JS_GetPrivate failed"; ! 56: ! 57: static void dbprintf(BOOL error, private_t* p, char* fmt, ...) ! 58: { ! 59: va_list argptr; ! 60: char sbuf[1024]; ! 61: ! 62: if(p==NULL || (!p->debug /*&& !error */)) ! 63: return; ! 64: ! 65: va_start(argptr,fmt); ! 66: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 67: sbuf[sizeof(sbuf)-1]=0; ! 68: va_end(argptr); ! 69: ! 70: lprintf(LOG_DEBUG,"%04d Socket %s%s",p->sock,error ? "ERROR: ":"",sbuf); ! 71: } ! 72: ! 73: /* Socket Destructor */ ! 74: ! 75: static void js_finalize_socket(JSContext *cx, JSObject *obj) ! 76: { ! 77: private_t* p; ! 78: ! 79: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) ! 80: return; ! 81: ! 82: if(p->external==FALSE && p->sock!=INVALID_SOCKET) { ! 83: close_socket(p->sock); ! 84: dbprintf(FALSE, p, "closed/deleted"); ! 85: } ! 86: ! 87: free(p); ! 88: ! 89: JS_SetPrivate(cx, obj, NULL); ! 90: } ! 91: ! 92: ! 93: /* Socket Object Methods */ ! 94: ! 95: static JSBool ! 96: js_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 97: { ! 98: private_t* p; ! 99: ! 100: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 101: JS_ReportError(cx,getprivate_failure,WHERE); ! 102: return(JS_FALSE); ! 103: } ! 104: ! 105: if(p->sock==INVALID_SOCKET) ! 106: return(JS_TRUE); ! 107: ! 108: close_socket(p->sock); ! 109: ! 110: p->last_error = ERROR_VALUE; ! 111: ! 112: dbprintf(FALSE, p, "closed"); ! 113: ! 114: p->sock = INVALID_SOCKET; ! 115: p->is_connected = FALSE; ! 116: ! 117: return(JS_TRUE); ! 118: } ! 119: ! 120: static ushort js_port(JSContext* cx, jsval val, int type) ! 121: { ! 122: char* cp; ! 123: JSString* str; ! 124: int32 i=0; ! 125: struct servent* serv; ! 126: ! 127: if(JSVAL_IS_NUMBER(val)) { ! 128: JS_ValueToInt32(cx,val,&i); ! 129: return((ushort)i); ! 130: } ! 131: if(JSVAL_IS_STRING(val)) { ! 132: str = JS_ValueToString(cx,val); ! 133: cp = JS_GetStringBytes(str); ! 134: if(isdigit(*cp)) ! 135: return((ushort)strtol(cp,NULL,0)); ! 136: serv = getservbyname(cp,type==SOCK_STREAM ? "tcp":"udp"); ! 137: if(serv!=NULL) ! 138: return(htons(serv->s_port)); ! 139: } ! 140: return(0); ! 141: } ! 142: ! 143: SOCKET DLLCALL js_socket(JSContext *cx, jsval val) ! 144: { ! 145: void* vp; ! 146: JSClass* cl; ! 147: SOCKET sock=INVALID_SOCKET; ! 148: ! 149: if(JSVAL_IS_OBJECT(val) && (cl=JS_GetClass(cx,JSVAL_TO_OBJECT(val)))!=NULL) { ! 150: if(cl->flags&JSCLASS_HAS_PRIVATE) ! 151: if((vp=JS_GetPrivate(cx,JSVAL_TO_OBJECT(val)))!=NULL) ! 152: sock=*(SOCKET*)vp; ! 153: } else if(val!=JSVAL_VOID) ! 154: JS_ValueToInt32(cx,val,(int32*)&sock); ! 155: ! 156: return(sock); ! 157: } ! 158: ! 159: void DLLCALL js_timeval(JSContext* cx, jsval val, struct timeval* tv) ! 160: { ! 161: jsdouble jsd; ! 162: ! 163: if(JSVAL_IS_INT(val)) ! 164: tv->tv_sec = JSVAL_TO_INT(val); ! 165: else if(JSVAL_IS_DOUBLE(val)) { ! 166: JS_ValueToNumber(cx,val,&jsd); ! 167: tv->tv_sec = (int)jsd; ! 168: tv->tv_usec = (int)(jsd*1000000.0)%1000000; ! 169: } ! 170: } ! 171: ! 172: static JSBool ! 173: js_bind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 174: { ! 175: ulong ip=0; ! 176: SOCKADDR_IN addr; ! 177: private_t* p; ! 178: ushort port=0; ! 179: ! 180: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 181: JS_ReportError(cx,getprivate_failure,WHERE); ! 182: return(JS_FALSE); ! 183: } ! 184: ! 185: memset(&addr,0,sizeof(addr)); ! 186: addr.sin_family = AF_INET; ! 187: ! 188: if(argc) ! 189: port = js_port(cx,argv[0],p->type); ! 190: addr.sin_port = htons(port); ! 191: if(argc>1 ! 192: && (ip=inet_addr(JS_GetStringBytes(JS_ValueToString(cx,argv[1]))))!=INADDR_NONE) ! 193: addr.sin_addr.s_addr = ip; ! 194: ! 195: if(bind(p->sock, (struct sockaddr *) &addr, sizeof(addr))!=0) { ! 196: p->last_error=ERROR_VALUE; ! 197: dbprintf(TRUE, p, "bind failed with error %d",ERROR_VALUE); ! 198: *rval = JSVAL_FALSE; ! 199: return(JS_TRUE); ! 200: } ! 201: ! 202: dbprintf(FALSE, p, "bound to port %u",port); ! 203: *rval = JSVAL_TRUE; ! 204: return(JS_TRUE); ! 205: } ! 206: ! 207: static JSBool ! 208: js_listen(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 209: { ! 210: private_t* p; ! 211: int32 backlog=1; ! 212: ! 213: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 214: JS_ReportError(cx,getprivate_failure,WHERE); ! 215: return(JS_FALSE); ! 216: } ! 217: ! 218: if(argc) ! 219: backlog = JS_ValueToInt32(cx,argv[0],&backlog); ! 220: ! 221: if(listen(p->sock, backlog)!=0) { ! 222: p->last_error=ERROR_VALUE; ! 223: dbprintf(TRUE, p, "listen failed with error %d",ERROR_VALUE); ! 224: *rval = JSVAL_FALSE; ! 225: return(JS_TRUE); ! 226: } ! 227: ! 228: dbprintf(FALSE, p, "listening, backlog=%d",backlog); ! 229: *rval = JSVAL_TRUE; ! 230: return(JS_TRUE); ! 231: } ! 232: ! 233: static JSBool ! 234: js_accept(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 235: { ! 236: private_t* p; ! 237: private_t* new_p; ! 238: JSObject* sockobj; ! 239: SOCKET new_socket; ! 240: ! 241: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 242: JS_ReportError(cx,getprivate_failure,WHERE); ! 243: return(JS_FALSE); ! 244: } ! 245: ! 246: if((new_socket=accept_socket(p->sock,NULL,NULL))==INVALID_SOCKET) { ! 247: p->last_error=ERROR_VALUE; ! 248: dbprintf(TRUE, p, "accept failed with error %d",ERROR_VALUE); ! 249: return(JS_TRUE); ! 250: } ! 251: ! 252: if((sockobj=js_CreateSocketObject(cx, obj, "new_socket", new_socket))==NULL) { ! 253: closesocket(new_socket); ! 254: JS_ReportError(cx,"Error creating new socket object"); ! 255: return(JS_TRUE); ! 256: } ! 257: if((new_p=(private_t*)JS_GetPrivate(cx,sockobj))==NULL) { ! 258: JS_ReportError(cx,getprivate_failure,WHERE); ! 259: return(JS_FALSE); ! 260: } ! 261: ! 262: new_p->type=p->type; ! 263: new_p->debug=p->debug; ! 264: new_p->nonblocking=p->nonblocking; ! 265: new_p->external=FALSE; /* let destructor close socket */ ! 266: new_p->is_connected=TRUE; ! 267: ! 268: dbprintf(FALSE, p, "accepted connection"); ! 269: *rval = OBJECT_TO_JSVAL(sockobj); ! 270: return(JS_TRUE); ! 271: } ! 272: ! 273: static JSBool ! 274: js_connect(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 275: { ! 276: int result; ! 277: ulong val; ! 278: ulong ip_addr; ! 279: ushort port; ! 280: JSString* str; ! 281: private_t* p; ! 282: SOCKADDR_IN addr; ! 283: fd_set socket_set; ! 284: struct timeval tv = {0, 0}; ! 285: ! 286: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 287: JS_ReportError(cx,getprivate_failure,WHERE); ! 288: return(JS_FALSE); ! 289: } ! 290: ! 291: str = JS_ValueToString(cx, argv[0]); ! 292: dbprintf(FALSE, p, "resolving hostname: %s", JS_GetStringBytes(str)); ! 293: if((ip_addr=resolve_ip(JS_GetStringBytes(str)))==INADDR_NONE) { ! 294: p->last_error=ERROR_VALUE; ! 295: dbprintf(TRUE, p, "resolve_ip failed with error %d",ERROR_VALUE); ! 296: *rval = JSVAL_FALSE; ! 297: return(JS_TRUE); ! 298: } ! 299: ! 300: port = js_port(cx,argv[1],p->type); ! 301: ! 302: tv.tv_sec = 10; /* default time-out */ ! 303: ! 304: if(argc>2) /* time-out value specified */ ! 305: js_timeval(cx,argv[2],&tv); ! 306: ! 307: dbprintf(FALSE, p, "connecting to port %u at %s", port, JS_GetStringBytes(str)); ! 308: ! 309: memset(&addr,0,sizeof(addr)); ! 310: addr.sin_addr.s_addr = ip_addr; ! 311: addr.sin_family = AF_INET; ! 312: addr.sin_port = htons(port); ! 313: ! 314: /* always set to nonblocking here */ ! 315: val=1; ! 316: ioctlsocket(p->sock,FIONBIO,&val); ! 317: ! 318: result=connect(p->sock, (struct sockaddr *)&addr, sizeof(addr)); ! 319: ! 320: if(result==SOCKET_ERROR ! 321: && (ERROR_VALUE==EWOULDBLOCK || ERROR_VALUE==EINPROGRESS)) { ! 322: FD_ZERO(&socket_set); ! 323: FD_SET(p->sock,&socket_set); ! 324: if(select(p->sock+1,NULL,&socket_set,NULL,&tv)==1) ! 325: result=0; /* success */ ! 326: } ! 327: ! 328: /* Restore original setting here */ ! 329: ioctlsocket(p->sock,FIONBIO,(ulong*)&(p->nonblocking)); ! 330: ! 331: if(result!=0) { ! 332: p->last_error=ERROR_VALUE; ! 333: dbprintf(TRUE, p, "connect failed with error %d",ERROR_VALUE); ! 334: *rval = JSVAL_FALSE; ! 335: return(JS_TRUE); ! 336: } ! 337: ! 338: p->is_connected = TRUE; ! 339: *rval = JSVAL_TRUE; ! 340: dbprintf(FALSE, p, "connected to port %u at %s", port, JS_GetStringBytes(str)); ! 341: ! 342: return(JS_TRUE); ! 343: } ! 344: ! 345: static JSBool ! 346: js_send(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 347: { ! 348: char* cp; ! 349: int len; ! 350: JSString* str; ! 351: private_t* p; ! 352: ! 353: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 354: JS_ReportError(cx,getprivate_failure,WHERE); ! 355: return(JS_FALSE); ! 356: } ! 357: ! 358: *rval = JSVAL_FALSE; ! 359: ! 360: str = JS_ValueToString(cx, argv[0]); ! 361: cp = JS_GetStringBytes(str); ! 362: len = JS_GetStringLength(str); ! 363: ! 364: if(sendsocket(p->sock,cp,len)==len) { ! 365: dbprintf(FALSE, p, "sent %u bytes",len); ! 366: *rval = JSVAL_TRUE; ! 367: } else { ! 368: p->last_error=ERROR_VALUE; ! 369: dbprintf(TRUE, p, "send of %u bytes failed",len); ! 370: } ! 371: ! 372: return(JS_TRUE); ! 373: } ! 374: ! 375: static JSBool ! 376: js_sendto(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 377: { ! 378: char* cp; ! 379: int len; ! 380: ulong ip_addr; ! 381: ushort port; ! 382: JSString* data_str; ! 383: JSString* ip_str; ! 384: private_t* p; ! 385: SOCKADDR_IN addr; ! 386: ! 387: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 388: JS_ReportError(cx,getprivate_failure,WHERE); ! 389: return(JS_FALSE); ! 390: } ! 391: ! 392: *rval = JSVAL_FALSE; ! 393: ! 394: /* data */ ! 395: data_str = JS_ValueToString(cx, argv[0]); ! 396: cp = JS_GetStringBytes(data_str); ! 397: len = JS_GetStringLength(data_str); ! 398: ! 399: /* address */ ! 400: ip_str = JS_ValueToString(cx, argv[1]); ! 401: dbprintf(FALSE, p, "resolving hostname: %s", JS_GetStringBytes(ip_str)); ! 402: if((ip_addr=resolve_ip(JS_GetStringBytes(ip_str)))==INADDR_NONE) { ! 403: p->last_error=ERROR_VALUE; ! 404: dbprintf(TRUE, p, "resolve_ip failed with error %d",ERROR_VALUE); ! 405: *rval = JSVAL_FALSE; ! 406: return(JS_TRUE); ! 407: } ! 408: ! 409: /* port */ ! 410: port = js_port(cx,argv[2],p->type); ! 411: ! 412: dbprintf(FALSE, p, "sending %d bytes to port %u at %s" ! 413: ,len, port, JS_GetStringBytes(ip_str)); ! 414: ! 415: memset(&addr,0,sizeof(addr)); ! 416: addr.sin_addr.s_addr = ip_addr; ! 417: addr.sin_family = AF_INET; ! 418: addr.sin_port = htons(port); ! 419: ! 420: if(sendto(p->sock,cp,len,0 /* flags */,(SOCKADDR*)&addr,sizeof(addr))==len) { ! 421: dbprintf(FALSE, p, "sent %u bytes",len); ! 422: *rval = JSVAL_TRUE; ! 423: } else { ! 424: p->last_error=ERROR_VALUE; ! 425: dbprintf(TRUE, p, "send of %u bytes failed",len); ! 426: } ! 427: ! 428: return(JS_TRUE); ! 429: } ! 430: ! 431: ! 432: static JSBool ! 433: js_sendfile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 434: { ! 435: char* fname; ! 436: long len; ! 437: int file; ! 438: JSString* str; ! 439: private_t* p; ! 440: ! 441: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 442: JS_ReportError(cx,getprivate_failure,WHERE); ! 443: return(JS_FALSE); ! 444: } ! 445: ! 446: *rval = JSVAL_FALSE; ! 447: ! 448: if((str = JS_ValueToString(cx, argv[0]))==NULL ! 449: || (fname=JS_GetStringBytes(str))==NULL) { ! 450: JS_ReportError(cx,"Failure reading filename"); ! 451: return(JS_FALSE); ! 452: } ! 453: ! 454: if((file=nopen(fname,O_RDONLY|O_BINARY))==-1) ! 455: return(JS_TRUE); ! 456: ! 457: #if 0 ! 458: len=filelength(file); ! 459: /* TODO: Probobly too big for alloca()... also, this is insane. */ ! 460: if((buf=malloc(len))==NULL) { ! 461: close(file); ! 462: return(JS_TRUE); ! 463: } ! 464: if(read(file,buf,len)!=len) { ! 465: free(buf); ! 466: close(file); ! 467: return(JS_TRUE); ! 468: } ! 469: close(file); ! 470: ! 471: if(sendsocket(p->sock,buf,len)==len) { ! 472: dbprintf(FALSE, p, "sent %u bytes",len); ! 473: *rval = JSVAL_TRUE; ! 474: } else { ! 475: p->last_error=ERROR_VALUE; ! 476: dbprintf(TRUE, p, "send of %u bytes failed",len); ! 477: } ! 478: free(buf); ! 479: #else ! 480: len = sendfilesocket(p->sock, file, NULL, 0); ! 481: if(len > 0) { ! 482: dbprintf(FALSE, p, "sent %u bytes",len); ! 483: *rval = JSVAL_TRUE; ! 484: } else { ! 485: p->last_error=ERROR_VALUE; ! 486: dbprintf(TRUE, p, "send of %s failed",fname); ! 487: } ! 488: #endif ! 489: ! 490: return(JS_TRUE); ! 491: } ! 492: ! 493: static JSBool ! 494: js_sendbin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 495: { ! 496: BYTE b; ! 497: WORD w; ! 498: DWORD l; ! 499: int32 val=0; ! 500: size_t wr=0; ! 501: size_t size=sizeof(DWORD); ! 502: private_t* p; ! 503: ! 504: *rval = JSVAL_FALSE; ! 505: ! 506: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 507: JS_ReportError(cx,getprivate_failure,WHERE); ! 508: return(JS_FALSE); ! 509: } ! 510: ! 511: JS_ValueToInt32(cx,argv[0],&val); ! 512: if(argc>1) ! 513: JS_ValueToInt32(cx,argv[1],(int32*)&size); ! 514: ! 515: switch(size) { ! 516: case sizeof(BYTE): ! 517: b = (BYTE)val; ! 518: wr=sendsocket(p->sock,&b,size); ! 519: break; ! 520: case sizeof(WORD): ! 521: w = (WORD)val; ! 522: if(p->network_byte_order) ! 523: w=htons(w); ! 524: wr=sendsocket(p->sock,(BYTE*)&w,size); ! 525: break; ! 526: case sizeof(DWORD): ! 527: l = val; ! 528: if(p->network_byte_order) ! 529: l=htonl(l); ! 530: wr=sendsocket(p->sock,(BYTE*)&l,size); ! 531: break; ! 532: default: ! 533: /* unknown size */ ! 534: dbprintf(TRUE, p, "unsupported binary write size: %d",size); ! 535: break; ! 536: } ! 537: if(wr==size) { ! 538: dbprintf(FALSE, p, "sent %u bytes (binary)",size); ! 539: *rval = JSVAL_TRUE; ! 540: } else { ! 541: p->last_error=ERROR_VALUE; ! 542: dbprintf(TRUE, p, "send of %u bytes (binary) failed",size); ! 543: } ! 544: ! 545: return(JS_TRUE); ! 546: } ! 547: ! 548: ! 549: static JSBool ! 550: js_recv(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 551: { ! 552: char* buf; ! 553: int32 len=512; ! 554: JSString* str; ! 555: ! 556: private_t* p; ! 557: ! 558: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 559: JS_ReportError(cx,getprivate_failure,WHERE); ! 560: return(JS_FALSE); ! 561: } ! 562: ! 563: if(argc) ! 564: JS_ValueToInt32(cx,argv[0],&len); ! 565: ! 566: if((buf=(char*)alloca(len+1))==NULL) { ! 567: JS_ReportError(cx,"Error allocating %u bytes",len+1); ! 568: return(JS_FALSE); ! 569: } ! 570: ! 571: len = recv(p->sock,buf,len,0); ! 572: if(len<0) { ! 573: p->last_error=ERROR_VALUE; ! 574: *rval = JSVAL_NULL; ! 575: return(JS_TRUE); ! 576: } ! 577: buf[len]=0; ! 578: ! 579: str = JS_NewStringCopyN(cx, buf, len); ! 580: if(str==NULL) ! 581: return(JS_FALSE); ! 582: ! 583: *rval = STRING_TO_JSVAL(str); ! 584: dbprintf(FALSE, p, "received %u bytes",len); ! 585: ! 586: return(JS_TRUE); ! 587: } ! 588: ! 589: static JSBool ! 590: js_recvfrom(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 591: { ! 592: char* buf; ! 593: char ip_addr[64]; ! 594: char port[32]; ! 595: int rd=0; ! 596: int32 len=512; ! 597: uintN n; ! 598: BOOL binary=FALSE; ! 599: BYTE b; ! 600: WORD w; ! 601: DWORD l; ! 602: jsval data_val=JSVAL_NULL; ! 603: JSString* str; ! 604: JSObject* retobj; ! 605: SOCKADDR_IN addr; ! 606: socklen_t addrlen; ! 607: ! 608: private_t* p; ! 609: ! 610: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 611: JS_ReportError(cx,getprivate_failure,WHERE); ! 612: return(JS_FALSE); ! 613: } ! 614: ! 615: *rval = JSVAL_NULL; ! 616: ! 617: for(n=0;n<argc;n++) { ! 618: if(JSVAL_IS_BOOLEAN(argv[n])) { ! 619: binary=JSVAL_TO_BOOLEAN(argv[n]); ! 620: if(binary) ! 621: len=sizeof(DWORD); ! 622: } else ! 623: JS_ValueToInt32(cx,argv[n],&len); ! 624: } ! 625: ! 626: addrlen=sizeof(addr); ! 627: ! 628: if(binary) { /* Binary/Integer Data */ ! 629: ! 630: switch(len) { ! 631: case sizeof(BYTE): ! 632: if((rd=recvfrom(p->sock,&b,len,0,(SOCKADDR*)&addr,&addrlen))==len) ! 633: data_val = INT_TO_JSVAL(b); ! 634: break; ! 635: case sizeof(WORD): ! 636: if((rd=recvfrom(p->sock,(BYTE*)&w,len,0,(SOCKADDR*)&addr,&addrlen))==len) { ! 637: if(p->network_byte_order) ! 638: w=ntohs(w); ! 639: data_val = INT_TO_JSVAL(w); ! 640: } ! 641: break; ! 642: case sizeof(DWORD): ! 643: if((rd=recvfrom(p->sock,(BYTE*)&l,len,0,(SOCKADDR*)&addr,&addrlen))==len) { ! 644: if(p->network_byte_order) ! 645: l=ntohl(l); ! 646: JS_NewNumberValue(cx,l,&data_val); ! 647: } ! 648: break; ! 649: } ! 650: ! 651: if(rd!=len) { ! 652: p->last_error=ERROR_VALUE; ! 653: return(JS_TRUE); ! 654: } ! 655: ! 656: } else { /* String Data */ ! 657: ! 658: if((buf=(char*)alloca(len+1))==NULL) { ! 659: JS_ReportError(cx,"Error allocating %u bytes",len+1); ! 660: return(JS_FALSE); ! 661: } ! 662: ! 663: len = recvfrom(p->sock,buf,len,0,(SOCKADDR*)&addr,&addrlen); ! 664: if(len<0) { ! 665: p->last_error=ERROR_VALUE; ! 666: return(JS_TRUE); ! 667: } ! 668: buf[len]=0; ! 669: ! 670: str = JS_NewStringCopyN(cx, buf, len); ! 671: ! 672: if(str==NULL) ! 673: return(JS_FALSE); ! 674: ! 675: data_val = STRING_TO_JSVAL(str); ! 676: } ! 677: ! 678: ! 679: if((retobj=JS_NewObject(cx,NULL,NULL,obj))==NULL) { ! 680: JS_ReportError(cx,"JS_NewObject failed"); ! 681: return(JS_FALSE); ! 682: } ! 683: ! 684: JS_DefineProperty(cx, retobj, "data" ! 685: ,data_val ! 686: ,NULL,NULL,JSPROP_ENUMERATE); ! 687: ! 688: sprintf(port,"%u",ntohs(addr.sin_port)); ! 689: if((str=JS_NewStringCopyZ(cx,port))==NULL) ! 690: return(JS_FALSE); ! 691: JS_DefineProperty(cx, retobj, "port" ! 692: ,STRING_TO_JSVAL(str) ! 693: ,NULL,NULL,JSPROP_ENUMERATE); ! 694: ! 695: SAFECOPY(ip_addr,inet_ntoa(addr.sin_addr)); ! 696: if((str=JS_NewStringCopyZ(cx,ip_addr))==NULL) ! 697: return(JS_FALSE); ! 698: JS_DefineProperty(cx, retobj, "ip_address" ! 699: ,STRING_TO_JSVAL(str) ! 700: ,NULL,NULL,JSPROP_ENUMERATE); ! 701: ! 702: *rval = OBJECT_TO_JSVAL(retobj); ! 703: ! 704: dbprintf(FALSE, p, "received %u bytes from %s:%s",len,ip_addr,port); ! 705: ! 706: return(JS_TRUE); ! 707: } ! 708: ! 709: ! 710: static JSBool ! 711: js_peek(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 712: { ! 713: char* buf; ! 714: int32 len=512; ! 715: JSString* str; ! 716: ! 717: private_t* p; ! 718: ! 719: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 720: JS_ReportError(cx,getprivate_failure,WHERE); ! 721: return(JS_FALSE); ! 722: } ! 723: ! 724: if(argc) ! 725: JS_ValueToInt32(cx,argv[0],&len); ! 726: ! 727: if((buf=(char*)alloca(len+1))==NULL) { ! 728: JS_ReportError(cx,"Error allocating %u bytes",len+1); ! 729: return(JS_FALSE); ! 730: } ! 731: len = recv(p->sock,buf,len,MSG_PEEK); ! 732: if(len<0) { ! 733: p->last_error=ERROR_VALUE; ! 734: *rval = JSVAL_NULL; ! 735: return(JS_TRUE); ! 736: } ! 737: buf[len]=0; ! 738: ! 739: str = JS_NewStringCopyN(cx, buf, len); ! 740: if(str==NULL) ! 741: return(JS_FALSE); ! 742: ! 743: *rval = STRING_TO_JSVAL(str); ! 744: dbprintf(FALSE, p, "received %u bytes, lasterror=%d" ! 745: ,len,ERROR_VALUE); ! 746: ! 747: return(JS_TRUE); ! 748: } ! 749: ! 750: static JSBool ! 751: js_recvline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 752: { ! 753: char ch; ! 754: char* buf; ! 755: int i; ! 756: int32 len=512; ! 757: BOOL rd; ! 758: time_t start; ! 759: int32 timeout=30; /* seconds */ ! 760: JSString* str; ! 761: private_t* p; ! 762: ! 763: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 764: JS_ReportError(cx,getprivate_failure,WHERE); ! 765: return(JS_FALSE); ! 766: } ! 767: ! 768: if(argc) ! 769: JS_ValueToInt32(cx,argv[0],&len); ! 770: ! 771: if((buf=(char*)alloca(len+1))==NULL) { ! 772: JS_ReportError(cx,"Error allocating %u bytes",len+1); ! 773: return(JS_FALSE); ! 774: } ! 775: ! 776: if(argc>1) ! 777: JS_ValueToInt32(cx,argv[1],(int32*)&timeout); ! 778: ! 779: start=time(NULL); ! 780: for(i=0;i<len;) { ! 781: ! 782: if(!socket_check(p->sock,&rd,NULL,1000)) { ! 783: p->last_error=ERROR_VALUE; ! 784: break; /* disconnected */ ! 785: } ! 786: ! 787: if(!rd) { ! 788: if(time(NULL)-start>timeout) { ! 789: dbprintf(FALSE, p, "recvline timeout (received: %d)",i); ! 790: *rval = JSVAL_NULL; ! 791: return(JS_TRUE); /* time-out */ ! 792: } ! 793: continue; /* no data */ ! 794: } ! 795: ! 796: if(recv(p->sock, &ch, 1, 0)!=1) { ! 797: p->last_error=ERROR_VALUE; ! 798: break; ! 799: } ! 800: ! 801: if(ch=='\n' /* && i>=1 */) /* Mar-9-2003: terminate on sole LF */ ! 802: break; ! 803: ! 804: buf[i++]=ch; ! 805: } ! 806: if(i>0 && buf[i-1]=='\r') ! 807: buf[i-1]=0; ! 808: else ! 809: buf[i]=0; ! 810: ! 811: str = JS_NewStringCopyZ(cx, buf); ! 812: if(str==NULL) ! 813: return(JS_FALSE); ! 814: ! 815: *rval = STRING_TO_JSVAL(str); ! 816: dbprintf(FALSE, p, "received %u bytes (recvline) lasterror=%d" ! 817: ,i,ERROR_VALUE); ! 818: ! 819: return(JS_TRUE); ! 820: } ! 821: ! 822: static JSBool ! 823: js_recvbin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 824: { ! 825: BYTE b; ! 826: WORD w; ! 827: DWORD l; ! 828: int size=sizeof(DWORD); ! 829: int rd=0; ! 830: private_t* p; ! 831: ! 832: *rval = INT_TO_JSVAL(-1); ! 833: ! 834: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 835: JS_ReportError(cx,getprivate_failure,WHERE); ! 836: return(JS_FALSE); ! 837: } ! 838: ! 839: if(argc) ! 840: JS_ValueToInt32(cx,argv[0],(int32*)&size); ! 841: ! 842: switch(size) { ! 843: case sizeof(BYTE): ! 844: if((rd=recv(p->sock,&b,size,0))==size) ! 845: *rval = INT_TO_JSVAL(b); ! 846: break; ! 847: case sizeof(WORD): ! 848: if((rd=recv(p->sock,(BYTE*)&w,size,0))==size) { ! 849: if(p->network_byte_order) ! 850: w=ntohs(w); ! 851: *rval = INT_TO_JSVAL(w); ! 852: } ! 853: break; ! 854: case sizeof(DWORD): ! 855: if((rd=recv(p->sock,(BYTE*)&l,size,0))==size) { ! 856: if(p->network_byte_order) ! 857: l=ntohl(l); ! 858: JS_NewNumberValue(cx,l,rval); ! 859: } ! 860: break; ! 861: } ! 862: ! 863: if(rd!=size) ! 864: p->last_error=ERROR_VALUE; ! 865: ! 866: return(JS_TRUE); ! 867: } ! 868: ! 869: ! 870: static JSBool ! 871: js_getsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 872: { ! 873: int opt; ! 874: int level; ! 875: int val; ! 876: private_t* p; ! 877: LINGER linger; ! 878: void* vp=&val; ! 879: socklen_t len=sizeof(val); ! 880: ! 881: *rval = INT_TO_JSVAL(-1); ! 882: ! 883: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 884: JS_ReportError(cx,getprivate_failure,WHERE); ! 885: return(JS_FALSE); ! 886: } ! 887: ! 888: if((opt = getSocketOptionByName(JS_GetStringBytes(JS_ValueToString(cx,argv[0])),&level)) == -1) ! 889: return(JS_TRUE); ! 890: ! 891: if(opt == SO_LINGER) { ! 892: vp=&linger; ! 893: len=sizeof(linger); ! 894: } ! 895: if(getsockopt(p->sock, level, opt, vp, &len)==0) { ! 896: if(opt == SO_LINGER) { ! 897: if(linger.l_onoff==TRUE) ! 898: val = linger.l_linger; ! 899: else ! 900: val = 0; ! 901: } ! 902: JS_NewNumberValue(cx,val,rval); ! 903: } else { ! 904: p->last_error=ERROR_VALUE; ! 905: dbprintf(TRUE, p, "error %d getting option %d" ! 906: ,ERROR_VALUE,opt); ! 907: } ! 908: ! 909: return(JS_TRUE); ! 910: } ! 911: ! 912: ! 913: static JSBool ! 914: js_setsockopt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 915: { ! 916: int opt; ! 917: int level; ! 918: int32 val=1; ! 919: private_t* p; ! 920: LINGER linger; ! 921: void* vp=&val; ! 922: socklen_t len=sizeof(val); ! 923: ! 924: ! 925: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 926: JS_ReportError(cx,getprivate_failure,WHERE); ! 927: return(JS_FALSE); ! 928: } ! 929: ! 930: opt = getSocketOptionByName(JS_GetStringBytes(JS_ValueToString(cx,argv[0])),&level); ! 931: JS_ValueToInt32(cx,argv[1],&val); ! 932: ! 933: if(opt == SO_LINGER) { ! 934: if(val) { ! 935: linger.l_onoff = TRUE; ! 936: linger.l_linger = (ushort)val; ! 937: } else { ! 938: ZERO_VAR(linger); ! 939: } ! 940: vp=&linger; ! 941: len=sizeof(linger); ! 942: } ! 943: ! 944: *rval = BOOLEAN_TO_JSVAL( ! 945: setsockopt(p->sock, level, opt, vp, len)==0); ! 946: p->last_error=ERROR_VALUE; ! 947: ! 948: return(JS_TRUE); ! 949: } ! 950: ! 951: static JSBool ! 952: js_ioctlsocket(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 953: { ! 954: int32 cmd; ! 955: int32 arg=0; ! 956: private_t* p; ! 957: ! 958: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 959: JS_ReportError(cx,getprivate_failure,WHERE); ! 960: return(JS_FALSE); ! 961: } ! 962: ! 963: JS_ValueToInt32(cx,argv[0],&cmd); ! 964: if(argc>1) ! 965: JS_ValueToInt32(cx,argv[1],&arg); ! 966: ! 967: if(ioctlsocket(p->sock,cmd,(ulong*)&arg)==0) ! 968: JS_NewNumberValue(cx,arg,rval); ! 969: else ! 970: *rval = INT_TO_JSVAL(-1); ! 971: ! 972: p->last_error=ERROR_VALUE; ! 973: ! 974: return(JS_TRUE); ! 975: } ! 976: ! 977: static JSBool ! 978: js_poll(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 979: { ! 980: private_t* p; ! 981: BOOL poll_for_write=FALSE; ! 982: fd_set socket_set; ! 983: fd_set* rd_set=NULL; ! 984: fd_set* wr_set=NULL; ! 985: uintN argn; ! 986: int result; ! 987: struct timeval tv = {0, 0}; ! 988: ! 989: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 990: JS_ReportError(cx,getprivate_failure,WHERE); ! 991: return(JS_FALSE); ! 992: } ! 993: ! 994: if(p->sock==INVALID_SOCKET) { ! 995: dbprintf(TRUE, p, "INVALID SOCKET in call to poll"); ! 996: *rval = INT_TO_JSVAL(-1); ! 997: return(JS_TRUE); ! 998: } ! 999: ! 1000: for(argn=0;argn<argc;argn++) { ! 1001: if(JSVAL_IS_BOOLEAN(argv[argn])) ! 1002: poll_for_write=JSVAL_TO_BOOLEAN(argv[argn]); ! 1003: else if(JSVAL_IS_NUMBER(argv[argn])) ! 1004: js_timeval(cx,argv[argn],&tv); ! 1005: } ! 1006: ! 1007: FD_ZERO(&socket_set); ! 1008: FD_SET(p->sock,&socket_set); ! 1009: if(poll_for_write) ! 1010: wr_set=&socket_set; ! 1011: else ! 1012: rd_set=&socket_set; ! 1013: ! 1014: result = select(p->sock+1,rd_set,wr_set,NULL,&tv); ! 1015: ! 1016: p->last_error=ERROR_VALUE; ! 1017: ! 1018: dbprintf(FALSE, p, "poll: select returned %d (errno %d)" ! 1019: ,result,p->last_error); ! 1020: ! 1021: *rval = INT_TO_JSVAL(result); ! 1022: ! 1023: return(JS_TRUE); ! 1024: } ! 1025: ! 1026: ! 1027: /* Socket Object Properites */ ! 1028: enum { ! 1029: SOCK_PROP_LAST_ERROR ! 1030: ,SOCK_PROP_IS_CONNECTED ! 1031: ,SOCK_PROP_IS_WRITEABLE ! 1032: ,SOCK_PROP_DATA_WAITING ! 1033: ,SOCK_PROP_NREAD ! 1034: ,SOCK_PROP_DEBUG ! 1035: ,SOCK_PROP_DESCRIPTOR ! 1036: ,SOCK_PROP_NONBLOCKING ! 1037: ,SOCK_PROP_LOCAL_IP ! 1038: ,SOCK_PROP_LOCAL_PORT ! 1039: ,SOCK_PROP_REMOTE_IP ! 1040: ,SOCK_PROP_REMOTE_PORT ! 1041: ,SOCK_PROP_TYPE ! 1042: ,SOCK_PROP_NETWORK_ORDER ! 1043: ! 1044: }; ! 1045: ! 1046: #ifdef BUILD_JSDOCS ! 1047: static char* socket_prop_desc[] = { ! 1048: "error status for the last socket operation that failed - <small>READ ONLY</small>" ! 1049: ,"<i>true</i> if socket is in a connected state - <small>READ ONLY</small>" ! 1050: ,"<i>true</i> if socket can accept written data - <small>READ ONLY</small>" ! 1051: ,"<i>true</i> if data is waiting to be read from socket - <small>READ ONLY</small>" ! 1052: ,"number of bytes waiting to be read - <small>READ ONLY</small>" ! 1053: ,"enable debug logging" ! 1054: ,"socket descriptor (advanced uses only)" ! 1055: ,"use non-blocking operation (default is <i>false</i>)" ! 1056: ,"local IP address (string in dotted-decimal format)" ! 1057: ,"local TCP or UDP port number" ! 1058: ,"remote IP address (string in dotted-decimal format)" ! 1059: ,"remote TCP or UDP port number" ! 1060: ,"socket type, <tt>SOCK_STREAM</tt> (TCP) or <tt>SOCK_DGRAM</tt> (UDP)" ! 1061: ,"<i>true</i> if binary data is to be sent in Network Byte Order (big end first), default is <i>true</i>" ! 1062: /* statically-defined properties: */ ! 1063: ,"array of socket option names supported by the current platform" ! 1064: ,NULL ! 1065: }; ! 1066: #endif ! 1067: ! 1068: static JSBool js_socket_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ! 1069: { ! 1070: jsint tiny; ! 1071: private_t* p; ! 1072: ! 1073: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 1074: JS_ReportError(cx,getprivate_failure,WHERE); ! 1075: return(JS_FALSE); ! 1076: } ! 1077: ! 1078: tiny = JSVAL_TO_INT(id); ! 1079: ! 1080: dbprintf(FALSE, p, "setting property %d",tiny); ! 1081: ! 1082: switch(tiny) { ! 1083: case SOCK_PROP_DEBUG: ! 1084: JS_ValueToBoolean(cx,*vp,&(p->debug)); ! 1085: break; ! 1086: case SOCK_PROP_DESCRIPTOR: ! 1087: JS_ValueToInt32(cx,*vp,(int32*)&(p->sock)); ! 1088: break; ! 1089: case SOCK_PROP_LAST_ERROR: ! 1090: JS_ValueToInt32(cx,*vp,(int32*)&(p->last_error)); ! 1091: break; ! 1092: case SOCK_PROP_NONBLOCKING: ! 1093: JS_ValueToBoolean(cx,*vp,&(p->nonblocking)); ! 1094: ioctlsocket(p->sock,FIONBIO,(ulong*)&(p->nonblocking)); ! 1095: break; ! 1096: case SOCK_PROP_NETWORK_ORDER: ! 1097: JS_ValueToBoolean(cx,*vp,&(p->network_byte_order)); ! 1098: break; ! 1099: } ! 1100: ! 1101: return(JS_TRUE); ! 1102: } ! 1103: ! 1104: static JSBool js_socket_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp) ! 1105: { ! 1106: jsint tiny; ! 1107: ulong cnt; ! 1108: BOOL rd; ! 1109: BOOL wr; ! 1110: private_t* p; ! 1111: socklen_t addr_len; ! 1112: SOCKADDR_IN addr; ! 1113: JSString* js_str; ! 1114: ! 1115: if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) { ! 1116: JS_ReportError(cx,getprivate_failure,WHERE); ! 1117: return(JS_FALSE); ! 1118: } ! 1119: ! 1120: tiny = JSVAL_TO_INT(id); ! 1121: ! 1122: #if 0 /* just too much */ ! 1123: dbprintf(FALSE, p, "getting property %d",tiny); ! 1124: #endif ! 1125: ! 1126: switch(tiny) { ! 1127: case SOCK_PROP_LAST_ERROR: ! 1128: *vp = INT_TO_JSVAL(p->last_error); ! 1129: break; ! 1130: case SOCK_PROP_IS_CONNECTED: ! 1131: if(!p->is_connected && !p->external) ! 1132: *vp = JSVAL_FALSE; ! 1133: else ! 1134: *vp = BOOLEAN_TO_JSVAL(socket_check(p->sock,NULL,NULL,0)); ! 1135: break; ! 1136: case SOCK_PROP_IS_WRITEABLE: ! 1137: socket_check(p->sock,NULL,&wr,0); ! 1138: *vp = BOOLEAN_TO_JSVAL(wr); ! 1139: break; ! 1140: case SOCK_PROP_DATA_WAITING: ! 1141: socket_check(p->sock,&rd,NULL,0); ! 1142: *vp = BOOLEAN_TO_JSVAL(rd); ! 1143: break; ! 1144: case SOCK_PROP_NREAD: ! 1145: cnt=0; ! 1146: if(ioctlsocket(p->sock, FIONREAD, &cnt)==0) ! 1147: JS_NewNumberValue(cx,cnt,vp); ! 1148: else ! 1149: *vp = JSVAL_ZERO; ! 1150: break; ! 1151: case SOCK_PROP_DEBUG: ! 1152: *vp = INT_TO_JSVAL(p->debug); ! 1153: break; ! 1154: case SOCK_PROP_DESCRIPTOR: ! 1155: *vp = INT_TO_JSVAL(p->sock); ! 1156: break; ! 1157: case SOCK_PROP_NONBLOCKING: ! 1158: *vp = BOOLEAN_TO_JSVAL(p->nonblocking); ! 1159: break; ! 1160: case SOCK_PROP_LOCAL_IP: ! 1161: addr_len = sizeof(addr); ! 1162: if(getsockname(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { ! 1163: p->last_error=ERROR_VALUE; ! 1164: *vp = JSVAL_VOID; ! 1165: } else { ! 1166: if((js_str=JS_NewStringCopyZ(cx,inet_ntoa(addr.sin_addr)))==NULL) ! 1167: return(JS_FALSE); ! 1168: *vp = STRING_TO_JSVAL(js_str); ! 1169: } ! 1170: break; ! 1171: case SOCK_PROP_LOCAL_PORT: ! 1172: addr_len = sizeof(addr); ! 1173: if(getsockname(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { ! 1174: p->last_error=ERROR_VALUE; ! 1175: *vp = JSVAL_ZERO; ! 1176: } else ! 1177: *vp = INT_TO_JSVAL(ntohs(addr.sin_port)); ! 1178: break; ! 1179: case SOCK_PROP_REMOTE_IP: ! 1180: addr_len = sizeof(addr); ! 1181: if(getpeername(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { ! 1182: p->last_error=ERROR_VALUE; ! 1183: *vp = JSVAL_VOID; ! 1184: } else { ! 1185: if((js_str=JS_NewStringCopyZ(cx,inet_ntoa(addr.sin_addr)))==NULL) ! 1186: return(JS_FALSE); ! 1187: *vp = STRING_TO_JSVAL(js_str); ! 1188: } ! 1189: break; ! 1190: case SOCK_PROP_REMOTE_PORT: ! 1191: addr_len = sizeof(addr); ! 1192: if(getpeername(p->sock, (struct sockaddr *)&addr,&addr_len)!=0) { ! 1193: p->last_error=ERROR_VALUE; ! 1194: *vp = JSVAL_ZERO; ! 1195: } else ! 1196: *vp = INT_TO_JSVAL(ntohs(addr.sin_port)); ! 1197: break; ! 1198: case SOCK_PROP_TYPE: ! 1199: *vp = INT_TO_JSVAL(p->type); ! 1200: break; ! 1201: case SOCK_PROP_NETWORK_ORDER: ! 1202: *vp = BOOLEAN_TO_JSVAL(p->network_byte_order); ! 1203: break; ! 1204: ! 1205: } ! 1206: ! 1207: return(TRUE); ! 1208: } ! 1209: ! 1210: #define SOCK_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY ! 1211: ! 1212: static jsSyncPropertySpec js_socket_properties[] = { ! 1213: /* name ,tinyid ,flags, ver */ ! 1214: ! 1215: { "error" ,SOCK_PROP_LAST_ERROR ,SOCK_PROP_FLAGS, 311 }, ! 1216: { "last_error" ,SOCK_PROP_LAST_ERROR ,JSPROP_READONLY, 310 }, /* alias */ ! 1217: { "is_connected" ,SOCK_PROP_IS_CONNECTED ,SOCK_PROP_FLAGS, 310 }, ! 1218: { "is_writeable" ,SOCK_PROP_IS_WRITEABLE ,SOCK_PROP_FLAGS, 311 }, ! 1219: { "is_writable" ,SOCK_PROP_IS_WRITEABLE ,JSPROP_READONLY, 312 }, /* alias */ ! 1220: { "data_waiting" ,SOCK_PROP_DATA_WAITING ,SOCK_PROP_FLAGS, 310 }, ! 1221: { "nread" ,SOCK_PROP_NREAD ,SOCK_PROP_FLAGS, 310 }, ! 1222: { "debug" ,SOCK_PROP_DEBUG ,JSPROP_ENUMERATE, 310 }, ! 1223: { "descriptor" ,SOCK_PROP_DESCRIPTOR ,JSPROP_ENUMERATE, 310 }, ! 1224: { "nonblocking" ,SOCK_PROP_NONBLOCKING ,JSPROP_ENUMERATE, 310 }, ! 1225: { "local_ip_address" ,SOCK_PROP_LOCAL_IP ,SOCK_PROP_FLAGS, 310 }, ! 1226: { "local_port" ,SOCK_PROP_LOCAL_PORT ,SOCK_PROP_FLAGS, 310 }, ! 1227: { "remote_ip_address" ,SOCK_PROP_REMOTE_IP ,SOCK_PROP_FLAGS, 310 }, ! 1228: { "remote_port" ,SOCK_PROP_REMOTE_PORT ,SOCK_PROP_FLAGS, 310 }, ! 1229: { "type" ,SOCK_PROP_TYPE ,SOCK_PROP_FLAGS, 310 }, ! 1230: { "network_byte_order",SOCK_PROP_NETWORK_ORDER,JSPROP_ENUMERATE, 311 }, ! 1231: {0} ! 1232: }; ! 1233: ! 1234: static JSClass js_socket_class = { ! 1235: "Socket" /* name */ ! 1236: ,JSCLASS_HAS_PRIVATE /* flags */ ! 1237: ,JS_PropertyStub /* addProperty */ ! 1238: ,JS_PropertyStub /* delProperty */ ! 1239: ,js_socket_get /* getProperty */ ! 1240: ,js_socket_set /* setProperty */ ! 1241: ,JS_EnumerateStub /* enumerate */ ! 1242: ,JS_ResolveStub /* resolve */ ! 1243: ,JS_ConvertStub /* convert */ ! 1244: ,js_finalize_socket /* finalize */ ! 1245: }; ! 1246: ! 1247: static jsSyncMethodSpec js_socket_functions[] = { ! 1248: {"close", js_close, 0, JSTYPE_VOID, "" ! 1249: ,JSDOCSTR("close (shutdown) the socket immediately") ! 1250: ,310 ! 1251: }, ! 1252: {"bind", js_bind, 0, JSTYPE_BOOLEAN, JSDOCSTR("[port] [,ip_address]") ! 1253: ,JSDOCSTR("bind socket to a TCP or UDP <i>port</i> (number or service name), " ! 1254: "optionally specifying a network interface (via <i>ip_address</i>)") ! 1255: ,311 ! 1256: }, ! 1257: {"connect", js_connect, 2, JSTYPE_BOOLEAN, JSDOCSTR("host, port [,timeout=<tt>10.0</tt>]") ! 1258: ,JSDOCSTR("connect to a remote port (number or service name) on the specified host (IP address or host name)" ! 1259: ", default <i>timeout</i> value is <i>10.0</i> (seconds)") ! 1260: ,311 ! 1261: }, ! 1262: {"listen", js_listen, 0, JSTYPE_BOOLEAN, JSDOCSTR("") ! 1263: ,JSDOCSTR("place socket in a state to listen for incoming connections (use before an accept)") ! 1264: ,310 ! 1265: }, ! 1266: {"accept", js_accept, 0, JSTYPE_OBJECT, JSDOCSTR("") ! 1267: ,JSDOCSTR("accept an incoming connection, returns a new <i>Socket</i> object representing the new connection") ! 1268: ,310 ! 1269: }, ! 1270: {"write", js_send, 1, JSTYPE_ALIAS }, ! 1271: {"send", js_send, 1, JSTYPE_BOOLEAN, JSDOCSTR("data") ! 1272: ,JSDOCSTR("send a string (AKA write)") ! 1273: ,310 ! 1274: }, ! 1275: {"sendto", js_sendto, 3, JSTYPE_BOOLEAN, JSDOCSTR("data, address, port") ! 1276: ,JSDOCSTR("send data to a specific host (IP address or host name) and port (number or service name), for UDP sockets") ! 1277: ,310 ! 1278: }, ! 1279: {"sendfile", js_sendfile, 1, JSTYPE_BOOLEAN, JSDOCSTR("path/filename") ! 1280: ,JSDOCSTR("send an entire file over the socket") ! 1281: ,310 ! 1282: }, ! 1283: {"writeBin", js_sendbin, 1, JSTYPE_ALIAS }, ! 1284: {"sendBin", js_sendbin, 1, JSTYPE_BOOLEAN, JSDOCSTR("value [,bytes=<tt>4</tt>]") ! 1285: ,JSDOCSTR("send a binary integer over the socket, default number of bytes is 4 (32-bits)") ! 1286: ,311 ! 1287: }, ! 1288: {"read", js_recv, 1, JSTYPE_ALIAS }, ! 1289: {"recv", js_recv, 1, JSTYPE_STRING, JSDOCSTR("[maxlen=<tt>512</tt>]") ! 1290: ,JSDOCSTR("receive a string, default maxlen is 512 characters (AKA read)") ! 1291: ,310 ! 1292: }, ! 1293: {"peek", js_peek, 0, JSTYPE_STRING, JSDOCSTR("[maxlen=<tt>512</tt>]") ! 1294: ,JSDOCSTR("receive a string, default maxlen is 512 characters, leaves string in receive buffer") ! 1295: ,310 ! 1296: }, ! 1297: {"readline", js_recvline, 0, JSTYPE_ALIAS }, ! 1298: {"readln", js_recvline, 0, JSTYPE_ALIAS }, ! 1299: {"recvline", js_recvline, 0, JSTYPE_STRING, JSDOCSTR("[maxlen=<tt>512</tt>] [,timeout=<tt>30.0</tt>]") ! 1300: ,JSDOCSTR("receive a line-feed terminated string, default maxlen is 512 characters, default timeout is 30 seconds (AKA readline and readln)") ! 1301: ,310 ! 1302: }, ! 1303: {"recvfrom", js_recvfrom, 0, JSTYPE_OBJECT, JSDOCSTR("[binary=<tt>false</tt>] [,maxlen=<tt>512</tt> or int_size=<tt>4</tt>]") ! 1304: ,JSDOCSTR("receive data (string or integer) from a socket (typically UDP)" ! 1305: "<p>returns object with <i>ip_address</i> and <i>port</i> of sender along with <i>data</i> properties" ! 1306: "<p><i>binary</i> defaults to <i>false</i>, <i>maxlen</i> defaults to 512 chars, <i>int_size</i> defaults to 4 bytes (32-bits)") ! 1307: ,311 ! 1308: }, ! 1309: {"readBin", js_recvbin, 0, JSTYPE_ALIAS }, ! 1310: {"recvBin", js_recvbin, 0, JSTYPE_NUMBER, JSDOCSTR("[bytes=<tt>4</tt>]") ! 1311: ,JSDOCSTR("receive a binary integer from the socket, default number of bytes is 4 (32-bits)") ! 1312: ,311 ! 1313: }, ! 1314: {"getoption", js_getsockopt, 1, JSTYPE_NUMBER, JSDOCSTR("option") ! 1315: ,JSDOCSTR("get socket option value, option may be socket option name " ! 1316: "(see <tt>sockopts</tt> in <tt>sockdefs.js</tt>) or number") ! 1317: ,310 ! 1318: }, ! 1319: {"setoption", js_setsockopt, 2, JSTYPE_BOOLEAN, JSDOCSTR("option, value") ! 1320: ,JSDOCSTR("set socket option value, option may be socket option name " ! 1321: "(see <tt>sockopts</tt> in <tt>sockdefs.js</tt>) or number") ! 1322: ,310 ! 1323: }, ! 1324: {"ioctl", js_ioctlsocket, 1, JSTYPE_NUMBER, JSDOCSTR("command [,argument=<tt>0</tt>]") ! 1325: ,JSDOCSTR("send socket IOCTL (advanced)") ! 1326: ,310 ! 1327: }, ! 1328: {"poll", js_poll, 1, JSTYPE_NUMBER, JSDOCSTR("[timeout=<tt>0</tt>] [,write=<tt>false</tt>]") ! 1329: ,JSDOCSTR("poll socket for read or write ability (default is <i>read</i>), " ! 1330: "default timeout value is 0.0 seconds (immediate timeout)") ! 1331: ,310 ! 1332: }, ! 1333: {0} ! 1334: }; ! 1335: ! 1336: static BOOL js_DefineSocketOptionsArray(JSContext *cx, JSObject *obj, int type) ! 1337: { ! 1338: size_t i; ! 1339: size_t count=0; ! 1340: jsval val; ! 1341: JSObject* array; ! 1342: socket_option_t* options; ! 1343: ! 1344: if((options=getSocketOptionList())==NULL) ! 1345: return(FALSE); ! 1346: ! 1347: if((array=JS_NewArrayObject(cx, 0, NULL))==NULL) ! 1348: return(FALSE); ! 1349: ! 1350: if(!JS_DefineProperty(cx, obj, "option_list", OBJECT_TO_JSVAL(array) ! 1351: , NULL, NULL, JSPROP_ENUMERATE)) ! 1352: return(FALSE); ! 1353: ! 1354: for(i=0; options[i].name!=NULL; i++) { ! 1355: if(options[i].type && options[i].type!=type) ! 1356: continue; ! 1357: val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,options[i].name)); ! 1358: JS_SetElement(cx, array, count++, &val); ! 1359: } ! 1360: return(TRUE); ! 1361: } ! 1362: ! 1363: /* Socket Constructor (creates socket descriptor) */ ! 1364: ! 1365: static JSBool ! 1366: js_socket_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ! 1367: { ! 1368: int32 type=SOCK_STREAM; /* default = TCP */ ! 1369: uintN i; ! 1370: private_t* p; ! 1371: char* protocol=NULL; ! 1372: ! 1373: for(i=0;i<argc;i++) { ! 1374: if(JSVAL_IS_NUMBER(argv[i])) ! 1375: JS_ValueToInt32(cx,argv[i],&type); ! 1376: else if(protocol==NULL) ! 1377: protocol=JS_GetStringBytes(JS_ValueToString(cx,argv[i])); ! 1378: } ! 1379: ! 1380: if((p=(private_t*)malloc(sizeof(private_t)))==NULL) { ! 1381: JS_ReportError(cx,"malloc failed"); ! 1382: return(JS_FALSE); ! 1383: } ! 1384: memset(p,0,sizeof(private_t)); ! 1385: ! 1386: if((p->sock=open_socket(type,protocol))==INVALID_SOCKET) { ! 1387: JS_ReportError(cx,"open_socket failed with error %d",ERROR_VALUE); ! 1388: return(JS_FALSE); ! 1389: } ! 1390: p->type = type; ! 1391: p->network_byte_order = TRUE; ! 1392: ! 1393: if(!JS_SetPrivate(cx, obj, p)) { ! 1394: JS_ReportError(cx,"JS_SetPrivate failed"); ! 1395: return(JS_FALSE); ! 1396: } ! 1397: ! 1398: if(!js_DefineSyncProperties(cx, obj, js_socket_properties)) { ! 1399: JS_ReportError(cx,"js_DefineSyncProperties failed"); ! 1400: return(JS_FALSE); ! 1401: } ! 1402: ! 1403: if(!js_DefineSocketOptionsArray(cx, obj, type)) ! 1404: return(JS_FALSE); ! 1405: ! 1406: if(!js_DefineSyncMethods(cx, obj, js_socket_functions, FALSE)) { ! 1407: JS_ReportError(cx,"js_DefineSyncMethods failed"); ! 1408: return(JS_FALSE); ! 1409: } ! 1410: ! 1411: #ifdef BUILD_JSDOCS ! 1412: js_DescribeSyncObject(cx,obj,"Class used for TCP/IP socket communications",310); ! 1413: js_DescribeSyncConstructor(cx,obj,"To create a new Socket object: " ! 1414: "<tt>load('sockdefs.js'); var s = new Socket(<i>type</i>, <i>protocol</i>)</tt><br>" ! 1415: "where <i>type</i> = <tt>SOCK_STREAM</tt> for TCP (default) or <tt>SOCK_DGRAM</tt> for UDP<br>" ! 1416: "and <i>protocol</i> (optional) = the name of the protocol or service the socket is to be used for" ! 1417: ); ! 1418: js_CreateArrayOfStrings(cx, obj, "_property_desc_list", socket_prop_desc, JSPROP_READONLY); ! 1419: #endif ! 1420: ! 1421: dbprintf(FALSE, p, "object constructed"); ! 1422: return(JS_TRUE); ! 1423: } ! 1424: ! 1425: JSObject* DLLCALL js_CreateSocketClass(JSContext* cx, JSObject* parent) ! 1426: { ! 1427: JSObject* sockobj; ! 1428: ! 1429: sockobj = JS_InitClass(cx, parent, NULL ! 1430: ,&js_socket_class ! 1431: ,js_socket_constructor ! 1432: ,0 /* number of constructor args */ ! 1433: ,NULL /* props, specified in constructor */ ! 1434: ,NULL /* funcs, specified in constructor */ ! 1435: ,NULL,NULL); ! 1436: ! 1437: return(sockobj); ! 1438: } ! 1439: ! 1440: JSObject* DLLCALL js_CreateSocketObject(JSContext* cx, JSObject* parent, char *name, SOCKET sock) ! 1441: { ! 1442: JSObject* obj; ! 1443: private_t* p; ! 1444: int type=SOCK_STREAM; ! 1445: socklen_t len; ! 1446: ! 1447: obj = JS_DefineObject(cx, parent, name, &js_socket_class, NULL ! 1448: ,JSPROP_ENUMERATE|JSPROP_READONLY); ! 1449: ! 1450: if(obj==NULL) ! 1451: return(NULL); ! 1452: ! 1453: if(!js_DefineSyncProperties(cx, obj, js_socket_properties)) ! 1454: return(NULL); ! 1455: ! 1456: len = sizeof(type); ! 1457: getsockopt(sock,SOL_SOCKET,SO_TYPE,(void*)&type,&len); ! 1458: ! 1459: if(!js_DefineSocketOptionsArray(cx, obj, type)) ! 1460: return(NULL); ! 1461: ! 1462: if((p=(private_t*)malloc(sizeof(private_t)))==NULL) ! 1463: return(NULL); ! 1464: memset(p,0,sizeof(private_t)); ! 1465: ! 1466: p->sock = sock; ! 1467: p->external = TRUE; ! 1468: p->network_byte_order = TRUE; ! 1469: ! 1470: if(!JS_SetPrivate(cx, obj, p)) { ! 1471: dbprintf(TRUE, p, "JS_SetPrivate failed"); ! 1472: return(NULL); ! 1473: } ! 1474: ! 1475: if (!js_DefineSyncMethods(cx, obj, js_socket_functions, FALSE)) ! 1476: return(NULL); ! 1477: ! 1478: dbprintf(FALSE, p, "object created"); ! 1479: ! 1480: return(obj); ! 1481: } ! 1482: ! 1483: #endif /* JAVSCRIPT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.