[or-cvs] r8495: added some changes to epoll() version. (bsockets/trunk/contrib/liboverlapped)

chiussi at seul.org chiussi at seul.org
Mon Sep 25 02:45:45 UTC 2006


Author: chiussi
Date: 2006-09-24 22:45:45 -0400 (Sun, 24 Sep 2006)
New Revision: 8495

Modified:
   bsockets/trunk/contrib/liboverlapped/cmd.c
   bsockets/trunk/contrib/liboverlapped/cmd.h
   bsockets/trunk/contrib/liboverlapped/env.c
   bsockets/trunk/contrib/liboverlapped/env.h
   bsockets/trunk/contrib/liboverlapped/file.c
   bsockets/trunk/contrib/liboverlapped/file.h
   bsockets/trunk/contrib/liboverlapped/list.c
   bsockets/trunk/contrib/liboverlapped/misc.c
   bsockets/trunk/contrib/liboverlapped/overlapped.c
   bsockets/trunk/contrib/liboverlapped/overlapped.h
   bsockets/trunk/contrib/liboverlapped/socket.c
   bsockets/trunk/contrib/liboverlapped/socket.h
   bsockets/trunk/contrib/liboverlapped/test.c
   bsockets/trunk/contrib/liboverlapped/test.h
Log:
added some changes to epoll() version.



Modified: bsockets/trunk/contrib/liboverlapped/cmd.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/cmd.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/cmd.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -7,6 +7,7 @@
 #include "misc.h"
 #include "list.h"
 #include "socket.h"
+#include "file.h"
 
 void cmd_post(struct _cmd *cmd, struct _file_env *env)  {
 
@@ -56,47 +57,62 @@
 
 	cmd->ret = ret;
 	cmd->err = err;
+
 	ASSERT(SetEvent(cmd->done_e));
 
 }
 
