Skip to content
Snippets Groups Projects
js_socket.c 95 KiB
Newer Older
Deucе's avatar
Deucе committed
		closesocket(sv[1]);
		return JS_FALSE;
	}
	args->sv[0] = sv[0];
	args->sv[1] = sv[1];
	args->sock = p->sock;
	args->socktype = p->type;
	args->host = strdup(p->hostname);
	args->port = port;
	args->nonblocking = p->nonblocking;
	if (args->host == NULL) {
		JS_ReportError(cx, "error duplicating hostname");
Deucе's avatar
Deucе committed
		closesocket(sv[0]);
		closesocket(sv[1]);
		free(args);
		return JS_FALSE;
	}
	_beginthread(js_connect_event_thread, 0 /* Can be smaller... */, args);

	// Success!
	p->is_connected = TRUE;
	JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
	return JS_TRUE;
}

rswindell's avatar
rswindell committed
static JSBool
js_connect(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
	ushort		port;
	JSString*	str;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	char		ip_str[256];
	struct addrinfo	hints,*res,*cur;
Deucе's avatar
Deucе committed
	int timeout = 10000; /* Default time-out */
	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
		return(JS_FALSE);
rswindell's avatar
rswindell committed

	str = JS_ValueToString(cx, argv[0]);
deuce's avatar
deuce committed
	if(p->hostname)
		free(p->hostname);
deuce's avatar
deuce committed
	JSSTRING_TO_MSTRING(cx, str, p->hostname, NULL);
deuce's avatar
deuce committed
	port = js_port(cx,argv[1],p->type);
deuce's avatar
deuce committed
	rc=JS_SUSPENDREQUEST(cx);
Deucе's avatar
Deucе committed

	if (argc > 2 && JSVAL_IS_OBJECT(argv[2]) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[2]))) {
		JSBool bgr = js_connect_event(cx, argc, arglist, p, port, obj);
		JS_RESUMEREQUEST(cx, rc);
		return bgr;
	}

deuce's avatar
deuce committed
	dbprintf(FALSE, p, "resolving hostname: %s", p->hostname);
deuce's avatar
deuce committed

	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = p->type;
	hints.ai_flags = AI_ADDRCONFIG;
	result = getaddrinfo(p->hostname, NULL, &hints, &res);
	if(result != 0) {
		JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
		p->last_error = ERROR_VALUE;
		dbprintf(TRUE, p, "getaddrinfo(%s) failed with error %d", p->hostname, result);
		return(JS_TRUE);
rswindell's avatar
rswindell committed
	}
	/* always set to nonblocking here */
	val=1;
	ioctlsocket(p->sock,FIONBIO,&val);
	result = SOCKET_ERROR;
	for(cur=res; cur != NULL; cur=cur->ai_next) {
deuce's avatar
deuce committed
		if(argc>2)	/* time-out value specified */
Deucе's avatar
Deucе committed
			timeout = js_polltimeout(cx, argv[2]);
deuce's avatar
deuce committed
		inet_addrtop((void *)cur->ai_addr, ip_str, sizeof(ip_str));
		dbprintf(FALSE, p, "connecting to %s on port %u at %s", ip_str, port, p->hostname);
		inet_setaddrport((void *)cur->ai_addr, port);
		result = connect(p->sock, cur->ai_addr, cur->ai_addrlen);

		if(result == SOCKET_ERROR) {
			result = ERROR_VALUE;
			if(result == EWOULDBLOCK || result == EINPROGRESS) {
				result = ETIMEDOUT;
Deucе's avatar
Deucе committed
				if (socket_writable(p->sock, timeout)) {
					int so_error = -1;
					socklen_t optlen = sizeof(so_error);
					if(getsockopt(p->sock, SOL_SOCKET, SO_ERROR, (void*)&so_error, &optlen) == 0 && so_error == 0)
						result = 0;	/* success */
					else
						result = so_error;
				}
deuce's avatar
deuce committed
		}
deuce's avatar
deuce committed
			break;
	}
	/* Restore original setting here */
	ioctlsocket(p->sock,FIONBIO,(ulong*)&(p->nonblocking));

	if(result!=0) {
deuce's avatar
deuce committed
		freeaddrinfo(res);
		p->last_error = result;
		dbprintf(TRUE, p, "connect failed with error %d", result);
		JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
		return(JS_TRUE);
rswindell's avatar
rswindell committed
	}
deuce's avatar
deuce committed
	memcpy(&p->remote_addr, cur->ai_addr, cur->ai_addrlen);
	freeaddrinfo(res);
rswindell's avatar
rswindell committed

	JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
deuce's avatar
deuce committed
	dbprintf(FALSE, p, "connected to %s on port %u at %s", ip_str, port, p->hostname);
rswindell's avatar
rswindell committed
	return(JS_TRUE);
}

