[or-cvs] r6917: Initial import for Mike Chiussi's bsockets library. (/ bsockets bsockets/trunk)

nickm at seul.org nickm at seul.org
Thu Jul 27 03:47:13 UTC 2006


Author: nickm
Date: 2006-07-26 23:47:11 -0400 (Wed, 26 Jul 2006)
New Revision: 6917

Added:
   bsockets/
   bsockets/branches/
   bsockets/tags/
   bsockets/trunk/
   bsockets/trunk/LICENSE
   bsockets/trunk/Makefile
   bsockets/trunk/bsocket.h
   bsockets/trunk/callback.c
   bsockets/trunk/callback.h
   bsockets/trunk/event.c
   bsockets/trunk/event.h
   bsockets/trunk/io.c
   bsockets/trunk/io.h
   bsockets/trunk/list.c
   bsockets/trunk/list.h
   bsockets/trunk/misc.c
   bsockets/trunk/misc.h
   bsockets/trunk/notes
   bsockets/trunk/select.c
   bsockets/trunk/select.h
   bsockets/trunk/socket.c
   bsockets/trunk/socket.h
   bsockets/trunk/sync.c
   bsockets/trunk/sync.h
   bsockets/trunk/test.c
   bsockets/trunk/test.h
   bsockets/trunk/todo
   bsockets/trunk/unix.c
   bsockets/trunk/unix.h
   bsockets/trunk/wait.c
   bsockets/trunk/wait.h
   svn-commit.tmp
Log:
Initial import for Mike Chiussi's bsockets library.


Added: bsockets/trunk/LICENSE
===================================================================
--- bsockets/trunk/LICENSE	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/LICENSE	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,33 @@
+==============================================================================
+BSOCK is distributed under this license
+
+Copyright (c) 2006 Mike Chiussi
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+    * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+==============================================================================
\ No newline at end of file


Property changes on: bsockets/trunk/LICENSE
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/Makefile
===================================================================
--- bsockets/trunk/Makefile	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/Makefile	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,23 @@
+test_HEADERS= test.h
+bsock_HEADERS = list.h test.h socket.h bsocket.h misc.h
+
+sock_OBJS = list.o socket.o unix.o event.o sync.o select.o wait.o misc.o io.o callback.o
+test_OBJS = test.o ${sock_OBJS}
+
+BIN_SUFFIX = .exe
+
+default: test libbsock.a 
+
+clean:
+	rm -f *.exe *.a *.o
+	
+libbsock.a: ${sock_OBJS}
+	ar -r $@ ${sock_OBJS} 
+
+test: ${test_OBJS} 
+	gcc -Wall -o test${BIN_SUFFIX} ${test_OBJS} -lws2_32
+
+
+%.o: %.c %.h ${test_HEADERS} ${bsock_HEADERS} 
+	gcc -g -Wall -c $<	
+	 


Property changes on: bsockets/trunk/Makefile
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/bsocket.h
===================================================================
--- bsockets/trunk/bsocket.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/bsocket.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,97 @@
+#ifndef _BSOCKET_H_
+#define _BSOCKET_H_
+
+#define USE_WIN32
+
+#ifdef USE_WIN32
+
+#define MAX_BSOCKETS 2048
+
+typedef struct _BFD_SET {
+	int hash[MAX_BSOCKETS];
+	int list[MAX_BSOCKETS];
+	int count;
+	int i;
+} bfd_set;
+
+
+#define BFD_COPY(X,Y)	*(X) = *(Y);
+
+#define	BFD_ZERO(X)		(X)->count = 0;\
+
+#define BFD_ISSET(F,X)	(((X)->hash[F] < (X)->count)\
+							&&\
+						((X)->list[(X)->hash[F]] == F))\
+
+#define BFD_SET(F,X)		if (!BFD_ISSET(F,X)) {\
+							(X)->hash[F] = (X)->count;\
+							(X)->list[(X)->count] = F;\
+							(X)->count++;\
+						}\
+
+#define BFD_CLR(F,X)	if ( BFD_ISSET(F,X) ) {\
+							(X)->i=(X)->hash[F];\
+							for (; (X)->i<(X)->count-1; (X)->i++) {\
+								(X)->list[(X)->i] = (X)->list[(X)->i+1];\
+								((X)->hash[(X)->list[(X)->i]])--;\
+							}\
+							(X)->count--;\
+						}\
+
+struct socket_env;
+struct socket_env *__GLOBAL_BSOCKET_ENV_;
+
+int winsock_start();
+
+int socket_win32(int, int, int, struct socket_env *);
+int close_win32(int, struct socket_env *);
+int connect_win32(int, struct sockaddr*,size_t,struct socket_env*);
+int socket_init_win32(struct socket_env*);
+int socket_cleanup_win32(struct socket_env*);
+int fcntl_win32(int,int,long, struct socket_env*);
+int select_win32(int, bfd_set*, bfd_set*, bfd_set*, struct timeval*, struct socket_env*);
+int getsockopt_win32(int, int, int, void*, int *, struct socket_env*);
+int send_win32(int, void*, size_t, int, struct socket_env*);
+int recv_win32(int, void*, size_t, int, struct socket_env*);
+
+#define bsocket_init(X)			socket_init_win32(X)
+#define bsocket_shutdown(X)		socket_cleanup_win32(X)
+
+#define bsocket(A,B,C)			socket_win32(A,B,C,__GLOBAL_BSOCKET_ENV_)
+#define bconnect(A,B,C)			connect_win32(A,B,C,__GLOBAL_BSOCKET_ENV_)
+#define bclose(X)				close_win32(X,__GLOBAL_BSOCKET_ENV_)
+
+#define bfcntl(X,Y,Z)			fcntl_win32(X,Y,Z,__GLOBAL_BSOCKET_ENV_)
+
+#define bselect(W,X,Y,Z,A)		select_win32(W,X,Y,Z,A,__GLOBAL_BSOCKET_ENV_)
+
+#define bgetsockopt(A,B,C,D,E)	getsockopt_win32(A,B,C,D,E,__GLOBAL_BSOCKET_ENV_)
+
+#define bsend(A,B,C,D)			send_win32(A,B,C,D,__GLOBAL_BSOCKET_ENV_)
+#define brecv(A,B,C,D)			recv_win32(A,B,C,D,__GLOBAL_BSOCKET_ENV_);
+
+#define F_SETFL					1
+
+#define	O_NONBLOCK				1
+#define O_BLOCK					2
+
+/**************/
+/*user options*/
+/**************/
+
+/*these should be throttled carefully, as too many open half-open sockets
+	or listening sockets wreak havoc on non-server kernels*/
+
+#define MAX_SIMUL_CONNECT 		9
+#define MAX_SIMUL_LISTEN  		5
+
+#if (MAX_SIMUL_CONNECT + MAX_SIMUL_LISTEN + 2 > WSA_MAXIMUM_WAIT_EVENTS )
+#error "Reduce MAX_SIMUL_CONNECT or MAX_SIMUL_LISTEN"
+#endif
+
+
+#else
+#endif
+
+#endif
+


Property changes on: bsockets/trunk/bsocket.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/callback.c
===================================================================
--- bsockets/trunk/callback.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/callback.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,111 @@
+#include <windows.h>
+
+#include "misc.h"
+#include "socket.h"
+#include "event.h"
+#include "wait.h"
+#include "select.h"
+#include "io.h"
+#include "list.h"
+
+void CALLBACK callback_write(
+	 IN DWORD err,
+	 IN DWORD len,
+	 IN WSAOVERLAPPED *wo,
+	 IN DWORD flags) {
+
+	//todo -- activate write_wait_list
+	//todo -- if write is incomplete, reiterate
+	//todo -- if error, raise exception
+
+}
+
+void CALLBACK callback_read(
+	IN DWORD err,
+	IN DWORD len,
+	IN WSAOVERLAPPED *wo,
+	IN DWORD flags) {
+
+	struct bsocket *b;
+	struct _msg *msg;
+
+	msg = (struct _msg*) wo->hEvent;
+
+	if (err == 0) {
+
+		ASSERT(len >= 0);
+
+
+		ASSERT(len <= MSG_SIZE);
+
+		b = bsocket_get(msg->fd,AS_READ,msg->env);
+
+		ASSERT(b != NULL);
+		ASSERT(b->fd == msg->fd);
+
+		if ( list_enqueue(msg,b->in_q ) == 0) {
+
+			msg->len = len;
+			printf("%d\n",msg->len);
+			fflush(stdout);
+
+			post_read(b,msg->env);
+			socket_raise(b->fd,IS_READABLE,TRUE,msg->env);
+
+		} else {
+
+			//todo -- dealloc msg?
+			socket_exception(b->fd,errno,msg->env);
+		}
+
+		bsocket_release(msg->fd,AS_READ,msg->env);
+
+	} else {
+
+		socket_exception(msg->fd,unixify_wsaerr(err),msg->env);
+	}
+
+}
+
+//caller must guarantee atomicity
+void make_connected(struct bsocket *b, struct bsocket *partner, struct socket_env *env) {
+
+	b->connected = TRUE;
+	b->partner = partner;
+
+	//todo -- start reading
+	bsocket_raise(b,IS_READABLE,FALSE,env);
+	bsocket_raise(b,IS_WRITABLE,TRUE,env);
+
+	post_read(b,env);
+
+}
+
+void complete_connect(int fd, int err, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	l = bsocket_list_get(env);
+
+	if (l != NULL) {
+
+		if (l[fd] != NULL) {
+
+			l[fd]->connecting = FALSE;
+
+			if (err) {
+
+				bsocket_exception(l[fd],err,env);
+
+			} else {
+
+				make_connected(l[fd],NULL,env);
+		}
+
+		}
+
+		bsocket_list_release(env);
+
+	}
+
+}


Property changes on: bsockets/trunk/callback.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/callback.h
===================================================================
--- bsockets/trunk/callback.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/callback.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,10 @@
+#ifndef _CALLBACK_H_
+#define _CALLBACK_H_
+
+
+void CALLBACK callback_write(DWORD, DWORD, OVERLAPPED*, DWORD);
+void CALLBACK callback_read (DWORD, DWORD, OVERLAPPED*, DWORD);
+
+void complete_connect(int, int, struct socket_env *);
+#endif
+