+void cmd_defer(struct _cmd *cmd, int code) {
+
+	if (cmd->f->blocking)
+		cmd->wait = TRUE;
+
+	if (!code) {
+		code = EAGAIN;
+	}
+
+	cmd_done(cmd,-1,code);
+
+}
+
 //cmd2 is ignored
 void cmd_dispatch(struct _cmd *cmd2, struct _file_env *env) {
 
 	struct _cmd *cmd;
-	struct _file *f;
-	struct _socket *s;
 
-
 	int err;
 	int out;
 
 	cmd_next(&cmd,env);
 
+
 	if (cmd == NULL)
 		return;
 
+	cmd->wait = FALSE;
+
 	if (cmd->fd != -1) {
-		f = file_get(cmd->fd,env);
-		if (f == NULL) {
+		cmd->f = file_get(cmd->fd,env);
+		if (cmd->f == NULL) {
 			cmd_done(cmd,-1,errno);
 			cmd = NULL;
 		}
 
-		switch (f->type) {
+		switch (cmd->f->type) {
 
 			case FT_SOCKET:
-				s = f->data;
+				cmd->s = cmd->f->data;
+				ASSERT(cmd->s != NULL);
 			break;
 
 			default:
 				ASSERT(FALSE);
 			break;
 		}
+	}
 
+	//todo -- check if is socket before using socket function
 
-	}
-
 	if (cmd != NULL) {
 
 		switch (cmd->type) {
@@ -115,25 +131,45 @@
 			break;
 
 			case CMD_SOCKET_CONNECT:
-				socket_connect(f,s,cmd,env);
+				socket_connect(cmd,env);
 			break;
 
 			case CMD_FILE_CLOSE:
 
-				//if there is an outstanding error, be sure to report it
-				if (f->err) {
+				//if there is an outstanding error, report it
+				if (cmd->f->err) {
 					out = -1;
-					err = f->err;
+					err = cmd->f->err;
 				} else {
 					out = 0;
 				}
 
-				file_close(f,env);
-
+				file_close(cmd->f,env);
 				cmd_done(cmd,out,err);
 
 			break;
 
+			case CMD_SOCKET_BIND:
+				socket_bind(cmd,env);
+			break;
+
+			case CMD_SOCKET_LISTEN:
+				socket_listen(cmd,env);
+			break;
+
+			case CMD_SOCKET_GET_NAME:
+				socket_get_name(cmd,env);
+			break;
+
+			case CMD_FILE_WAIT:
+				file_wait(cmd,(int)cmd->arg[0],env);
+			break;
+
+			case CMD_FILE_ERROR:
+				file_last_error(cmd->f,cmd->arg[0]);
+				cmd_done(cmd,0,0);
+			break;
+
 			default:
 				ASSERT(FALSE);
 			break;

Modified: bsockets/trunk/contrib/liboverlapped/cmd.h
===================================================================
--- bsockets/trunk/contrib/liboverlapped/cmd.h	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/cmd.h	2006-09-25 02:45:45 UTC (rev 8495)
@@ -2,36 +2,30 @@
 #define _CMD_H_
 
 #include <windows.h>
+
 #include "env.h"
 
-struct _cmd {
-
-	HANDLE done_e;
-
-	void *arg[32];
-
-	int type;
-
-	int ret;
-	int err;
-
-	int fd;
-};
-
 void cmd_post(struct _cmd*, struct _file_env*);
 void cmd_next(struct _cmd**, struct _file_env*);
 void cmd_done(struct _cmd*, int, int);
+void cmd_defer(struct _cmd*, int);
 void cmd_dispatch(struct _cmd *cmd, struct _file_env*);
 
 #define CMD_PING	1
 
 #define CMD_FILE_CLOSE	10
+#define CMD_FILE_ERROR	11 	//get last file error, if any
+#define CMD_FILE_WAIT	19
 
-
 #define CMD_SOCKET_NEW		20
 #define CMD_SOCKET_CONNECT	21
+#define CMD_SOCKET_BIND		22
+#define CMD_SOCKET_LISTEN	23
+#define CMD_SOCKET_ACCEPT	24
 
+#define CMD_SOCKET_GET_NAME	40
 
+
 #define CMD_SHUTDOWN 100
 
 

Modified: bsockets/trunk/contrib/liboverlapped/env.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/env.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/env.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -6,12 +6,20 @@
 #include "env.h"
 #include "cmd.h"
 #include "list.h"
+#include "file.h"
 
 static struct _file_env_options default_env_options = {
 	1000,
-	1000
+	1000,
+	10,
+	10
 };
 
+//make sure nothing is wrong with the options the user gave
+int env_check_options(struct _file_env_options *opt) {
+	return -1;
+}
+
 void env_main_loop(struct _file_env *env) {
 
 	int i;
@@ -38,12 +46,13 @@
 
 			default:
 				i = r - WAIT_OBJECT_0;
-				env->ev_callback[i](env->cmd[i],env);
+				env->ev_callback[i](env->ev_data[i],env);
 			break;
 		}
 	}
 }
 
+
 void env_ping(struct _file_env *env) {
 
 	struct _cmd cmd;
@@ -89,12 +98,12 @@
 	}
 
 	if (env->fd != NULL) {
-		for (i=0; i<env->opt.maxfiles; i++)
+		for (i=0; i<env->opt.max_files; i++)
 			if (env->fd[i] != NULL) {
 				file_close(env->fd[i],env);
 			}
 
-		for (i=0; i<env->opt.maxfiles; i++)
+		for (i=0; i<env->opt.max_files; i++)
 			ASSERT(env->fd[i] == NULL);
 	}
 
@@ -110,6 +119,9 @@
 		list_free(env->cmd_q);
 	}
 
+	if (env->waiting_to_connect != NULL) {
+		list_free(env->waiting_to_connect);
+	}
 
 	for (i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++) {
 		if (env->ev[i] != NULL) {
@@ -132,7 +144,6 @@
 	int out;
 
 	//note: the user is responsible for manually init'ing winsock
-
 	if (opt == NULL) {
 		opt = &default_env_options;
 	}
@@ -149,27 +160,35 @@
 	env->post_m = NULL;
 	env->cmd_q = NULL;
 	env->thread = NULL;
+	env->waiting_to_connect = NULL;
 
+	env->connections_half_open = 0;
+
 	for (i=0; i<WSA_MAXIMUM_WAIT_EVENTS;i++) {
 		env->ev[i] = NULL;
 	}
 
 	memcpy(&env->opt,opt, sizeof(struct _file_env_options));
 
-	env->fd = malloc(sizeof(struct _file*)*opt->maxfiles);
+	env->fd = malloc(sizeof(struct _file*)*opt->max_files);
 
-	for (i=0; i<opt->maxfiles; i++) {
+	for (i=0; i<opt->max_files; i++) {
 		env->fd[i] = NULL;
 	}
 
 	env->free_q = list_new();
+	CHECK(env->free_q != NULL,0);
 
-	for (i=0; i<opt->maxfiles; i++) {
+	env->waiting_to_connect = list_new();
+	CHECK(env->waiting_to_connect != NULL,0);
+
+	for (i=0; i<opt->max_files; i++) {
 		list_enqueue((void*) i,env->free_q);
 	}
 
 	for (i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++) {
 		env->ev[i] = WSACreateEvent();
+		env->ev_callback[i] = NULL;
 		CHECK0(env->ev[i] != WSA_INVALID_EVENT);
 	}
 

Modified: bsockets/trunk/contrib/liboverlapped/env.h
===================================================================
--- bsockets/trunk/contrib/liboverlapped/env.h	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/env.h	2006-09-25 02:45:45 UTC (rev 8495)
@@ -2,10 +2,73 @@
 #define _ENV_H_
 
 #include "overlapped.h"
-#include "file.h"
+#include "list.h"
 
-struct _cmd;
+struct _file {
 
+	/*system file identifier*/
+	void *handle;
+
+	/*local file identifier*/
+	int fd;
+
+	/*what time of file are we (ie, disk file, socket, epoll, etc)*/
+	int type;
+	void *data; //pointer to type specific data
+
+	/*input and output streams*/
+	struct _list *in_buf;
+	struct _list *out_buf;
+
+	/*the last error that occured during file processin
+	(should be reset everytime it is looked at)	*/
+	int err;
+
+	/*set if we are open/connected to something*/
+	int open;
+
+	/*true if we are in blocking mode*/
+	int blocking;
+
+	/*state - is the socket currently one of the above*/
+	int ready[32];
+
+	/*lists of callbacks to be executed if and when the socket becomes available*/
+	struct _list *read_callbacks;
+	struct _list *write_callbacks;
+
+	/*records the value of the last error that occured*/
+	int error;
+
+
+};
+
+struct _cmd {
+
+	HANDLE done_e;
+
+	void *arg[32];
+
+	int type;
+
+	int ret;
+	int err;
+
+	int fd;
+
+	/*these can only be touched after command as been dispatched*/
+	struct _file *f;
+	struct _socket *s;
+
+	/*a helper member, makes code prettier in some places*/
+	int i;
+
+	/*true if command as been defered (ie, tell user EAGAIN)*/
+	int wait;
+
+};
+
+
 struct _file_env {
 
 	/*environment options*/
@@ -34,9 +97,16 @@
 		(struct _cmd*, struct _file_env *);
 
 	//holds the command associated with that spot on ev
-	struct _cmd *cmd[WSA_MAXIMUM_WAIT_EVENTS];
+	void *ev_data[WSA_MAXIMUM_WAIT_EVENTS];
+
+	/* */
+	int connections_half_open;
+	struct _list *waiting_to_connect;
+
 };
 
+void env_watch_socket_event(struct _cmd *, void *, struct _file_env *);
+void env_unwatch_socket_event(SOCKET s, int i, struct _file_env *);
 
 #endif
 

Modified: bsockets/trunk/contrib/liboverlapped/file.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/file.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/file.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -5,35 +5,112 @@
 #include "misc.h"
 #include "env.h"
 #include "list.h"
+#include "cmd.h"
 
+struct _callback {
+	void (*fun)();
+	void *data;
+};
+
+struct _callback *cb_new(void *fun, void *data) {
+
+	struct _callback *out;
+
+	out = (struct _callback*) malloc(sizeof(struct _callback));
+
+	if (out != NULL) {
+
+		out->fun = fun;
+		out->data = data;
+	} else {
+		errno = ENOMEM;
+	}
+	return out;
+}
+
+void cb_free(struct _callback *cb) {
+	free(cb);
+}
+
 struct _file *file_get(int fd, struct _file_env *env) {
 
 	struct _file *out;
 
-	if (fd < 0 || fd >= env->opt.maxfiles) {
-
+	if (fd < 0 || fd >= env->opt.max_files) {
 		errno = EINVAL;
 		out = NULL;
-
 	} else {
-
 		out = env->fd[fd];
-
 		if (out == NULL) {
 			errno = EBADF;
 		}
+	}
+	return out;
+}
 
+void file_control(struct _cmd *cmd, struct _file_env *env) {
+
+}
+
+void file_wait(struct _cmd *cmd, int state, struct _file_env *env) {
+
+	struct _callback *cb;
+	struct _list *l;
+
+	int out = 0;
+
+	if (!cmd->f->ready[state]) {
+
+		cb = cb_new(cmd_done,cmd);
+		CHECK(cb != NULL,0);
+
+		switch (state) {
+
+			case FILE_IS_READABLE:
+				l = cmd->f->read_callbacks;
+			break;
+
+			case FILE_IS_WRITABLE:
+				l = cmd->f->write_callbacks;
+			break;
+
+			default:
+				ASSERT(FALSE);
+			break;
+		}
+		CHECK(list_enqueue(cb,l) != NULL,0);
+	} else {
+		cmd_done(cmd,0,0);
 	}
 
-	return out;
+	fail:
 
+	if (out == -1) {
+
+		cmd_done(cmd,-1,errno);
+
+		if (cb != NULL)
+			cb_free(cb);
+
+	}
+
+
 }
 
-void file_exception(struct _file *f, int code) {
+//get and set the last error for this file
+void file_last_error(struct _file *f, int *r) {
+	*r = f->error;
+	f->error = 0;
+}
 
+void file_exception(struct _file *f, int code, struct _file_env *env) {
+
+	//raise readable and writable
+
 	switch (f->type) {
 
 		case FT_SOCKET:
+			//todo -- unwatch socket events
 			closesocket((SOCKET) f->handle);
 		break;
 
@@ -43,18 +120,50 @@
 	}
 }
 
+void file_raise(struct _file *f, int type, int code, struct _file_env *env) {
+
+	struct _callback *cb;
+	struct _list *l;
+
+	/*set status bit*/
+	f->ready[type] = TRUE;
+
+
+	switch (type) {
+
+		case FILE_IS_READABLE:
+			l = f->read_callbacks;
+		break;
+
+		case FILE_IS_WRITABLE:
+			l = f->write_callbacks;
+		break;
+
+		default:
+			ASSERT(FALSE);
+		break;
+	}
+
+	/*does anyone want to know we are ready?*/
+	//todo -- iterate through list, dont use queue interface
+	while (list_dequeue(&cb,l) == 0) {
+		//todo -- if an epoll pointer, requeue, do not free
+		cb->fun(cb->data,0,0);
+		cb_free(cb);
+	}
+}
+
 void file_close(struct _file *f, struct _file_env *env) {
 
 	if (f->fd != -1) {
-		file_exception(f,ECLOSED);
-		ASSERT(env->fd[f->fd] = f);
+		file_exception(f,ECLOSED,env);
+		ASSERT(env->fd[f->fd] == f);
 		env->fd[f->fd] = NULL;
 	}
 
 	if (f->in_buf != NULL) {
 		//todo dump in buffer
 		list_free(f->in_buf);
-
 	}
 
 	if (f->out_buf != NULL) {
@@ -62,6 +171,18 @@
 		list_free(f->out_buf);
 	}
 
+	if (f->read_callbacks != NULL) {
+		//todo -- assert list is empty
+		list_free(f->read_callbacks);
+	}
+
+	if (f->write_callbacks != NULL) {
+		//todo -- assert list is empty
+		list_free(f->write_callbacks);
+	}
+
+	//todo
+	/*if file is in the middle of doing something interrupt it */
 	if (f->data != NULL)
 		free(f->data);
 
@@ -72,6 +193,7 @@
 
 	struct _file *f;
 
+	int i;
 	int out;
 
 	f = (struct _file*) malloc(sizeof(struct _file));
@@ -83,12 +205,21 @@
 	f->in_buf = NULL;
 	f->out_buf = NULL;
 	f->open = FALSE;
+	f->data = NULL;
+	f->blocking = TRUE;
 
+	f->read_callbacks = NULL;
+	f->write_callbacks = NULL;
+
 	/*find a fd for our new friend*/
 	CHECK(list_dequeue(&f->fd,env->free_q) == 0, ENFILE);
 
+	for (i=0; i<5; i++) {
+		f->ready[i] = FALSE;
+	}
+
 	ASSERT(f->fd >= 0);
-	ASSERT(f->fd < env->opt.maxfiles);
+	ASSERT(f->fd < env->opt.max_files);
 
 	env->fd[f->fd] = f;
 
@@ -98,6 +229,12 @@
 	f->out_buf = list_new();
 	CHECK(f->out_buf != NULL,0);
 
+	f->read_callbacks = list_new();
+	CHECK(f->read_callbacks != NULL,0);
+
+	f->write_callbacks = list_new();
+	CHECK(f->write_callbacks != NULL,0);
+
 	fail:
 
 	if (out == -1) {

Modified: bsockets/trunk/contrib/liboverlapped/file.h
===================================================================
--- bsockets/trunk/contrib/liboverlapped/file.h	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/file.h	2006-09-25 02:45:45 UTC (rev 8495)
@@ -1,40 +1,22 @@
 #ifndef _FILE_H_
 #define _FILE_H_
 
+#include "env.h"
 
-struct _file {
+#define FILE_IS_READABLE 1
+#define FILE_IS_WRITABLE 2
 
-	/*system file identifier*/
-	void *handle;
 
-	/*local file identifier*/
-	int fd;
-
-	/*what time of file are we (ie, disk file, socket, epoll, etc)*/
-	int type;
-	void *data; //pointer to type specific data
-
-	/*input and output streams*/
-	struct _list *in_buf;
-	struct _list *out_buf;
-
-	/*the last error that occured during file processin
-	(should be reset everytime it is looked at)	*/
-	int err;
-
-	/*set if we are open/connected to something*/
-	int open;
-
-	/*true if we are in blocking mode*/
-	int blocking;
-
-};
-
-void file_close(struct _file *, struct _file_env *env);
-struct _file *file_new(struct _file_env *env);
-struct _file *file_get(int fd, struct _file_env *env);
-
 #define FT_SOCKET	1
 #define FT_EPOLL	2
 
+
+void file_close(struct _file *, struct _file_env *);
+struct _file *file_new(struct _file_env *);
+struct _file *file_get(int fd, struct _file_env *);
+void file_exception(struct _file*, int, struct _file_env *);
+void file_wait(struct _cmd*, int, struct _file_env *);
+
+void file_raise(struct _file *, int, int, struct _file_env *);
+void file_last_error(struct _file *, int*);
 #endif

Modified: bsockets/trunk/contrib/liboverlapped/list.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/list.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/list.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -132,7 +132,6 @@
 void list_free(struct _list *list) {
 
 	int n;
-
 	while (list_dequeue(&n,list) == 0);
 	free(list);
 }

Modified: bsockets/trunk/contrib/liboverlapped/misc.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/misc.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/misc.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -8,17 +8,10 @@
 
 	switch (err) {
 
-
-
-
 		default:
 			out = err;
 		break;
-
-
 	}
-
 	return out;
-
 }
 

Modified: bsockets/trunk/contrib/liboverlapped/overlapped.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/overlapped.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/overlapped.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -4,6 +4,7 @@
 
 #include "overlapped.h"
 #include "cmd.h"
+#include "file.h"
 
 struct _file_env *__GLOBAL_FILE_ENV_;
 
@@ -41,11 +42,89 @@
 	CMD_PROC(CMD_SOCKET_NEW,-1,3,af,type,protocol);
 }
 
-
 int bclose(int fd) {
 	CMD_PROC(CMD_FILE_CLOSE,fd,0,NULL);
 }
 
 int bconnect(int fd, struct sockaddr *name, int namelen) {
-	CMD_PROC(CMD_SOCKET_CONNECT,fd,2,name,namelen);
+
+	struct _cmd cmd;
+	struct _cmd cmd2;
+
+	int r;
+
+	cmd.type = CMD_SOCKET_CONNECT;
+	cmd.fd = fd;
+	cmd.arg[0] = name;
+	cmd.arg[1] = (void*) namelen;
+
+	cmd_post(&cmd,__GLOBAL_FILE_ENV_);
+
+	if (cmd.ret == -1) {
+
+		if (cmd.wait) {
+
+			cmd2.type = CMD_FILE_WAIT;
+			cmd2.fd = fd;
+			cmd2.arg[0] = (void*) FILE_IS_WRITABLE;
+			cmd_post(&cmd2,__GLOBAL_FILE_ENV_);
+
+			cmd2.type = CMD_FILE_ERROR;
+			cmd2.fd = fd;
+			cmd2.arg[0] = &r;
+			cmd_post(&cmd2,__GLOBAL_FILE_ENV_);
+
+			if (r) {
+				errno = r;
+				return -1;
+			} else {
+				return 0;
+			}
+
+		} else {
+			errno = cmd.err;
+			return cmd.ret;
+		}
+	} else {
+		return cmd.ret;
+	}
 }
+
+int baccept(int fd, struct sockaddr* name, int *namelen) {
+
+	struct _cmd cmd;
+
+	cmd.type = CMD_SOCKET_ACCEPT;
+	cmd.fd = fd;
+	cmd.arg[0] = name;
+	cmd.arg[1] = namelen;
+
+	cmd_post(&cmd,__GLOBAL_FILE_ENV_);
+
+	if (cmd.ret == -1) {
+
+		if (cmd.wait) {
+
+		} else {
+			errno = cmd.err;
+		}
+
+	} else {
+		return cmd.ret;
+	}
+
+	return -1;
+}
+
+int bbind(int fd, struct sockaddr *name, int namelen) {
+	CMD_PROC(CMD_SOCKET_BIND,fd,2,name,namelen);
+}
+
+int blisten(int fd, int backlog) {
+	CMD_PROC(CMD_SOCKET_LISTEN,fd,1,backlog);
+}
+
+int bgetsockname(int fd, struct sockaddr *name, int *namelen) {
+	CMD_PROC(CMD_SOCKET_GET_NAME,fd,2,name,namelen);
+}
+

Modified: bsockets/trunk/contrib/liboverlapped/overlapped.h
===================================================================
--- bsockets/trunk/contrib/liboverlapped/overlapped.h	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/overlapped.h	2006-09-25 02:45:45 UTC (rev 8495)
@@ -1,6 +1,7 @@
 #ifndef _OVERLAPPED_H_
 #define _OVERLAPPED_H_
 
+#include <windows.h>
 #include <errno.h>
 
 extern struct _file_env *__GLOBAL_FILE_ENV_;
@@ -8,39 +9,52 @@
 /* */
 
 struct _file_env_options {
-	int maxfiles;
-	int maxsockets;
+	int max_files;
+	int max_sockets;
+	int max_half_open_connections;
+	int max_listeners;
 };
 
 
-/*user functions*/
+/***user functions***/
 
+/*environment functions*/
 int env_init(struct _file_env_options *);
 void env_shutdown();
 
-/**/
+/*socket functions*/
 int bsocket(int, int, int );
+int bbind(int, struct sockaddr*, int);
+int blisten(int, int);
+int baccept(int, struct sockaddr*, int*);
+int bconnect(int, struct sockaddr*, int);
 
+int bgetsockname(int, struct sockaddr*, int*);
 
-/*provide some unix errno values, in case your win32 compiler doesn't have them*/
+/*provide some unix errno values, in case your win32 compiler doesn't have them
+  feel free to add more.*/
 
-#define LOVERLAPPED_PRIVATE_ERRNO	100000
+#define LOVERLAPPED_PRIVATE_ERRNO(X)	(1010000+X)
 
 #ifndef ENOMEM
-#define ENOMEM		LOVERLAPPED_PRIVATE_ERRNO+1
+#define ENOMEM		LOVERLAPPED_PRIVATE_ERRNO(1)
 #endif
 
 #ifndef ECLOSED
-#define ECLOSED		LOVERLAPPED_PRIVATE_ERRNO+2
+#define ECLOSED		LOVERLAPPED_PRIVATE_ERRNO(2)
 #endif
 
 #ifndef EISCONN
-#define EISCONN		LOVERLAPPED_PRIVATE_ERRNO+3
+#define EISCONN		LOVERLAPPED_PRIVATE_ERRNO(3)
 #endif
 
 #ifndef EALREADY
-#define EALREADY	LOVERLAPPED_PRIVATE_ERRNO+3
+#define EALREADY	LOVERLAPPED_PRIVATE_ERRNO(4)
 #endif
 
+#ifndef EINPROGRESS
+#define EINPROGRESS	LOVERLAPPED_PRIVATE_ERRNO(5)
+#endif
 
+
 #endif

Modified: bsockets/trunk/contrib/liboverlapped/socket.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/socket.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/socket.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -7,36 +7,278 @@
 #include "env.h"
 #include "misc.h"
 #include "cmd.h"
+#include "list.h"
 
-void socket_exception( ) {
+//todo -- make sure we implment ALL system calls
 
+struct __connect_data {
+	struct _file *f;
+	struct _socket *s;
+	void *name;
+	int namelen;
+};
+
+static
+void cd_free(struct __connect_data *cd) {
+
+	if (cd == NULL)
+		return;
+
+	if (cd->name != NULL) {
+		free(cd->name);
+	}
+
+	free(cd);
+
 }
 
-void socket_connect(struct _file *f, struct _socket *s, struct _cmd *cmd, struct _file_env *env) {
+static
+struct __connect_data* cd_new(struct _file *f, struct _socket *s, void *name, int namelen)  {
 
+	struct __connect_data *cd;
+
 	int out;
 
-	out = 0;
+	cd = (struct __connect_data*) malloc(sizeof(struct __connect_data));
 
-	CHECK(!f->open,EISCONN);
-	CHECK(!s->connecting,EALREADY);
+	CHECK(cd != NULL,ENOMEM);
 
+	cd->name = malloc(namelen);
+	CHECK(cd->name != NULL,ENOMEM);
 
+	memcpy(cd->name,name,namelen);
 
+	cd->f = f;
+	cd->s = s;
+
+	return cd;
+
 	fail:
+	cd_free(cd);
+	return NULL;
+}
 
-	cmd_done(cmd,out,errno);
+void socket_unwatch_event(struct _file *f, struct _socket *s, struct _file_env *env) {
 
+	int r;
+
+	r = WSAEventSelect((SOCKET) f->handle,env->ev[s->watch_index],0);
+	ASSERT(r == 0);
+
+	r = WSAResetEvent(env->ev[s->watch_index]);
+	ASSERT(r == TRUE);
+
+	env->ev_callback[s->watch_index] = NULL;
+
 }
 
+void socket_watch_event(struct _file *f, struct _socket *s,
+	void *callback, void *data, int eventflag, struct _file_env *env ) {
+
+	int i;
+	int r;
+
+	for (i=0; i<WSA_MAXIMUM_WAIT_EVENTS; i++) {
+
+		if (env->ev_callback[i] == NULL) {
+
+			env->ev_callback[i] = callback;
+			env->ev_data[i] = data;
+
+			r = WSAEventSelect((SOCKET) f->handle,env->ev[i],eventflag);
+			ASSERT(r == 0);
+
+			s->watch_index = i;
+
+			return;
+		}
+
+	}
+
+	ASSERT(FALSE);
+
+}
+
+void socket_get_name(struct _cmd *cmd, struct _file_env *env) {
+
+	int r;
+
+	r = getsockname((SOCKET) cmd->f->handle, cmd->arg[0], cmd->arg[1]);
+
+	if (r != SOCKET_ERROR){
+		cmd_done(cmd,0,0);
+	} else {
+		cmd_done(cmd,-1,unixify_w32err(WSAGetLastError()));
+	}
+
+}
+
+void socket_listen(struct _cmd *cmd, struct _file_env *env) {
+
+	int r;
+
+	r = listen((SOCKET) cmd->f->handle, (int) cmd->arg[0]);
+
+	if (r != SOCKET_ERROR) {
+		cmd_done(cmd,0,0);
+	} else {
+		cmd_done(cmd,-1,unixify_w32err(WSAGetLastError()));
+	}
+}
+
+void socket_bind(struct _cmd *cmd, struct _file_env *env) {
+
+	int r;
+
+	r = bind((SOCKET) cmd->f->handle,cmd->arg[0],(int) cmd->arg[1]);
+
+	if (r != SOCKET_ERROR) {
+		cmd_done(cmd,0,0);
+	} else {
+		cmd_done(cmd,-1,unixify_w32err(WSAGetLastError()));
+	}
+
+}
+
+static
+int socket_queue_connection(struct _cmd *cmd,struct _file_env *env) {
+
+	struct __connect_data *cd;
+
+	cd = cd_new(cmd->f,cmd->s,cmd->arg[0],(int)cmd->arg[1]);
+
+	if (cd != NULL) {
+		if (list_enqueue(cd,env->waiting_to_connect) != NULL) {
+			return 0;
+		} else {
+			cd_free(cd);
+			return -1;
+		}
+	} else {
+		return -1;
+	}
+
+}
+
+static
+void socket_start_reading(struct _file *f,struct _socket *s, struct _file_env *env) {
+	//add something to cmd_q that says "begin the reading"
+}
+
+static
+void socket_make_connected(struct _file *f, struct _socket *s, struct _file_env *env) {
+
+	file_raise(f,FILE_IS_READABLE,FALSE,env);
+	file_raise(f,FILE_IS_WRITABLE,TRUE,env);
+
+	f->open = TRUE;
+	s->connecting = FALSE;
+
+	socket_start_reading(f,s,env);
+
+}
+
+void socket_connect_callback(struct __connect_data *c, struct _file_env *env) {
+
+	WSANETWORKEVENTS we;
+
+	int err;
+	int r;
+
+	r = WSAEnumNetworkEvents((SOCKET) c->f->handle,NULL,&we);
+	//failure indicates a programming error, not a copeable network error
+	ASSERT(r == 0);
+	//we must have trigged a FD_CONNECT event
+	ASSERT(we.lNetworkEvents & FD_CONNECT);
+	//.. and nothing else
+	ASSERT((we.lNetworkEvents & (~FD_CONNECT)) == 0 );
+
+	if ( (err = we.iErrorCode[FD_CONNECT_BIT]) == 0) {
+		socket_make_connected(c->f,c->s,env);
+	} else {
+		file_exception(c->f,unixify_w32err(err),env);
+	}
+
+	env->connections_half_open--;
+	socket_unwatch_event(c->f,c->s,env);
+	cd_free(c);
+
+}
+
+static
+void socket_process_connections(struct _file_env *env) {
+
+	struct __connect_data *cd;
+
+	int err;
+	int out;
+	int r;
+
+	CHECK(env->connections_half_open <= env->opt.max_half_open_connections,0);
+
+	while (TRUE) {
+
+		CHECK(list_dequeue(&cd,env->waiting_to_connect ) == 0,0);
+
+		r = connect((SOCKET) cd->f->handle,cd->name,cd->namelen);
+
+		if (r == SOCKET_ERROR) {
+
+			switch(err = WSAGetLastError()) {
+
+				case WSAEWOULDBLOCK:
+				case WSAEINVAL:
+					socket_watch_event
+						(cd->f,cd->s,socket_connect_callback,cd,FD_CONNECT,env);
+					env->connections_half_open++;
+				break;
+
+				default:
+					file_exception(cd->f,unixify_w32err(err), env);
+				break;
+			}
+
+		} else {
+			socket_make_connected(cd->f,cd->s,env);
+		}
+
+	}
+
+	fail:
+	return;
+}
+
+void socket_connect(struct _cmd *cmd, struct _file_env *env) {
+
+	int out;
+
+	CHECK(!cmd->f->open,EISCONN);
+	CHECK(!cmd->s->connecting,EALREADY);
+
+	CHECK(socket_queue_connection(cmd,env) == 0,0);
+
+	cmd_defer(cmd,EINPROGRESS);
+
+	socket_process_connections(env);
+
+	return;
+
+	fail:
+
+	cmd_done(cmd,-1,errno);
+
+}
+
 void socket_new(struct _cmd *cmd, struct _file_env *env) {
 
+	struct _file *f;
 	struct _socket *s;
-	struct _file *f;
 
 	int out;
+	int nb;
 
 	out = 0;
+	nb = 1;
 
 	f = file_new(env);
 	CHECK(f != NULL,0);
@@ -44,6 +286,7 @@
 	s = (struct _socket*) malloc(sizeof(struct _socket));
 	CHECK(s != NULL,ENOMEM);
 
+	//todo -- set tcp stack size to zero
 
 	f->handle = (void*)
 		WSASocket(	(int) cmd->arg[0],
@@ -54,12 +297,16 @@
 					WSA_FLAG_OVERLAPPED);
 	CHECK_(f->handle != (void*) INVALID_SOCKET);
 
+	//the underlying socket is always non-blocking
+	//there is no reason for this operation to fail
+	ASSERT(ioctlsocket((SOCKET) f->handle,FIONBIO,(DWORD*) &nb) == 0);
+
 	f->type = FT_SOCKET;
-
 	s->connecting = FALSE;
-
 	f->data = s;
 
+	out = f->fd;
+
 	fail:
 
 	if (out == -1 && f != NULL) {

Modified: bsockets/trunk/contrib/liboverlapped/socket.h
===================================================================
--- bsockets/trunk/contrib/liboverlapped/socket.h	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/socket.h	2006-09-25 02:45:45 UTC (rev 8495)
@@ -3,14 +3,17 @@
 
 struct _socket {
 	int connecting;
+	int watch_index;
 };
 
-
 struct _cmd;
 struct _file_env;
 
 void socket_new(struct _cmd *, struct _file_env *);
+void socket_connect(struct _cmd *, struct _file_env *);
+void socket_bind(struct _cmd *, struct _file_env *);
+void socket_listen(struct _cmd*, struct _file_env *);
+void socket_get_name(struct _cmd*, struct _file_env *);
 
-
 #endif
 

Modified: bsockets/trunk/contrib/liboverlapped/test.c
===================================================================
--- bsockets/trunk/contrib/liboverlapped/test.c	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/test.c	2006-09-25 02:45:45 UTC (rev 8495)
@@ -3,19 +3,24 @@
 
 #include "overlapped.h"
 #include "test.h"
+		#include "env.h"
 
-#define MAX_FILES		2000
-//todo -- implement maximum sockets checking
-#define MAX_SOCKETS		1500
+#define MAX_FILES 2000
+#define MAX_SOCKETS 1500
 
-struct _file_env_options fo = {
+struct sockaddr_in lh;
+
+static struct _file_env_options fo = {
 	MAX_FILES,
-	MAX_SOCKETS
+	MAX_SOCKETS,
+	100,
+	100
 };
 
 int test_fileinit() {
 
-	int mega_tests = 10;
+	//crank this up to be more thorough
+	int mega_tests = 1;
 	int fd;
 
 	int i;
@@ -39,27 +44,75 @@
 	return 0;
 }
 
-//make sure connect/accept behave properly
+//do some simple stuff with connect
 int test_connect() {
 
-	//const int n = 500;
+	struct sockaddr_in lh2;
 
+	int client;
+	int server;
+	int tests = 100;
+	int r;
+	int z;
+
 	TESTeq(env_init(&fo),0);
 
+	while (tests--) {
+
+		/*simple blocking server*/
+		server = bsocket(AF_INET,SOCK_STREAM,0);
+		TEST(server != -1);
+
+		client = bsocket(AF_INET,SOCK_STREAM,0);
+		TEST(client != -1);
+
+		r = bbind(server,(struct sockaddr*) &lh,sizeof(lh));
+		TEST(r != -1);
+
+		r = blisten(server,10);
+		TEST(r != -1);
+
+		z = sizeof(lh2);
+		r =  bgetsockname(server,(struct sockaddr*) &lh2,&z);
+		TEST(r != -1);
+
+		r = bconnect(client,(struct sockaddr*) &lh2,sizeof(lh2));
+		TEST(r != -1);
+
+		r = baccept(server,NULL,NULL);
+		TEST(r != -1);
+
+
+	}
+
 	env_shutdown();
 
 	return 0;
+}
 
+//make sure connect/accept behave properly
+int test_blocking_server() {
+	TEST(FALSE);
+	return 0;
+}
 
+int test_nonblocking_server() {
+	TEST(FALSE);
+	return 0;
 }
 
+
 struct test_case {
 	int (*fun)();
 	char *desc;
 };
 
 struct test_case tc[] = {
-	{test_fileinit,"Test creating and destroying some sockets"},
+//	{test_fileinit,"Test creating and destroying some sockets"},
+	{test_connect,"Test usage of connect()"},
+//	{test_basic_epoll,"Test basic usage of epoll()"},
+//	{test_blocking_server,"Test blocking implementation of echo server."},
+//	{test_nonblocking_server,"\t(non-blocking"},
 	//{test_socketconnect,"Test connection to ."},
 
 	{NULL,NULL}
@@ -98,6 +151,10 @@
 	int good=0;
 	int bad=0;
 
+	lh.sin_family = AF_INET;
+	lh.sin_addr.s_addr = inet_addr("127.0.0.1");
+	lh.sin_port = 0;
+
 	if ( winsock_start() != 0) {
 		printf("Couldn't init winsock: %d",WSAGetLastError());
 		fflush(stdout);

Modified: bsockets/trunk/contrib/liboverlapped/test.h
===================================================================
--- bsockets/trunk/contrib/liboverlapped/test.h	2006-09-25 02:31:56 UTC (rev 8494)
+++ bsockets/trunk/contrib/liboverlapped/test.h	2006-09-25 02:45:45 UTC (rev 8495)
@@ -5,8 +5,8 @@
 int res2_;
 
 #define TESTeq(A,B)  	if ( (res_ = A) != (res2_ = B) ) {\
-							printf("\nTest failed: %s [%d] != %s [%d]\n\tline:%d   errno:%d\n"\
-							,#A,res_,#B,res2_,__LINE__,errno\
+							printf("\nTest failed: %s [%d] != %s [%d]\n\tline:%d   errno:%d w32err:%d\n"\
+							,#A,res_,#B,res2_,__LINE__,errno,(int) WSAGetLastError()\
 								);\
 							return 1;\
 						}\



More information about the tor-commits mailing list