static JSBool
js_send(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	size_t		len;
rswindell's avatar
rswindell committed
	JSString*	str;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
rswindell's avatar
rswindell committed

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
rswindell's avatar
rswindell committed

	str = JS_ValueToString(cx, argv[0]);
deuce's avatar
deuce committed
	JSSTRING_TO_MSTRING(cx, str, cp, &len);
deuce's avatar
deuce committed
	if(cp==NULL)
		return JS_TRUE;
rswindell's avatar
rswindell committed

	ret = js_socket_sendsocket(p,cp,len,TRUE);
	if(ret >= 0) {
		dbprintf(FALSE, p, "sent %d of %lu bytes",ret,len);
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(ret));
		dbprintf(TRUE, p, "send of %lu bytes failed",len);
deuce's avatar
deuce committed
	free(cp);
rswindell's avatar
rswindell committed
	return(JS_TRUE);
}

deuce's avatar
deuce committed
static JSBool
js_sendline(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	size_t		len;
	JSString*	str;
	js_socket_private_t*	p;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
deuce's avatar
deuce committed
		return(JS_FALSE);
	}

	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	str = JS_ValueToString(cx, argv[0]);
	JSSTRING_TO_MSTRING(cx, str, cp, &len);
deuce's avatar
deuce committed
	if(cp==NULL)
		return JS_TRUE;

	rc=JS_SUSPENDREQUEST(cx);
	if(js_socket_sendsocket(p,cp,len,FALSE)==len && js_socket_sendsocket(p,"\r\n",2,TRUE)==2) {
		dbprintf(FALSE, p, "sent %lu bytes",len+2);
deuce's avatar
deuce committed
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
	} else {
		p->last_error=ERROR_VALUE;
		dbprintf(TRUE, p, "send of %lu bytes failed",len+2);
deuce's avatar
deuce committed
	}
	free(cp);
	JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
	return(JS_TRUE);
}