Property changes on: bsockets/trunk/callback.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/event.c
===================================================================
--- bsockets/trunk/event.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/event.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,648 @@
+#include <windows.h>
+#include <stdio.h>
+
+#include "list.h"
+#include "event.h"
+#include "socket.h"
+#include "misc.h"
+#include "select.h"
+#include "callback.h"
+#include "io.h"
+
+struct _connect_data *connect_data_new(struct sockaddr *name, size_t len) {
+
+	struct _connect_data *out;
+
+	out = (struct _connect_data *)
+		malloc(sizeof(struct _connect_data));
+
+	if (out != NULL) {
+
+		out->name = malloc(len);
+
+		if (out->name != NULL) {
+
+			memcpy(out->name,name,len);
+			out->len  = len;
+
+		} else {
+
+			errno = ENOMEM;
+			free(out);
+			out = NULL;
+
+		}
+
+	} else {
+		errno = ENOMEM;
+	}
+
+	return out;
+
+}
+
+void connect_data_free(struct _connect_data *d) {
+	free(d->name);
+	free(d);
+}
+
+void event_free(struct _event *e) {
+
+	ASSERT(e != NULL);
+
+	switch (e->type) {
+
+		case EV_CONNECT:
+
+			if (e->data != NULL) {
+				connect_data_free(e->data);
+			}
+
+		break;
+
+		case EV_CLOSE:
+		case EV_SHUTDOWN:
+		case EV_PING:
+		case EV_EXCEPTION:
+			//nothing to do
+		break;
+
+		case EV_WRITE:
+			//nothing to do
+		break;
+
+		default:
+			ASSERT(FALSE);
+		break;
+
+	}
+
+	free(e);
+
+}
+
+void event_respond(struct _event *e, int ret, int err) {
+
+	int out;
+
+
+	if (ret) {
+		out = ret;
+	} else {
+		out = 0;
+	}
+
+	if (e->ret != NULL) {
+
+		*e->ret = out;
+
+	}
+
+	if (e->err != NULL) {
+		*e->err = err;
+	}
+
+
+	if (e->sig != NULL) {
+
+		ASSERT(SetEvent(e->sig));
+	}
+
+
+	event_free(e);
+
+}
+
+//if a bsocket is passed, it is the users responsibility to ensure it remains locked
+//during the event processing
+int event_post(struct bsocket *b, int type, void *data, int *ret, int *err, int wait, struct socket_env *env) {
+
+	HANDLE w;
+	struct _event *e;
+
+	int out;
+
+	out = 0;
+	e = (struct _event*)
+		malloc(sizeof(struct _event));
+
+	CHECK(e != NULL,ENOMEM);
+
+	if (wait) {
+		w = CreateEvent(NULL,TRUE,FALSE,NULL);
+		CHECK_(w != NULL);
+	} else {
+		w = NULL;
+	}
+
+	if (b != NULL) {
+		e->s = b->s;
+		e->fd = b->fd;
+	}
+
+	e->type = type;
+	e->data = data;
+	e->ret = ret;
+	e->sig = w;
+	e->err = err;
+
+
+	MUTEX_ACQUIRE(env->post_m);
+
+	if (list_enqueue(e,env->event_q) == NULL) {
+		out = -1;
+	}
+
+	ASSERT(WSASetEvent(env->post_e));
+
+	MUTEX_RELEASE(env->post_m);
+
+	if (w != NULL) {
+		ASSERT( WaitForSingleObject(w,INFINITE) == WAIT_OBJECT_0);
+	}
+
+	fail:
+
+
+	if (out == -1) {
+		e->type = EV_PING;
+		event_free(e);
+	}
+
+
+	return out;
+
+}
+
+struct _event *event_copy(struct _event *e) {
+
+	struct _event *out;
+
+	out = (struct _event*) malloc(sizeof(struct _event));
+
+	if (out != NULL ) {
+
+		out->s = e->s;
+		out->fd = e->fd;
+		out->type = e->type;
+		out->data = e->data;
+
+		out->ret = NULL;
+		out->sig = NULL;
+		out->err = NULL;
+
+	} else {
+
+		errno = ENOMEM;
+
+	}
+
+	return out;
+
+}
+
+
+void event_ping(struct socket_env *env) {
+
+	ASSERT( event_post(NULL,EV_PING,NULL,NULL,NULL,TRUE,env) == 0);
+
+}
+
+int post_connect(struct bsocket *b, struct sockaddr *name, size_t len, struct socket_env *env) {
+
+	struct _connect_data *c;
+
+	int out;
+	int r;
+	int ret;
+
+	out = 0;
+	c = connect_data_new(name,len);
+
+	CHECK(c != NULL,0);
+
+	r = event_post(b, EV_CONNECT,c,&ret,NULL,TRUE,env);
+
+	CHECK(r == 0,0);
+
+	if (ret) {
+		errno = ret;
+		out = -1;
+	} else {
+		out = 0;
+	}
+
+	fail:
+	return out;
+}
+
+int post_write(struct bsocket *b, int *ret, int *err, struct socket_env *env) {
+
+	ASSERT(b->write_buf != NULL);
+
+	b->write_wb.buf = b->write_buf;
+	b->write_wb.len = b->write_len;
+
+	return  event_post(b,EV_WRITE,&b->write_wb,ret,err,TRUE,env);
+
+
+}
+
+int post_exception(struct bsocket *b, int err, struct socket_env *env) {
+
+	return event_post(b,EV_EXCEPTION,(void*) err,NULL,NULL,FALSE,env);
+
+}
+
+int post_close(struct bsocket *b, struct socket_env *env) {
+
+	return post_exception(b,ECLOSED,env);
+
+}
+
+int post_read(struct bsocket *b, struct socket_env *env) {
+
+	return event_post(b,EV_READ,NULL,NULL,NULL,FALSE,env);
+
+}
+
+struct _event *event_next(struct socket_env *env) {
+
+	struct _event *e;
+
+	MUTEX_ACQUIRE(env->post_m);
+
+	if (list_dequeue(&e,env->event_q)) {
+
+		WSAResetEvent(env->post_e);
+		e = NULL;
+		errno = EEMPTY;
+	}
+
+	MUTEX_RELEASE(env->post_m);
+
+	return e;
+
+}
+
+//todo -- make this less hideous
+//todo -- is it possible for there to be events related to a socket after closure?
+
+#define E_NOTIFY	(0+WAIT_OBJECT_0)
+#define E_CONNECT	(1+WAIT_OBJECT_0)
+#define E_ACCEPT	(2+WAIT_OBJECT_0)
+
+#define E_INSERT(S,FD,TYPE) 	for (_j=1; _j<WSA_MAXIMUM_WAIT_EVENTS; ) {\
+									if (ev[_j].fd == -1) {\
+										ASSERT( WSAEventSelect(S,we[_j],TYPE) ==0 );\
+										ev[_j].fd	= FD;\
+										ev[_j].s 	= S;\
+										ev[_j].type	= TYPE;\
+										switch(TYPE) {\
+											case FD_CONNECT:\
+												connect_lookup[(int)FD] = _j;\
+											break;\
+											case FD_ACCEPT:\
+												listen_lookup[(int)FD] = _j;\
+											break;\
+											default:\
+												ASSERT(FALSE);\
+											break;\
+										}\
+										_j = WSA_MAXIMUM_WAIT_EVENTS+2;\
+									} else {\
+										_j++;\
+									}\
+								}\
+								ASSERT(_j == (WSA_MAXIMUM_WAIT_EVENTS+2));\
+
+#define E_DELETE(X)				ASSERT(X>0); ASSERT(X<WSA_MAXIMUM_WAIT_EVENTS);\
+								ASSERT( WSAEventSelect(ev[X].s,we[X],0) == 0);\
+								connect_lookup[(int) ev[X].fd] = -1;\
+								listen_lookup[(int) ev[X].fd]  = -1;\
+								ev[X].fd = -1;\
+
+struct __ev {
+	SOCKET s;
+	int fd;
+	int type;
+};
+
+void event_manager(struct socket_env *env) {
+
+	SOCKET connect_lookup[MAX_BSOCKETS];
+	SOCKET listen_lookup[MAX_BSOCKETS];
+
+	WSAEVENT we[WSA_MAXIMUM_WAIT_EVENTS];
+	struct __ev ev[WSA_MAXIMUM_WAIT_EVENTS];
+
+	WSANETWORKEVENTS ne;
+
+	WSAOVERLAPPED *wo;
+
+	struct _connect_data *c;
+	struct _event *e2;
+	struct _event *e;
+
+	struct _list *connect_q;
+
+	int i, _j;
+	int err;
+	int out;
+	int resume;
+	int r,z;
+	int type;
+
+	int x;
+	int connect_count;
+
+	connect_q = NULL;
+
+	we[0] 	= env->post_e;
+
+	resume = TRUE;
+	connect_count = 0;
+
+
+	connect_q = list_new();
+
+	CHECK(connect_q != NULL, 0);
+
+	for (i=1; i<WSA_MAXIMUM_WAIT_EVENTS; i++) {
+
+		we[i] = WSACreateEvent();
+		CHECK_(we[i] != WSA_INVALID_EVENT);
+
+		ev[i].fd = -1;
+
+	}
+
+	x = 0;
+
+	for (i=0; i<MAX_BSOCKETS; i++) {
+		connect_lookup[i] = (SOCKET) -1;
+		listen_lookup[i]  = (SOCKET) -1;
+	}
+
+	while (resume) {
+
+		r = WSAWaitForMultipleEvents(WSA_MAXIMUM_WAIT_EVENTS,we,FALSE,INFINITE,TRUE);
+
+		ASSERT(connect_count <= MAX_SIMUL_CONNECT);
+
+		switch (r) {
+
+			case E_NOTIFY:
+
+				e = event_next(env);
+
+				if (e == NULL) {
+					ASSERT(errno == EEMPTY);
+					break;
+				}
+
+				switch (e->type) {
+
+					case EV_PING:
+						event_respond(e,0,0);
+					break;
+
+					case EV_EXCEPTION:
+
+						z = 0;
+
+						if ((i = connect_lookup[(SOCKET) ev->fd]) != -1) {
+							E_DELETE(i);
+							z++;
+						}
+
+						if ((i = listen_lookup[(SOCKET) ev->fd]) != -1) {
+							E_DELETE(i);
+							z++;
+						}
+
+						ASSERT(z <= 1);
+
+						//todo cancel any outstanding i/o (do we need to?)
+						ASSERT(closesocket(e->s) == 0);
+
+						event_respond(e,0,0);
+
+					break;
+
+					case EV_SHUTDOWN:
+						resume = FALSE;
+						event_respond(e,0,0);
+					break;
+
+					case EV_CONNECT:
+
+						//schedule connection request
+						if ( (c = e->data) != NULL) {
+
+							e2 = event_copy(e);
+							e->data = NULL;
+
+							if (e2 != NULL) {
+
+								if (list_enqueue(e2,connect_q) == NULL) {
+
+									event_respond(e,-1,errno);
+
+								} else {
+
+									event_respond(e,0,0);
+
+								}
+
+							} else {
+
+								event_respond(e,-1,errno);
+							}
+
+
+						} else {
+
+							event_respond(e,-1,errno);
+
+						}
+
+						//process as many as we can right now
+						while ( connect_count < MAX_SIMUL_CONNECT
+								&&
+								list_dequeue(&e,connect_q) == 0
+						) {
+							c = e->data;
+
+							z = connect(e->s,c->name,c->len);
+
+							if (z == 0) {
+
+								//todo -- start reading
+								socket_raise(e->fd,IS_WRITABLE,TRUE,env);
+
+							} else {
+
+								if (WSAGetLastError() == WSAEWOULDBLOCK ) {
+
+									E_INSERT(e->s,e->fd,FD_CONNECT);
+
+									connect_count++;
+
+								} else {
+
+								//todo -- is there a memory leak here?
+									complete_connect(
+										e->fd,
+										unixify_wsaerr(WSAGetLastError()),
+										env	);
+
+
+								}
+
+							}
+
+						}
+
+					break;
+
+					case EV_READ:
+
+						invoke_read(e->s,e->fd,env);
+
+					break;
+
+					case EV_WRITE:
+
+						wo = (WSAOVERLAPPED*)
+							malloc(sizeof(WSAOVERLAPPED));
+
+
+						r = WSASend(
+								e->s,
+								(WSABUF*) (e->data),
+								1,
+								(DWORD*) &z,
+								0,
+								wo,
+								callback_write);
+
+						if (r == 0) {
+
+							event_respond(e,z,0);
+
+						} else {
+
+							switch(err = WSAGetLastError()) {
+
+								case WSA_IO_PENDING:
+									event_respond(e,z,0);
+								break;
+
+								default:
+									event_respond(e,-1,unixify_wsaerr(err));
+								break;
+							}
+
+						}
+
+					break;
+
+					case EV_LISTEN:
+						ASSERT(FALSE);
+					break;
+
+
+					default:
+						ASSERT(FALSE);
+					break;
+
+				}
+
+			break;
+
+			default:
+
+				i   = r - WSA_WAIT_EVENT_0;
+
+				ASSERT(i < WSA_MAXIMUM_WAIT_EVENTS);
+
+				z   = WSAEnumNetworkEvents(ev[i].s,we[i],&ne);
+
+				if (z != SOCKET_ERROR) {
+
+					ASSERT( ne.lNetworkEvents & ev[i].type);
+					//make sure no other events are getting set
+					ASSERT( (ne.lNetworkEvents & ~(ev[i].type)) == 0);
+
+					switch (ev[i].type) {
+
+						case FD_CONNECT:
+							err 	= ne.iErrorCode[FD_CONNECT_BIT];
+							type	= IS_WRITABLE;
+						break;
+
+						case FD_ACCEPT:
+							err		= ne.iErrorCode[FD_ACCEPT_BIT];
+							type 	= IS_READABLE;
+						break;
+
+						default:
+							ASSERT(FALSE);
+						break;
+					}
+
+					if (err) {
+
+						complete_connect(ev[i].fd,unixify_wsaerr(err),env);
+
+					} else {
+
+						complete_connect(ev[i].fd,0,env);
+					}
+
+				} else {
+
+
+					complete_connect(ev[i].fd,unixify_wsaerr(err),env);
+
+				}
+
+				if (ev[i].type == FD_CONNECT) {
+
+					//todo -- figure out a way to test the element is being deleted
+
+					E_DELETE(i);
+
+					//if (connect_count >= MAX_SIMUL_CONNECT) {
+					connect_count--;
+
+					ASSERT(event_post(NULL,EV_CONNECT,NULL,NULL,NULL,FALSE,env) == 0);
+
+				}
+
+			break;
+
+			case WSA_WAIT_FAILED:
+			case WSA_WAIT_TIMEOUT:
+				ASSERT(FALSE);
+			break;
+
+			case WAIT_IO_COMPLETION:
+			break;
+
+		}
+
+
+	}
+
+	fail:
+
+	if (connect_q != NULL)
+		list_free(connect_q);
+
+
+}
+
+
+


Property changes on: bsockets/trunk/event.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/event.h
===================================================================
--- bsockets/trunk/event.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/event.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,53 @@
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+#include "socket.h"
+
+#define EV_PING			(0)
+#define	EV_SOCK			(1)
+#define EV_CLOSE		(2)
+#define EV_CONNECT		(3)
+#define EV_LISTEN		(4)
+#define EV_WRITE		(5)
+#define EV_READ			(6)
+
+#define EV_EXCEPTION	(50)
+
+#define EV_SHUTDOWN		(100)
+
+struct _connect_data {
+
+	void 	*name;
+	size_t	len;
+
+};
+
+struct _event {
+
+	HANDLE sig;
+	SOCKET s;
+
+	void *data;
+	int *ret;
+	int *err;
+
+	int type;
+	int fd;
+
+};
+
+struct _connect_data *connect_data_new(struct sockaddr*,size_t);
+
+void event_ping(struct socket_env *);
+int event_connect(struct bsocket *, struct sockaddr*, size_t, struct socket_env*);
+
+int event_post(struct bsocket *, int, void*, int*, int*, int, struct socket_env*);
+void event_manager(struct socket_env *);
+
+int post_connect(struct bsocket *, struct sockaddr *, size_t len, struct socket_env *env);
+int post_exception(struct bsocket *, int, struct socket_env*);
+int post_read(struct bsocket *, struct socket_env *);
+int post_write(struct bsocket *, int*, int*, struct socket_env*);
+int post_close(struct bsocket *, struct socket_env*);
+
+#endif


Property changes on: bsockets/trunk/event.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/io.c
===================================================================
--- bsockets/trunk/io.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/io.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,295 @@
+#include <windows.h>
+
+#include "bsocket.h"
+#include "callback.h"
+#include "select.h"
+#include "socket.h"
+#include "misc.h"
+#include "event.h"
+#include "list.h"
+#include "io.h"
+
+struct _msg *msg_new() {
+
+	struct _msg *out;
+
+	out = (struct _msg*)
+		malloc(sizeof(struct _msg));
+
+	if (out != NULL) {
+
+		out->data = out->o_data;
+
+		out->buf_wb.buf = out->o_data;
+		out->buf_wb.len = MSG_SIZE;
+
+
+	} else {
+
+		errno = ENOMEM;
+
+	}
+
+	return out;
+
+}
+
+void msg_free(struct _msg *msg) {
+
+	free(msg);
+
+}
+
+
+void invoke_read(SOCKET s, int fd, struct socket_env *env) {
+
+	WSAOVERLAPPED *wo;
+
+	struct _msg *msg;
+
+	int err;
+
+	int out;
+	int r,z;
+	int flags;
+
+	int resume;
+
+	wo = NULL;
+
+	msg = msg_new();
+
+	CHECK(msg != NULL,0);
+
+	wo = (WSAOVERLAPPED*)
+		malloc(sizeof(WSAOVERLAPPED));
+
+	CHECK(wo != NULL,ENOMEM);
+
+	msg->fd = fd;
+	msg->s  = s;
+	msg->env = env;
+
+	wo->hEvent = msg;
+
+	resume = TRUE;
+
+	out = 0;
+
+	flags = 0;
+
+	while (resume) {
+
+		resume = FALSE;
+
+		z = 0;
+
+		r = WSARecv(
+				s,
+				&msg->buf_wb,
+				1,
+				(DWORD*) &z,
+				(DWORD*) &flags,
+				wo,
+				callback_read
+		);
+
+		if (r != SOCKET_ERROR) {
+
+			if (z == 0) {
+
+				out = -1;
+				err = 0;
+				resume = FALSE;
+
+			} else {
+				resume = TRUE;
+
+			}
+
+
+		} else {
+
+			err = WSAGetLastError();
+
+			CHECK(err == WSA_IO_PENDING,err);
+
+		}
+
+	}
+
+	fail:
+
+	if (out == -1) {
+
+		socket_exception(fd,unixify_wsaerr(err), env);
+
+		if (wo != NULL) {
+			free(wo);
+		}
+
+	}
+
+}
+
+//put EOF in input stream
+//atomicity must have write permissions for socket, list ownership not needed (todo ?)
+void bsocket_eof(struct bsocket *b) {
+
+	//NULL data indicates EOF
+	list_enqueue(NULL,b->in_q);
+
+}
+
+//todo -- check is connected
+int recv_win32(int fd, void *buf, size_t len, int flags, struct socket_env *env) {
+
+	struct bsocket *b;
+
+	struct _msg *msg;
+
+	int out;
+	int r;
+
+	int copy_len;
+
+	int space_left;
+	int data_read;
+
+	void *pos;
+
+	CHECK(len > 0, EINVAL);
+
+	b = bsocket_get(fd,AS_READ,env);
+	CHECK(b != NULL,0);
+
+	if ( list_is_empty(b->in_q)) {
+
+		CHECK(b->blocking,EAGAIN);
+
+		bsocket_release(fd,AS_READ,env);
+
+		r = wait_until(b,IS_READABLE,env);
+
+		b = bsocket_get(fd,AS_READ,env);
+		CHECK(b != NULL,0);
+	}
+
+	space_left = len;
+	pos = buf;
+	data_read = 0;
+
+	//todo -- if next message is EOF, return everything up until it
+
+	while (space_left) {
+
+		r = list_queuepeek(&msg,b->in_q);
+		ASSERT(r == 0);
+
+		if (msg != NULL) {
+
+			copy_len = min(space_left,msg->len);
+			ASSERT(copy_len > 0);
+
+			memcpy(pos,msg->data,copy_len);
+
+			msg->len -= copy_len;
+
+			ASSERT(msg->len >= 0);
+
+			if (msg->len == 0 ) {
+
+				msg_free(msg);
+				ASSERT(list_dequeue(NULL,b->in_q) == 0);
+
+			} else {
+				msg->data += copy_len;
+
+			}
+
+			pos 		+= copy_len;
+			space_left	-= copy_len;
+			data_read	+= copy_len;
+
+
+		} else {
+
+			space_left = 0;
+
+		}
+
+
+
+
+	}
+
+	out = data_read;
+
+	fail:
+
+	if (b != NULL) {
+		bsocket_release(fd,AS_READ,env);
+	}
+
+	return out;
+}
+
+int send_socketpair_win32() {
+
+	return -1;
+
+}
+
+int send_win32 (int fd, void *buf, size_t len, int flags, struct socket_env *env) {
+
+	struct bsocket *b;
+
+	int err;
+	int r;
+	int z;
+	int out;
+
+	b = bsocket_get(fd,AS_WRITE,env);
+	CHECK(b != NULL,0);
+
+	//todo -- if socketpair, send_socketpair_win32
+
+	//todo -- is this good enough to guarantee the socket is writable?
+	if (b->blocking == FALSE) {
+		CHECK(b->write_buf == NULL,EAGAIN);
+	}
+
+	r = wait_until(b,IS_WRITABLE,env);
+
+	//todo
+	//bsocket_raise(b,IS_WRITABLE,0,env);
+
+	CHECK(r == 0,0);
+
+	b->write_buf = malloc(len);
+	CHECK(b != NULL,ENOMEM);
+	memcpy(b->write_buf,buf,len);
+
+	b->write_len = len;
+
+	r = post_write(b,&z,&err,env);
+
+	CHECK(r == 0,0);
+
+	out = z;
+
+	if (out == -1)
+		errno = err;
+
+	fail:
+
+	if ( (out == -1) && (b->write_buf != NULL )) {
+		free(b->write_buf);
+	}
+
+	if (b != NULL) {
+		bsocket_release(fd,AS_WRITE,env);
+	}
+
+	return out;
+}


