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);