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