Property changes on: bsockets/trunk/io.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/io.h
===================================================================
--- bsockets/trunk/io.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/io.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,27 @@
+#ifndef _IO_H_
+#define _IO_H_
+
+//keep in increments of kernel page size
+#define MSG_SIZE	4096
+
+
+struct _msg {
+
+	SOCKET s;
+	WSABUF buf_wb;
+
+	struct socket_env *env;
+
+	char o_data[MSG_SIZE];
+
+	int len;
+	int fd;
+
+	void *data;
+
+};
+
+void bsocket_eof(struct bsocket *);
+void invoke_read(SOCKET s, int fd, struct socket_env *);
+
+#endif


Property changes on: bsockets/trunk/io.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/list.c
===================================================================
--- bsockets/trunk/list.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/list.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,150 @@
+#include <stdlib.h>
+#include <errno.h>
+#include "list.h"
+
+
+int list_is_empty(struct _list *list) {
+
+	return list->head == NULL;
+
+}
+
+void list_data(void *data, struct _list_node *n) {
+		//todo -- this is ugly, why?
+		*((void**) data) = n->data;
+
+}
+
+struct _list_node *list_enqueue(void *data, struct _list *list) {
+
+	struct _list_node *n;
+	struct _monitor *m;
+
+	n = (struct _list_node*) malloc(sizeof(struct _list_node));
+
+	if (n != NULL) {
+
+		m = data;
+
+		n->next = NULL;
+		n->prev = list->tail;
+		n->parent = list;
+
+		n->data = data;
+
+		if (list->tail != NULL) {
+			list->tail->next = n;
+		}
+
+		list->tail = n;
+
+		if (list->head == NULL) {
+			list->head = n;
+		}
+
+	} else {
+		errno = ENOMEM;
+	}
+
+	return n;
+
+}
+
+void list_node_detach(struct _list_node *n) {
+
+	struct _list_node *ne;
+	struct _list_node *pr;
+
+	struct _list *list;
+
+	list = n->parent;
+
+	ne = n->next;
+	pr = n->prev;
+
+	if (ne != NULL) {
+		ne->prev = pr;
+	}
+
+	if (pr != NULL) {
+		pr->next = ne;
+	}
+
+	if (n == list->head) {
+		list->head = ne;
+	}
+
+	if (n == list->tail) {
+		list->tail = pr;
+	}
+
+	list_node_free(n);
+
+}
+
+int list_queuepeek(void *data, struct _list *list) {
+
+	int out;
+
+	if (list->head != NULL) {
+
+		list_data(data,list->head);
+
+		out = 0;
+	} else {
+		out = 1;
+	}
+
+	return out;
+}
+
+int list_dequeue(void *data, struct _list *list) {
+
+	int out;
+
+	if ( (out = list_queuepeek(data,list)) == 0) {
+
+		list_node_detach(list->head);
+
+	}
+
+	return out;
+}
+
+
+void list_node_free(struct _list_node *node) {
+
+	free(node);
+
+}
+
+
+
+struct _list *list_new() {
+
+	struct _list *out;
+
+	out = (struct _list*)
+		malloc(sizeof(struct _list));
+
+	if (out != NULL) {
+
+		out->head = NULL;
+		out->tail = NULL;
+
+	} else {
+		errno = ENOMEM;
+	}
+
+	return(out);
+
+}
+
+void list_free(struct _list *list) {
+
+	int n;
+
+	while (list_dequeue(&n,list) == 0);
+	free(list);
+
+}


Property changes on: bsockets/trunk/list.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/list.h
===================================================================
--- bsockets/trunk/list.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/list.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,41 @@
+#ifndef _LIST_H_
+#define _LIST_H_
+
+
+struct _list_node {
+
+	struct _list_node *next;
+	struct _list_node *prev;
+
+	struct _list *parent;
+
+	void *data;
+
+};
+
+
+struct _list {
+
+	struct _list_node *head;
+	struct _list_node *tail;
+
+	//some optional data to be associated with the list (ie, list id)
+	void *data;
+
+};
+
+struct _list *list_new();
+void list_free(struct _list *);
+
+struct _list_node *list_enqueue(void*, struct _list *);
+int list_dequeue(void*, struct _list *);
+int list_queuepeek(void*, struct _list *);
+int list_is_empty(struct _list *);
+
+void list_node_detach(struct _list_node *);
+
+void list_node_free(struct _list_node *);
+
+
+#endif
+


Property changes on: bsockets/trunk/list.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/misc.c
===================================================================
--- bsockets/trunk/misc.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/misc.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,48 @@
+#include <windows.h>
+
+#include "misc.h"
+
+
+char _G_VERY_BAD_NEWS_[] = "\nSerious error, can't cope. Here is as much information as we can give...\n\tfile:%s line:%d errno:%d win32 err:%d\n";
+
+
+HANDLE make_thread (void *func, void *data) {
+
+	return CreateThread(NULL,0,func, data, 0, NULL);
+
+}
+
+/*"borrowed" from msdn*/
+int winsock_start() {
+	WORD wVersionRequested;
+	WSADATA wsaData;
+	int err;
+
+	wVersionRequested = MAKEWORD( 2, 2 );
+
+	err = WSAStartup( wVersionRequested, &wsaData );
+
+	if ( err != 0 ) {
+
+		return 1;
+	}
+
+	if ( LOBYTE( wsaData.wVersion ) != 2 ||
+			HIBYTE( wsaData.wVersion ) != 2 ) {
+
+		WSACleanup();
+		return 1;
+	}
+
+	return 0;
+}
+
+
+//im not going to think about overflow. if you want to wait more than 5
+//years or something like that, TS
+int timeval_to_millis(struct timeval *tv) {
+
+	return (tv->tv_sec)*1000;
+
+}
+


Property changes on: bsockets/trunk/misc.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/misc.h
===================================================================
--- bsockets/trunk/misc.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/misc.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,41 @@
+#ifndef _MISC_H_
+#define _MISC_H_
+
+#include <windows.h>
+#include <stdio.h>
+
+extern char _G_VERY_BAD_NEWS_[];
+
+#define VERY_BAD_NEWS fprintf(stderr,_G_VERY_BAD_NEWS_,__FILE__,__LINE__,errno,(int)GetLastError()); fflush(stderr);
+
+
+#define CHECK_(X) 		if (!(X)) {\
+							errno = unixify_wsaerr(GetLastError());\
+							out = -1;\
+							goto fail;\
+						}\
+
+#define CHECK(X,Y) 		if (!(X)) {\
+							if (Y != 0) {\
+								errno = Y;\
+							}\
+							out = -1;\
+							goto fail;\
+						}\
+
+#define ASSERT(X)		if (!(X)) {  fflush(stdout); VERY_BAD_NEWS ; _exit(1); }
+
+#define MUTEX_ACQUIRE(X)	ASSERT(WaitForSingleObject(X,INFINITE) == WAIT_OBJECT_0)
+#define MUTEX_RELEASE(X)	ASSERT(ReleaseMutex(X))
+
+
+
+int winsock_start();
+HANDLE make_thread(void*,void*);
+
+//todo -- if timeval not defined, give it something to work with
+
+int timeval_to_millis(struct timeval *);
+
+#endif
+


Property changes on: bsockets/trunk/misc.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/notes
===================================================================
--- bsockets/trunk/notes	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/notes	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,40 @@
+- make sure atomic/release doesnt cause other calls to block when socket is in blocking mode
+- make sure we set all events before closing them, otherwise blocking calls might block indefinitely, also find a way to show that the socket as closed
+- always release mutex before closing them
+- atomic/release should ensure the socket in question is open and not closing.
+- you cannot free a socket unless you own the list otherwise we cannot guarantee that mutexes inside atomic() still exist
+- make sure that socket error is reset after everytime it is looked at
+
+
+- check how many open reads we can have
+
+Ridiculous scenarios to think about
+
+1. User is select()ing while close() is called on one of the waiting descriptors elsewhere
+
+Why this is bad:
+The user could be waiting for a read operation, 
+
+Why it doesn't matter:
+This behavior is illegal (?)
+
+What will happen in bsock
+select will return -1, sockopt err will be set
+
+2. 
+
+
+
+sync issues
+-----------
+1. error array does not need syncronization because it may only be set by the 
+   event manager and read after event array indicates it is finished with socket
+
+2. we do not need to worry about closing a socket while there is a pending connect
+   which is queued. bconnect() will block until this is at least connected, so
+   any bclose() will block until the appropraite time.
+
+compatability issues
+--------------------
+1. openssl uses SO_*TIMEO flags. winsock has no support for this option, and implementing
+   it would force us to rip apart the existing code. is there any nice way to code.


Property changes on: bsockets/trunk/notes
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/select.c
===================================================================
--- bsockets/trunk/select.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/select.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,407 @@
+#include <windows.h>
+
+#include "bsocket.h"
+#include "event.h"
+#include "socket.h"
+#include "select.h"
+#include "misc.h"
+#include "io.h"
+
+void bsocket_raise(struct bsocket *b, int type, int active, struct socket_env *env ) {
+
+	struct _wait_list *wl;
+
+	wl = NULL;
+
+	switch (type) {
+
+		case IS_READABLE:
+			wl = b->read_wl;
+		break;
+
+		case IS_WRITABLE:
+			wl = b->write_wl;
+		break;
+
+		case IS_EXCEPTED:
+			wl = b->except_wl;
+		break;
+
+		default:
+
+			ASSERT(FALSE);
+		break;
+
+	}
+
+	ASSERT(wl != NULL);
+
+	if (active) {
+		wl_activate(wl,0);
+	} else {
+		wl_deactivate(wl);
+	}
+
+}
+
+void socket_raise(int fd, int type, int active, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	l = bsocket_list_get(env);
+
+	if (l != NULL) {
+
+		if (l[fd] != NULL) {
+			bsocket_raise(l[fd],type,active,env);
+		}
+
+		bsocket_list_release(env);
+
+	}
+
+}
+
+void socket_set_err(int fd, int err, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	l = bsocket_list_get(env);
+
+	if (l != NULL) {
+
+		if (l[fd] != NULL) {
+
+			l[fd]->err = err;
+
+		}
+
+		bsocket_list_release(env);
+
+	}
+
+}
+
+void socket_last_err(int fd, int *err, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	l = bsocket_list_get(env);
+
+	if (l != NULL) {
+
+		if (l[fd] != NULL) {
+
+			*err = l[fd]->err;
+			l[fd]->err = 0;
+
+		}
+
+		bsocket_list_release(env);
+
+	}
+
+}
+
+//atomicity is provided by caller -- must own list
+void bsocket_exception(struct bsocket *b, int err, struct socket_env *env) {
+
+//	ASSERT(err != 0);
+
+	if (b->s != INVALID_SOCKET) {
+
+		b->err		= err;
+		b->closed	= TRUE;
+		b->eof		= TRUE;
+
+		bsocket_raise(b,IS_READABLE,TRUE,env);
+		bsocket_raise(b,IS_WRITABLE,TRUE,env);
+		bsocket_raise(b,IS_EXCEPTED,TRUE,env);
+
+		post_exception(b,err,env);
+
+		b->s = INVALID_SOCKET;
+
+	}
+
+
+}
+
+void socket_exception(int fd, int err, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	l = bsocket_list_get(env);
+
+	if (l != NULL) {
+
+		if (l[fd] != NULL) {
+			bsocket_exception(l[fd],err,env);
+		}
+
+		bsocket_list_release(env);
+
+	}
+
+}
+
+int wait_until_group(struct bsocket **b, int *flag, int num, int timeout, struct socket_env *env) {
+
+	struct _wait_list **wl;
+
+	int i,j;
+	int out;
+	int r;
+
+	out = 0;
+
+	wl = (struct _wait_list **)  malloc(sizeof(struct _wait_list*)*(num+1));
+
+	CHECK(wl != NULL,ENOMEM);
+
+	for (i=0; i<num; i++) {
+
+		switch(flag[i]) {
+
+			case IS_READABLE:
+				wl[i] = b[i]->read_wl;
+			break;
+
+			case IS_WRITABLE:
+				wl[i] = b[i]->write_wl;
+			break;
+
+			case IS_EXCEPTED:
+				wl[i] = b[i]->except_wl;
+			break;
+
+			default:
+				ASSERT(FALSE);
+			break;
+
+		}
+
+		ASSERT(wl[i] != NULL);
+
+	}
+
+	for (i=0; i<num; i++) {
+
+		for (j=0; j<i; j++) {
+
+			ASSERT(wl[j] != wl[i]);
+		}
+
+	}
+
+	//todo == major sync issue here, fix next
+	r = wait_many_timeout(wl,num,timeout);
+
+	if (r == -1) {
+		ASSERT( (errno == ETIMEDOUT && timeout != -1)
+				||
+				(errno == ECLOSED)
+
+		);
+		out = -1;
+	} else {
+		out = r;
+	}
+
+
+	fail:
+
+	if (wl != NULL) {
+		free(wl);
+	}
+
+	return out;
+
+}
+
+int wait_until(struct bsocket *b, int flag, struct socket_env *env) {
+
+	struct bsocket *bl[1];
+	int fl[1];
+
+	bl[0] = b;
+	fl[0] = flag;
+
+	return wait_until_group(bl,fl,1,-1,env);
+
+}
+
+
+
+
+#define M_INSERT(X)		objects[count] = X;\
+						count++;\
+
+#define M_DELETE(X)		ASSERT(X < mutex_count);\
+						ASSERT(X >= 0);\
+						for (_i=X; _i<mutex_count-1; _i++) {\
+							desired_objects[_i] = desired_objects[_i+1];\
+						}\
+						mutex_count--;\
+
+
+int select_win32(int z, bfd_set *readfds, bfd_set *writefds, bfd_set *exceptfds,
+	struct timeval *timeout, struct socket_env *env) {
+
+	const int sets = 3;
+
+	bfd_set *fds[sets];
+	int		*t;
+
+
+	struct bsocket **b;
+	struct bsocket **l;
+	struct bsocket *c;
+
+	int count;
+	int i,j;
+	int fd_count;
+	int out;
+	int r;
+
+	int to;
+
+	int types[sets];
+
+	fds[0] = readfds;
+	fds[1] = writefds;
+	fds[2] = exceptfds;
+
+	types[0] = IS_READABLE;
+	types[1] = IS_WRITABLE;
+	types[2] = IS_EXCEPTED;
+
+
+	b = NULL;
+	fd_count = 0;
+	l = NULL;
+
+	//get this size
+	for (i=0; i<sets; i++) {
+		if (fds[i] != NULL) {
+			fd_count += fds[i]->count;
+		}
+	}
+
+	CHECK(fd_count > 0,EINVAL);
+
+
+	b = (struct bsocket**) malloc((sizeof(struct bsocket*))*(fd_count+1));
+
+	t = (int*) malloc((sizeof (int))*(fd_count+1));
+
+	CHECK(b != NULL,ENOMEM);
+	CHECK(t != NULL,ENOMEM);
+
+	l = bsocket_list_get(env);
+
+	CHECK(l != NULL,0);
+
+	count = 0;
+
+	for (i=0; i<sets; i++) {
+
+		if (fds[i] != NULL) {
+
+			for (j=0; j<fds[i]->count; j++) {
+
+				b[count] = l[fds[i]->list[j]];
+				t[count] = types[i];
+
+				count++;
+			}
+		}
+	}
+
+	bsocket_list_release(env);
+	l = NULL;
+
+	/*convert timeval to milliseconds*/
+	if (timeout != NULL) {
+		to = timeval_to_millis(timeout);
+	} else {
+		to = -1;
+	}
+
+	//todo -- major, what happens if someone closes socket right here
+	//(before we start waiting on it?)
+
+	r = wait_until_group(b,t,fd_count,to,env);
+
+	if (r != -1) {
+
+		//we need to know that socket is still valid
+		c = bsocket_get(b[r]->fd,AS_GLOBAL,env);
+		CHECK(c != NULL,0);
+
+		if (readfds != NULL) {
+			BFD_ZERO(readfds);
+		}
+
+		if (writefds != NULL) {
+			BFD_ZERO(writefds);
+		}
+
+		if (exceptfds != NULL) {
+			BFD_ZERO(exceptfds);
+		}
+
+		switch (t[r]) {
+
+			case IS_READABLE:
+				BFD_SET(c->fd,readfds);
+			break;
+
+			case IS_WRITABLE:
+				BFD_SET(c->fd,writefds);
+			break;
+
+			case IS_EXCEPTED:
+				BFD_SET(c->fd,exceptfds);
+			break;
+
+			default:
+				ASSERT(FALSE);
+			break;
+		}
+
+
+		bsocket_release(c->fd,AS_GLOBAL,env);
+
+		out = 1;
+
+	} else {
+
+		if (errno == ETIMEDOUT) {
+
+			out = 0;
+
+		} else {
+
+			out = -1;
+
+		}
+
+	}
+
+
+	fail:
+	if (b != NULL) {
+		free(b);
+	}
+
+	if (l != NULL) {
+		bsocket_list_release(env);
+	}
+
+	return out;
+
+}
+
+
+


