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