tAll code now uses the new metaserver at SourceForge - 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 2eaeaade9e1413d2b357873738485f14ee86310e
 (DIR) parent 47ea05dc1f971516f22a9f5621f84bcf74657111
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Sat,  9 Jun 2001 23:16:52 +0000
       
       All code now uses the new metaserver at SourceForge
       
       
       Diffstat:
         M src/AIPlayer.c                      |      12 ++++++------
         M src/curses_client.c                 |      18 +++++++++---------
         M src/dopewars.c                      |      28 ++++++++++++++++------------
         M src/dopewars.h                      |       9 ++++++---
         M src/gtk_client.c                    |      17 +++++++++--------
         M src/message.c                       |      75 +++++++++++++++++++++-----------
         M src/message.h                       |       5 +++--
         M src/serverside.c                    |     180 +++++++++++++++++++------------
         M src/serverside.h                    |       2 +-
       
       9 files changed, 212 insertions(+), 134 deletions(-)
       ---
 (DIR) diff --git a/src/AIPlayer.c b/src/AIPlayer.c
       t@@ -54,7 +54,7 @@ void AIPlayerLoop() {
           gchar *pt;
           Player *AIPlay;
           fd_set readfs,writefs;
       -   gboolean DataWaiting,QuitRequest;
       +   gboolean DoneOK,QuitRequest;
           int MaxSock;
        
           AIPlay=g_new(Player,1);
       t@@ -91,11 +91,7 @@ void AIPlayerLoop() {
                 printf("Error in select\n"); exit(1);
              }
        
       -      if (!RespondToSelect(&AIPlay->NetBuf,&readfs,&writefs,
       -                           NULL,&DataWaiting)) {
       -         g_print(_("Connection to server lost!\n"));
       -         break;
       -      } else if (DataWaiting) {
       +      if (RespondToSelect(&AIPlay->NetBuf,&readfs,&writefs,NULL,&DoneOK)) {
                 QuitRequest=FALSE;
                 while ((pt=GetWaitingPlayerMessage(AIPlay))!=NULL) {
                    if (HandleAIMessage(pt,AIPlay)) {
       t@@ -105,6 +101,10 @@ void AIPlayerLoop() {
                 }
                 if (QuitRequest) break;
              }
       +      if (!DoneOK) {
       +         g_print(_("Connection to server lost!\n"));
       +         break;
       +      }
           }
           ShutdownNetwork();
           g_print(_("AI Player terminated OK.\n"));
 (DIR) diff --git a/src/curses_client.c b/src/curses_client.c
       t@@ -1507,7 +1507,7 @@ static void Curses_DoGame(Player *Play) {
           char HaveWorthless;
           Player *tmp;
           struct sigaction sact;
       -   gboolean DataWaiting;
       +   gboolean DoneOK;
        
           DisplayMode=DM_NONE;
           QuitRequest=FALSE;
       t@@ -1653,8 +1653,14 @@ static void Curses_DoGame(Player *Play) {
                 perror("bselect"); exit(1);
              }
              if (Client) {
       -         if (!RespondToSelect(&Play->NetBuf,&readfs,&writefs,
       -                              NULL,&DataWaiting)) {
       +         if (RespondToSelect(&Play->NetBuf,&readfs,&writefs,NULL,&DoneOK)) {
       +            while ((pt=GetWaitingPlayerMessage(Play))!=NULL) {
       +               HandleClientMessage(pt,Play);
       +               g_free(pt);
       +            }
       +            if (QuitRequest) return;
       +         }
       +         if (!DoneOK) {
                    attrset(TextAttr);
                    clear_line(22);
                    mvaddstr(22,0,_("Connection to server lost! "
       t@@ -1662,12 +1668,6 @@ static void Curses_DoGame(Player *Play) {
                    nice_wait();
                    SwitchToSinglePlayer(Play);
                    print_status(Play,TRUE);
       -         } else if (DataWaiting) {
       -            while ((pt=GetWaitingPlayerMessage(Play))!=NULL) {
       -               HandleClientMessage(pt,Play);
       -               g_free(pt);
       -            }
       -            if (QuitRequest) return;
                 }
              }
              if (FD_ISSET(0,&readfs)) {
 (DIR) diff --git a/src/dopewars.c b/src/dopewars.c
       t@@ -150,11 +150,11 @@ struct BITCH Bitch = {
           50000,150000
        };
        
       -struct METASERVER MetaServer = { 0,0,0,NULL,NULL,NULL,NULL,NULL };
       +struct METASERVER MetaServer = { 0,NULL,0,NULL,0,NULL,NULL,NULL,NULL };
        
        struct METASERVER DefaultMetaServer = {
       -   1,80,7802,"bellatrix.pcl.ox.ac.uk","/~ben/cgi-bin/server.pl","","",
       -   "dopewars server"
       +   1,"dopewars.sourceforge.net",80,"",8080,"/metaserver.php",
       +   "","","dopewars server"
        };
        
        int NumTurns=31;
       t@@ -174,17 +174,20 @@ struct GLOBALS Globals[NUMGLOB] = {
           { &MetaServer.Active,NULL,NULL,NULL,"MetaServer.Active",
             N_("Non-zero if server should report to a metaserver"),
             NULL,NULL,0,"",NULL,NULL },
       -   { &MetaServer.HttpPort,NULL,NULL,NULL,"MetaServer.HttpPort",
       -     N_("Port for metaserver communication (client)"),
       +   { NULL,NULL,&MetaServer.Name,NULL,"MetaServer.Name",
       +     N_("Metaserver name to report/get server details to/from"),
             NULL,NULL,0,"",NULL,NULL },
       -   { &MetaServer.UdpPort,NULL,NULL,NULL,"MetaServer.UdpPort",
       -     N_("Port for metaserver communication (server)"),
       +   { &MetaServer.Port,NULL,NULL,NULL,"MetaServer.Port",
       +     N_("Port for metaserver communication"),
             NULL,NULL,0,"",NULL,NULL },
       -   { NULL,NULL,&MetaServer.Name,NULL,"MetaServer.Name",
       -     N_("Metaserver name to report server details to"),
       +   { NULL,NULL,&MetaServer.ProxyName,NULL,"MetaServer.ProxyName",
       +     N_("Name of the proxy (if needed) for metaserver communication"),
       +     NULL,NULL,0,"",NULL,NULL },
       +   { &MetaServer.ProxyPort,NULL,NULL,NULL,"MetaServer.ProxyPort",
       +     N_("Port for communicating with the proxy server"),
             NULL,NULL,0,"",NULL,NULL },
           { NULL,NULL,&MetaServer.Path,NULL,"MetaServer.Path",
       -     N_("Path of the CGI script on the metaserver (client)"),
       +     N_("Path of the script on the metaserver"),
             NULL,NULL,0,"",NULL,NULL },
           { NULL,NULL,&MetaServer.LocalName,NULL,"MetaServer.LocalName",
             N_("Preferred hostname of your server machine"),NULL,NULL,0,"",NULL,NULL },
       t@@ -1183,9 +1186,10 @@ void CopyNames(struct NAMES *dest,struct NAMES *src) {
        
        void CopyMetaServer(struct METASERVER *dest,struct METASERVER *src) {
           dest->Active=src->Active;
       -   dest->HttpPort=src->HttpPort;
       -   dest->UdpPort=src->UdpPort;
       +   dest->Port=src->Port;
       +   dest->ProxyPort=src->ProxyPort;
           AssignName(&dest->Name,src->Name);
       +   AssignName(&dest->ProxyName,src->ProxyName);
           AssignName(&dest->Path,src->Path);
           AssignName(&dest->LocalName,src->LocalName);
           AssignName(&dest->Password,src->Password);
 (DIR) diff --git a/src/dopewars.h b/src/dopewars.h
       t@@ -91,8 +91,11 @@ struct NAMES {
        
        struct METASERVER {
           int Active;
       -   int HttpPort,UdpPort;
       -   gchar *Name,*Path,*LocalName,*Password,*Comment;
       +   gchar *Name;
       +   int Port;
       +   gchar *ProxyName;
       +   int ProxyPort;
       +   gchar *Path,*LocalName,*Password,*Comment;
        };
        
        struct PRICES {
       t@@ -329,7 +332,7 @@ typedef struct tag_serverdata {
           char *Comment,*Version,*Update,*UpSince;
        } ServerData;
        
       -#define NUMGLOB 86
       +#define NUMGLOB 87
        struct GLOBALS {
           int *IntVal;
           price_t *PriceVal;
 (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c
       t@@ -257,9 +257,15 @@ void ListInventory(GtkWidget *widget,gpointer data) {
        void GetClientMessage(gpointer data,gint socket,
                              GdkInputCondition condition) {
           gchar *pt;
       -   gboolean DataWaiting;
       -   if (!PlayerHandleNetwork(ClientData.Play,condition&GDK_INPUT_READ,
       -                            condition&GDK_INPUT_WRITE,&DataWaiting)) {
       +   gboolean DoneOK;
       +   if (PlayerHandleNetwork(ClientData.Play,condition&GDK_INPUT_READ,
       +                           condition&GDK_INPUT_WRITE,&DoneOK)) {
       +      while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) {
       +         HandleClientMessage(pt,ClientData.Play);
       +         g_free(pt);
       +      }
       +   }
       +   if (!DoneOK) {
              if (Network) gdk_input_remove(ClientData.GdkInputTag);
              if (InGame) {
        /* The network connection to the server was dropped unexpectedly */
       t@@ -267,11 +273,6 @@ void GetClientMessage(gpointer data,gint socket,
                           "single player mode"));
                 SwitchToSinglePlayer(ClientData.Play);
              }
       -   } else if (DataWaiting) {
       -      while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) {
       -         HandleClientMessage(pt,ClientData.Play);
       -         g_free(pt);
       -      }
           }
        }
        
 (DIR) diff --git a/src/message.c b/src/message.c
       t@@ -297,8 +297,14 @@ void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd) {
           NetBuf->fd=fd;
        }
        
       -static void MetaConnectError(gchar *Msg) {
       -   g_warning(_("Cannot connect to metaserver: %s"),Msg);
       +gboolean IsNetworkBufferActive(NetworkBuffer *NetBuf) {
       +/* Returns TRUE if the pointer is to a valid network buffer, and it's */
       +/* connected to an active socket.                                     */
       +   return (NetBuf && NetBuf->fd>=0);
       +}
       +
       +static void ConnectError(gchar *Msg) {
       +   g_warning(_("Cannot connect to remote host: %s"),Msg);
        }
        
        gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
       t@@ -309,7 +315,7 @@ gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
           retval=StartConnect(&NetBuf->fd,RemoteHost,RemotePort,TRUE);
        
           if (retval) {
       -      MetaConnectError(retval); return FALSE;
       +      ConnectError(retval); return FALSE;
           } else {
              NetBuf->WaitConnect=TRUE;
              return TRUE;
       t@@ -358,7 +364,7 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
                 retval=FinishConnect(NetBuf->fd);
                 if (retval) {
                    *WriteOK=FALSE;
       -            MetaConnectError(retval);
       +            ConnectError(retval);
                 } else NetBuf->WaitConnect=FALSE;
              }
              return FALSE;
       t@@ -370,37 +376,43 @@ static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady,
        
           if (ReadReady) {
              *ReadOK=ReadDataFromWire(NetBuf);
       -      if (ReadOK) DataWaiting=TRUE;
       +      if (NetBuf->ReadBuf.DataPresent>0) DataWaiting=TRUE;
           }
           return DataWaiting;
        }
        
        gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds,
                                 fd_set *writefds,fd_set *errorfds,
       -                         gboolean *DataWaiting) {
       +                         gboolean *DoneOK) {
        /* Responds to a select() call by reading/writing data as necessary.   */
       -/* If any data were read, DataWaiting is set TRUE. Returns TRUE unless */
       -/* a fatal error (i.e. the connection was broken) occurred.            */
       +/* If any data were read, TRUE is returned. "DoneOK" is set 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),
       +   gboolean DataWaiting=FALSE;
       +
       +   *DoneOK=TRUE;
       +   if (!NetBuf || NetBuf->fd<=0) return DataWaiting;
       +   DataWaiting=DoNetworkBufferStuff(NetBuf,FD_ISSET(NetBuf->fd,readfds),
                                FD_ISSET(NetBuf->fd,writefds),
                                errorfds ? FD_ISSET(NetBuf->fd,errorfds) : FALSE,
                                &ReadOK,&WriteOK,&ErrorOK);
       -   return (WriteOK && ErrorOK && ReadOK);
       +   *DoneOK=(WriteOK && ErrorOK && ReadOK);
       +   return DataWaiting;
        }
        
        gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady,
       -                             gboolean WriteReady,gboolean *DataWaiting) {
       -/* Reads and writes player data from/to the network if it is ready.    */
       -/* If any data were read, DataWaiting is set TRUE. Returns TRUE unless */
       -/* a fatal error (i.e. the connection was broken) occurred.            */
       +                             gboolean WriteReady,gboolean *DoneOK) {
       +/* Reads and writes player data from/to the network if it is ready.  */
       +/* If any data were read, TRUE is returned. "DoneOK" is set 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);
       +   gboolean DataWaiting=FALSE;
       +
       +   *DoneOK=TRUE;
       +   if (!Play || Play->NetBuf.fd<=0) return DataWaiting;
       +
       +   DataWaiting=DoNetworkBufferStuff(&Play->NetBuf,ReadReady,WriteReady,FALSE,
       +                                    &ReadOK,&WriteOK,&ErrorOK);
        
        /* If we've written out everything, then ask not to be notified of
           socket write-ready status in future */
       t@@ -408,7 +420,9 @@ gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady,
               SocketWriteTestPt) {
              (*SocketWriteTestPt)(Play,FALSE);
           }
       -   return (WriteOK && ErrorOK && ReadOK);
       +
       +   *DoneOK=(WriteOK && ErrorOK && ReadOK);
       +   return DataWaiting;
        }
        
        gchar *GetWaitingPlayerMessage(Player *Play) {
       t@@ -1103,11 +1117,21 @@ char *OpenMetaServerConnection(int *HttpSock) {
                            N_("Metaserver not running HTTP or connection denied");
           struct sockaddr_in HttpAddr;
           struct hostent *he;
       +   gchar *MetaName;
       +   int MetaPort;
       +
       +/* If a proxy is defined, connect to that. Otherwise, connect to the
       +   metaserver directly */ 
       +   if (MetaServer.ProxyName[0]) {
       +      MetaName=MetaServer.ProxyName; MetaPort=MetaServer.ProxyPort;
       +   } else {
       +      MetaName=MetaServer.Name; MetaPort=MetaServer.Port;
       +   }
        
       -   if ((he=gethostbyname(MetaServer.Name))==NULL) return NoHost;
       +   if ((he=gethostbyname(MetaName))==NULL) return NoHost;
           if ((*HttpSock=socket(AF_INET,SOCK_STREAM,0))==-1) return NoSocket;
           HttpAddr.sin_family=AF_INET;
       -   HttpAddr.sin_port=htons(MetaServer.HttpPort);
       +   HttpAddr.sin_port=htons(MetaPort);
           HttpAddr.sin_addr=*((struct in_addr *)he->h_addr);
           memset(HttpAddr.sin_zero,0,sizeof(HttpAddr.sin_zero));
           if (connect(*HttpSock,(struct sockaddr *)&HttpAddr,
       t@@ -1139,8 +1163,9 @@ void ReadMetaServerData(int HttpSock) {
           gboolean HeaderDone;
        
           ClearServerList();
       -   buf=g_strdup_printf("GET %s?output=text&getlist=%d HTTP/1.0\n\n",
       -                       MetaServer.Path,METAVERSION);
       +   buf=g_strdup_printf("GET %s?output=text&getlist=%d HTTP/1.1\n"
       +                       "Host: %s:%d\n\n",MetaServer.Path,METAVERSION,
       +                       MetaServer.Name,MetaServer.Port);
           send(HttpSock,buf,strlen(buf),0);
           g_free(buf);
           HeaderDone=FALSE;
 (DIR) diff --git a/src/message.h b/src/message.h
       t@@ -120,6 +120,7 @@ char *StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
        char *FinishConnect(int fd);
        
        void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator);
       +gboolean IsNetworkBufferActive(NetworkBuffer *NetBuf);
        void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd);
        gboolean StartNetworkBufferConnect(NetworkBuffer *NetBuf,gchar *RemoteHost,
                                           unsigned RemotePort);
       t@@ -128,9 +129,9 @@ void SetSelectForNetworkBuffer(NetworkBuffer *NetBuf,fd_set *readfds,
                                       fd_set *writefds,fd_set *errorfds,int *MaxSock);
        gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds,
                                 fd_set *writefds,fd_set *errorfds,
       -                         gboolean *DataWaiting);
       +                         gboolean *DoneOK);
        gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady,
       -                             gboolean WriteReady,gboolean *DataWaiting);
       +                             gboolean WriteReady,gboolean *DoneOK);
        gboolean ReadPlayerDataFromWire(Player *Play);
        void QueuePlayerMessageForSend(Player *Play,gchar *data);
        gboolean WritePlayerDataToWire(Player *Play);
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -60,9 +60,9 @@
        #define METAUPDATETIME  (10800)
        
        /* Don't report players logging in/out to the metaserver more frequently */
       -/* than once every 5 minutes (so as not to overload the metaserver, or   */
       -/* slow down our own server).                                            */
       -#define METAMINTIME (300)
       +/* than once every minute (so as not to overload the metaserver, or slow */
       +/* down our own server).                                                 */
       +#define METAMINTIME (60)
        
        int TerminateRequest,ReregisterRequest;
        
       t@@ -70,8 +70,9 @@ int MetaUpdateTimeout;
        int MetaMinTimeout;
        gboolean WantQuit=FALSE;
        
       -/* Do we want to talk to the metaserver when the timeout expires? */
       -gboolean MetaPending=FALSE;
       +/* Do we want to update the player details on the metaserver when the
       +   timeout expires? */
       +gboolean MetaPlayerPending=FALSE;
        
        GSList *FirstServer=NULL;
        
       t@@ -128,55 +129,72 @@ int SendToMetaServer(char Up,int MetaSock,char *data,
           return 1;
        }
        
       -void RegisterWithMetaServer(gboolean Up,gboolean SendData) {
       +void RegisterWithMetaServer(gboolean Up,gboolean SendData,
       +                            gboolean RespectTimeout) {
        /* Sends server details to the metaserver, if specified. If "Up" is  */
        /* TRUE, informs the metaserver that the server is now accepting     */
        /* connections - otherwise tells the metaserver that this server is  */
        /* about to go down. If "SendData" is TRUE, then also sends game     */
       -/* data (e.g. scores) to the metaserver. If networking is disabled,  */
       -/* does nothing.                                                     */
       +/* data (e.g. scores) to the metaserver. If "RespectTimeout" is TRUE */
       +/* then the update is delayed if a previous update happened too      */
       +/* recently. If networking is disabled, this function does nothing.  */
        #if NETWORKING
           struct HISCORE MultiScore[NUMHISCORE],AntiqueScore[NUMHISCORE];
           GString *text;
           gchar *prstr;
       +   gchar *MetaName;
       +   int MetaPort;
           int i;
        
       -   if (!MetaServer.Active || !NotifyMetaServer) return;
       -   if (MetaMinTimeout > time(NULL)) {
       -      MetaPending=TRUE;
       +   if (!MetaServer.Active || !NotifyMetaServer || WantQuit) return;
       +
       +   if (MetaMinTimeout > time(NULL) && RespectTimeout) {
       +      g_print("Attempt to connect to metaserver too frequently - waiting for next timeout\n");
       +      MetaPlayerPending=TRUE;
              return;
           }
        
       -/* If the previous connect hung for so long that it's still pending, then
       +/* If the previous connect hung for so long that it's still active, then
           break the connection before we start a new one */
           ShutdownNetworkBuffer(&MetaNetBuf);
        
       -   if (StartNetworkBufferConnect(&MetaNetBuf,"dopewars.sourceforge.net",80)) {
       -      g_print("Waiting for metaserver connect...\n");
       +/* If a proxy is defined, connect to that. Otherwise, connect to the
       +   metaserver directly */
       +   if (MetaServer.ProxyName[0]) {
       +      MetaName=MetaServer.ProxyName; MetaPort=MetaServer.ProxyPort;
       +   } else {
       +      MetaName=MetaServer.Name; MetaPort=MetaServer.Port;
           }
       -   MetaPending=FALSE;
       +
       +   if (StartNetworkBufferConnect(&MetaNetBuf,MetaName,MetaPort)) {
       +      g_print("Waiting for metaserver connect to %s:%d...\n",MetaName,MetaPort);
       +   } else return;
       +   MetaPlayerPending=FALSE;
           text=g_string_new("");
        
       -   g_string_sprintf(text,"GET /metaserver.php?");
       +   g_string_sprintf(text,"GET %s?output=text&",MetaServer.Path);
        
       -   g_string_sprintfa(text,"port=%d&version=%s&players=%d&maxplay=%d&comment=%s",
       -                    Port,VERSION,CountPlayers(FirstServer),MaxClients,
       -                    MetaServer.Comment);
       +   g_string_sprintfa(text,"up=%d&port=%d&version=%s&players=%d"
       +                     "&maxplay=%d&comment=%s",
       +                     Up ? 1 : 0,Port,VERSION,CountPlayers(FirstServer),
       +                     MaxClients,MetaServer.Comment);
        
        
       -   if (HighScoreRead(MultiScore,AntiqueScore)) {
       -      for (i=0;i<NUMHISCORE;i++) if (MultiScore[i].Name && MultiScore[i].Name[0]) {
       -         g_string_sprintfa(text,"&nm[%d]=%s&dt[%d]=%s&st[%d]=%s&sc[%d]=%s",
       -                           i,MultiScore[i].Name,i,MultiScore[i].Time,
       -                           i,MultiScore[i].Dead ? "dead" : "alive",
       -                           i,prstr=FormatPrice(MultiScore[i].Money));
       -         g_free(prstr);
       +   if (SendData && HighScoreRead(MultiScore,AntiqueScore)) {
       +      for (i=0;i<NUMHISCORE;i++) {
       +         if (MultiScore[i].Name && MultiScore[i].Name[0]) {
       +            g_string_sprintfa(text,"&nm[%d]=%s&dt[%d]=%s&st[%d]=%s&sc[%d]=%s",
       +                              i,MultiScore[i].Name,i,MultiScore[i].Time,
       +                              i,MultiScore[i].Dead ? "dead" : "alive",
       +                              i,prstr=FormatPrice(MultiScore[i].Money));
       +            g_free(prstr);
       +         }
              }
           }
        
           g_string_sprintfa(text," HTTP/1.1");
           QueueMessageForSend(&MetaNetBuf,text->str);
       -   g_string_sprintf(text,"Host: dopewars.sourceforge.net\n");
       +   g_string_sprintf(text,"Host: %s:%d\n",MetaServer.Name,MetaServer.Port);
           QueueMessageForSend(&MetaNetBuf,text->str);
           g_string_free(text,TRUE);
           
       t@@ -263,7 +281,7 @@ void HandleServerMessage(gchar *buf,Player *Play) {
                          if (pt!=Play && !IsCop(pt)) SendPlayerDetails(pt,Play,C_LIST);
                       }
                       SendServerMessage(NULL,C_NONE,C_ENDLIST,Play,NULL);
       -               RegisterWithMetaServer(TRUE,FALSE);
       +               RegisterWithMetaServer(TRUE,FALSE,TRUE);
                       Play->ConnectTimeout=0;
        
                       if (Network) {
       t@@ -442,7 +460,6 @@ void ClientLeftServer(Player *Play) {
        
        void CleanUpServer() {
        /* Closes down the server and frees up associated handles and memory */
       -   if (Server) RegisterWithMetaServer(FALSE,FALSE);
           while (FirstServer) {
              FirstServer=RemovePlayer((Player *)FirstServer->data,FirstServer);
           }
       t@@ -664,10 +681,29 @@ void StartServer() {
           }
        #endif
        
       -   RegisterWithMetaServer(TRUE,TRUE);
       +   RegisterWithMetaServer(TRUE,TRUE,FALSE);
        }
        
       -gboolean HandleServerCommand(char *string) {
       +void RequestServerShutdown() {
       +/* Begin the process of shutting down the server. In order to do this, */
       +/* we need to log out all of the currently connected players, and tell */
       +/* the metaserver that we're shutting down. We only shut down properly */
       +/* once all of these messages have been completely sent and            */
       +/* acknowledged. (Of course, this can be overridden by a SIGINT or     */
       +/* similar in the case of unresponsive players.)                       */
       +   RegisterWithMetaServer(FALSE,FALSE,FALSE);
       +   BroadcastToClients(C_NONE,C_QUIT,NULL,NULL,NULL);
       +   WantQuit=TRUE;
       +}
       +
       +gboolean IsServerShutdown() {
       +/* Returns TRUE if the actions initiated by RequestServerShutdown()  */
       +/* have been successfully completed, such that we can shut down the  */
       +/* server properly now.                                              */
       +   return (WantQuit && !FirstServer && !IsNetworkBufferActive(&MetaNetBuf));
       +}
       +
       +void HandleServerCommand(char *string) {
           GSList *list;
           Player *tmp;
           g_scanner_input_text(Scanner,string,strlen(string));
       t@@ -676,9 +712,7 @@ gboolean HandleServerCommand(char *string) {
                  strcmp(string,"?")==0) {
                 ServerHelp();
              } else if (strcasecmp(string,"quit")==0) {
       -         if (!FirstServer) return TRUE;
       -         WantQuit=TRUE;
       -         BroadcastToClients(C_NONE,C_QUIT,NULL,NULL,NULL);
       +         RequestServerShutdown();
              } else if (strncasecmp(string,"msg:",4)==0) {
                 BroadcastToClients(C_NONE,C_MSG,string+4,NULL,NULL);
              } else if (strcasecmp(string,"list")==0) {
       t@@ -707,7 +741,6 @@ gboolean HandleServerCommand(char *string) {
                 g_warning(_("Unknown command - try \"help\" for help..."));
              }
           }
       -   return FALSE;
        }
        
        Player *HandleNewConnection() {
       t@@ -736,7 +769,7 @@ void StopServer() {
           RemovePidFile();
        }
        
       -gboolean RemovePlayerFromServer(Player *Play,gboolean WantQuit) {
       +void RemovePlayerFromServer(Player *Play,gboolean WantQuit) {
        #ifdef GUI_SERVER
           if (Play->InputTag) gdk_input_remove(Play->InputTag);
        #endif
       t@@ -747,10 +780,9 @@ gboolean RemovePlayerFromServer(Player *Play,gboolean WantQuit) {
              SetPlayerName(Play,NULL);
        /* Report the new high scores (if any) and the new number of players
           to the metaserver */
       -      RegisterWithMetaServer(TRUE,TRUE);
       +      RegisterWithMetaServer(TRUE,TRUE,TRUE);
           }
           FirstServer=RemovePlayer(Play,FirstServer);
       -   return (!FirstServer && WantQuit);
        }
        
        void ServerLoop() {
       t@@ -765,7 +797,7 @@ void ServerLoop() {
           struct timeval timeout;
           int MinTimeout;
           GString *LineBuf;
       -   gboolean EndOfLine,DataWaiting;
       +   gboolean EndOfLine,DoneOK;
           gchar *buf;
        
           InitNetworkBuffer(&MetaNetBuf,'\n');
       t@@ -800,9 +832,13 @@ void ServerLoop() {
                 if (errno==EINTR) {
                    if (ReregisterRequest) {
                       ReregisterRequest=0;
       -               RegisterWithMetaServer(TRUE,TRUE);
       +               RegisterWithMetaServer(TRUE,TRUE,FALSE);
                       continue;
       -            } else if (TerminateRequest) break; else continue;
       +            } else if (TerminateRequest) {
       +               RequestServerShutdown();
       +               if (IsServerShutdown()) break;
       +               else continue;
       +            } else continue;
                 }
                 perror("select"); bgetch(); break;
              }
       t@@ -810,41 +846,48 @@ void ServerLoop() {
              if (FD_ISSET(0,&readfs)) {
                 if (ReadServerKey(LineBuf,&EndOfLine)==FALSE) {
                    if (isatty(0)) {
       -               break;
       +               RequestServerShutdown();
       +               if (IsServerShutdown()) break;
                    } else {
                       g_message(_("Standard input closed."));
                       InputClosed=TRUE;
                    }
                 } else if (EndOfLine) {
       -            if (HandleServerCommand(LineBuf->str)) break;
       +            HandleServerCommand(LineBuf->str);
       +            if (IsServerShutdown()) break;
                    g_string_truncate(LineBuf,0);
                 }
              }
              if (FD_ISSET(ListenSock,&readfs)) {
                 HandleNewConnection();
              }
       -      if (!RespondToSelect(&MetaNetBuf,&readfs,&writefs,
       -                           &errorfs,&DataWaiting)) {
       -         g_warning("Metaserver connection closed");
       -         ShutdownNetworkBuffer(&MetaNetBuf);
       -      } else if (DataWaiting) {
       +      if (RespondToSelect(&MetaNetBuf,&readfs,&writefs,&errorfs,&DoneOK)) {
                 while ((buf=GetWaitingMessage(&MetaNetBuf))) {
                    g_print("Meta: %s\n",buf);
                    g_free(buf);
                 }
              }
       +      if (!DoneOK) {
       +         g_print("Meta: (closed)\n");
       +         ShutdownNetworkBuffer(&MetaNetBuf);
       +         if (IsServerShutdown()) break;
       +      }
              list=FirstServer;
              while (list) {
                 nextlist=g_slist_next(list);
                 tmp=(Player *)list->data;
       -         if (tmp && !RespondToSelect(&tmp->NetBuf,&readfs,&writefs,&errorfs,
       -                                     &DataWaiting)) {
       -/* The socket has been shut down, or the buffer was filled - remove player */
       -            if (RemovePlayerFromServer(tmp,WantQuit)) break;
       -            tmp=NULL;
       -         } else if (tmp && DataWaiting) {
       +         if (tmp) {
       +            if (RespondToSelect(&tmp->NetBuf,&readfs,&writefs,
       +                                &errorfs,&DoneOK)) {
        /* If any complete messages were read, process them */
       -            HandleServerPlayer(tmp);
       +               HandleServerPlayer(tmp);
       +            }
       +            if (!DoneOK) {
       +/* The socket has been shut down, or the buffer was filled - remove player */
       +               RemovePlayerFromServer(tmp,WantQuit);
       +               if (IsServerShutdown()) break;
       +               tmp=NULL;
       +            }
                 }
                 list=nextlist;
              }
       t@@ -914,30 +957,31 @@ static void GuiQuitServer() {
        
        static void GuiDoCommand(GtkWidget *widget,gpointer data) {
           gchar *text;
       -   gboolean retval;
           text=gtk_editable_get_chars(GTK_EDITABLE(widget),0,-1);
           gtk_editable_delete_text(GTK_EDITABLE(widget),0,-1);
       -   retval=HandleServerCommand(text);
       +   HandleServerCommand(text);
           g_free(text);
       -   if (retval) GuiQuitServer();
       +   if (IsServerShutdown()) GuiQuitServer();
        }
        
        static void GuiHandleSocket(gpointer data,gint socket,
                                    GdkInputCondition condition) {
           Player *Play;
       -   gboolean DataWaiting;
       +   gboolean DoneOK;
           Play = (Player *)data;
        
           /* Sanity check - is the player still around? */
           if (!g_slist_find(FirstServer,(gpointer)Play)) return;
        
       -   if (!PlayerHandleNetwork(Play,condition&GDK_INPUT_READ,
       -                            condition&GDK_INPUT_WRITE,&DataWaiting)) {
       -      if (RemovePlayerFromServer(Play,WantQuit)) GuiQuitServer();
       -   } else if (DataWaiting) {
       +   if (PlayerHandleNetwork(Play,condition&GDK_INPUT_READ,
       +                           condition&GDK_INPUT_WRITE,&DoneOK)) {
              HandleServerPlayer(Play);
              GuiSetTimeouts();  /* We may have set some new timeouts */
           }
       +   if (!DoneOK) {
       +      RemovePlayerFromServer(Play,WantQuit);
       +      if (IsServerShutdown()) GuiQuitServer();
       +   }
        }
        
        void SetSocketWriteTest(Player *Play,gboolean WriteTest) {
       t@@ -964,7 +1008,8 @@ static gint GuiRequestDelete(GtkWidget *widget,GdkEvent *event,gpointer data) {
              GuiQuitServer();
           } else {
              TriedPoliteShutdown=TRUE;
       -      if (HandleServerCommand("quit")) GuiQuitServer();
       +      HandleServerCommand("quit");
       +      if (IsServerShutdown()) GuiQuitServer();
           }
           return TRUE; /* Never allow automatic deletion - we handle it manually */
        }
       t@@ -2384,13 +2429,12 @@ GSList *HandleTimeouts(GSList *First) {
           time_t timenow;
        
           timenow=time(NULL);
       -   if (MetaMinTimeout!=0 && MetaMinTimeout<=timenow) {
       +   if (MetaMinTimeout<=timenow) {
              MetaMinTimeout=0;
       -      if (MetaPending) RegisterWithMetaServer(TRUE,FALSE);
       +      if (MetaPlayerPending) RegisterWithMetaServer(TRUE,TRUE,FALSE);
           }
           if (MetaUpdateTimeout!=0 && MetaUpdateTimeout<=timenow) {
       -      MetaUpdateTimeout=0;
       -      RegisterWithMetaServer(TRUE,FALSE);
       +      RegisterWithMetaServer(TRUE,FALSE,FALSE);
           }
           list=First;
           while (list) {
 (DIR) diff --git a/src/serverside.h b/src/serverside.h
       t@@ -43,7 +43,7 @@ void BreakHandle();
        void ClientLeftServer(Player *Play);
        void StartServer();
        void StopServer();
       -gboolean HandleServerCommand(char *string);
       +void HandleServerCommand(char *string);
        Player *HandleNewConnection();
        void ServerLoop();
        void HandleServerPlayer(Player *Play);