Property changes on: bsockets/trunk/select.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/select.h
===================================================================
--- bsockets/trunk/select.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/select.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,29 @@
+#ifndef _SELECT_H_
+#define _SELECT_H_
+
+#include "socket.h"
+
+int  bsocket_last_err (struct bsocket *, int *, struct socket_env*);
+void bsocket_set_err (struct bsocket *, int, struct socket_env*);
+
+void socket_last_err(int, int*,struct socket_env*);
+void socket_set_err(int, int ,struct socket_env*);
+
+int wait_until_group(struct bsocket**, int*, int, int, struct socket_env*);
+int wait_until(struct bsocket *,int, struct socket_env*);
+
+
+void bsocket_raise(struct bsocket *, int, int, struct socket_env*);
+void bsocket_exception(struct bsocket *, int,  struct socket_env*);
+
+void socket_raise(int, int, int, struct socket_env*);
+void socket_exception(int, int, struct socket_env*);
+
+
+#define IS_READABLE		(1)
+#define IS_WRITABLE		(2)
+#define IS_EXCEPTED		(4)
+
+#endif
+
+


Property changes on: bsockets/trunk/select.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/socket.c
===================================================================
--- bsockets/trunk/socket.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/socket.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,510 @@
+#include <windows.h>
+#include <winbase.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "event.h"
+#include "bsocket.h"
+#include "errno.h"
+#include "socket.h"
+#include "unix.h"
+#include "list.h"
+#include "wait.h"
+#include "sync.h"
+#include "select.h"
+#include "misc.h"
+
+//support only turning off and on socket blocking, will add more features as needed
+int fcntl_win32(int fd, int cmd, long args, struct socket_env *env ) {
+
+	struct bsocket *b;
+	int out;
+
+	b = bsocket_get(fd,AS_GLOBAL,env);
+	CHECK(b != NULL,0);
+
+	out = 0;
+
+	switch (cmd) {
+
+		case F_SETFL:
+
+			switch(args) {
+
+				case O_NONBLOCK:
+					b->blocking = FALSE;
+				break;
+
+				case O_BLOCK:
+					b->blocking = TRUE;
+				break;
+
+				default:
+					CHECK(FALSE, ENOTSUP);
+				break;
+
+			}
+
+		break;
+
+		default:
+			CHECK(FALSE, ENOTSUP);
+		break;
+
+	}
+
+	fail:
+
+	if (b != NULL)
+		bsocket_release(fd,AS_GLOBAL,env);
+
+	return out;
+
+}
+
+//we will add more features as they become needed
+int getsockopt_win32(int fd, int level, int optname, void *optval, int *optlen, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	int out;
+
+
+	l = NULL;
+	l = bsocket_list_get(env);
+
+	CHECK(l[fd] != NULL,EBADF);
+
+	out = 0;
+
+	switch (level) {
+
+		case SOL_SOCKET:
+
+			switch (optname) {
+
+				case SO_ERROR:
+
+
+					CHECK(*optlen >= sizeof(int),EINVAL);
+
+					*((int*) optval) = l[fd]->err;
+					*optlen = sizeof(int);
+
+
+				break;
+
+				default:
+
+				break;
+
+			}
+
+		break;
+
+		default:
+			CHECK(FALSE,ENOTSUP);
+		break;
+
+	}
+
+	fail:
+
+	bsocket_list_release(env);
+
+	return out;
+}
+
+
+int connect_win32(int fd, struct sockaddr *name, size_t len, struct socket_env *env) {
+
+	struct bsocket *b;
+
+	int err;
+	int out;
+
+	out = 0;
+
+	b = bsocket_get(fd,AS_RW,env);
+
+	CHECK(b != NULL,0);
+	CHECK(b->connected == FALSE,EISCONN);
+	CHECK(b->connecting == FALSE,EALREADY);
+
+	b->connecting = TRUE;
+
+	socket_raise(fd,IS_WRITABLE,FALSE,env);
+
+	out = post_connect(b,name, len, env);
+
+	if (b->blocking) {
+
+		wait_until(b,IS_WRITABLE,env);
+
+		socket_last_err(fd,&err,env);
+
+		if (err) {
+
+			errno 	=  err;
+			out 	= -1;
+
+		} else {
+
+			out = 0;
+
+		}
+
+	} else {
+
+		errno = EINPROGRESS;
+		out = -1;
+
+	}
+
+	fail:
+
+	if (b != NULL) {
+		bsocket_release(fd,AS_RW,env);
+	}
+
+
+	return out;
+
+}
+
+void bsocket_free(struct bsocket *b) {
+
+	if (b->read_wl != NULL) {
+		ASSERT(b->read_wl->waiting == NULL);
+		wl_free(b->read_wl);
+	}
+
+	if (b->write_wl != NULL) {
+		ASSERT(b->write_wl->waiting == NULL);
+		wl_free(b->write_wl);
+	}
+
+	if (b->except_wl != NULL) {
+		ASSERT(b->except_wl->waiting == NULL);
+		wl_free(b->except_wl);
+	}
+
+}
+
+
+//todo handle SO_LINGER
+int bsocket_close(struct bsocket *b, struct socket_env *env) {
+
+	SetEvent(b->close_e);
+
+	bsocket_exception(b,ECLOSED,env);
+
+	bsocket_list_release(env);
+
+	//manually aquire all socket mutexes (don't use atomic!)
+	MUTEX_ACQUIRE(b->read_m);
+	MUTEX_ACQUIRE(b->write_m);
+	MUTEX_ACQUIRE(env->list_m);
+
+	if (!b->closed) {
+		ASSERT(post_close(b,env) == 0);
+	}
+
+	//return fd
+	list_enqueue((void*) b->fd, env->free_q);
+
+	bsocket_free(b);
+
+	env->b[b->fd] = NULL;
+
+	//todo if there is an outstanding error, that becomes the output of close
+
+	return 0;
+
+}
+
+//todo -- fix so that close_win32 does not require any new memory
+int close_win32(int fd, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	int out;
+
+	l = bsocket_list_get(env);
+	ASSERT(l != NULL);
+	CHECK(l[fd] != NULL,EBADF);
+
+	out = bsocket_close(l[fd],env);
+
+	bsocket_list_release(env);
+
+	fail:
+
+	return out;
+
+
+}
+
+struct bsocket *bsocket_new(SOCKET s) {
+
+	struct bsocket *b;
+
+	int out;
+
+	b = (struct bsocket *) malloc(sizeof(struct bsocket));
+
+	CHECK(b != NULL,ENOMEM);
+
+	b->s			= s;
+	b->blocking 	= TRUE;
+	b->connected 	= FALSE;
+	b->connecting	= FALSE;
+
+	b->read_m 		= NULL;
+	b->write_m 		= NULL;
+
+	b->close_e		= NULL;
+
+	b->read_wl		= NULL;
+	b->write_wl		= NULL;
+	b->except_wl	= NULL;
+
+	b->in_q			= NULL;
+	b->partner 		= NULL;
+
+	b->read_m = CreateMutex(NULL,FALSE,NULL);
+	CHECK_(b->read_m != NULL);
+
+	b->write_m = CreateMutex(NULL,FALSE,NULL);
+	CHECK_(b->write_m != NULL);
+
+	b->close_e = CreateEvent(NULL,TRUE,FALSE,NULL);
+	CHECK_(b->close_e != NULL);
+
+	b->err = 0;
+	b->connected = FALSE;
+	b->connecting = FALSE;
+	b->closed = FALSE;
+
+	b->read_wl	= wl_new();
+	CHECK(b->read_wl != NULL,0);
+	wl_activate(b->read_wl,0);
+
+	b->write_wl	= wl_new();
+	CHECK(b->write_wl != NULL,0);
+	wl_activate(b->write_wl,0);
+
+	b->except_wl = wl_new();
+	CHECK(b->except_wl != NULL, 0);
+	//do not open except list
+
+	b->write_buf = NULL;
+
+	b->in_q = list_new();
+	CHECK(b->in_q != NULL,0);
+
+	fail:
+
+	if (out == -1) {
+
+		bsocket_free(b);
+		return NULL;
+
+	} else {
+		return b;
+	}
+
+	ASSERT(FALSE);
+}
+
+
+int socket_win32(int af, int type, int protocol, struct socket_env *env) {
+
+	SOCKET s;
+
+	struct bsocket *b;
+	int nonblocking;
+	int fd;
+	int out;
+
+	nonblocking=1;
+	out = 0;
+
+	s = WSASocket(af,type,protocol,NULL,0,WSA_FLAG_OVERLAPPED);
+
+	CHECK_(s != INVALID_SOCKET);
+
+	CHECK_( ioctlsocket(s,FIONBIO,(u_long*) &nonblocking) == 0);
+
+	b = bsocket_new(s);
+
+	CHECK(b != NULL,0);
+
+	CHECK( (fd = claim_free_fd(b,env)) >= 0,0);
+
+	b->fd = fd;
+
+	fail:
+
+	if (out == -1) {
+
+		if (b != NULL) {
+			bsocket_free(b);
+		}
+
+		if (s != INVALID_SOCKET) {
+			ASSERT(closesocket(s) == 0);
+		}
+
+	} else {
+		out = fd;
+
+	}
+
+	return out;
+
+}
+
+int socket_init_win32(struct socket_env *env) {
+
+	HANDLE h;
+
+	int i;
+	int out;
+
+	out = 0;
+	h = NULL;
+
+	ASSERT( sizeof(int) == sizeof(DWORD));
+
+
+	if (env == NULL) {
+
+		env = (struct socket_env *)
+				malloc(sizeof(struct socket_env));
+		__GLOBAL_BSOCKET_ENV_ = env;
+	}
+
+	CHECK(env != NULL,ENOMEM);
+
+	env->free_q = list_new();
+	CHECK(env->free_q != NULL,0);
+
+	env->event_q = list_new();
+	CHECK(env->event_q != NULL,0);
+
+	for (i=0; i<MAX_BSOCKETS; i++) {
+
+		env->b[i] = NULL;
+
+		CHECK(list_enqueue((void*) i,env->free_q) != NULL,0);
+
+	}
+
+	env->post_e = WSACreateEvent();
+	CHECK_(env->post_e != WSA_INVALID_EVENT);
+
+	env->shutdown_e = CreateEvent(NULL,TRUE,FALSE,NULL);
+	CHECK_(env->shutdown_e != NULL);
+
+	env->post_m = CreateMutex(NULL,FALSE,NULL);
+	CHECK_(env->post_m != NULL);
+
+	env->list_m = CreateMutex(NULL,FALSE,NULL);
+	CHECK_(env->list_m != NULL);
+
+
+	env->wait_m = CreateMutex(NULL,FALSE,NULL);
+	CHECK_(env->wait_m != NULL);
+
+	CHECK_((h = make_thread(event_manager,env)) != NULL);
+
+	env->event_t = h;
+
+	event_ping(env);
+
+	fail:
+	//todo fix memory leak on failure
+	if (h != NULL && out == -1) {
+		TerminateThread(h,1);
+		CloseHandle(h);
+	}
+
+	return out;
+
+}
+
+int socket_cleanup_win32(struct socket_env *env) {
+
+	struct bsocket **l;
+
+	int i;
+	int out;
+	int r;
+	int was_null;
+
+	out = 0;
+	was_null = FALSE;
+
+	//todo -- i can smell a sync issue here
+
+	if (env == NULL) {
+		env = __GLOBAL_BSOCKET_ENV_;
+		was_null = TRUE;
+
+	}
+
+	ASSERT(SetEvent(env->shutdown_e));
+
+	MUTEX_ACQUIRE(env->list_m);
+
+	l = env->b;
+
+	for (i=0; i<MAX_BSOCKETS; i++) {
+
+		if (l[i] != NULL) {
+
+			r = bsocket_close(l[i],env);
+
+		}
+
+	}
+
+	//todo replace with post_shutdown
+	ASSERT(event_post(NULL,EV_SHUTDOWN,NULL,NULL,NULL,FALSE,env) == 0);
+
+
+	r = WaitForSingleObject (env->event_t,1000);
+
+	ASSERT(r == WAIT_OBJECT_0);
+
+
+	//make sure we have cleaned up properly
+	//todo - get rid of this when we are confident it isn't a problem
+	for (i=0; i<MAX_BSOCKETS; i++) {
+
+		ASSERT(env->b[i] == NULL);
+	}
+
+
+	ASSERT(CloseHandle(env->shutdown_e));
+	//ASSERT(CloseHandle(env->free_m));
+	ASSERT(CloseHandle(env->list_m));
+	ASSERT(CloseHandle(env->post_m));
+	ASSERT(CloseHandle(env->wait_m));
+
+	list_free(env->free_q);
+
+	free(env);
+
+	if (was_null) {
+		__GLOBAL_BSOCKET_ENV_ = NULL;
+	}
+
+	goto fail;
+	fail:
+
+	return out;
+
+}
+


