|
|
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.