js_sendto(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	size_t		len;
	ushort		port;
	JSString*	data_str;
	JSString*	ip_str;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	struct addrinfo hints,*res,*cur;
	int			result;
	char		ip_addr[INET6_ADDRSTRLEN];
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	/* data */
	data_str = JS_ValueToString(cx, argv[0]);
deuce's avatar
deuce committed
	JSSTRING_TO_MSTRING(cx, data_str, cp, &len);
deuce's avatar
deuce committed
	if(cp==NULL)
		return JS_TRUE;

	/* address */
	ip_str = JS_ValueToString(cx, argv[1]);
deuce's avatar
deuce committed
	if(p->hostname)
		free(p->hostname);
deuce's avatar
deuce committed
	JSSTRING_TO_MSTRING(cx, ip_str, p->hostname, NULL);
	if(JS_IsExceptionPending(cx)) {
		free(cp);
		return JS_FALSE;
	}
	if(p->hostname==NULL) {
		free(cp);
		return JS_TRUE;
	}
deuce's avatar
deuce committed
	port = js_port(cx,argv[2],p->type);
deuce's avatar
deuce committed
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed

	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = p->type;
	hints.ai_flags = AI_ADDRCONFIG;
deuce's avatar
deuce committed
	dbprintf(FALSE, p, "resolving hostname: %s", p->hostname);
deuce's avatar
deuce committed

	if((result=getaddrinfo(p->hostname, NULL, &hints, &res) != 0)) {
		p->last_error = ERROR_VALUE;
		dbprintf(TRUE, p, "getaddrinfo(%s) failed with error %d", p->hostname, result);
		JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
deuce's avatar
deuce committed
		free(cp);
deuce's avatar
deuce committed
	for(cur=res; cur; cur=cur->ai_next) {
		inet_addrtop((void *)cur->ai_addr, ip_addr, sizeof(ip_addr));
		dbprintf(FALSE, p, "sending %lu bytes to %s port %u at %s"
deuce's avatar
deuce committed
			,len, ip_addr, port, p->hostname);
		inet_setaddrport((void *)cur->ai_addr, port);
		if(sendto(p->sock,cp,len,0 /* flags */,cur->ai_addr,cur->ai_addrlen)==len) {
			dbprintf(FALSE, p, "sent %lu bytes",len);
deuce's avatar
deuce committed
			JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
		} else {
			p->last_error=ERROR_VALUE;
			dbprintf(TRUE, p, "send of %lu bytes failed to %s",len, ip_addr);
deuce's avatar
deuce committed
		}
deuce's avatar
deuce committed
	free(cp);
deuce's avatar
deuce committed
	freeaddrinfo(res);
static JSBool
js_sendfile(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	int			file;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
		return(JS_FALSE);
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
deuce's avatar
deuce committed
	JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
	HANDLE_PENDING(cx, fname);
deuce's avatar
deuce committed
	if(fname==NULL) {
		JS_ReportError(cx, "Failure reading filename");
		return(JS_FALSE);
deuce's avatar
deuce committed
	if((file=nopen(fname,O_RDONLY|O_BINARY))==-1) {
deuce's avatar
deuce committed
		free(fname);
		return(JS_TRUE);
deuce's avatar
deuce committed
	len = js_socket_sendfilesocket(p, file, NULL, 0);
	if(len > 0) {
		dbprintf(FALSE, p, "sent %"PRIdOFF" bytes",len);
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
	} else {
		p->last_error=ERROR_VALUE;
		dbprintf(TRUE, p, "send of %s failed",fname);
	}
	free(fname);
	return(JS_TRUE);
}

js_sendbin(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	BYTE		b;
	WORD		w;
	DWORD		l;
	int32		val=0;
	size_t		wr=0;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
	if(argc && argv[0]!=JSVAL_VOID)
	if(argc>1 && argv[1]!=JSVAL_VOID)
	switch(size) {
		case sizeof(BYTE):
			b = (BYTE)val;
deuce's avatar
deuce committed
			wr=js_socket_sendsocket(p,&b,size,TRUE);
			break;
		case sizeof(WORD):
			w = (WORD)val;
			if(p->network_byte_order)
				w=htons(w);
deuce's avatar
deuce committed
			wr=js_socket_sendsocket(p,(BYTE*)&w,size,TRUE);
			break;
		case sizeof(DWORD):
			l = val;
			if(p->network_byte_order)
				l=htonl(l);
deuce's avatar
deuce committed
			wr=js_socket_sendsocket(p,(BYTE*)&l,size,TRUE);
			/* unknown size */
			dbprintf(TRUE, p, "unsupported binary write size: %d",size);
			break;
	}
	if(wr==size) {
		dbprintf(FALSE, p, "sent %u bytes (binary)",size);
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
	} else {
		p->last_error=ERROR_VALUE;
		dbprintf(TRUE, p, "send of %u bytes (binary) failed",size);
	}
rswindell's avatar
rswindell committed
static JSBool
js_recv(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	int32		timeout=120;
rswindell's avatar
rswindell committed
	JSString*	str;
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
rswindell's avatar
rswindell committed

	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
rswindell's avatar
rswindell committed

	if(argc && argv[0]!=JSVAL_VOID) {
		JS_ValueToInt32(cx,argv[0],&len);
rswindell's avatar
rswindell committed

		if(argc > 1 && argv[1]!=JSVAL_VOID) {
			JS_ValueToInt32(cx,argv[1],&timeout);
	if((buf=(char*)malloc(len+1))==NULL) {
		JS_ReportError(cx, "Error allocating %u bytes",len+1);
rswindell's avatar
rswindell committed

Deucе's avatar
Deucе committed
	len = js_socket_recv(cx,p,buf,len,0,timeout);
		JS_SET_RVAL(cx, arglist, JSVAL_NULL);
rswindell's avatar
rswindell committed
	buf[len]=0;

	str = JS_NewStringCopyN(cx, buf, len);
		return(JS_FALSE);
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
	dbprintf(FALSE, p, "received %u bytes",len);
rswindell's avatar
rswindell committed
	return(JS_TRUE);
}

js_recvfrom(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	char		ip_addr[INET6_ADDRSTRLEN];
	uintN		n;
	BOOL		binary=FALSE;
	BYTE		b;
	WORD		w;
	DWORD		l;
	jsval		data_val=JSVAL_NULL;
deuce's avatar
deuce committed
	union xp_sockaddr	addr;
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	for(n=0;n<argc;n++) {
		if(JSVAL_IS_BOOLEAN(argv[n])) {
			binary=JSVAL_TO_BOOLEAN(argv[n]);
			if(binary)
				len=sizeof(DWORD);
			JS_ValueToInt32(cx,argv[n],&len);
	addrlen=sizeof(addr.addr);

	if(binary) {	/* Binary/Integer Data */

		switch(len) {
			case sizeof(BYTE):
deuce's avatar
deuce committed
				if((rd=recvfrom(p->sock,&b,len,0,&addr.addr,&addrlen))==len)
					data_val = INT_TO_JSVAL(b);
				break;
			case sizeof(WORD):
deuce's avatar
deuce committed
				if((rd=recvfrom(p->sock,(BYTE*)&w,len,0,&addr.addr,&addrlen))==len) {
					if(p->network_byte_order)
						w=ntohs(w);
					data_val = INT_TO_JSVAL(w);
				}
				break;
rswindell's avatar
rswindell committed
			default:
deuce's avatar
deuce committed
				if((rd=recvfrom(p->sock,(BYTE*)&l,len,0,&addr.addr,&addrlen))==len) {
					if(p->network_byte_order)
						l=ntohl(l);
					data_val=UINT_TO_JSVAL(l);
		if(rd!=len) {
			p->last_error=ERROR_VALUE;
			return(JS_TRUE);
		}

	} else {		/* String Data */

		if((buf=(char*)malloc(len+1))==NULL) {
			JS_ReportError(cx, "Error allocating %u bytes",len+1);
deuce's avatar
deuce committed
		len = recvfrom(p->sock,buf,len,0,&addr.addr,&addrlen);
		if(len<0) {
			p->last_error=ERROR_VALUE;
		str = JS_NewStringCopyN(cx, buf, len);
		if(str==NULL)
			return(JS_FALSE);

		data_val = STRING_TO_JSVAL(str);
	}
	if((retobj=JS_NewObject(cx,NULL,NULL,obj))==NULL) {
		JS_ReportError(cx, "JS_NewObject failed");
		return(JS_FALSE);
	JS_DefineProperty(cx, retobj, "data"
		,NULL,NULL,JSPROP_ENUMERATE);

deuce's avatar
deuce committed
	sprintf(port,"%u",inet_addrport(&addr));
	if((str=JS_NewStringCopyZ(cx,port))==NULL)
		return(JS_FALSE);
	JS_DefineProperty(cx, retobj, "port"
		,STRING_TO_JSVAL(str)
deuce's avatar
deuce committed
	inet_addrtop(&addr, ip_addr, sizeof(ip_addr));
	if((str=JS_NewStringCopyZ(cx,ip_addr))==NULL)
		return(JS_FALSE);
	JS_DefineProperty(cx, retobj, "ip_address"
		,STRING_TO_JSVAL(str)
		,NULL,NULL,JSPROP_ENUMERATE);

	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(retobj));
	dbprintf(FALSE, p, "received %u bytes from %s:%s",len,ip_addr,port);
js_peek(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
		JS_ValueToInt32(cx,argv[0],&len);
	if((buf=(char*)malloc(len+1))==NULL) {
		JS_ReportError(cx, "Error allocating %u bytes",len+1);
deuce's avatar
deuce committed
	if(p->session==-1)
Deucе's avatar
Deucе committed
		len = js_socket_recv(cx, p,buf,len,MSG_PEEK,120);
deuce's avatar
deuce committed
	else
		len=0;
		p->last_error=ERROR_VALUE;
		JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	str = JS_NewStringCopyN(cx, buf, len);
	if(str==NULL)
		return(JS_FALSE);
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
rswindell's avatar
rswindell committed
	dbprintf(FALSE, p, "received %u bytes, lasterror=%d"
		,len,ERROR_VALUE);
/* Returns 0 if there is rx data waiting */
/* Returns 1 if the 'timeout' period has elapsed (with no data waiting) */
/* Returns 2 if the socket has been disconnected (regardless of any data waiting) */
/* Returns 3 if there was no rx data waiting and the 'timeout' period has not yet elapsed */
deuce's avatar
deuce committed
static int
deuce's avatar
deuce committed
js_sock_read_check(js_socket_private_t *p, time_t start, int32 timeout, int i)
deuce's avatar
deuce committed
{
	BOOL		rd;

	if(timeout > 0 && time(NULL)-start>timeout) {
		dbprintf(FALSE, p, "recvline timeout (received: %d)",i);
		return 1;
	}

	if(!socket_check(p->sock,&rd,NULL,1000)) {
		p->last_error=ERROR_VALUE;
		return 2;
	}

	if(!rd) {
		if(time(NULL)-start>timeout) {
			dbprintf(FALSE, p, "recvline timeout (received: %d)",i);
			return 1;
		}
		return 3;
	}
	return 0;
}

/* This method is to return null on error/timeout, not void/undefined */
js_recvline(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	int			i,got;
	int32		timeout=30;	/* seconds */
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
		JS_ValueToInt32(cx,argv[0],&len);
	if((buf=(char*)malloc(len+1))==NULL) {
		JS_ReportError(cx, "Error allocating %u bytes",len+1);
		JS_ValueToInt32(cx,argv[1],&timeout);
	for(i=0;i<len;) {
deuce's avatar
deuce committed
		if(p->session==-1) {
			switch(js_sock_read_check(p,start,timeout,i)) {
				case 1:	// time-out */
				case 2: // disconnected
					if(i) {		// some data was received before the error/disconnection
						len=0;	// so break the loop
						continue;
					}
					// no data received, so just return null
deuce's avatar
deuce committed
					JS_RESUMEREQUEST(cx, rc);
					free(buf);
					return JS_TRUE;
				case 3:	// no data and no time-out... yet
deuce's avatar
deuce committed
					continue;
Deucе's avatar
Deucе committed
		if((got=js_socket_recv(cx, p, &ch, 1, 0, i?1:timeout))!=1) {
			if(p->session == -1)
				p->last_error = ERROR_VALUE;
			if (i == 0) {			// no data received
				JS_RESUMEREQUEST(cx, rc);
				free(buf);			// so return null (not an empty string)
				return(JS_TRUE);
		if(ch=='\n' /* && i>=1 */) /* Mar-9-2003: terminate on sole LF */
	str = JS_NewStringCopyZ(cx, buf);
	if(str==NULL)
		return(JS_FALSE);
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
rswindell's avatar
rswindell committed
	dbprintf(FALSE, p, "received %u bytes (recvline) lasterror=%d"
js_recvbin(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
	if(argc && argv[0]!=JSVAL_VOID)
	switch(size) {
		case sizeof(BYTE):
Deucе's avatar
Deucе committed
			if((rd=js_socket_recv(cx, p,&b,size,MSG_WAITALL,120))==size)
				JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(b));
Deucе's avatar
Deucе committed
			if((rd=js_socket_recv(cx, p,(BYTE*)&w,size,MSG_WAITALL,120))==size) {
				if(p->network_byte_order)
					w=ntohs(w);
				JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(w));
Deucе's avatar
Deucе committed
			if((rd=js_socket_recv(cx, p,(BYTE*)&l,size,MSG_WAITALL,120))==size) {
				if(p->network_byte_order)
					l=ntohl(l);
				JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(l));
js_getsockopt(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	js_socket_private_t*	p;
	LINGER		linger;
	void*		vp=&val;
	socklen_t	len=sizeof(val);
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	char		*cstr;
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
deuce's avatar
deuce committed
	JSVALUE_TO_ASTRING(cx, argv[0], cstr, 64, NULL);
deuce's avatar
deuce committed
	if((opt = getSocketOptionByName(cstr, &level)) == -1) {
	if(opt == SO_LINGER) {
		vp=&linger;
		len=sizeof(linger);
	}
	if(getsockopt(p->sock, level, opt, vp, &len)==0) {
		if(opt == SO_LINGER) {
			if(linger.l_onoff==TRUE)
				val = linger.l_linger;
			else
				val = 0;
		}
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(val));
		dbprintf(TRUE, p, "error %d getting option %d"
js_setsockopt(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	js_socket_private_t*	p;
	LINGER		linger;
	void*		vp=&val;
	socklen_t	len=sizeof(val);
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	char		*optname;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
Deucе's avatar
Deucе committed
	if (p->sock == INVALID_SOCKET)
		return JS_TRUE;
deuce's avatar
deuce committed
	JSVALUE_TO_ASTRING(cx, argv[0], optname, 64, NULL);
deuce's avatar
deuce committed
	opt = getSocketOptionByName(optname,&level);
deuce's avatar
deuce committed
	if(argv[1]!=JSVAL_VOID) {
	if(opt == SO_LINGER) {
		if(val) {
			linger.l_onoff = TRUE;
			linger.l_linger = (ushort)val;
		} else {
			ZERO_VAR(linger);
		}
		vp=&linger;
		len=sizeof(linger);
	}

	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(
		setsockopt(p->sock, level, opt, vp, len)==0));
js_ioctlsocket(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
	int32		cmd=0;
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
		return(JS_FALSE);
	if(argc && argv[0]!=JSVAL_VOID)
		JS_ValueToInt32(cx,argv[0],&cmd);
	if(argc>1 && argv[1]!=JSVAL_VOID)
		JS_ValueToInt32(cx,argv[1],&arg);
deuce's avatar
deuce committed
	if(ioctlsocket(p->sock,cmd,(ulong*)&arg)==0) {
		JS_SET_RVAL(cx, arglist,INT_TO_JSVAL(arg));
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));

	p->last_error=ERROR_VALUE;

	return(JS_TRUE);
}

js_poll(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	js_socket_private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
#ifdef PREFER_POLL
	int timeout = 0;
	struct pollfd *fds;
	nfds_t nfds;
	jsval objval = OBJECT_TO_JSVAL(obj);
#else
deuce's avatar
deuce committed
	SOCKET	high=0;
Deucе's avatar
Deucе committed
	fd_set  socket_set;
	fd_set* rd_set=NULL;
	fd_set* wr_set=NULL;
	struct  timeval tv = {0, 0};
#endif
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(js_socket_private_t*)js_GetClassPrivate(cx, obj, &js_socket_class))==NULL) {
deuce's avatar
deuce committed
	if(p->sock==INVALID_SOCKET && p->set == NULL) {
		dbprintf(TRUE, p, "INVALID SOCKET in call to poll");
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
	for(argn=0;argn<argc;argn++) {
		if(JSVAL_IS_BOOLEAN(argv[argn]))
			poll_for_write=JSVAL_TO_BOOLEAN(argv[argn]);
Deucе's avatar
Deucе committed
		else if(JSVAL_IS_NUMBER(argv[argn])) {
#ifdef PREFER_POLL
Deucе's avatar
Deucе committed
			timeout = js_polltimeout(cx, argv[argn]);
#else
			js_timeval(cx,argv[argn],&tv);
Deucе's avatar
Deucе committed
#endif
		}
#ifdef PREFER_POLL
	if (p->peeked && !poll_for_write) {
		result = 1;
	}
	else {
		nfds = js_socket_numsocks(cx, objval);
		fds = calloc(nfds, sizeof(*fds));
		if (fds == NULL) {