tNon-blocking connect() stuff abstracted out - vaccinewars - be a doctor and try to vaccinate the world (HTM) git clone git://src.adamsgaard.dk/vaccinewars (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit 45b249824bdc27adbbf0520267da561dd4636bcc (DIR) parent 7d0b10dce7f72780b488b3df2800347731565a73 (HTM) Author: Ben Webb <ben@salilab.org> Date: Wed, 6 Jun 2001 12:05:10 +0000 Non-blocking connect() stuff abstracted out Diffstat: M src/dopewars.h | 9 +++++---- M src/gtk_client.c | 6 +++--- M src/message.c | 106 ++++++++++++++++++++++--------- M src/message.h | 6 ++++++ M src/serverside.c | 20 ++++++++++++++++++++ 5 files changed, 109 insertions(+), 38 deletions(-) --- (DIR) diff --git a/src/dopewars.h b/src/dopewars.h t@@ -279,10 +279,11 @@ typedef struct tagConnBuf { /* Handles reading and writing messages from/to a network connection */ typedef struct tagNetworkBuffer { - int fd; /* File descriptor of the socket */ - char Terminator; /* Character that separates messages */ - ConnBuf ReadBuf; /* New data, waiting for the application */ - ConnBuf WriteBuf; /* Data waiting to be written to the wire */ + int fd; /* File descriptor of the socket */ + char Terminator; /* Character that separates messages */ + ConnBuf ReadBuf; /* New data, waiting for the application */ + ConnBuf WriteBuf; /* Data waiting to be written to the wire */ + gboolean WaitConnect; /* TRUE if a non-blocking connect is in progress */ } NetworkBuffer; struct PLAYER_T { (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c t@@ -1868,8 +1868,8 @@ struct StartGameStruct { gint ConnectTag; }; -static void FinishConnect(gpointer data,gint socket, - GdkInputCondition condition) { +static void FinishServerConnect(gpointer data,gint socket, + GdkInputCondition condition) { gchar *text,*NetworkError; struct StartGameStruct *widgets; t@@ -1902,7 +1902,7 @@ static void DoConnect(struct StartGameStruct *widgets) { NetworkError=SetupNetwork(TRUE); if (!NetworkError) { widgets->ConnectTag=gdk_input_add(ClientSock,GDK_INPUT_WRITE, - FinishConnect,(gpointer)widgets); + FinishServerConnect,(gpointer)widgets); } else { text=g_strdup_printf(_("Status: Could not connect (%s)"),NetworkError); gtk_label_set_text(GTK_LABEL(widgets->status),text); (DIR) diff --git a/src/message.c b/src/message.c t@@ -288,6 +288,7 @@ void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator) { NetBuf->ReadBuf.Data=NetBuf->WriteBuf.Data=NULL; NetBuf->ReadBuf.Length=NetBuf->WriteBuf.Length=0; NetBuf->ReadBuf.DataPresent=NetBuf->WriteBuf.DataPresent=0; + NetBuf->WaitConnect=FALSE; } void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd) { t@@ -296,6 +297,25 @@ void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd) { NetBuf->fd=fd; } +static void MetaConnectError(gchar *Msg) { + g_warning(_("Cannot connect to metaserver: %s"),Msg); +} + +gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost, + unsigned RemotePort) { + gchar *retval; + + ShutdownNetworkBuffer(NetBuf); + retval=StartConnect(&NetBuf->fd,RemoteHost,RemotePort,TRUE); + + if (retval) { + MetaConnectError(retval); return FALSE; + } else { + NetBuf->WaitConnect=TRUE; + return TRUE; + } +} + void ShutdownNetworkBuffer(NetworkBuffer *NetBuf) { /* Frees the network buffer's data structures (leaving it in the */ /* 'initialised' state) and closes the accompanying socket. */ t@@ -316,7 +336,9 @@ void SetSelectForNetworkBuffer(NetworkBuffer *NetBuf,fd_set *readfds, FD_SET(NetBuf->fd,readfds); if (errorfds) FD_SET(NetBuf->fd,errorfds); if (NetBuf->fd >= *MaxSock) *MaxSock=NetBuf->fd+1; - if (NetBuf->WriteBuf.DataPresent) FD_SET(NetBuf->fd,writefds); + if (NetBuf->WriteBuf.DataPresent || NetBuf->WaitConnect) { + FD_SET(NetBuf->fd,writefds); + } } static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady, t@@ -328,8 +350,20 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady, /* operations, and returns TRUE if data was read and is waiting for */ /* processing. */ gboolean DataWaiting=FALSE; + gchar *retval; *ReadOK=*WriteOK=*ErrorOK=TRUE; + if (NetBuf->WaitConnect) { + if (WriteReady) { + retval=FinishConnect(NetBuf->fd); + if (retval) { + *WriteOK=FALSE; + MetaConnectError(retval); + } else NetBuf->WaitConnect=FALSE; + } + return FALSE; + } + if (ErrorReady) *ErrorOK=FALSE; if (WriteReady) *WriteOK=WriteDataToWire(NetBuf); t@@ -348,6 +382,8 @@ gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds, /* If any data were read, DataWaiting is set TRUE. Returns TRUE unless */ /* a fatal error (i.e. the connection was broken) occurred. */ gboolean ReadOK,WriteOK,ErrorOK; + *DataWaiting=FALSE; + if (!NetBuf || NetBuf->fd<=0) return TRUE; *DataWaiting=DoNetworkBufferStuff(NetBuf,FD_ISSET(NetBuf->fd,readfds), FD_ISSET(NetBuf->fd,writefds), errorfds ? FD_ISSET(NetBuf->fd,errorfds) : FALSE, t@@ -361,6 +397,8 @@ gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady, /* If any data were read, DataWaiting is set TRUE. Returns TRUE unless */ /* a fatal error (i.e. the connection was broken) occurred. */ gboolean ReadOK,WriteOK,ErrorOK; + *DataWaiting=FALSE; + if (!Play || Play->NetBuf.fd<=0) return TRUE; *DataWaiting=DoNetworkBufferStuff(&Play->NetBuf,ReadReady,WriteReady,FALSE, &ReadOK,&WriteOK,&ErrorOK); t@@ -831,59 +869,48 @@ price_t GetNextPrice(gchar **Data,price_t Default) { } #if NETWORKING -char *SetupNetwork(gboolean NonBlocking) { -/* Sets up the connection from the client to the server. If the connection */ -/* is successful, Network and Client are set to TRUE, and ClientSock is a */ -/* file descriptor for the newly-opened socket. NULL is returned. If the */ -/* connection fails, a pointer to an error message is returned. */ -/* If "NonBlocking" is TRUE, a non-blocking connect() is carried out. In */ -/* this case, the routine returns successfully after initiating the */ -/* connect call; the caller should then select() the socket for writing, */ -/* before calling FinishSetupNetwork() */ +char *StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort, + gboolean NonBlocking) { struct sockaddr_in ClientAddr; struct hostent *he; static char NoHost[]= N_("Could not find host"); static char NoSocket[]= N_("Could not create network socket"); static char NoConnect[]= N_("Connection refused or no server present"); - Network=Client=Server=FALSE; - - if ((he=gethostbyname(ServerName))==NULL) { + if ((he=gethostbyname(RemoteHost))==NULL) { return NoHost; } - ClientSock=socket(AF_INET,SOCK_STREAM,0); - if (ClientSock==SOCKET_ERROR) { + *fd=socket(AF_INET,SOCK_STREAM,0); + if (*fd==SOCKET_ERROR) { return NoSocket; } ClientAddr.sin_family=AF_INET; - ClientAddr.sin_port=htons(Port); + ClientAddr.sin_port=htons(RemotePort); ClientAddr.sin_addr=*((struct in_addr *)he->h_addr); memset(ClientAddr.sin_zero,0,sizeof(ClientAddr.sin_zero)); - if (NonBlocking) fcntl(ClientSock,F_SETFL,O_NONBLOCK); - if (connect(ClientSock,(struct sockaddr *)&ClientAddr, + if (NonBlocking) fcntl(*fd,F_SETFL,O_NONBLOCK); + if (connect(*fd,(struct sockaddr *)&ClientAddr, sizeof(struct sockaddr))==-1) { #ifdef CYGWIN if (GetSocketError()==WSAEWOULDBLOCK) return NULL; #else if (GetSocketError()==EINPROGRESS) return NULL; #endif - CloseSocket(ClientSock); + CloseSocket(*fd); *fd=-1; return NoConnect; } else { - fcntl(ClientSock,F_SETFL,O_NONBLOCK); + fcntl(*fd,F_SETFL,O_NONBLOCK); } - Client=TRUE; Network=TRUE; return NULL; } -char *FinishSetupNetwork() { +char *FinishConnect(int fd) { static char NoConnect[]= N_("Connection refused or no server present"); #ifdef CYGWIN if (GetSocketError()!=0) return NoConnect; - Client=Network=TRUE; - return NULL; + else return NULL; #else int optval; #ifdef HAVE_SOCKLEN_T t@@ -893,18 +920,35 @@ char *FinishSetupNetwork() { #endif optlen=sizeof(optval); - if (getsockopt(ClientSock,SOL_SOCKET,SO_ERROR,&optval,&optlen)==-1) { - return NoConnect; - } - if (optval==0) { - Client=Network=TRUE; - return NULL; - } else { + if (getsockopt(fd,SOL_SOCKET,SO_ERROR,&optval,&optlen)==-1) { return NoConnect; } + if (optval==0) return NULL; + else return NoConnect; #endif /* CYGWIN */ } +char *SetupNetwork(gboolean NonBlocking) { +/* Sets up the connection from the client to the server. If the connection */ +/* is successful, Network and Client are set to TRUE, and ClientSock is a */ +/* file descriptor for the newly-opened socket. NULL is returned. If the */ +/* connection fails, a pointer to an error message is returned. */ +/* If "NonBlocking" is TRUE, a non-blocking connect() is carried out. In */ +/* this case, the routine returns successfully after initiating the */ +/* connect call; the caller should then select() the socket for writing, */ +/* before calling FinishSetupNetwork() */ + char *retval; + + Network=Client=Server=FALSE; + retval=StartConnect(&ClientSock,ServerName,Port,NonBlocking); + if (!retval) Client=Network=TRUE; + return retval; +} + +char *FinishSetupNetwork() { + return FinishConnect(ClientSock); +} + #endif /* NETWORKING */ void SwitchToSinglePlayer(Player *Play) { (DIR) diff --git a/src/message.h b/src/message.h t@@ -115,8 +115,14 @@ void SendPrintMessage(Player *From,char AICode,Player *To,char *Data); void SendQuestion(Player *From,char AICode,Player *To,char *Data); #if NETWORKING +char *StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort, + gboolean NonBlocking); +char *FinishConnect(int fd); + void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator); void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd); +gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost, + unsigned RemotePort); void ShutdownNetworkBuffer(NetworkBuffer *NetBuf); void SetSelectForNetworkBuffer(NetworkBuffer *NetBuf,fd_set *readfds, fd_set *writefds,fd_set *errorfds,int *MaxSock); (DIR) diff --git a/src/serverside.c b/src/serverside.c t@@ -773,6 +773,14 @@ void ServerLoop() { int MinTimeout; GString *LineBuf; gboolean EndOfLine,DataWaiting; + NetworkBuffer MetaNetBuf; + gchar *buf; + + InitNetworkBuffer(&MetaNetBuf,'\n'); +/* if (StartNetworkBufferConnect(&MetaNetBuf,"bellatrix.pcl.ox.ac.uk",80)) { + g_print("Waiting for metaserver connect...\n"); + QueueMessageForSend(&MetaNetBuf,"GET /~ben/cgi-bin/server.pl?getlist=1&output=text HTTP/1.0\n"); + }*/ StartServer(); t@@ -785,6 +793,8 @@ void ServerLoop() { FD_SET(ListenSock,&readfs); FD_SET(ListenSock,&errorfs); topsock=ListenSock+1; + SetSelectForNetworkBuffer(&MetaNetBuf,&readfs,&writefs, + &errorfs,&topsock); for (list=FirstServer;list;list=g_slist_next(list)) { tmp=(Player *)list->data; if (!IsCop(tmp)) { t@@ -825,6 +835,16 @@ void ServerLoop() { if (FD_ISSET(ListenSock,&readfs)) { HandleNewConnection(); } + if (!RespondToSelect(&MetaNetBuf,&readfs,&writefs, + &errorfs,&DataWaiting)) { +/* g_warning("Metaserver connection closed");*/ + ShutdownNetworkBuffer(&MetaNetBuf); + } else if (DataWaiting) { + while ((buf=GetWaitingMessage(&MetaNetBuf))) { + g_print("Meta: %s\n",buf); + g_free(buf); + } + } list=FirstServer; while (list) { nextlist=g_slist_next(list);