Browse Source

added socket sendto/recvfrom/select/fd_size

Nicolas Cannasse 8 years ago
parent
commit
800015dde7
1 changed files with 107 additions and 0 deletions
  1. 107 0
      src/std/socket.c

+ 107 - 0
src/std/socket.c

@@ -20,6 +20,10 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #ifdef _WIN32
+
+#define FD_SETSIZE	65536
+#pragma warning(disable:4548)
+
 #	include <string.h>
 #	define _WINSOCKAPI_
 #	include <hl.h>
@@ -313,6 +317,104 @@ HL_PRIM bool hl_socket_set_fast_send( hl_socket *s, bool b ) {
 	return setsockopt(s->sock,IPPROTO_TCP,TCP_NODELAY,(char*)&fast,sizeof(fast)) == 0;
 }
 
+HL_PRIM int hl_socket_send_to( hl_socket *s, char *data, int len, int host, int port ) {
+	struct sockaddr_in addr;
+	memset(&addr,0,sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons((unsigned short)port);
+	*(int*)&addr.sin_addr.s_addr = host;
+	len = sendto(s->sock, data, len, MSG_NOSIGNAL, (struct sockaddr*)&addr, sizeof(addr));
+	if( len == SOCKET_ERROR )
+		return block_error();
+	return len;
+}
+
+HL_PRIM int hl_socket_recv_from( hl_socket *s, char *data, int len, int *host, int *port ) {
+	struct sockaddr_in saddr;
+	int slen = sizeof(saddr);
+	len = recvfrom(s->sock, data, len, MSG_NOSIGNAL, (struct sockaddr*)&saddr, &slen);
+	if( len == SOCKET_ERROR ) {
+#ifdef	HL_WIN
+		if( WSAGetLastError() == WSAECONNRESET )
+			len = 0;
+		else
+#endif
+		return block_error();
+	}
+	*host = *(int*)&saddr.sin_addr;
+	*port = ntohs(saddr.sin_port);
+	return len;
+}
+
+HL_PRIM int hl_socket_fd_size( int size ) {
+	if( size > FD_SETSIZE )
+		return -1;
+#	ifdef HL_WIN
+	return FDSIZE(size);
+#	else
+	return sizeof(fd_set);
+#	endif
+}
+
+static fd_set *make_socket_set( varray *a, char **tmp, int *tmp_size, unsigned int *max ) {
+	fd_set *set = (fd_set*)*tmp;
+	int i, req;
+	if( a == NULL )
+		return set;
+	req = hl_socket_fd_size(a->size);
+	if( *tmp_size < req )
+		return NULL;
+	*tmp_size -= req;
+	FD_ZERO(set);
+	for(i=0;i<a->size;i++) {
+		hl_socket *s= hl_aptr(a,hl_socket*)[i];
+		if( s== NULL ) break;
+		if( s->sock > *max ) *max = s->sock;
+		FD_SET(s->sock,set);
+	}
+	return set;
+}
+
+static void make_array_result( fd_set *set, varray *a ) {
+	int i;
+	int pos = 0;
+	hl_socket **aptr = hl_aptr(a,hl_socket*);
+	if( a == NULL )
+		return;
+	for(i=0;i<a->size;i++) {
+		hl_socket *s = aptr[i];
+		if( s == NULL )
+			break;
+		if( FD_ISSET(set,s->sock) )
+			aptr[pos++] = s;
+	}
+	if( pos < a->size )
+		aptr[pos++] = NULL;
+}
+
+HL_PRIM bool hl_socket_select( varray *ra, varray *wa, varray *ea, char *tmp, int tmp_size, double timeout ) {
+	struct timeval tval, *tt;
+	fd_set *rs, *ws, *es;
+	unsigned int max = 0;
+	rs = make_socket_set(ra,&tmp,&tmp_size,&max);
+	ws = make_socket_set(wa,&tmp,&tmp_size,&max);
+	es = make_socket_set(ea,&tmp,&tmp_size,&max);
+	if( rs == NULL || ws == NULL || es == NULL )
+		return false;
+	if( timeout < 0 )
+		tt = NULL;
+	else {
+		tt = &tval;
+		init_timeval(timeout,tt);
+	}
+	if( select((int)(max+1),ra?rs:NULL,wa?ws:NULL,ea?es:NULL,tt) == SOCKET_ERROR )
+		return false;
+	make_array_result(rs,ra);
+	make_array_result(ws,wa);
+	make_array_result(es,ea);
+	return true;
+}
+
 #define _SOCK	_ABSTRACT(hl_socket)
 DEFINE_PRIM(_VOID,socket_init,_NO_ARG);
 DEFINE_PRIM(_SOCK,socket_new,_BOOL);
@@ -335,3 +437,8 @@ DEFINE_PRIM(_BOOL,socket_set_timeout,_SOCK _F64);
 DEFINE_PRIM(_BOOL,socket_shutdown,_SOCK _BOOL _BOOL);
 DEFINE_PRIM(_BOOL,socket_set_blocking,_SOCK _BOOL);
 DEFINE_PRIM(_BOOL,socket_set_fast_send,_SOCK _BOOL);
+
+DEFINE_PRIM(_I32, socket_send_to, _SOCK _BYTES _I32 _I32 _I32);
+DEFINE_PRIM(_I32, socket_recv_from, _SOCK _BYTES _I32 _REF(_I32) _REF(_I32));
+DEFINE_PRIM(_I32, socket_fd_size, _I32 );
+DEFINE_PRIM(_BOOL, socket_select, _ARR _ARR _ARR _BYTES _I32 _F64);