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