Skip to content
Snippets Groups Projects
js_socket.c 57.2 KiB
Newer Older
	{"readln",		js_recvline,	0,	JSTYPE_ALIAS },
	{"recvline",	js_recvline,	0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>] [,timeout=<tt>30.0</tt>]")
	,JSDOCSTR("receive a line-feed terminated string, default maxlen is 512 characters, default timeout is 30 seconds (AKA readline and readln)")
	{"recvfrom",	js_recvfrom,	0,	JSTYPE_OBJECT,	JSDOCSTR("[binary=<tt>false</tt>] [,maxlen=<tt>512</tt> or int_size=<tt>4</tt>]")
	,JSDOCSTR("receive data (string or integer) from a socket (typically UDP)"
rswindell's avatar
rswindell committed
	"<p>returns object with <i>ip_address</i> and <i>port</i> of sender along with <i>data</i> properties"
	"<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)")
	},
	{"readBin",		js_recvbin,		0,	JSTYPE_ALIAS },
	{"recvBin",		js_recvbin,		0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=<tt>4</tt>]")
	,JSDOCSTR("receive a binary integer from the socket, default number of bytes is 4 (32-bits)")
	{"getoption",	js_getsockopt,	1,	JSTYPE_NUMBER,	JSDOCSTR("option")
	,JSDOCSTR("get socket option value, option may be socket option name "
	"(see <tt>sockopts</tt> in <tt>sockdefs.js</tt>) or number")
	{"setoption",	js_setsockopt,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("option, value")
	,JSDOCSTR("set socket option value, option may be socket option name "
	"(see <tt>sockopts</tt> in <tt>sockdefs.js</tt>) or number")
	{"ioctl",		js_ioctlsocket,	1,	JSTYPE_NUMBER,	JSDOCSTR("command [,argument=<tt>0</tt>]")
	,JSDOCSTR("send socket IOCTL (advanced)")					
	{"poll",		js_poll,		1,	JSTYPE_NUMBER,	JSDOCSTR("[timeout=<tt>0</tt>] [,write=<tt>false</tt>]")
	,JSDOCSTR("poll socket for read or write ability (default is <i>read</i>), "
	"default timeout value is 0.0 seconds (immediate timeout)")
static JSBool js_socket_resolve(JSContext *cx, JSObject *obj, jsid id)
{
	char*			name=NULL;
deuce's avatar
deuce committed
	JSBool			ret;
deuce's avatar
deuce committed
	if(id != JSID_VOID && id != JSID_EMPTY) {
		jsval idval;
		
		JS_IdToValue(cx, id, &idval);
deuce's avatar
deuce committed
		if(JSVAL_IS_STRING(idval)) {
			JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
			HANDLE_PENDING(cx, name);
deuce's avatar
deuce committed
		}
deuce's avatar
deuce committed
	}
deuce's avatar
deuce committed
	ret=js_SyncResolve(cx, obj, name, js_socket_properties, js_socket_functions, NULL, 0);
	if(name)
		free(name);
	return ret;
}

static JSBool js_socket_enumerate(JSContext *cx, JSObject *obj)
{
deuce's avatar
deuce committed
	return(js_socket_resolve(cx, obj, JSID_VOID));
}

static JSClass js_socket_class = {
     "Socket"				/* name			*/
    ,JSCLASS_HAS_PRIVATE	/* flags		*/
	,JS_PropertyStub		/* addProperty	*/
	,JS_PropertyStub		/* delProperty	*/
	,js_socket_get			/* getProperty	*/
	,js_socket_set			/* setProperty	*/
	,js_socket_enumerate	/* enumerate	*/
	,js_socket_resolve		/* resolve		*/
	,JS_ConvertStub			/* convert		*/
	,js_finalize_socket		/* finalize		*/
};

static BOOL js_DefineSocketOptionsArray(JSContext *cx, JSObject *obj, int type)
{
	size_t		i;
	size_t		count=0;
	jsval		val;
	JSObject*	array;
	socket_option_t* options;

	if((options=getSocketOptionList())==NULL)
		return(FALSE);

	if((array=JS_NewArrayObject(cx, 0, NULL))==NULL) 
		return(FALSE);

	if(!JS_DefineProperty(cx, obj, "option_list", OBJECT_TO_JSVAL(array)
		, NULL, NULL, JSPROP_ENUMERATE))
		return(FALSE);

	for(i=0; options[i].name!=NULL; i++) {
		if(options[i].type && options[i].type!=type)
			continue;
		val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,options[i].name));
		JS_SetElement(cx, array, count++, &val);
	}
	return(TRUE);
}

/* Socket Constructor (creates socket descriptor) */

JSObject* DLLCALL js_CreateSocketObjectWithoutParent(JSContext* cx, SOCKET sock, CRYPT_CONTEXT session)
{
	JSObject*	obj;
	js_socket_private_t*	p;
	int			type=SOCK_STREAM;
	socklen_t	len;

	obj=JS_NewObject(cx, &js_socket_class, NULL, NULL);

	if(obj==NULL)
		return(NULL);

	len = sizeof(type);
	getsockopt(sock,SOL_SOCKET,SO_TYPE,(void*)&type,&len);

	if(!js_DefineSocketOptionsArray(cx, obj, type))
		return(NULL);

	if((p=(js_socket_private_t*)malloc(sizeof(js_socket_private_t)))==NULL)
		return(NULL);
	memset(p,0,sizeof(js_socket_private_t));

	p->sock = sock;
	p->external = TRUE;
	p->network_byte_order = TRUE;
deuce's avatar
deuce committed
	p->unflushed = 0;

	if (p->sock != INVALID_SOCKET) {
		len=sizeof(p->remote_addr);
		if(getpeername(p->sock, &p->remote_addr.addr,&len)==0)
			p->is_connected=TRUE;
	}

	if(!JS_SetPrivate(cx, obj, p)) {
		dbprintf(TRUE, p, "JS_SetPrivate failed");
		return(NULL);
	}

	dbprintf(FALSE, p, "object created");

	return(obj);
}

js_socket_constructor(JSContext *cx, uintN argc, jsval *arglist)
	SOCKET sock;
	JSObject *obj;
	jsval *argv=JS_ARGV(cx, arglist);
	int32	type=SOCK_STREAM;	/* default = TCP */
deuce's avatar
deuce committed
	js_socket_private_t* p;
	BOOL	from_descriptor=FALSE;
		if(JSVAL_IS_NUMBER(argv[i])) {
			if (from_descriptor) {
#ifdef WIN32
				JS_ValueToECMAUint32(cx,argv[i],&sock);
#else
				JS_ValueToInt32(cx,argv[i],&sock);
#endif
				obj = js_CreateSocketObjectWithoutParent(cx, sock, -1);
				if (obj == NULL) {
					JS_ReportError(cx, "Failed to create external socket object");
					return JS_FALSE;
				}
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj));
				FREE_AND_NULL(protocol);
				return JS_TRUE;
			}
			else
				JS_ValueToInt32(cx,argv[i],&type);
		}
		else if(JSVAL_IS_BOOLEAN(argv[i]))
			from_descriptor = TRUE;