Property changes on: bsockets/trunk/socket.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/socket.h
===================================================================
--- bsockets/trunk/socket.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/socket.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,92 @@
+#ifndef _SOCKET_H_
+#define _SOCKET_H_
+
+#include <windows.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "unix.h"
+#include "bsocket.h"
+#include "sync.h"
+#include "wait.h"
+
+//todo move this checking stuff into another header
+
+#define AS_READ  		(1)
+#define AS_WRITE 		(2)
+#define AS_ERR			(4)
+
+#define AS_RW			(AS_READ|AS_WRITE)
+#define AS_GLOBAL		(AS_READ|AS_WRITE|AS_ERR)
+
+#define AE_POST 		(1)
+#define AE_LIST			(2)
+#define AE_FREE			(4)
+#define AE_WAIT			(8)
+
+#define AE_GLOBAL		(AE_POST|AE_LIST|AE_FREE|AE_WAIT)
+
+
+struct bsocket {
+
+	SOCKET s;
+
+	HANDLE read_m;
+	HANDLE write_m;
+
+	HANDLE close_e;
+
+	struct _wait_list	*read_wl;
+	struct _wait_list	*write_wl;
+	struct _wait_list	*except_wl;
+
+	int blocking;
+
+	int connected;
+	int connecting;
+	int closed;
+
+	int err;
+	int eof;
+
+	int fd;
+
+	/*writing business*/
+
+	WSABUF	write_wb;
+
+	void *write_buf;
+	void *write_pointer;
+	int write_len;
+
+	/*reading business*/
+	struct _list *in_q;
+
+	/*this is non-null if the socket is part of a socketpair*/
+	struct bsocket *partner;
+
+
+};
+
+struct socket_env {
+
+	HANDLE		shutdown_e;
+
+	HANDLE		list_m;
+	HANDLE		post_m;
+	//HANDLE		free_m;
+	HANDLE		wait_m;
+
+	HANDLE		event_t;
+
+	WSAEVENT	post_e;
+
+	struct bsocket *b[MAX_BSOCKETS];
+
+	struct _list *free_q;
+	struct _list *event_q;
+
+};
+
+
+#endif


Property changes on: bsockets/trunk/socket.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/sync.c
===================================================================
--- bsockets/trunk/sync.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/sync.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,296 @@
+#include <windows.h>
+#include <errno.h>
+
+#include "unix.h"
+#include "socket.h"
+#include "sync.h"
+#include "list.h"
+#include "misc.h"
+
+int claim_free_fd(struct bsocket *b, struct socket_env *env) {
+
+	struct bsocket **l;
+
+	int out;
+
+	//we don't care about the output, this just gives us list
+	//ownership
+	l = bsocket_list_get(env);
+
+	CHECK(l != NULL, 0);
+
+	if (list_dequeue(&out,env->free_q) == 0) {
+
+		l[out] = b;
+
+	} else {
+		errno = EMFILE;
+		out = -1;
+	}
+
+	bsocket_list_release(env);
+
+	fail:
+	return out;
+}
+
+
+struct bsocket **bsocket_list_get(struct socket_env *env) {
+
+	if (atomic(-1,AE_LIST)) {
+		return NULL;
+	}
+
+
+	return env->b;
+
+}
+
+void bsocket_list_release(struct socket_env *env) {
+	release(-1,AE_LIST);
+}
+
+int wait_lock(struct socket_env *env) {
+
+	//todo is there any acceptable reason for this to fail?
+	ASSERT(atomic(-1,AE_WAIT) == 0);
+
+	return 0;
+
+}
+
+void wait_lock_release(struct socket_env *env) {
+
+	release(-1,AE_WAIT);
+
+}
+
+struct bsocket *bsocket_get(int fd, int access, struct socket_env *env) {
+
+	struct bsocket **l;
+	struct bsocket *out;
+
+	if (fd < 0) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (fd >= MAX_BSOCKETS) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	out = NULL;
+	l = bsocket_list_get(env);
+
+	if (l != NULL) {
+
+		if (!atomic(fd,access)) {
+			out = l[fd];
+		}
+
+		bsocket_list_release(env);
+
+	}
+
+//	printf("bsocket_get out\n");
+	//fflush(stdout);
+
+	return out;
+
+
+}
+
+void bsocket_release(int fd, int access, struct socket_env *env) {
+
+	release(fd,access);
+
+}
+
+#define M_INSERT(X)		objects[count] = X;\
+						count++;\
+
+#define M_DELETE(X)		ASSERT(X < mutex_count);\
+						ASSERT(X >= 0);\
+						for (_i=X; _i<mutex_count-1; _i++) {\
+							desired_objects[_i] = desired_objects[_i+1];\
+						}\
+						mutex_count--;\
+
+//in this version, we leave it up to the calling thread to have appropriate lock ownership
+//undefined behavior occurs if this function is called after an environment shutdown
+int lookup_mutexes(int fd, int type, struct socket_env *env, HANDLE *objects) {
+
+	struct bsocket *b;
+	int count;
+
+	count = 0;
+
+	if (fd == -1) {
+
+		M_INSERT(env->shutdown_e)
+
+		if (type & AE_POST) {
+			M_INSERT(env->post_m);
+
+		}
+
+		if (type & AE_LIST) {
+			M_INSERT(env->list_m);
+		}
+
+	//	if (type & AE_FREE) {
+	//		M_INSERT(env->free_m);
+	//	}
+
+		if (type & AE_WAIT) {
+			M_INSERT(env->wait_m);
+		}
+
+
+	} else {
+
+		//to look up these mutexes, and guarantee they will not be closed during
+		//lookup the calling thread must own one mutex
+
+		b = env->b[fd];
+
+		if (b == NULL) {
+			errno = EBADF;
+			return -1;
+		}
+
+		M_INSERT(b->close_e)
+
+		if (type & AS_READ) {
+
+			M_INSERT(b->read_m);
+		}
+
+		if (type & AS_WRITE) {
+
+			M_INSERT(b->write_m);
+		}
+
+		//if (type & AS_ERR) {
+		//	M_INSERT(b->err_m);
+		//}
+
+
+	}
+
+
+	return count;
+}
+
+//claim ownership of the mutexes listed in type belonging to fd, or the global
+//environment when fd = -1
+int atomic_win32(int fd, int type, struct socket_env *env) {
+
+	int _i;
+
+	HANDLE close_event;
+	HANDLE desired_objects[8];
+
+	int mutex_count,mutex_count_2 = 0;
+	int out;
+
+	int r;
+
+	out = 0;
+
+	r =  lookup_mutexes(fd,type,env,desired_objects);
+
+	if (r == -1) {
+
+		return -1;
+
+	} else {
+		mutex_count = r;
+	}
+
+
+	mutex_count_2 = mutex_count;
+
+	close_event = desired_objects[0];
+
+	ASSERT(mutex_count > 1);
+
+	while (mutex_count > 1) {
+
+	SetLastError(0);
+
+	//todo -- get rid of this
+	r = WaitForMultipleObjects(mutex_count,desired_objects,FALSE,INFINITE);
+
+		switch(r) {
+
+			case WAIT_TIMEOUT:
+			//this might not seem like a critical failure, however i want to know
+			//if we are not releasing mutexes
+			case WAIT_ABANDONED:
+			//there is no acceptable reason for wfmo() to fail
+			case WAIT_FAILED:
+				ASSERT(FALSE);
+			break;
+
+			//close triggered, we should leave immediately
+			case WAIT_OBJECT_0:
+				//not a critical issue but we want to know if we claimed any mutexes
+				//(we shouldn't have)
+				ASSERT(mutex_count_2 == mutex_count);
+				errno = ECLOSED;
+				mutex_count = 0;
+				out = -1;
+			break;
+
+			default:
+				M_DELETE(r - WAIT_OBJECT_0);
+
+			break;
+
+		}
+	}
+
+
+	if (out != -1) {
+
+		ASSERT(mutex_count == 1);
+		ASSERT(desired_objects[0] == close_event);
+	}
+
+	return out;
+
+}
+
+void release_win32(int fd, int type, struct socket_env *env) {
+
+	HANDLE desired_events[8];
+
+	int r;
+
+	//on the first iteration of shutdown, it is closing the socket and failing
+	//because it thinks it doesnt exist because it isn't in the list
+
+	r = lookup_mutexes(fd,type,env,desired_events);
+
+	//dont use this with type as zero
+	ASSERT( r > 1);
+	//printf("start ",r);
+
+	//rember events[0] is close event, we dont want to touch that yet
+	while (r > 1) {
+		/*todo assert around this*/
+	//	printf("%d ",desired_events[r-1]);
+	//	fflush(stdout);
+		ASSERT(ReleaseMutex(desired_events[r-1]));
+		r--;
+	}
+
+	//printf("\n");
+	//fflush(stdout);
+
+
+}
+
+


Property changes on: bsockets/trunk/sync.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/sync.h
===================================================================
--- bsockets/trunk/sync.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/sync.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,24 @@
+#ifndef _SYNC_H_
+#define _SYNC_H_
+
+#define	SYNC_PRIVATE_ERRNO 120000
+
+
+#define atomic(X,Y)		atomic_win32(X,Y,env)
+#define release(X,Y)	release_win32(X,Y,env)
+
+struct bsocket **bsocket_list_get(struct socket_env*);
+void bsocket_list_release(struct socket_env*);
+
+struct bsocket *bsocket_get(int, int, struct socket_env *);
+void bsocket_release(int, int, struct socket_env *);
+
+int atomic_win32(int, int, struct socket_env *);
+void release_win32(int, int, struct socket_env *);
+
+int claim_free_fd(struct bsocket *, struct socket_env *);
+void release_fd(int, struct socket_env *);
+
+
+#endif
+


