tNon-blocking connect() stuff abstracted out - vaccinewars - be a doctor and tr… | |
git clone git://src.adamsgaard.dk/vaccinewars | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 45b249824bdc27adbbf0520267da561dd4636bcc | |
parent 7d0b10dce7f72780b488b3df2800347731565a73 | |
Author: Ben Webb <[email protected]> | |
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(-) | |
--- | |
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 { | |
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); | |
diff --git a/src/message.c b/src/message.c | |
t@@ -288,6 +288,7 @@ void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminat… | |
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 … | |
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_se… | |
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 *NetBu… | |
/* 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 *rea… | |
/* 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 ReadRea… | |
/* 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) { | |
diff --git a/src/message.h b/src/message.h | |
t@@ -115,8 +115,14 @@ void SendPrintMessage(Player *From,char AICode,Player *To… | |
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); | |
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&o… | |
+ }*/ | |
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); |