deuce's avatar
deuce committed
		else if(protocol==NULL) {
			JSVALUE_TO_MSTRING(cx, argv[i], protocol, NULL);
			HANDLE_PENDING(cx, protocol);
deuce's avatar
deuce committed
		}

	obj=JS_NewObject(cx, &js_socket_class, NULL, NULL);
	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj));

deuce's avatar
deuce committed
	if((p=(js_socket_private_t*)malloc(sizeof(js_socket_private_t)))==NULL) {
		JS_ReportError(cx,"malloc failed");
deuce's avatar
deuce committed
		if(protocol)
			free(protocol);
deuce's avatar
deuce committed
	memset(p,0,sizeof(js_socket_private_t));
	if((p->sock=open_socket(type,protocol))==INVALID_SOCKET) {
		JS_ReportError(cx,"open_socket failed with error %d",ERROR_VALUE);
deuce's avatar
deuce committed
		if(protocol)
			free(protocol);
		free(p);
deuce's avatar
deuce committed
	if(protocol)
		free(protocol);
	p->network_byte_order = TRUE;
deuce's avatar
deuce committed
	p->session=-1;
deuce's avatar
deuce committed
	p->unflushed = 0;
		JS_ReportError(cx,"JS_SetPrivate failed");
		free(p);
	if(!js_DefineSocketOptionsArray(cx, obj, type))
		return(JS_FALSE);

	js_DescribeSyncObject(cx,obj,"Class used for TCP/IP socket communications",310);
	js_DescribeSyncConstructor(cx,obj,"To create a new Socket object: "
rswindell's avatar
rswindell committed
		"<tt>load('sockdefs.js'); var s = new Socket(<i>type</i>, <i>protocol</i>)</tt><br>"
		"where <i>type</i> = <tt>SOCK_STREAM</tt> for TCP (default) or <tt>SOCK_DGRAM</tt> for UDP<br>"
		"and <i>protocol</i> (optional) = the name of the protocol or service the socket is to be used for<br>"
		"To create a socket from a socket descriptor: "
		"<tt>var s = new Socket(true, <i>descriptor</i>)</tt><br>"
		"where <i>descriptor</i> is the numerical value of an existing valid socket descriptor"
rswindell's avatar
rswindell committed
		);
	js_CreateArrayOfStrings(cx, obj, "_property_desc_list", socket_prop_desc, JSPROP_READONLY);
#endif

	dbprintf(FALSE, p, "object constructed");
	return(JS_TRUE);
}

rswindell's avatar
rswindell committed
JSObject* DLLCALL js_CreateSocketClass(JSContext* cx, JSObject* parent)
{
	JSObject*	sockobj;

	sockobj = JS_InitClass(cx, parent, NULL
		,&js_socket_class
		,js_socket_constructor
		,0	/* number of constructor args */
		,NULL /* props, specified in constructor */
		,NULL /* funcs, specified in constructor */
rswindell's avatar
rswindell committed
		,NULL,NULL);

	return(sockobj);
}

JSObject* DLLCALL js_CreateSocketObject(JSContext* cx, JSObject* parent, char *name, SOCKET sock, CRYPT_CONTEXT session)
	obj = js_CreateSocketObjectWithoutParent(cx, sock, session);
rswindell's avatar
rswindell committed
	if(obj==NULL)
		return(NULL);
	JS_DefineProperty(cx, parent, name, OBJECT_TO_JSVAL(obj), NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY);
deuce's avatar
deuce committed

	return(obj);
}

