[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