Property changes on: bsockets/trunk/sync.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/test.c
===================================================================
--- bsockets/trunk/test.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/test.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,1769 @@
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+#include "bsocket.h"
+#include "socket.h"
+#include "select.h"
+
+#include "list.h"
+#include "test.h"
+#include "unix.h"
+#include "sync.h"
+#include "wait.h"
+#include "misc.h"
+
+#define TEST_MSG "hello!"
+
+int res;
+
+//test ideas
+/*
+1. multiple non-blocking connect()s on same socket (should fail with EAGAIN?)
+2. if socket is connected, try connecting (should fail with ECONN)
+3. is there some case where we can add a connect event and the event manager wont think we've
+   added it?
+4. assert event_q is empty when exiting event manager
+5. test select timeout
+*/
+
+
+//todo is there something that is guarnateed to be unreachable?
+#define BAD_ADDR "1.2.3.4"
+
+struct sockaddr_in localhost;
+struct sockaddr_in google;
+
+struct test_case {
+	int (*fun)();
+	void *data;
+	char *desc;
+
+};
+
+HANDLE new_thread(void *fun, void *data) {
+	return CreateThread(NULL,0,fun,data,0,NULL);
+}
+
+
+static int ran(int max) {
+
+	int out;
+
+	//todo might cause overflow if RAND_MAX is too big on your system
+	out = ((rand()*max)-1)/(RAND_MAX);
+
+	ASSERT(out < max);
+	ASSERT(out >= 0);
+
+	return out;
+
+}
+
+
+void loopback_server_helper(SOCKET s) {
+
+	int c;
+
+
+	while ( (c = accept(s,NULL,0)) != INVALID_SOCKET) {
+		//
+	}
+
+	closesocket(s);
+
+}
+
+int loopback_server(int *port) {
+
+	SOCKET s;
+
+	struct sockaddr_in in;
+	struct sockaddr_in name;
+
+	int out;
+	int r;
+	int len;
+	out = 0;
+
+	s = socket(AF_INET,SOCK_STREAM,0);
+
+	CHECK_(s != INVALID_SOCKET);
+
+	in.sin_family		 	= AF_INET;
+	in.sin_addr.s_addr	  	= htonl(INADDR_LOOPBACK);
+	in.sin_port				= htons(0);
+
+	r = bind(s,(struct sockaddr*) &in,sizeof(in));
+
+	CHECK_(r != SOCKET_ERROR);
+
+	r = listen(s,10);
+
+	CHECK_(r != SOCKET_ERROR);
+
+	len = sizeof(struct sockaddr_in);
+	r = getsockname(s, (struct sockaddr*) &name, &len);
+
+	CHECK_(r != SOCKET_ERROR);
+
+	CHECK_(new_thread(loopback_server_helper,(void*) s) != NULL);
+
+	*port = name.sin_port;
+	out = (int) s;
+
+	fail:
+
+	if (out == -1 && s != INVALID_SOCKET ) {
+
+	}
+
+	return out;
+}
+
+
+int test_active_refusal_nonblocking(){
+
+	bfd_set fds;
+
+	int fd;
+	int r;
+
+	int z;
+	int len;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+	TEST(fd == 0);
+
+	//you better not be running a local service on port 81
+	bfcntl(fd,F_SETFL,O_NONBLOCK);
+
+	r = bconnect(fd,(struct sockaddr*)&localhost,sizeof(localhost));
+
+	TEST(r == -1);
+
+	TEST(errno == EINPROGRESS);
+
+	BFD_ZERO(&fds);
+	TEST(fds.count ==  0);
+
+	BFD_SET(fd,&fds);
+
+	TEST(fds.count == 1);
+
+	r = bselect(0,NULL,&fds,NULL,NULL);
+
+	TEST(r == 1);
+
+	TEST(BFD_ISSET(fd,&fds));
+
+	len = sizeof(z);
+	//printf("%d\n",1);
+	//fflush(stdout);
+
+	TEST(bgetsockopt(fd,SOL_SOCKET,SO_ERROR,&z,&len) == 0);
+
+	TEST(z == ECONNREFUSED);
+
+
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+}
+
+
+int test_active_refusal_blocking() {
+
+	int fd;
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	errno = 0;
+	r = bconnect(fd, (struct sockaddr*) &localhost,sizeof(localhost));
+
+	TEST(r == -1);
+
+	TEST(errno == ECONNREFUSED);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return  0;
+}
+
+int _g_fd_;
+
+int test_connect_close_helper(struct sockaddr_in *name) {
+
+	int r;
+
+	r = bconnect(_g_fd_,(struct sockaddr*)name,sizeof(struct sockaddr_in));
+
+	SILENT_TEST(r == -1);
+	SILENT_TEST(errno == ECLOSED);
+
+	return 0;
+
+}
+
+int test_connect_close() {
+
+	HANDLE h;
+
+	struct sockaddr_in in;
+	int fd;
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	in.sin_family = AF_INET;
+	in.sin_addr.s_addr = inet_addr(BAD_ADDR);
+	in.sin_port = htons(10001);
+
+	_g_fd_ = fd;
+
+	h = new_thread(test_connect_close_helper,&in);
+
+	Sleep(5);
+
+	TEST(bclose(fd) == 0);
+
+	TEST(WaitForSingleObject(h,100) == 0);
+	TEST(GetExitCodeThread(h,(DWORD*) &r));
+
+	TEST(r == 0);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+
+int test_parallel_connect() {
+
+	struct sockaddr_in in;
+
+	int fd;
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	in.sin_family = AF_INET;
+	in.sin_addr.s_addr = inet_addr(BAD_ADDR);
+	in.sin_port = htons(10001);
+
+	bfcntl(fd,F_SETFL,O_NONBLOCK);
+
+	errno = 0;
+
+	r = bconnect(fd,(struct sockaddr*) &in, sizeof(in));
+
+	TEST(r == -1);
+	TEST(errno == EINPROGRESS);
+
+	r = bconnect(fd,(struct sockaddr*) &in, sizeof(in));
+
+
+	TEST(r == -1);
+	TEST(errno == EALREADY);
+
+	bfcntl(fd,F_SETFL,O_BLOCK);
+
+	r = bconnect(fd,(struct sockaddr*) &in, sizeof(in));
+
+	TEST(r == -1);
+	TEST(errno == EALREADY);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd >= 0);
+
+	google.sin_port = htons(80);
+
+	r = bconnect(fd,(struct sockaddr*) &google, sizeof(google));
+
+	TEST(r == 0);
+
+	r = bconnect(fd,(struct sockaddr*)  &google, sizeof(google));
+
+	TEST(r == -1);
+	TEST(errno == EISCONN);
+
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+}
+
+int test_badconnection_blocking() {
+
+	int fd;
+	int r;
+
+	struct sockaddr_in in;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd >= 0);
+	TEST(fd < MAX_BSOCKETS);
+
+	in.sin_family = AF_INET;
+	in.sin_addr.s_addr = inet_addr(BAD_ADDR);
+	in.sin_port = htons(80);
+
+	errno = 0;
+	r = bconnect(fd,(struct sockaddr*) &in,sizeof(in));
+
+	TEST( r == -1);
+	TEST( errno == ETIMEDOUT);
+
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_overflowsocket() {
+
+	int fd[MAX_BSOCKETS];
+
+	int f;
+	int i;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	for (i=0; i<MAX_BSOCKETS; i++) {
+
+		fd[i] = bsocket(AF_INET,SOCK_STREAM,0);
+
+		TEST(fd[i] >= 0);
+		TEST(fd[i] < MAX_BSOCKETS);
+
+	}
+
+	errno = 0;
+
+	f = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(f == -1);
+	TEST(errno == EMFILE);
+
+	errno = 0;
+
+
+
+
+	TEST(bclose(fd[0]) == 0);
+	TEST(errno == 0);
+
+
+
+	f = bsocket(AF_INET,SOCK_STREAM,0);
+
+
+	TEST(f != -1);
+	TEST(errno == 0);
+
+	for (i=1; i<MAX_BSOCKETS; i++)	{
+
+		TEST(bclose(fd[i]) == 0);
+		TEST(errno == 0);
+
+	}
+
+
+
+
+	f = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(f != -1);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+//todo -- think of a way to check if there is a memory leak
+int test_socketinit() {
+
+	int fd;
+	int tests = 1;
+
+	while (tests--) {
+
+		TEST(bsocket_init(NULL) == 0 );
+
+		fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+		TEST(fd >= 0);
+		TEST(fd < MAX_BSOCKETS);
+
+		TEST(bclose(fd) == 0);
+
+		TEST(bsocket_shutdown(NULL) == 0 );
+
+	}
+
+	return 0;
+}
+
+int test_createlist() {
+
+	struct _list *list;
+
+	list = list_new();
+
+	TEST(list != NULL);
+	TEST(list->head == NULL);
+	TEST(list->tail == NULL);
+
+	list_free(list);
+
+	return 0;
+
+}
+
+int test_basicqueue() {
+
+	struct _list *list;
+
+	int d = 666;
+	int r, res2;
+
+	list = list_new();
+
+	TEST(list != NULL);
+
+	TEST(list_enqueue((void*)d,list) != NULL);
+
+	TEST(list->head != NULL);
+	TEST(list->tail != NULL);
+	TEST(list->head == list->tail);
+
+	r = list_dequeue(&res2,list);
+
+	TEST(r == 0);
+	TEST(res2 == d);
+
+	TEST(list->head == NULL);
+	TEST(list->tail == NULL);
+
+	list_free(list);
+
+	return 0;
+
+}
+
+
+/*add random values to a queue, and them pull them out*/
+int test_bigqueue() {
+
+	const int num = 10001;
+
+	struct _list *list;
+
+	int *v = (int*) malloc((sizeof(int))*num);
+
+	int i;
+	int r;
+	int n;
+
+	list = list_new();
+
+	for (i=0; i<num; i++) {
+
+		r = rand();
+		v[i] = r;
+		TEST(list_enqueue((void*) r,list) != NULL);
+
+	}
+
+	for (i=0; i<num; i++) {
+		n = list_dequeue(&r,list);
+		TEST(n == 0);
+		TEST(r == v[i]);
+	}
+
+	n = list_dequeue(&r,list);
+	TEST(n != 0);
+
+	TEST(list->head == NULL);
+	TEST(list->tail == NULL);
+
+	free(v);
+	list_free(list);
+
+	return 0;
+
+}
+
+int test_envmutex_helper(struct socket_env *env) {
+
+	int claimed;
+
+	claimed = 0;
+
+	if (WaitForSingleObject(env->list_m,0) == WAIT_OBJECT_0) {
+		claimed++;
+	}
+
+
+//	if (WaitForSingleObject(env->free_m,0) == WAIT_OBJECT_0) {
+//		claimed++;
+//	}
+
+	if (WaitForSingleObject(env->post_m,0) == WAIT_OBJECT_0) {
+		claimed++;
+	}
+
+	if (WaitForSingleObject(env->wait_m,0) == WAIT_OBJECT_0) {
+		claimed++;
+	}
+
+	if (claimed) {
+		release(-1,AE_GLOBAL);
+	}
+
+	return claimed;
+
+}
+
+//todo - should do test for each mutex, but this is good enough for now
+int test_envmutex() {
+
+	HANDLE h;
+
+	struct socket_env *env;
+
+	int r;
+	int tests = 1000;
+
+	TEST((bsocket_init(NULL) == 0));
+
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	while(tests--) {
+
+		atomic(-1,AE_GLOBAL);
+
+		/*check if any of the mutexes can be claimed (very bad if)*/
+		h = new_thread(test_envmutex_helper,env);
+
+		TEST(h != NULL);
+
+		r = WaitForSingleObject(h,1000);
+
+		TEST(r == WAIT_OBJECT_0);
+		TEST(GetExitCodeThread(h,(DWORD*)&r));
+
+		TEST(r == 0);
+		CloseHandle(h);
+
+		release(-1,AE_GLOBAL);
+
+		/*now make sure they were released properly*/
+		h = new_thread(test_envmutex_helper,env);
+
+		TEST(h != NULL);
+
+		r = WaitForSingleObject(h,1000);
+
+		TEST(r == WAIT_OBJECT_0);
+
+		TEST(GetExitCodeThread(h,(DWORD*)&r));
+
+		TEST(r == 3);
+
+		CloseHandle(h);
+
+	}
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_envmutexclose_helper(struct socket_env *env) {
+
+	struct bsocket **l;
+
+
+	l = bsocket_list_get(env);
+
+	SILENT_TEST(l == NULL);
+	SILENT_TEST(errno == ECLOSED);
+
+	return 0;
+}
+
+int test_envmutexclose() {
+
+	HANDLE h;
+
+	struct bsocket **l;
+
+	struct socket_env *env;
+
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	l = bsocket_list_get(env);
+	TEST(l != NULL);
+
+	h = new_thread(test_envmutexclose_helper,env);
+	Sleep(10);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	TEST(WaitForSingleObject(h,100) == WAIT_OBJECT_0);
+	TEST(GetExitCodeThread(h,(DWORD*) &r));
+
+	TEST(r == 0);
+
+	CloseHandle(h);
+
+	return 0;
+
+}
+
+int test_socketmutex_helper(struct bsocket *b) {
+
+	struct socket_env *env;
+	int count;
+
+	count = 0;
+
+	if (WaitForSingleObject(b->read_m,0) == WAIT_OBJECT_0)  {
+		count++;
+	}
+
+	if (WaitForSingleObject(b->write_m,0) == WAIT_OBJECT_0) {
+		count++;
+	}
+
+	if (count) {
+		env = __GLOBAL_BSOCKET_ENV_;
+		release(b->fd,AS_GLOBAL);
+	}
+
+	return count;
+}
+
+//todo - a test for each mutex individually
+int test_socketmutex() {
+
+	HANDLE h;
+
+	struct socket_env *env;
+
+	int r;
+	int fd;
+
+	TEST(bsocket_init(NULL) == 0);
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+	TEST(fd == 0);
+
+	errno = 0;
+
+	r = atomic(fd,AS_GLOBAL);
+
+	TEST(r == 0);
+
+	h = new_thread(test_socketmutex_helper,env->b[fd]);
+	TEST(h != NULL);
+
+	r = WaitForSingleObject(h,2000);
+	TEST(r == WAIT_OBJECT_0);
+
+	GetExitCodeThread(h, (DWORD*) &r);
+	TEST(r == 0);
+
+	CloseHandle(h);
+
+	release(fd,AS_GLOBAL);
+
+	h = new_thread(test_socketmutex_helper,env->b[fd]);
+	TEST(h != NULL);
+
+	r = WaitForSingleObject(h,2000);
+	TEST(r == WAIT_OBJECT_0);
+
+	GetExitCodeThread(h, (DWORD*) &r);
+
+	TEST(atomic(fd,AS_GLOBAL) == 0);
+	release(fd,AS_GLOBAL);
+
+	TEST(r == 2);
+
+	CloseHandle(h);
+
+	TEST(bclose(fd) == 0);
+
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+}
+
+
+//attempt to grab a mutex for a socket that does not exist
+int test_badsocket() {
+
+	struct socket_env *env;
+
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	errno = 0;
+
+	r = atomic(0,AS_READ);
+
+	TEST(r == -1);
+	TEST(errno == EBADF);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_socketmutexclose_helper(int fd) {
+
+	struct socket_env *env;
+
+	int r;
+
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	errno = 0;
+	r = atomic(fd,AS_GLOBAL);
+
+	SILENT_TEST(r == -1);
+	SILENT_TEST(errno == ECLOSED);
+
+
+	return 0;
+
+
+}
+
+int test_socketmutexclose() {
+
+	HANDLE h;
+	struct socket_env *env;
+
+	int fd;
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	atomic(fd,AS_GLOBAL);
+
+	h = new_thread(test_socketmutexclose_helper,(void*)fd);
+
+	Sleep(30);
+
+	TEST(bclose(fd) == 0);
+
+	r = WaitForSingleObject(h,10000);
+
+	TEST(r == WAIT_OBJECT_0);
+
+	GetExitCodeThread(h,(DWORD*)&r);
+
+	TEST(r == 0);
+
+	CloseHandle(h);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_syncstruct() {
+
+	struct bsocket *b;
+	//struct bsocket **l;
+	struct socket_env *env;
+
+	int fd;
+	int rounds;
+
+	rounds = 1000;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+	env = __GLOBAL_BSOCKET_ENV_;
+
+	TEST(fd == 0);
+
+	while(rounds--) {
+
+		b = bsocket_get(fd,AS_GLOBAL,env);
+
+		bsocket_release(fd,AS_GLOBAL,env);
+
+		TEST(bsocket_list_get(env) != NULL);
+
+		bsocket_list_release(env);
+
+	}
+
+	TEST(bclose(fd) == 0);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+}
+
+int test_listdetach() {
+
+	struct _list *list;
+	struct _list_node *n;
+
+	int i;
+	int elements = 500;
+	int tests = 500;
+
+	int remove_this_guy;
+	int r;
+	int num;
+
+	while (tests--) {
+
+		list = list_new();
+		TEST(list != NULL);
+
+		remove_this_guy = ran(elements);
+
+		n = NULL;
+
+		for (i=0; i<elements; i++) {
+			if (i == remove_this_guy) {
+				n = list_enqueue((void*) i,list);
+				TEST(n != NULL);
+			} else {
+				TEST(list_enqueue((void*) i,list) != NULL);
+			}
+
+		}
+
+		TEST(n != NULL);
+
+		list_node_detach(n);
+
+		for (i=0; i<elements; i++) {
+
+			if (i != remove_this_guy) {
+
+				r = list_dequeue(&num,list);
+				TEST(r == 0);
+
+				TEST(num == i);
+
+			}
+
+		}
+
+		r = list_dequeue(&num,list);
+
+		TEST(r != 0);
+
+		list_free(list);
+
+	}
+
+	return 0;
+}
+
+int test_waitclose_helper(struct _wait_list *wl) {
+
+	int r;
+
+	r = wait_one(wl);
+
+	if (r == -1) {
+		return errno;
+	}
+
+	return 0;
+}
+
+int test_waitclose() {
+
+	HANDLE h;
+
+	struct _wait_list *wl;
+	int r;
+
+	wl = wl_new();
+
+	TEST(wl != NULL);
+
+	h = new_thread(test_waitclose_helper,wl);
+
+	Sleep(100);
+
+	wl_free(wl);
+
+	TEST(WaitForSingleObject(h,INFINITE) == WAIT_OBJECT_0);
+
+	TEST(GetExitCodeThread(h,(DWORD*) &r));
+
+	TEST(r == ECLOSED);
+
+	return 0;
+}
+
+int test_waitfail_helper(struct _wait_list *wl) {
+
+	int r;
+
+	r = wait_one(wl);
+
+	SILENT_TEST(r == 0);
+
+	return 0;
+}
+
+//todo -- what are other situations when this should fail?
+int test_waitfail() {
+
+	HANDLE h;
+
+	struct _wait_list *wl;
+
+	int tests = 10;
+	int r;
+
+	wl = wl_new();
+
+	while (tests--) {
+
+		TEST(wl != NULL);
+
+		h = new_thread(test_waitfail_helper, wl);
+
+		TEST(h != NULL);
+
+		Sleep(10);
+
+		r = wait_one(wl);
+
+		TEST(r == -1);
+		TEST(errno == EAGAIN);
+
+		wl_activate(wl,0);
+
+		TEST(WaitForSingleObject(h,INFINITE) == WAIT_OBJECT_0);
+		TEST(GetExitCodeThread(h,(DWORD*) &r));
+		TEST(r == 0);
+
+		wl_deactivate(wl);
+
+		CloseHandle(h);
+
+	}
+
+	wl_free(wl);
+
+	return 0;
+
+}
+
+int test_waitobject_helper(void *d) {
+
+	struct _wait_list *l;
+	//todo figure out a better way to do this test
+
+
+	l = (struct _wait_list*) d;
+
+	wl_activate((struct _wait_list*) l,0);
+
+	return 0;
+}
+
+//todo think of a more comprehensive test
+int test_waitobject() {
+
+	HANDLE h;
+
+	const int items = 1000;
+
+	struct _wait_list *wl[items];
+	struct _wait_list *desired[2];
+
+	int i;
+	int n,m;
+	int r;
+
+	int tests = 50;
+
+	int wake_this_guy;
+
+	for (i=0; i<items; i++) {
+		wl[i] = wl_new();
+		TEST(wl[i] != NULL);
+	}
+
+	while (tests--) {
+
+		n = ran(items);
+
+		while ( (m = ran(items)) == n);
+
+		TEST(m != n);
+
+		desired[0] = wl[n];
+		desired[1] = wl[m];
+
+		wake_this_guy = ran(2);
+
+		h = new_thread(test_waitobject_helper,desired[wake_this_guy]);
+
+		TEST(WaitForSingleObject(h,INFINITE) == WAIT_OBJECT_0);
+
+		CloseHandle(h);
+
+		r = wait_many(desired,2);
+
+
+	//	printf("%d %d\n",r, wake_this_guy);
+
+		TEST(r == wake_this_guy);
+
+
+		wl_deactivate(desired[wake_this_guy]);
+
+
+	}
+
+	for (i=0; i<items; i++) {
+		wl_free(wl[i]);
+	}
+
+
+	return 0;
+
+}
+
+int simplewait_tests = 100000;
+
+int test_simplewaitobject_helper(struct _wait_list *l) {
+
+	int tests = simplewait_tests;
+
+	while(tests--) {
+		wl_activate(l,0);
+	}
+
+	return 0;
+
+}
+
+int test_simplewaitobject() {
+
+	HANDLE h;
+
+	struct _wait_list *l;
+	int r;
+
+	int tests = simplewait_tests;
+
+	l = wl_new();
+
+	h = new_thread(test_simplewaitobject_helper,l);
+
+	TEST(WaitForSingleObject(h,INFINITE) == WAIT_OBJECT_0);
+
+	CloseHandle(h);
+
+	while(tests--) {
+
+		TEST(l != NULL);
+
+		r = wait_one(l);
+
+		TEST(r == 0);
+
+	}
+
+	/*after this, make sure it blocks*/
+
+	wl_free(l);
+
+	return 0;
+}
+
+
+int test_errnosafe_helper() {
+
+	ASSERT(errno == 0);
+
+	errno = 101;
+	ASSERT( errno == 101);
+
+	return 500;
+
+}
+
+int test_errnosafe() {
+
+	HANDLE h;
+	errno = 102;
+
+	ASSERT(errno == 102);
+
+	h = new_thread(test_errnosafe_helper, NULL);
+
+	TEST(h != NULL);
+	TEST(WaitForSingleObject(h,INFINITE) == WAIT_OBJECT_0);
+
+	CloseHandle(h);
+
+	TEST(errno == 102);
+
+	return 0;
+
+}
+
+int test_maxoverlapped_server(SOCKET s) {
+
+	while ( accept(s,NULL,0) != SOCKET_ERROR);
+
+	return 0;
+}
+
+void CALLBACK test_maxoverlapped_callback (
+ IN DWORD dwError, IN DWORD cbTransferred,
+ IN LPWSAOVERLAPPED lpOverlapped,
+ IN DWORD dwFlags
+) {
+
+
+}
+
+
+int test_maxoverlapped() {
+
+	const int msg_len = 4096;
+
+	HANDLE h;
+
+	SOCKET s;
+	SOCKET c[MAX_BSOCKETS];
+
+	WSABUF buf[MAX_BSOCKETS];
+	WSAOVERLAPPED wo[MAX_BSOCKETS];
+
+	struct sockaddr_in in;
+	struct sockaddr_in name;
+
+	int r;
+	int i;
+
+	int recv, flags;
+
+	s = socket(AF_INET,SOCK_STREAM,0);
+
+	TEST(s != INVALID_SOCKET);
+
+	in.sin_family = AF_INET;
+	in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	in.sin_port = htons(0);
+
+	r = bind(s,(struct sockaddr*) &in,sizeof(struct sockaddr_in));
+	TEST(r != SOCKET_ERROR);
+
+	i = sizeof(struct sockaddr_in);
+	r = getsockname(s,(struct sockaddr*) &name,&i);
+	TEST(r == 0);
+
+	r = listen(s,10);
+	TEST(r != SOCKET_ERROR);
+
+	h = new_thread(test_maxoverlapped_server,(void*) s);
+	TEST(h != NULL);
+
+	for (i=0; i<MAX_BSOCKETS; i++) {
+
+		c[i] = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
+		TEST(c[i] != INVALID_SOCKET);
+
+		r  = connect(c[i],(struct sockaddr*) &name,sizeof(struct sockaddr_in));
+		TEST(r != SOCKET_ERROR);
+
+		flags = 0;
+
+		buf[i].buf = malloc(msg_len);
+		buf[i].len = msg_len;
+
+		SetLastError(0);
+
+		r = WSARecv(c[i],&buf[i],1,(DWORD*) &recv, (DWORD*)&flags,&wo[i],test_maxoverlapped_callback);
+
+		TEST(r == SOCKET_ERROR);
+		TEST(WSAGetLastError() == WSA_IO_PENDING);
+	}
+
+	for (i=0; i<MAX_BSOCKETS; i++) {
+		TEST(closesocket(c[i]) == 0);
+	}
+
+	closesocket(s);
+	return 0;
+}
+
+//todo -- come up with more comprehensive test
+int test_bselect_macros() {
+
+	bfd_set fd;
+
+	BFD_ZERO(&fd);
+
+	TEST(fd.count == 0);
+//	TEST(fd.hash[0] == -1);
+
+	BFD_SET(0,&fd);
+
+	TEST(fd.count == 1);
+	TEST(fd.list[0] == 0);
+
+	TEST(fd.hash[0] == 0);
+
+	BFD_SET(1000,&fd);
+
+	TEST(fd.count == 2);
+	TEST(fd.list[0] == 0);
+	TEST(fd.list[1] == 1000);
+
+	TEST(fd.hash[0]  == 0);
+	TEST(fd.hash[1000] == 1);
+
+	BFD_SET(2000,&fd);
+	TEST(BFD_ISSET(0,&fd) );
+	TEST(BFD_ISSET(1000,&fd));
+	TEST(BFD_ISSET(2000,&fd));
+
+	TEST(fd.count == 3);
+	TEST(fd.list[0] == 0);
+	TEST(fd.list[1] == 1000);
+	TEST(fd.list[2] == 2000);
+
+	TEST(fd.hash[0]	   == 0);
+	TEST(fd.hash[1000] == 1);
+	TEST(fd.hash[2000] == 2);
+
+	BFD_CLR(0,&fd);
+	TEST(!BFD_ISSET(0,&fd));
+	TEST(BFD_ISSET(1000,&fd));
+	TEST(BFD_ISSET(2000,&fd));
+
+	TEST(fd.count == 2);
+	TEST(fd.list[0] == 1000);
+	TEST(fd.list[1] == 2000);
+
+
+	//TEST(fd.hash[0] == -1);
+	TEST(fd.hash[1000]	== 0);
+	TEST(fd.hash[2000]  == 1);
+
+	BFD_SET(0,&fd);
+
+	TEST(fd.count == 3);
+	TEST(fd.list[0] == 1000);
+	TEST(fd.list[1] == 2000);
+	TEST(fd.list[2] == 0);
+
+	TEST(fd.hash[0]    == 2);
+	TEST(fd.hash[1000] == 0);
+	TEST(fd.hash[2000] == 1);
+
+	BFD_CLR(2000,&fd);
+	TEST(BFD_ISSET(0,&fd));
+	TEST(BFD_ISSET(1000,&fd));
+	TEST(!BFD_ISSET(2000,&fd));
+
+	TEST(fd.count == 2);
+	TEST(fd.list[0] 	== 1000);
+	TEST(fd.list[1]		== 0);
+
+	TEST(fd.hash[0]		== 1);
+	TEST(fd.hash[1000]	== 0);
+//	TEST(fd.hash[2000] 	== -1);
+
+	BFD_SET(2000,&fd);
+
+	TEST(fd.count == 3);
+	TEST(fd.list[0] == 1000);
+	TEST(fd.list[1] == 0);
+	TEST(fd.list[2] == 2000);
+
+	TEST(fd.hash[0] == 1);
+	TEST(fd.hash[1000] == 0);
+	TEST(fd.hash[2000] == 2);
+
+	BFD_CLR(2000,&fd);
+	TEST(BFD_ISSET(0,&fd));
+	TEST(BFD_ISSET(1000,&fd));
+	TEST(!BFD_ISSET(2000,&fd));
+
+	TEST(fd.count == 2);
+	TEST(fd.list[0] == 1000);
+	TEST(fd.list[1]	== 0);
+
+	TEST(fd.hash[0]		== 1);
+	TEST(fd.hash[1000]	== 0);
+	//TEST(fd.hash[2000]  == -1);
+
+	BFD_ZERO(&fd);
+
+	TEST(fd.count == 0);
+	TEST(!BFD_ISSET(0,&fd));
+	TEST(!BFD_ISSET(1000,&fd));
+	TEST(!BFD_ISSET(2000,&fd));
+
+//	TEST(fd.hash[0] == -1);
+//	TEST(fd.hash[1000] == -1);
+//	TEST(fd.hash[2000] == -1);
+
+	return 0;
+}
+
+int test_connect_google( ) {
+
+	int fd;
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	google.sin_port = htons(80);
+
+	r = bconnect(fd,(struct sockaddr*) &google,sizeof(google));
+
+	TEST(r == 0);
+
+	r = bclose(fd);
+
+	TEST(r == 0);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_setsocketerr() {
+
+	int fd;
+
+	int err;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	socket_set_err(fd,666,__GLOBAL_BSOCKET_ENV_);
+
+	socket_last_err(fd,&err,__GLOBAL_BSOCKET_ENV_);
+
+	TEST(err == 666);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_multi_connect()  {
+
+	const int clients = 300;
+
+	bfd_set fds_out, fds_in;
+	struct sockaddr_in in;
+
+	int err;
+	int len;
+	int fd[clients];
+	int i;
+	int s;
+
+	int r;
+	int z;
+
+	int port;
+	int counter;
+	int good;
+
+	s = loopback_server(&port);
+
+	TEST(s != 0);
+
+	TEST(bsocket_init(NULL) == 0);
+
+	in.sin_family = AF_INET;
+	in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	in.sin_port = port;
+
+	BFD_ZERO(&fds_in);
+
+	for (i=0; i<clients; i++) {
+
+		fd[i] = bsocket(AF_INET,SOCK_STREAM,0);
+
+		TEST(fd[i] >= 0);
+
+		TEST(bfcntl(fd[i],F_SETFL,O_NONBLOCK) == 0);
+
+		TEST(fd[i] != -1);
+		BFD_SET(fd[i],&fds_in);
+	}
+
+	for (i=0; i<clients; i++) {
+		r = bconnect(fd[i],(struct sockaddr*) &in, sizeof(in));
+
+		TEST(r == -1);
+		TEST(errno == EINPROGRESS);
+	}
+
+	BFD_COPY(&fds_out,&fds_in);
+
+	counter = 0;
+	good = FALSE;
+	while (
+
+		(r = bselect(0,NULL,&fds_out,NULL,NULL)) == 1) {
+
+		len = sizeof(int);
+
+		z = bgetsockopt( fds_out.list[0],SOL_SOCKET,SO_ERROR,&err,&len);
+
+		TEST(z == 0);
+
+		if (err == 0) {
+			good = TRUE;
+		}
+
+
+		BFD_CLR(fds_out.list[0], &fds_in);
+
+		BFD_COPY(&fds_out,&fds_in);
+		counter++;
+	}
+
+	//make sure at least one connection succeeded
+	TEST(good);
+
+
+	TEST(counter == clients);
+
+	TEST(r == -1);
+
+	TEST(fds_out.count == 0);
+
+	for (i=0; i<clients; i++) {
+		TEST(bclose(fd[i]) == 0);
+	}
+
+	//todo -- why does this fail
+	//TEST(closesocket(s) == 0);
+	closesocket(s);
+
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+}
+
+
+int test_simple_write_helper() {
+
+	SOCKET s;
+	SOCKET c;
+
+	int r;
+
+	s = socket(AF_INET,SOCK_STREAM,0);
+
+	SILENT_TEST(s != INVALID_SOCKET);
+
+	SILENT_TEST(bind(s,(struct sockaddr*) &localhost,sizeof(localhost)) == 0);
+
+	SILENT_TEST(listen(s,1) == 0);
+
+	c = accept(s,NULL,0);
+
+	SILENT_TEST(c != INVALID_SOCKET);
+
+	r = -1;
+
+	SILENT_TEST(recv(c,(char*) &r,sizeof(r),0) == sizeof(r));
+
+	SILENT_TEST(r == 666);
+
+	closesocket(s);
+	closesocket(c);
+
+	return 0;
+
+}
+
+int test_simple_write() {
+
+	HANDLE h;
+
+	int msg;
+
+	int fd;
+	int r;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	/*start server*/
+
+	h = new_thread(test_simple_write_helper,NULL);
+	Sleep(100);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+
+	TEST(fd == 0);
+
+	r = bconnect(fd, (struct sockaddr *) &localhost,sizeof(localhost));
+
+	TEST(r == 0);
+
+	msg = 666;
+
+	r = bsend(fd,&msg,sizeof(msg),0);
+
+	TEST(r == sizeof(msg));
+
+	TEST(WaitForSingleObject(h,1000) == WAIT_OBJECT_0);
+
+	TEST(GetExitCodeThread(h,(DWORD*) &r));
+
+	TEST(r == 0);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+}
+
+int test_simple_read_helper() {
+
+	SOCKET s;
+	SOCKET c;
+
+	int r;
+	int msg;
+
+
+	s = socket(AF_INET,SOCK_STREAM,0);
+
+	SILENT_TEST(s != INVALID_SOCKET);
+
+	r = bind(s,(struct sockaddr*) &localhost,sizeof(localhost));
+	SILENT_TEST(r == 0);
+
+	r = listen(s,10);
+	SILENT_TEST(r == 0);
+
+	c = accept(s,NULL,0);
+	SILENT_TEST(c != INVALID_SOCKET);
+
+	msg = 666;
+	Sleep(100);
+
+	r = send(c,(char*) &msg, sizeof(msg),0);
+	SILENT_TEST(r == sizeof(msg));
+
+	closesocket(s);
+	closesocket(c);
+
+	return 0;
+
+}
+
+int test_simple_read() {
+
+	HANDLE h;
+
+	int fd;
+	int r;
+	int msg;
+
+	TEST(bsocket_init(NULL) == 0);
+
+	h = new_thread(test_simple_read_helper,NULL);
+	TEST(h != NULL);
+
+	fd = bsocket(AF_INET,SOCK_STREAM,0);
+	TEST(fd == 0);
+
+	r = bconnect(fd,(struct sockaddr*) &localhost,sizeof(localhost));
+	TEST(r == 0);
+
+	r = brecv(fd,&msg,sizeof(msg),0);
+
+	TEST(r == sizeof(msg));
+	TEST(msg == 666);
+
+	TEST(bsocket_shutdown(NULL) == 0);
+
+	return 0;
+
+}
+
+int test_verify_npp_usage() {
+	errno = 666;
+	return -1;
+}
+
+
+int test_complex_select() {
+	return -1;
+}
+
+
+struct test_case tc[] =
+
+{
+	{test_errnosafe,NULL,"Check if errno is thread safe."},
+	{test_createlist,NULL,"Create and destroy list"},
+	{test_basicqueue,NULL,"Create list, add and remove single element. Check integrity."},
+	{test_bigqueue,NULL,"Insertion and removal of a large number of random elements into queue."},
+	{test_listdetach,NULL,"Test detaching node from list."},
+	{test_envmutex,NULL,"Test environment mutexes."},
+	{test_envmutexclose,NULL,"Test if shutdown properly closes mutexes."},
+	{test_setsocketerr,NULL,"Test setting socket error."},
+	{test_socketmutex,NULL,"Test socket mutexes."},
+	{test_socketmutexclose,NULL,"Test if socket close properly releases mutex ownership."},
+	{test_syncstruct,NULL,"Simple usage of synchronization objects."},
+	{test_badsocket,NULL,"Test is mutex fails for non-existent socket."},
+	{test_socketinit,NULL,"Test indempotency of init operation"},
+	{test_overflowsocket,NULL,"Testing if bsocket() fails after creating too many sockets."},
+	{test_simplewaitobject,NULL,"Testing simple usage of wait objects."},
+	{test_waitobject,NULL,"Test more complicated usage of wait objects."},
+	{test_waitfail,NULL,"Tests if a wait object fails when it should."},
+	{test_waitclose,NULL,"Test if a wait object behaves properly on closure."},
+	{test_maxoverlapped,NULL,"Test if we can have a sufficient number of outstanding operations."},
+	{test_bselect_macros,NULL,"Testing bselect() macros."},
+//	{test_multieventselect,NULL,"Can we have more than one socket associated with a WSAevent."},
+	//{test_theory1,NULL,"Test theory #1 (WSAwfme does not block when socket closed."},
+	//todo -- find a way to reduce timeout
+	//{test_badconnection_blocking,NULL,"Test if connection to unreachable host fails appropriately. (blocking)"},
+	{test_parallel_connect,NULL,"Test if multiple connections to same socket fail appropriately."},
+	{test_connect_close,NULL,"Test if close() while waiting on connect causes problems."},
+	{test_connect_google,NULL,"Test connection to google.com"},
+	{test_active_refusal_blocking,NULL,"Test if active refusal handled properly. (blocking)"},
+	{test_active_refusal_nonblocking,NULL,"\t(non-blocking)"},
+	{test_multi_connect,NULL,"Test rapid firing server with connections."},
+	{test_simple_write,NULL,"Connect and send some data to a server."},
+	{test_simple_read,NULL,"Connect and read some data from a server."},
+	{test_verify_npp_usage,NULL,"Check that the NPP is not being used for large sends."},
+	{NULL,NULL,NULL}
+};
+
+//todo -- one of the tests is opening and not closing a large number of handles
+int main(int argc, char **argv) {
+
+	struct hostent *host;
+
+	/*todo warn user about this putting strain on system*/
+	int i = 0;
+
+	int pass = 0;
+	int fail = 0;
+
+	srand(time(NULL));
+
+	//todo uncomment
+	winsock_start();
+
+	//lookup googles address before starting (we want something that should be available)
+
+	host = gethostbyname("google.com");
+	ASSERT(host != NULL);
+
+	google.sin_family = AF_INET;
+	google.sin_addr = *(struct in_addr *) host->h_addr;
+
+	localhost.sin_family = AF_INET;
+	localhost.sin_addr.s_addr = inet_addr("127.0.0.1");
+	localhost.sin_port = htons(81);
+
+	if (argc > 1) {
+		i = atoi(argv[1]);
+	}
+
+	while (tc[i].fun != NULL) {
+
+		printf("Test #%d: %s\n",i,tc[i].desc);
+		fflush(stdout);
+
+		if ( tc[i].fun() ) {
+
+			printf("\n");
+			fflush(stdout);
+			fail++;
+		} else {
+			pass++;
+		}
+
+		i++;
+
+		if (argc > 1)
+			break;
+
+	}
+
+	printf("\nTesting Report: %d passed, %d failed\n",pass,fail);
+
+	return 0;
+
+}
+


Property changes on: bsockets/trunk/test.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/test.h
===================================================================
--- bsockets/trunk/test.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/test.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,10 @@
+#ifndef _TEST_H_
+#define _TEST_H
+
+#define TEST(X)  			if (!((res = X))) { printf("Assertion failed: \"%s\" [errno:%d, w32err:%d line:%d]\n", #X,errno,(int) GetLastError(),__LINE__); fflush(stdout); return 1; }
+#define SILENT_TEST(X)		if (!(X)) { return GetLastError(); }
+
+#endif
+
+
+


Property changes on: bsockets/trunk/test.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/todo
===================================================================
--- bsockets/trunk/todo	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/todo	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,10 @@
+todo
+-----
+
+- make getsockopt()
+- make listen()
+- make accept()
+- make read()
+- make write()
+- make socketpair()
+- make bsocket.c (links to system specific versions)


Property changes on: bsockets/trunk/todo
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/unix.c
===================================================================
--- bsockets/trunk/unix.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/unix.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,49 @@
+#include <windows.h>
+
+#include "unix.h"
+
+
+int unixify_wsaerr(DWORD err) {
+
+	int out = -1;
+
+	switch (err) {
+
+		case 0:
+			out = 0;
+		break;
+
+		case WSANOTINITIALISED:
+			out = ENOTINIT;
+		break;
+
+		case WSAEMFILE:
+			out = EMFILE;
+		break;
+
+		case WSAENOBUFS:
+			out = ENOBUFS;
+		break;
+
+		case WSAETIMEDOUT:
+			out = ETIMEDOUT;
+		break;
+
+		case WSAEWOULDBLOCK:
+			out = EINPROGRESS;
+		break;
+
+		case WSAECONNREFUSED:
+			out = ECONNREFUSED;
+		break;
+
+		default:
+			out = err;
+		break;
+
+	}
+
+	return out;
+
+}
+


Property changes on: bsockets/trunk/unix.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/unix.h
===================================================================
--- bsockets/trunk/unix.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/unix.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,68 @@
+#ifndef _UNIX_H_
+#define _UNIX_H_
+
+#include <windows.h>
+#include <errno.h>
+
+int unixify_wsaerr(DWORD);
+
+#define BSOCK_PRIVATE_ERRNO 110000
+
+//todo check that these are in private ranges
+#ifndef ENOBUFS
+#define ENOBUFS			(BSOCK_PRIVATE_ERRNO+1)
+#endif
+
+#ifndef EMFILE
+#define EMFILE			(BSOCK_PRIVATE_ERRNO+2)
+#endif
+
+#ifndef ENOSYS
+#define ENOSYS			(BSOCK_PRIVATE_ERRNO+3)
+#endif
+
+#ifndef EINVAL
+#define EINVAL			(BSOCK_PRIVATE_ERRNO+4)
+#endif
+
+#ifndef ENOTINIT
+#define ENOTINIT		(BSOCK_PRIVATE_ERRNO+5)
+#endif
+
+#ifndef EALREADY
+#define EALREADY		(BSOCK_PRIVATE_ERRNO+6)
+#endif
+
+#ifndef EISCONN
+#define EISCONN			(BSOCK_PRIVATE_ERRNO+7)
+#endif
+
+#ifndef EBADF
+#define EBADF			(BSOCK_PRIVATE_ERRNO+8)
+#endif
+
+#ifndef EINPROGRESS
+#define	EINPROGRESS		(BSOCK_PRIVATE_ERRNO+9)
+#endif
+
+#ifndef ETIMEDOUT
+#define	ETIMEDOUT		(BSOCK_PRIVATE_ERRNO+10)
+#endif
+
+#ifndef ECONNREFUSED
+#define ECONNREFUSED	(BSOCK_PRIVATE_ERRNO+11)
+#endif
+
+#ifndef EEMPTY
+#define EEMPTY			(BSOCK_PRIVATE_ERRNO+12)
+#endif
+
+#ifndef ENOTSUP
+#define ENOTSUP			(BSOCK_PRIVATE_ERRNO+13)
+#endif
+
+#ifndef ECLOSED
+#define ECLOSED			(BSOCK_PRIVATE_ERRNO+14)
+#endif
+
+#endif


Property changes on: bsockets/trunk/unix.h
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/wait.c
===================================================================
--- bsockets/trunk/wait.c	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/wait.c	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,346 @@
+#include <windows.h>
+
+#include "unix.h"
+#include "list.h"
+#include "wait.h"
+#include "misc.h"
+
+
+//todo, come up with a way to recycle monitor objects so we dont have
+//keep allocating them for each wait operation
+
+//todo -- resolve external race conditions with AE_LIST
+
+//todo -- when activated with error code, each wait should return with that error code
+int monitor_link(struct _wait_list *l, struct _monitor *m) {
+
+	int out;
+
+	out = 0;
+
+	ASSERT(l != NULL);
+	ASSERT(m != NULL);
+
+
+	if (l->active) {
+
+		out = 1;
+
+	} else {
+
+		if (l->waiting == NULL) {
+
+			CHECK(list_enqueue(l, m->where) != NULL,0);
+
+			l->waiting = m;
+
+
+		} else {
+
+			errno = EAGAIN;
+			out = -1;
+
+		}
+
+	}
+
+	fail:
+
+	return out;
+}
+
+void monitor_detach(struct _monitor *m) {
+
+	struct _wait_list *l;
+
+	ASSERT(m != NULL);
+
+	while (list_dequeue(&l,m->where) == 0) {
+
+		ASSERT(l != NULL);
+		ASSERT(l->waiting == m);
+
+		l->waiting = NULL;
+
+	}
+
+	ASSERT(m->where->head == NULL);
+	ASSERT(m->where->tail == NULL);
+
+}
+
+//todo -- this function should not require any time of atomicity
+void monitor_wait(struct _monitor *m, int timeout) {
+
+	int r;
+
+	ASSERT(m != NULL);
+
+	if (timeout == -1) {
+		timeout = INFINITE;
+	}
+
+
+	r = WaitForSingleObject(m->event,timeout);
+
+	switch(r) {
+
+		case WAIT_OBJECT_0:
+			ASSERT(
+				(m->who != NULL) ||
+				(m->who == NULL && m->err != 0)
+				);
+
+		break;
+
+
+		case WAIT_TIMEOUT:
+			ASSERT(timeout != INFINITE);
+			m->who = NULL;
+			m->err = ETIMEDOUT;
+			monitor_detach(m);
+		break;
+
+
+		default:
+			ASSERT(FALSE);
+		break;
+
+
+	}
+
+	ASSERT(m->where != NULL);
+	ASSERT(m->where->head == NULL);
+
+	if (m->who == NULL) {
+		ASSERT(m->err != 0);
+	}
+
+}
+
+void monitor_free(struct _monitor *m) {
+
+	ASSERT(m != NULL);
+
+	monitor_detach(m);
+
+	if (m->event != NULL)
+		ASSERT(CloseHandle(m->event));
+
+	if (m->where != NULL)
+		list_free(m->where);
+
+	free(m);
+
+}
+
+struct _monitor *monitor_new() {
+
+	struct _monitor *m;
+	int out;
+	int err;
+
+	out = 0;
+	err = 0;
+
+	m = (struct _monitor*)
+		malloc(sizeof(struct _monitor));
+
+	CHECK(m != NULL,ENOMEM);
+
+	m->where = list_new();
+	CHECK(m->where != NULL,0);
+
+	m->event = CreateEvent(NULL,FALSE,FALSE,NULL);
+	CHECK_(m->event != NULL);
+
+	fail:
+	err = errno;
+
+	if (out == -1) {
+
+		if (m != NULL) {
+			ASSERT(FALSE);
+			monitor_free(m);
+			m = NULL;
+		}
+
+	}
+
+	errno = err;
+	return m;
+}
+
+//todo -- get rid of multiple release mutexes
+//this code is a nightmare, clean it up
+int wait_many_timeout(struct _wait_list **d, int n, int timeout) {
+
+	struct _monitor *m;
+
+	ASSERT(d != NULL);
+
+	int i;
+	int out;
+	int r;
+
+
+	m = monitor_new();
+
+	CHECK(m != NULL,0);
+
+
+	for (i=0; i<n; i++) {
+
+		r = monitor_link(d[i],m);
+
+		CHECK(r != -1,0);
+
+		if (r == 1) {
+
+			//we have found one which is open, no need to keep looking
+			monitor_free(m);
+
+			//todo -- i hate this
+			return i;
+
+		} else {
+			ASSERT(r == 0)
+		}
+
+	}
+
+	monitor_wait(m,timeout);
+
+	//todo -- why was this here?
+	//ASSERT(m->who != NULL);
+
+	out = -1;
+	if (m->err) {
+
+		errno = m->err;
+
+		CHECK(FALSE,0);
+	}
+
+	//todo -- there must be a way to do this in constant time
+	for(i=0; i<n; i++) {
+		if (d[i] == m->who) {
+			out = i;
+			i = n+1;
+		}
+	}
+
+	ASSERT(out >= 0);
+	ASSERT(out < n);
+
+	fail:
+
+	if (m != NULL) {
+		monitor_free(m);
+	}
+
+	return out;
+}
+
+int wait_many(struct _wait_list **d, int n) {
+	return wait_many_timeout(d,n,-1);
+}
+
+int wait_one(struct _wait_list *item) {
+
+	struct _wait_list *d[1];
+
+	d[0] = item;
+
+	return wait_many(d,1);
+
+}
+
+/*
+void wl_open(struct _wait_list *wl) {
+
+	ASSERT(wl != NULL);
+
+	wl_activate(wl,0);
+	wl->active = -1;
+
+}
+
+void wl_close(struct _wait_list *wl)  {
+
+	ASSERT(wl != NULL);
+	//you are not allowed to call wl_close on a closed lists
+	ASSERT(wl->waiting == NULL);
+
+	wl->active = 0;
+
+}
+
+*/
+
+void wl_activate(struct _wait_list *l, int code) {
+
+	struct _monitor *m;
+
+	ASSERT(l != NULL);
+
+	if ( (m = l->waiting) != NULL) {
+
+
+		monitor_detach(m);
+		m->who = l;
+		m->err = code;
+
+		SetEvent(m->event);
+
+	}
+
+
+	l->active = TRUE;
+
+
+}
+
+void wl_deactivate(struct _wait_list *l) {
+
+	ASSERT(l->waiting == NULL);
+	ASSERT(l->active);
+
+	l->active = FALSE;
+
+}
+
+void wl_free (struct _wait_list *l){
+
+	wl_activate(l,ECLOSED);
+
+	ASSERT(l != NULL)
+
+	free(l);
+
+}
+
+struct _wait_list *wl_new() {
+
+	struct _wait_list *out;
+
+	out =  (struct _wait_list*)	malloc(sizeof(struct _wait_list));
+
+	if (out != NULL) {
+
+		out->waiting = NULL;
+		out->active = 0;
+
+	} else {
+
+		errno = ENOMEM;
+
+	}
+
+	return out;
+}
+
+
+
+
+


Property changes on: bsockets/trunk/wait.c
___________________________________________________________________
Name: svn:executable
   + 

Added: bsockets/trunk/wait.h
===================================================================
--- bsockets/trunk/wait.h	2006-07-27 03:17:50 UTC (rev 6916)
+++ bsockets/trunk/wait.h	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,53 @@
+#ifndef _WAIT_H_
+#define _WAIT_H_
+
+struct _wait_list {
+
+	/*a queue of monitors who want to be woken up in order when data is
+		available*/
+
+	struct _monitor *waiting;
+
+	int active;
+
+};
+
+
+struct _monitor {
+
+	/*whoever is waiting on this monitor is waiting for this event
+		to be triggered before doing anything*/
+
+	HANDLE event;
+
+	/*nodes which are in lines in which we are currently waiting*/
+	struct _list *where;
+
+
+	/*a pointer to the object who woke us up */
+	struct _wait_list *who;
+
+	int err;
+	int timeout;
+
+};
+
+
+
+struct _wait_list *wl_new();
+void wl_free();
+
+int wait_one(struct _wait_list *);
+int wait_many(struct _wait_list **, int);
+
+int wait_many_timeout(struct _wait_list **, int, int);
+
+void wl_open(struct _wait_list *);
+void wl_close(struct _wait_list *);
+
+void wl_activate(struct _wait_list *, int);
+void wl_deactivate(struct _wait_list *);
+
+//void wl_wakeall(struct _wait_list *, int);
+
+#endif


Property changes on: bsockets/trunk/wait.h
___________________________________________________________________
Name: svn:executable
   + 

Added: svn-commit.tmp
===================================================================
--- svn-commit.tmp	2006-07-27 03:17:50 UTC (rev 6916)
+++ svn-commit.tmp	2006-07-27 03:47:11 UTC (rev 6917)
@@ -0,0 +1,5 @@
+Inital import for Mike Chiussi's bsockets library.
+
+--This line, and those below, will be ignored--
+
+A    .



More information about the tor-commits mailing list