JSObject* DLLCALL js_CreateSocketObjectFromSet(JSContext* cx, JSObject* parent, char *name, struct xpms_set *set)
{
	JSObject*	obj;
	js_socket_private_t*	p;
	int			type=SOCK_STREAM;
	socklen_t	len;

	obj = JS_DefineObject(cx, parent, name, &js_socket_class, NULL
		,JSPROP_ENUMERATE|JSPROP_READONLY);

	if(obj==NULL)
		return(NULL);

	if(set->sock_count < 1)
		return NULL;

	len = sizeof(type);
	getsockopt(set->socks[0].sock,SOL_SOCKET,SO_TYPE,(void*)&type,&len);

	if(!js_DefineSocketOptionsArray(cx, obj, type))
		return(NULL);

	if((p=(js_socket_private_t*)malloc(sizeof(js_socket_private_t)))==NULL)
		return(NULL);
	memset(p,0,sizeof(js_socket_private_t));

	p->set = set;
	p->sock = INVALID_SOCKET;
	p->external = TRUE;
	p->network_byte_order = TRUE;
	p->session=-1;
deuce's avatar
deuce committed
	p->unflushed = 0;
	if(!JS_SetPrivate(cx, obj, p)) {
		dbprintf(TRUE, p, "JS_SetPrivate failed");
rswindell's avatar
rswindell committed
		return(NULL);
	}

	dbprintf(FALSE, p, "object created");
#endif	/* JAVSCRIPT */