tLow-level error and network handling 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 75487908600e5379fe2f8412948355e8df683006 (DIR) parent b561f151374a4e7b19c84e2eb4ec514bffe352fa (HTM) Author: Ben Webb <ben@salilab.org> Date: Mon, 1 Oct 2001 18:09:56 +0000 Low-level error and network handling abstracted out Diffstat: M src/AIPlayer.c | 25 +++++++++++++++---------- M src/Makefile.am | 6 +++--- M src/Makefile.in | 11 ++++++----- M src/curses_client.c | 88 +++++++++++++++++-------------- M src/dopeos.c | 50 ------------------------------- M src/dopeos.h | 37 ------------------------------- M src/dopewars.h | 41 ++----------------------------- M src/gtk_client.c | 177 +++++++++++++++---------------- M src/gtkport.c | 25 ++----------------------- M src/gtkport.h | 2 -- M src/message.c | 690 ++----------------------------- M src/message.h | 74 +++---------------------------- M src/serverside.c | 80 +++++++++++++++++++------------ M src/winmain.c | 1 - 14 files changed, 244 insertions(+), 1063 deletions(-) --- (DIR) diff --git a/src/AIPlayer.c b/src/AIPlayer.c t@@ -46,7 +46,6 @@ static void AISendRandomMessage(Player *AIPlay); static void AISetName(Player *AIPlay); static void AIHandleQuestion(char *Data,AICode AI,Player *AIPlay,Player *From); -#define NUMNAMES 8 #define MINSAFECASH 300 #define MINSAFEHEALTH 140 t@@ -64,21 +63,23 @@ int RealLoanShark,RealBank,RealGunShop,RealPub; void AIPlayerLoop() { /* Main loop for AI players. Connects to server, plays game, */ /* and then disconnects. */ - gchar *pt; + GString *errstr; + gchar *msg; Player *AIPlay; fd_set readfs,writefs; gboolean DoneOK,QuitRequest; int MaxSock; + errstr=g_string_new(""); AIPlay=g_new(Player,1); FirstClient=AddPlayer(0,AIPlay,FirstClient); g_message(_("AI Player started; attempting to contact server at %s:%d..."), ServerName,Port); - pt=SetupNetwork(FALSE); - if (pt) { + if (!SetupNetwork(errstr)) { g_log(NULL,G_LOG_LEVEL_CRITICAL, _("Could not connect to dopewars server\n(%s)\n" - "AI Player terminating abnormally."),_(pt)); + "AI Player terminating abnormally."),errstr->str); + g_string_free(errstr,TRUE); return; } BindNetworkBufferToSocket(&AIPlay->NetBuf,ClientSock); t@@ -106,8 +107,8 @@ void AIPlayerLoop() { if (RespondToSelect(&AIPlay->NetBuf,&readfs,&writefs,NULL,&DoneOK)) { QuitRequest=FALSE; - while ((pt=GetWaitingPlayerMessage(AIPlay))!=NULL) { - if (HandleAIMessage(pt,AIPlay)) { + while ((msg=GetWaitingPlayerMessage(AIPlay))!=NULL) { + if (HandleAIMessage(msg,AIPlay)) { QuitRequest=TRUE; break; } t@@ -119,17 +120,21 @@ void AIPlayerLoop() { break; } } - ShutdownNetwork(); + ShutdownNetwork(AIPlay); + g_string_free(errstr,TRUE); + FirstClient=RemovePlayer(AIPlay,FirstClient); g_print(_("AI Player terminated OK.\n")); } void AISetName(Player *AIPlay) { /* Chooses a random name for the AI player, and informs the server */ - char *AINames[NUMNAMES] = { + char *AINames[] = { "Chip", "Dopey", "Al", "Dan", "Bob", "Fred", "Bert", "Jim" }; + const gint NumNames = sizeof(AINames)/sizeof(AINames[0]); gchar *text; - text=g_strdup_printf("AI) %s",AINames[brandom(0,NUMNAMES)]); + + text=g_strdup_printf("AI) %s",AINames[brandom(0,NumNames)]); SetPlayerName(AIPlay,text); g_free(text); SendNullClientMessage(AIPlay,C_NONE,C_NAME,NULL,GetPlayerName(AIPlay)); (DIR) diff --git a/src/Makefile.am b/src/Makefile.am t@@ -1,7 +1,7 @@ bin_PROGRAMS = dopewars -dopewars_SOURCES = AIPlayer.c serverside.c dopewars.c message.c \ - curses_client.c gtk_client.c winmain.c \ - dopeos.c tstring.c @GTKPORT_C@ +dopewars_SOURCES = AIPlayer.c curses_client.c dopeos.c dopewars.c \ + error.c gtk_client.c message.c network.c serverside.c \ + tstring.c winmain.c @GTKPORT_C@ dopewars_DEPENDENCIES = @INTLLIBS@ @GTKPORT_O@ @WNDRES@ INCLUDES = @GTK_CFLAGS@ -I.. -I. LDADD = @GTKPORT_O@ @GTK_LIBS@ @INTLLIBS@ @WNDRES@ (DIR) diff --git a/src/Makefile.in b/src/Makefile.in t@@ -94,7 +94,7 @@ l = @l@ localedir = @localedir@ bin_PROGRAMS = dopewars -dopewars_SOURCES = AIPlayer.c serverside.c dopewars.c message.c curses_client.c gtk_client.c winmain.c dopeos.c tstring.c @GTKPORT_C@ +dopewars_SOURCES = AIPlayer.c curses_client.c dopeos.c dopewars.c error.c gtk_client.c message.c network.c serverside.c tstring.c winmain.c @GTKPORT_C@ dopewars_DEPENDENCIES = @INTLLIBS@ @GTKPORT_O@ @WNDRES@ INCLUDES = @GTK_CFLAGS@ -I.. -I. t@@ -112,8 +112,9 @@ PROGRAMS = $(bin_PROGRAMS) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -dopewars_OBJECTS = AIPlayer.o serverside.o dopewars.o message.o \ -curses_client.o gtk_client.o winmain.o dopeos.o tstring.o +dopewars_OBJECTS = AIPlayer.o curses_client.o dopeos.o dopewars.o \ +error.o gtk_client.o message.o network.o serverside.o tstring.o \ +winmain.o dopewars_LDADD = $(LDADD) dopewars_LDFLAGS = CFLAGS = @CFLAGS@ t@@ -128,8 +129,8 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = gtar GZIP_ENV = --best DEP_FILES = .deps/AIPlayer.P .deps/curses_client.P .deps/dopeos.P \ -.deps/dopewars.P .deps/gtk_client.P .deps/message.P .deps/serverside.P \ -.deps/tstring.P .deps/winmain.P +.deps/dopewars.P .deps/error.P .deps/gtk_client.P .deps/message.P \ +.deps/network.P .deps/serverside.P .deps/tstring.P .deps/winmain.P SOURCES = $(dopewars_SOURCES) OBJECTS = $(dopewars_OBJECTS) (DIR) diff --git a/src/curses_client.c b/src/curses_client.c t@@ -216,11 +216,11 @@ static void SelectServerManually(void) { g_free(text); g_free(PortText); } -static char *SelectServerFromMetaServer(Player *Play) { +static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) { /* Contacts the dopewars metaserver, and obtains a list of valid */ /* server/port pairs, one of which the user should select. */ -/* Returns a pointer to a static string containing an error */ -/* message if the connection failed, otherwise NULL. */ +/* Returns TRUE on success; on failure FALSE is returned, and */ +/* errstr is assigned an error message. */ int c; GSList *ListPt; ServerData *ThisServer; t@@ -228,22 +228,23 @@ static char *SelectServerFromMetaServer(Player *Play) { gint index; fd_set readfds,writefds; int maxsock; - gboolean DoneOK=TRUE; + gboolean DoneOK; HttpConnection *MetaConn; - static char NoServers[] = N_("No servers listed on metaserver"); attrset(TextAttr); clear_bottom(); mvaddstr(17,1,_("Please wait... attempting to contact metaserver...")); refresh(); - MetaConn = OpenMetaHttpConnection(); - - if (!MetaConn) return "Cannot connect"; + if (!OpenMetaHttpConnection(&MetaConn)) { + g_string_assign_error(errstr,&MetaConn->NetBuf.error); + CloseHttpConnection(MetaConn); + return FALSE; + } ClearServerList(&ServerList); - while(DoneOK) { + do { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(0,&readfds); maxsock=1; SetSelectForNetworkBuffer(&MetaConn->NetBuf,&readfds,&writefds, t@@ -263,16 +264,15 @@ static char *SelectServerFromMetaServer(Player *Play) { while (HandleWaitingMetaServerData(MetaConn,&ServerList)) {} } if (!DoneOK) { - g_print("Metaserver communication closed"); + if (IsHttpError(MetaConn)) { + g_string_assign_error(errstr,&MetaConn->NetBuf.error); + CloseHttpConnection(MetaConn); + return FALSE; + } } - } + } while (DoneOK); CloseHttpConnection(MetaConn); -/* clear_line(17); - mvaddstr(17,1, - _("Connection to metaserver established. Obtaining server list...")); - refresh();*/ - text=g_string_new(""); ListPt=ServerList; t@@ -321,23 +321,30 @@ static char *SelectServerFromMetaServer(Player *Play) { break; } } - if (!ServerList) return NoServers; + if (!ServerList) { + g_string_assign(errstr,"No servers listed on metaserver"); + return FALSE; + } clear_line(17); refresh(); g_string_free(text,TRUE); - return NULL; + return TRUE; } -static char ConnectToServer(Player *Play) { +static gboolean ConnectToServer(Player *Play) { /* Connects to a dopewars server. Prompts the user to select a server */ /* if necessary. Returns TRUE, unless the user elected to quit the */ /* program rather than choose a valid server. */ - char *pt=NULL,*MetaError=NULL; + gboolean MetaOK=TRUE,NetOK=TRUE; + GString *errstr; gchar *text; int c; + + errstr = g_string_new(""); + if (strcasecmp(ServerName,SN_META)==0 || ConnectMethod==CM_META) { ConnectMethod=CM_META; - MetaError=SelectServerFromMetaServer(Play); + MetaOK=SelectServerFromMetaServer(Play,errstr); } else if (strcasecmp(ServerName,SN_PROMPT)==0 || ConnectMethod==CM_PROMPT) { ConnectMethod=CM_PROMPT; t@@ -345,31 +352,33 @@ static char ConnectToServer(Player *Play) { } else if (strcasecmp(ServerName,SN_SINGLE)==0 || ConnectMethod==CM_SINGLE) { ConnectMethod=CM_SINGLE; + g_string_free(errstr,TRUE); return TRUE; } while (1) { attrset(TextAttr); clear_bottom(); - if (!MetaError) { + if (MetaOK) { mvaddstr(17,1, _("Please wait... attempting to contact dopewars server...")); refresh(); - pt=SetupNetwork(FALSE); + NetOK=SetupNetwork(errstr); } - if (pt || MetaError) { + if (!NetOK || !MetaOK) { clear_line(17); - if (MetaError) { + if (!MetaOK) { /* Display of an error while contacting the metaserver */ - text=g_strdup_printf(_("Error: %s"),_(MetaError)); + mvaddstr(16,1,_("Cannot get metaserver details")); + text=g_strdup_printf(" (%s)",errstr->str); mvaddstr(17,1,text); g_free(text); } else { /* Display of an error message while trying to contact a dopewars server (the error message itself is displayed on the next screen line) */ mvaddstr(16,1,_("Could not start multiplayer dopewars")); - text=g_strdup_printf(" (%s)",_(pt)); + text=g_strdup_printf(" (%s)",errstr->str); mvaddstr(17,1,text); g_free(text); } - pt=MetaError=NULL; + MetaOK=NetOK=TRUE; attrset(PromptAttr); mvaddstr(18,1, _("Will you... C>onnect to a different host and/or port")); t@@ -388,11 +397,13 @@ static char ConnectToServer(Player *Play) { the same (C>onnect, L>ist, Q>uit, P>lay single-player) */ c=GetKey(_("CLQP"),"CLQP",FALSE,FALSE,FALSE); switch(c) { - case 'Q': return FALSE; + case 'Q': g_string_free(errstr,TRUE); + return FALSE; case 'P': ConnectMethod=CM_SINGLE; + g_string_free(errstr,TRUE); return TRUE; case 'L': ConnectMethod=CM_META; - MetaError=SelectServerFromMetaServer(Play); + MetaOK=SelectServerFromMetaServer(Play,errstr); break; case 'C': ConnectMethod=CM_PROMPT; SelectServerManually(); t@@ -400,6 +411,7 @@ static char ConnectToServer(Player *Play) { } } else break; } + g_string_free(errstr,TRUE); return TRUE; } #endif /* NETWORKING */ t@@ -1870,7 +1882,6 @@ static void Curses_DoGame(Player *Play) { void CursesLoop(void) { char c; - gchar *Name=NULL; Player *Play; start_curses(); t@@ -1885,20 +1896,17 @@ void CursesLoop(void) { display_intro(); - c='Y'; - while(c=='Y') { - Play=g_new(Player,1); - FirstClient=AddPlayer(0,Play,FirstClient); - SetPlayerName(Play,Name); + Play=g_new(Player,1); + FirstClient=AddPlayer(0,Play,FirstClient); + do { Curses_DoGame(Play); - g_free(Name); Name=g_strdup(GetPlayerName(Play)); - ShutdownNetwork(); + ShutdownNetwork(Play); CleanUpServer(); attrset(TextAttr); mvaddstr(23,20,_("Play again? ")); c=GetKey(_("YN"),"YN",TRUE,TRUE,FALSE); - } - g_free(Name); + } while (c=='Y'); + FirstClient=RemovePlayer(Play,FirstClient); end_curses(); } (DIR) diff --git a/src/dopeos.c b/src/dopeos.c t@@ -220,7 +220,6 @@ void sigemptyset(int *mask) {} void sigaddset(int *mask,int sig) {} int sigaction(int sig,struct sigaction *sact,char *pt) { return 0; } void sigprocmask(int flag,int *mask,char *pt) {} -void gettimeofday(void *pt,void *pt2) {} void standout() {} void standend() {} t@@ -280,46 +279,11 @@ int bselect(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds, return retval; } -#if NETWORKING -int GetSocketError() { -#ifdef GUI_CLIENT - if (AsyncSocketError) return AsyncSocketError; - else -#endif -return WSAGetLastError(); -} - -void fcntl(SOCKET s,int fsetfl,long cmd) { - unsigned long param=1; - ioctlsocket(s,cmd,¶m); -} - -void StartNetworking() { - WSADATA wsaData; - if (WSAStartup(MAKEWORD(1,0),&wsaData)!=0) { - printf("Cannot initialise WinSock!\n"); - exit(1); - } -} - -void StopNetworking() { WSACleanup(); } - -void SetReuse(SOCKET sock) { - BOOL tmp; - tmp=TRUE; - if (setsockopt(sock,SOL_SOCKET, - SO_REUSEADDR,(char *)(&tmp),sizeof(tmp))==-1) { - perror("setsockopt"); exit(1); - } -} - /* We don't do locking under Win32 right now */ int ReadLock(FILE *fp) { return 0; } int WriteLock(FILE *fp) { return 0; } void ReleaseLock(FILE *fp) { } -#endif /* NETWORKING */ - #else /* Code for Unix build */ #ifdef HAVE_UNISTD_H t@@ -351,20 +315,6 @@ int bgetch() { } #endif -#if NETWORKING -int GetSocketError() { return errno; } -void StartNetworking() {} -void StopNetworking() {} -void SetReuse(int sock) { - int i; - i=1; - if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR, - &i,sizeof(i))==-1) { - perror("setsockopt"); exit(1); - } -} -#endif /* NETWORKING */ - static int DoLock(FILE *fp,int l_type) { struct flock lk; (DIR) diff --git a/src/dopeos.h b/src/dopeos.h t@@ -30,10 +30,6 @@ #include <windows.h> #include <string.h> -#if NETWORKING -#include <winsock.h> -#endif - #include <stdio.h> void refresh(); t@@ -104,40 +100,19 @@ int bgetch(); char *index(char *str,char ch); int getopt(int argc,char *argv[],char *str); extern char *optarg; -#define F_SETFL 0 -#define O_NONBLOCK FIONBIO typedef int ssize_t; -void gettimeofday(void *pt,void *pt2); void standout(); void standend(); void endwin(); int bselect(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfs, struct timeval *tm); -#if NETWORKING -int GetSocketError(); -void fcntl(SOCKET s,int fsetfl,long cmd); -#define CloseSocket(sock) closesocket(sock) -void StartNetworking(); -void StopNetworking(); -void SetReuse(SOCKET sock); -#endif - #else /* Definitions for Unix build */ #include <sys/types.h> #include <stdio.h> - -#ifdef NETWORKING -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <unistd.h> -#endif /* NETWORKING */ - #include <errno.h> /* Only include sys/wait.h on those systems which support it */ t@@ -172,14 +147,6 @@ int bgetch(void); #define bselect select -#if NETWORKING -#define CloseSocket(sock) close(sock) -int GetSocketError(void); -void StartNetworking(void); -void StopNetworking(void); -void SetReuse(int sock); -#endif /* NETWORKING */ - #endif /* CYGWIN */ void MicroSleep(int microsec); t@@ -189,10 +156,6 @@ int WriteLock(FILE *fp); void ReleaseLock(FILE *fp); /* Now make definitions if they haven't been done properly */ -#ifndef SOCKET_ERROR -#define SOCKET_ERROR -1 -#endif - #ifndef WEXITSTATUS #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif (DIR) diff --git a/src/dopewars.h b/src/dopewars.h t@@ -43,6 +43,8 @@ #include <glib.h> #include "dopeos.h" +#include "error.h" +#include "network.h" /* Make price_t be a long long if the type is supported by the compiler */ #if SIZEOF_LONG_LONG == 0 t@@ -235,45 +237,6 @@ struct TDopeList { }; typedef struct TDopeList DopeList; -typedef struct tagConnBuf { - gchar *Data; /* bytes waiting to be read/written */ - int Length; /* allocated length of the "Data" buffer */ - int DataPresent; /* number of bytes currently in "Data" */ -} ConnBuf; - -typedef struct _NetworkBuffer NetworkBuffer; - -typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write); - -typedef enum { - ET_NOERROR, ET_CUSTOM, ET_ERRNO, -#ifdef CYGWIN - ET_WIN32, ET_WINSOCK -#else - ET_HERRNO -#endif -} ErrorType; - -typedef struct _LastError { - gint code; - ErrorType type; -} LastError; - -/* Handles reading and writing messages from/to a network connection */ -struct _NetworkBuffer { - int fd; /* File descriptor of the socket */ - gint InputTag; /* Identifier for gdk_input routines */ - NBCallBack CallBack; /* Function called when the socket read- or - write-able status changes */ - gpointer CallBackData; /* Data accessible to the callback function */ - char Terminator; /* Character that separates messages */ - char StripChar; /* Character that should be removed from 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 */ - LastError error; /* Any error from the last operation */ -}; - struct PLAYER_T { guint ID; int Turn; (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c t@@ -62,7 +62,6 @@ struct StatusWidgets { struct ClientDataStruct { GtkWidget *window,*messages; - gchar *PlayerName; Player *Play; GtkItemFactory *Menu; struct StatusWidgets Status; t@@ -71,6 +70,14 @@ struct ClientDataStruct { guint JetAccel; }; +struct StartGameStruct { + GtkWidget *dialog,*name,*hostname,*port,*antique,*status,*metaserv; +#ifdef NETWORKING + HttpConnection *MetaConn; + GSList *NewMetaList; +#endif +}; + static struct ClientDataStruct ClientData; static gboolean InGame=FALSE; t@@ -95,10 +102,13 @@ static void GetClientMessage(gpointer data,gint socket, static void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write); static void MetaSocketStatus(NetworkBuffer *NetBuf,gboolean Read, gboolean Write); +static void FinishServerConnect(struct StartGameStruct *widgets, + gboolean ConnectOK); /* List of servers on the metaserver */ static GSList *MetaList=NULL; -#endif + +#endif /* NETWORKING */ static void HandleClientMessage(char *buf,Player *Play); static void PrepareHighScoreDialog(void); t@@ -268,15 +278,21 @@ void ListInventory(GtkWidget *widget,gpointer data) { void GetClientMessage(gpointer data,gint socket, GdkInputCondition condition) { gchar *pt; - gboolean DoneOK; + NetworkBuffer *NetBuf; + gboolean DoneOK,Connecting; + + NetBuf = &ClientData.Play->NetBuf; + Connecting = NetBuf->WaitConnect; if (PlayerHandleNetwork(ClientData.Play,condition&GDK_INPUT_READ, - condition&GDK_INPUT_WRITE,&DoneOK)) { + condition&GDK_INPUT_WRITE,&DoneOK) && !Connecting) { while ((pt=GetWaitingPlayerMessage(ClientData.Play))!=NULL) { HandleClientMessage(pt,ClientData.Play); g_free(pt); } } - if (!DoneOK) { + if (Connecting && (!NetBuf->WaitConnect || !DoneOK)) { + FinishServerConnect(data,DoneOK); + } else if (!DoneOK) { if (InGame) { /* The network connection to the server was dropped unexpectedly */ g_warning(_("Connection to server lost - switching to " t@@ -294,7 +310,7 @@ void SocketStatus(NetworkBuffer *NetBuf,gboolean Read,gboolean Write) { NetBuf->InputTag=gdk_input_add(NetBuf->fd, (Read ? GDK_INPUT_READ : 0) | (Write ? GDK_INPUT_WRITE : 0), - GetClientMessage,NULL); + GetClientMessage,NetBuf->CallBackData); } } #endif /* NETWORKING */ t@@ -331,14 +347,16 @@ void HandleClientMessage(char *pt,Player *Play) { case C_PUSH: /* The server admin has asked us to leave - so warn the user, and do so */ ShutdownNetworkBuffer(&Play->NetBuf); - g_warning(_("You have been pushed from the server.")); + g_warning(_("You have been pushed from the server.\n" + "Switching to single player mode.")); SwitchToSinglePlayer(Play); UpdateMenus(); break; case C_QUIT: /* The server has sent us notice that it is shutting down */ ShutdownNetworkBuffer(&Play->NetBuf); - g_warning(_("The server has terminated.")); + g_warning(_("The server has terminated.\n" + "Switching to single player mode.")); SwitchToSinglePlayer(Play); UpdateMenus(); break; t@@ -1542,19 +1560,10 @@ void QuestionDialog(char *Data,Player *From) { } void StartGame(void) { - Player *Play; - Play=ClientData.Play=g_new(Player,1); - FirstClient=AddPlayer(0,Play,FirstClient); -#ifdef NETWORKING - if (Network) { - BindNetworkBufferToSocket(&Play->NetBuf,ClientSock); - SetNetworkBufferCallBack(&Play->NetBuf,SocketStatus,NULL); - } -#endif + Player *Play=ClientData.Play; InitAbilities(Play); SendAbilities(Play); - SetPlayerName(Play,ClientData.PlayerName); - SendNullClientMessage(Play,C_NONE,C_NAME,NULL,ClientData.PlayerName); + SendNullClientMessage(Play,C_NONE,C_NAME,NULL,GetPlayerName(Play)); InGame=TRUE; UpdateMenus(); gtk_widget_show_all(ClientData.vbox); t@@ -1565,9 +1574,7 @@ void EndGame(void) { DisplayFightMessage(NULL); gtk_widget_hide_all(ClientData.vbox); gtk_editable_delete_text(GTK_EDITABLE(ClientData.messages),0,-1); - g_free(ClientData.PlayerName); - ClientData.PlayerName=g_strdup(GetPlayerName(ClientData.Play)); - ShutdownNetwork(); + ShutdownNetwork(ClientData.Play); UpdatePlayerLists(); CleanUpServer(); InGame=FALSE; t@@ -1741,8 +1748,10 @@ char GtkLoop(int *argc,char **argv[],gboolean ReturnOnFail) { g_log_set_handler(NULL,LogMask()|G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_WARNING, LogMessage,NULL); - ClientData.PlayerName=NULL; - ClientData.Play=NULL; +/* Create the main player */ + ClientData.Play=g_new(Player,1); + FirstClient=AddPlayer(0,ClientData.Play,FirstClient); + window=ClientData.window=gtk_window_new(GTK_WINDOW_TOPLEVEL); /* Title of main window in GTK+ client */ t@@ -1816,6 +1825,9 @@ char GtkLoop(int *argc,char **argv[],gboolean ReturnOnFail) { gtk_main(); +/* Free the main player */ + FirstClient=RemovePlayer(ClientData.Play,FirstClient); + return TRUE; } t@@ -1900,15 +1912,6 @@ _("\nFor information on the command line options, type dopewars -h at your\n" gtk_widget_show_all(dialog); } -struct StartGameStruct { - GtkWidget *dialog,*name,*hostname,*port,*antique,*status,*metaserv; -#ifdef NETWORKING - gint ConnectTag; - HttpConnection *MetaConn; - GSList *NewMetaList; -#endif -}; - static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets, gchar **PlayerName) { g_free(*PlayerName); t@@ -1923,45 +1926,54 @@ static gboolean GetStartGamePlayerName(struct StartGameStruct *widgets, } #ifdef NETWORKING -static void FinishServerConnect(gpointer data,gint socket, - GdkInputCondition condition) { - gchar *text,*NetworkError; - struct StartGameStruct *widgets; +static void ConnectError(struct StartGameStruct *widgets,gboolean meta) { + GString *neterr; + gchar *text; + LastError *error; - widgets=(struct StartGameStruct *)data; + if (meta) error=&widgets->MetaConn->NetBuf.error; + else error=&ClientData.Play->NetBuf.error; - gdk_input_remove(widgets->ConnectTag); - widgets->ConnectTag=0; - NetworkError=FinishSetupNetwork(); - if (NetworkError) { -/* Error: GTK+ client could not connect to the given dopewars server */ - text=g_strdup_printf(_("Status: Could not connect (%s)"),NetworkError); - gtk_label_set_text(GTK_LABEL(widgets->status),text); - g_free(text); + if (!IsError(error)) return; + + neterr = g_string_new(""); + g_string_assign_error(neterr,error); + + if (meta) { +/* Error: GTK+ client could not connect to the metaserver */ + text=g_strdup_printf(_("Status: Could not connect to metaserver (%s)"), + neterr->str); } else { +/* Error: GTK+ client could not connect to the given dopewars server */ + text=g_strdup_printf(_("Status: Could not connect (%s)"),neterr->str); + } + + gtk_label_set_text(GTK_LABEL(widgets->status),text); + g_free(text); + g_string_free(neterr,TRUE); +} + +void FinishServerConnect(struct StartGameStruct *widgets,gboolean ConnectOK) { + if (ConnectOK) { + Client=Network=TRUE; gtk_widget_destroy(widgets->dialog); StartGame(); + } else { + ConnectError(widgets,FALSE); } } static void DoConnect(struct StartGameStruct *widgets) { - gchar *text,*NetworkError; + gchar *text; /* Message displayed during the attempted connect to a dopewars server */ text=g_strdup_printf(_("Status: Attempting to contact %s..."),ServerName); gtk_label_set_text(GTK_LABEL(widgets->status),text); g_free(text); - if (widgets->ConnectTag!=0) { - gdk_input_remove(widgets->ConnectTag); CloseSocket(ClientSock); - widgets->ConnectTag=0; - } - NetworkError=SetupNetwork(TRUE); - if (!NetworkError) { - widgets->ConnectTag=gdk_input_add(ClientSock,GDK_INPUT_WRITE, - FinishServerConnect,(gpointer)widgets); + if (StartNetworkBufferConnect(&ClientData.Play->NetBuf,ServerName,Port)) { + SetNetworkBufferCallBack(&ClientData.Play->NetBuf,SocketStatus, + (gpointer)widgets); } else { - text=g_strdup_printf(_("Status: Could not connect (%s)"),NetworkError); - gtk_label_set_text(GTK_LABEL(widgets->status),text); - g_free(text); + ConnectError(widgets,FALSE); } } t@@ -1973,7 +1985,7 @@ static void ConnectToServer(GtkWidget *widget,struct StartGameStruct *widgets) { text=gtk_editable_get_chars(GTK_EDITABLE(widgets->port),0,-1); Port=atoi(text); g_free(text); - if (!GetStartGamePlayerName(widgets,&ClientData.PlayerName)) return; + if (!GetStartGamePlayerName(widgets,&ClientData.Play->Name)) return; DoConnect(widgets); } t@@ -1985,11 +1997,13 @@ static void FillMetaServerList(struct StartGameStruct *widgets, GSList *ListPt; gint row; + if (UseNewList && !widgets->NewMetaList) return; + metaserv=widgets->metaserv; gtk_clist_freeze(GTK_CLIST(metaserv)); gtk_clist_clear(GTK_CLIST(metaserv)); - if (UseNewList && widgets->NewMetaList) { + if (UseNewList) { ClearServerList(&MetaList); MetaList=widgets->NewMetaList; widgets->NewMetaList=NULL; t@@ -2032,7 +2046,7 @@ static void HandleMetaSock(gpointer data,gint socket, &widgets->NewMetaList)) {} } if (!DoneOK) { - g_print("Metaserver communication closed\n"); + ConnectError(widgets,TRUE); CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL; FillMetaServerList(widgets,TRUE); t@@ -2054,17 +2068,17 @@ static void UpdateMetaServerList(GtkWidget *widget, struct StartGameStruct *widgets) { GtkWidget *metaserv; if (widgets->MetaConn) { - CloseHttpConnection(widgets->MetaConn); - widgets->MetaConn=NULL; + CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL; } ClearServerList(&widgets->NewMetaList); - widgets->MetaConn = OpenMetaHttpConnection(); - - if (widgets->MetaConn) { + if (OpenMetaHttpConnection(&widgets->MetaConn)) { metaserv=widgets->metaserv; SetNetworkBufferCallBack(&widgets->MetaConn->NetBuf, MetaSocketStatus,(gpointer)widgets); + } else { + ConnectError(widgets,TRUE); + CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL; } } t@@ -2083,7 +2097,7 @@ static void MetaServerConnect(GtkWidget *widget, AssignName(&ServerName,ThisServer->Name); Port=ThisServer->Port; - if (!GetStartGamePlayerName(widgets,&ClientData.PlayerName)) return; + if (!GetStartGamePlayerName(widgets,&ClientData.Play->Name)) return; DoConnect(widgets); } } t@@ -2093,21 +2107,14 @@ static void StartSinglePlayer(GtkWidget *widget, struct StartGameStruct *widgets) { WantAntique= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->antique)); - if (!GetStartGamePlayerName(widgets,&ClientData.PlayerName)) return; + if (!GetStartGamePlayerName(widgets,&ClientData.Play->Name)) return; StartGame(); gtk_widget_destroy(widgets->dialog); } static void CloseNewGameDia(GtkWidget *widget, struct StartGameStruct *widgets) { - g_log_set_handler(NULL,LogMask()|G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_WARNING, - LogMessage,NULL); #ifdef NETWORKING - if (widgets->ConnectTag) { - gdk_input_remove(widgets->ConnectTag); - CloseSocket(ClientSock); - widgets->ConnectTag=0; - } if (widgets->MetaConn) { CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL; t@@ -2116,18 +2123,6 @@ static void CloseNewGameDia(GtkWidget *widget, #endif } -static void NewGameLogMessage(const gchar *log_domain,GLogLevelFlags log_level, - const gchar *message,gpointer user_data) { - struct StartGameStruct *widgets; - gchar *text; - - widgets = (struct StartGameStruct *)user_data; - - text=g_strdup_printf(_("Status: %s"),message); - gtk_label_set_text(GTK_LABEL(widgets->status),text); - g_free(text); -} - void NewGameDialog(void) { GtkWidget *vbox,*vbox2,*hbox,*label,*entry,*notebook,*frame,*button; GtkWidget *dialog; t@@ -2146,7 +2141,6 @@ void NewGameDialog(void) { server_titles[3]=_("Players"); server_titles[4]=_("Comment"); - widgets.ConnectTag=0; widgets.MetaConn=NULL; widgets.NewMetaList=NULL; t@@ -2183,9 +2177,7 @@ void NewGameDialog(void) { entry=widgets.name=gtk_entry_new(); gtk_widget_add_accelerator(entry,"grab-focus",accel_group,AccelKey,0, GTK_ACCEL_VISIBLE | GTK_ACCEL_SIGNAL_VISIBLE); - if (ClientData.PlayerName) { - gtk_entry_set_text(GTK_ENTRY(entry),ClientData.PlayerName); - } + gtk_entry_set_text(GTK_ENTRY(entry),GetPlayerName(ClientData.Play)); gtk_box_pack_start(GTK_BOX(hbox),entry,TRUE,TRUE,0); gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0); t@@ -2323,9 +2315,6 @@ void NewGameDialog(void) { label=widgets.status=gtk_label_new(_("Status: Waiting for user input")); gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0); - g_log_set_handler(NULL,LogMask()|G_LOG_LEVEL_MESSAGE|G_LOG_LEVEL_WARNING, - NewGameLogMessage,(gpointer)&widgets); - gtk_container_add(GTK_CONTAINER(widgets.dialog),vbox); gtk_widget_grab_focus(widgets.name); (DIR) diff --git a/src/gtkport.c b/src/gtkport.c t@@ -30,25 +30,6 @@ #include "gtkport.h" #include "nls.h" -/* Internationalization stuff */ - -#ifdef ENABLE_NLS -#include <locale.h> -#include <libintl.h> -#define _(String) gettext (String) -#ifdef gettext_noop -#define N_(String) gettext_noop (String) -#else -#define N_(String) (String) -#endif -#else -#define gettext(String) (String) -#define dgettext(Domain,Message) (Message) -#define dcgettext(Domain,Message,Type) (Message) -#define _(String) (String) -#define N_(String) (String) -#endif - #ifdef CYGWIN #include <windows.h> t@@ -636,7 +617,6 @@ static GSList *WindowList=NULL; static GSList *GdkInputs=NULL; static GSList *GtkTimeouts=NULL; static HWND TopLevel=NULL; -long AsyncSocketError=0; static WNDPROC wpOrigEntryProc,wpOrigTextProc; t@@ -942,9 +922,9 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) { } break; case WM_SOCKETDATA: - AsyncSocketError=WSAGETSELECTERROR(lParam); +/* Make any error available by the usual WSAGetLastError() mechanism */ + WSASetLastError(WSAGETSELECTERROR(lParam)); DispatchSocketEvent((SOCKET)wParam,WSAGETSELECTEVENT(lParam)); - AsyncSocketError=0; break; case WM_TIMER: DispatchTimeoutEvent((UINT)wParam); t@@ -983,7 +963,6 @@ void win32_init(HINSTANCE hInstance,HINSTANCE hPrevInstance,char *MainIcon) { hInst=hInstance; hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT); WindowList=NULL; - AsyncSocketError=0; if (!hPrevInstance) { wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = MainWndProc; (DIR) diff --git a/src/gtkport.h b/src/gtkport.h t@@ -700,8 +700,6 @@ void gtk_progress_bar_update(GtkProgressBar *pbar,gfloat percentage); guint gtk_timeout_add(guint32 interval,GtkFunction function,gpointer data); void gtk_timeout_remove(guint timeout_handler_id); -extern long AsyncSocketError; - #else /* CYGWIN */ /* Include standard GTK+ headers on Unix systems */ (DIR) diff --git a/src/message.c b/src/message.c t@@ -25,9 +25,6 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif #ifndef CYGWIN #include <sys/types.h> t@@ -40,6 +37,7 @@ #include "dopeos.h" #include "dopewars.h" #include "message.h" +#include "network.h" #include "nls.h" #include "serverside.h" #include "tstring.h" t@@ -274,279 +272,7 @@ gboolean HaveAbility(Player *Play,gint Type) { else return (Play->Abil.Shared[Type]); } -void ClearError(LastError *error) { - error->type=ET_NOERROR; -} - -void SetError(LastError *error,ErrorType type,gint code) { - error->type=type; - error->code=code; -} - -typedef struct _ErrStr { - int code; - char *string; -} ErrStr; - -static ErrStr CustomErrStr[] = { - { E_FULLBUF,N_("Connection dropped due to full buffer") }, - { 0,NULL } -}; - -#ifdef CYGWIN - -static ErrStr WSAErrStr[] = { - { WSANOTINITIALISED,N_("WinSock has not been properly initialised") }, - { WSAENETDOWN,N_("The network subsystem has failed") }, - { WSAEADDRINUSE,N_("Address already in use") }, - { WSAENETDOWN,N_("Cannot reach the network") }, - { WSAETIMEDOUT,N_("The connection timed out") }, - { WASEMFILE,N_("Out of file descriptors") }, - { WASENOBUFS,N_("Out of buffer space") }, - { WSAEOPNOTSUPP,N_("Operation not supported") }, - { WSAECONNABORTED,N_("Connection aborted due to failure") }, - { WSAECONNRESET,N_("Connection reset by remote host") }, - { WSAECONNREFUSED,N_("Connection refused") }, - { WSAEAFNOSUPPORT,N_("Address family not supported") }, - { WSAEPROTONOSUPPORT,N_("Protocol not supported") }, - { WSAESOCKTNOSUPPORT,N_("Socket type not supported") }, - { WSAHOST_NOT_FOUND,N_("Host not found") }, - { WSATRY_AGAIN,N_("Temporary name server error - try again later") }, - { WSANO_RECOVERY,N_("Failed to contact nameserver") }, - { WSANO_DATA,N_("Valid name, but no DNS data record present") }, - { 0,NULL } -}; - -#else - -static ErrStr DNSErrStr[] = { - { HOST_NOT_FOUND,N_("Host not found") }, - { TRY_AGAIN,N_("Temporary name server error - try again later") }, - { 0,NULL } -}; - -#endif - -static gchar *LookupErrorCode(gint code,ErrStr *str,gchar *fallbackstr) { - for (;str && str->string;str++) { - if (code==str->code) return g_strdup(_(str->string)); - } - return g_strdup_printf(fallbackstr,code); -} - -gchar *GetErrorString(LastError *error) { - switch (error->type) { - case ET_NOERROR: - return NULL; - case ET_CUSTOM: - return LookupErrorCode(error->code,CustomErrStr, - _("Unknown internal error code %d")); - case ET_ERRNO: - return g_strdup(strerror(error->code)); -#ifdef CYGWIN - case ET_WIN32: - return NULL; - case ET_WINSOCK: - return LookupErrorCode(error->code,WSAErrStr, - _("Unknown WinSock error code %d")); -#else - case ET_HERRNO: - return LookupErrorCode(error->code,DNSErrStr, - _("Unknown DNS error code %d")); -#endif - } - return NULL; -} - #if NETWORKING -static void NetBufCallBack(NetworkBuffer *NetBuf) { - if (NetBuf && NetBuf->CallBack) { - (*NetBuf->CallBack)(NetBuf,!NetBuf->WaitConnect, - NetBuf->WriteBuf.DataPresent || NetBuf->WaitConnect); - } -} - -static void NetBufCallBackStop(NetworkBuffer *NetBuf) { - if (NetBuf && NetBuf->CallBack) (*NetBuf->CallBack)(NetBuf,FALSE,FALSE); -} - -void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator,char StripChar) { -/* Initialises the passed network buffer, ready for use. Messages sent */ -/* or received on the buffered connection will be terminated by the */ -/* given character, and if they end in "StripChar" it will be removed */ -/* before the messages are sent or received. */ - NetBuf->fd=-1; - NetBuf->InputTag=0; - NetBuf->CallBack=NULL; - NetBuf->CallBackData=NULL; - NetBuf->Terminator=Terminator; - NetBuf->StripChar=StripChar; - NetBuf->ReadBuf.Data=NetBuf->WriteBuf.Data=NULL; - NetBuf->ReadBuf.Length=NetBuf->WriteBuf.Length=0; - NetBuf->ReadBuf.DataPresent=NetBuf->WriteBuf.DataPresent=0; - NetBuf->WaitConnect=FALSE; - ClearError(&NetBuf->error); -} - -void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack, - gpointer CallBackData) { - NetBufCallBackStop(NetBuf); - NetBuf->CallBack=CallBack; - NetBuf->CallBackData=CallBackData; - NetBufCallBack(NetBuf); -} - -void BindNetworkBufferToSocket(NetworkBuffer *NetBuf,int fd) { -/* Sets up the given network buffer to handle data being sent/received */ -/* through the given socket */ - NetBuf->fd=fd; -} - -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, - unsigned RemotePort) { - gchar *retval; - - ShutdownNetworkBuffer(NetBuf); - retval=StartConnect(&NetBuf->fd,RemoteHost,RemotePort,TRUE); - - if (retval) { - SetError(&NetBuf->error,ET_HERRNO,h_errno); - ConnectError(retval); return FALSE; - } else { - NetBuf->WaitConnect=TRUE; - -/* Notify the owner if necessary to check for the connection completing */ - NetBufCallBack(NetBuf); - - return TRUE; - } -} - -void ShutdownNetworkBuffer(NetworkBuffer *NetBuf) { -/* Frees the network buffer's data structures (leaving it in the */ -/* 'initialised' state) and closes the accompanying socket. */ - - NetBufCallBackStop(NetBuf); - - if (NetBuf->fd>=0) CloseSocket(NetBuf->fd); - - g_free(NetBuf->ReadBuf.Data); - g_free(NetBuf->WriteBuf.Data); - - InitNetworkBuffer(NetBuf,NetBuf->Terminator,NetBuf->StripChar); -} - -void SetSelectForNetworkBuffer(NetworkBuffer *NetBuf,fd_set *readfds, - fd_set *writefds,fd_set *errorfds,int *MaxSock) { -/* Updates the sets of read and write file descriptors to monitor */ -/* input to/output from the given network buffer. MaxSock is updated */ -/* with the highest-numbered file descriptor (plus 1) for use in a */ -/* later select() call. */ - if (!NetBuf || NetBuf->fd<=0) return; - FD_SET(NetBuf->fd,readfds); - if (errorfds) FD_SET(NetBuf->fd,errorfds); - if (NetBuf->fd >= *MaxSock) *MaxSock=NetBuf->fd+1; - if (NetBuf->WriteBuf.DataPresent || NetBuf->WaitConnect) { - FD_SET(NetBuf->fd,writefds); - } -} - -static gboolean DoNetworkBufferStuff(NetworkBuffer *NetBuf,gboolean ReadReady, - gboolean WriteReady,gboolean ErrorReady, - gboolean *ReadOK,gboolean *WriteOK, - gboolean *ErrorOK) { -/* Reads and writes data if the network connection is ready. Sets the */ -/* various OK variables to TRUE if no errors occurred in the relevant */ -/* operations, and returns TRUE if data was read and is waiting for */ -/* processing. */ - gboolean DataWaiting=FALSE,ConnectDone=FALSE; - gchar *retval; - *ReadOK=*WriteOK=*ErrorOK=TRUE; - - if (ErrorReady) *ErrorOK=FALSE; - else if (NetBuf->WaitConnect) { - if (WriteReady) { - retval=FinishConnect(NetBuf->fd); - ConnectDone=TRUE; - NetBuf->WaitConnect=FALSE; - - if (retval) { - *WriteOK=FALSE; - ConnectError(retval); - } - } - } else { - if (WriteReady) *WriteOK=WriteDataToWire(NetBuf); - - if (ReadReady) { - *ReadOK=ReadDataFromWire(NetBuf); - if (NetBuf->ReadBuf.DataPresent>0) DataWaiting=TRUE; - } - } - - if (!(*ErrorOK && *WriteOK && *ReadOK)) { -/* We don't want to check the socket any more */ - NetBufCallBackStop(NetBuf); -/* If there were errors, then the socket is now useless - so close it */ - CloseSocket(NetBuf->fd); - NetBuf->fd=-1; - } else if (ConnectDone) { -/* If we just connected, then no need to listen for write-ready status - any more */ - NetBufCallBack(NetBuf); - } else if (WriteReady && NetBuf->WriteBuf.DataPresent==0) { -/* If we wrote out everything, then tell the owner so that the socket no - longer needs to be checked for write-ready status */ - NetBufCallBack(NetBuf); - } - - return DataWaiting; -} - -gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds, - fd_set *writefds,fd_set *errorfds, - gboolean *DoneOK) { -/* Responds to a select() call by reading/writing data as necessary. */ -/* 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; - 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); - *DoneOK=(WriteOK && ErrorOK && ReadOK); - return DataWaiting; -} - -gboolean NetBufHandleNetwork(NetworkBuffer *NetBuf,gboolean ReadReady, - gboolean WriteReady,gboolean *DoneOK) { - gboolean ReadOK,WriteOK,ErrorOK; - gboolean DataWaiting=FALSE; - - *DoneOK=TRUE; - if (!NetBuf || NetBuf->fd<=0) return DataWaiting; - - DataWaiting=DoNetworkBufferStuff(NetBuf,ReadReady,WriteReady,FALSE, - &ReadOK,&WriteOK,&ErrorOK); - - *DoneOK=(WriteOK && ErrorOK && ReadOK); - return DataWaiting; -} - gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady, gboolean WriteReady,gboolean *DoneOK) { /* Reads and writes player data from/to the network if it is ready. */ t@@ -565,324 +291,31 @@ gchar *GetWaitingPlayerMessage(Player *Play) { return GetWaitingMessage(&Play->NetBuf); } -gint CountWaitingMessages(NetworkBuffer *NetBuf) { -/* Returns the number of complete (terminated) messages waiting in the */ -/* given network buffer. This is the number of times that */ -/* GetWaitingMessage() can be safely called without it returning NULL. */ - ConnBuf *conn; - gint i,msgs=0; - - conn=&NetBuf->ReadBuf; - - if (conn->Data) for (i=0;i<conn->DataPresent;i++) { - if (conn->Data[i]==NetBuf->Terminator) msgs++; - } - return msgs; -} - -gchar *GetWaitingMessage(NetworkBuffer *NetBuf) { -/* Reads a complete (terminated) message from the network buffer. The */ -/* message is removed from the buffer, and returned as a null-terminated */ -/* string (the network terminator is removed). If no complete message is */ -/* waiting, NULL is returned. The string is dynamically allocated, and */ -/* so must be g_free'd by the caller. */ - ConnBuf *conn; - int MessageLen; - char *SepPt; - gchar *NewMessage; - conn=&NetBuf->ReadBuf; - if (!conn->Data || !conn->DataPresent) return NULL; - SepPt=memchr(conn->Data,NetBuf->Terminator,conn->DataPresent); - if (!SepPt) return NULL; - *SepPt='\0'; - MessageLen=SepPt-conn->Data+1; - SepPt--; - if (NetBuf->StripChar && *SepPt==NetBuf->StripChar) *SepPt='\0'; - NewMessage=g_new(gchar,MessageLen); - memcpy(NewMessage,conn->Data,MessageLen); - if (MessageLen<conn->DataPresent) { - memmove(&conn->Data[0],&conn->Data[MessageLen], - conn->DataPresent-MessageLen); - } - conn->DataPresent-=MessageLen; - return NewMessage; -} - gboolean ReadPlayerDataFromWire(Player *Play) { return ReadDataFromWire(&Play->NetBuf); } -gboolean ReadDataFromWire(NetworkBuffer *NetBuf) { -/* Reads any waiting data on the given network buffer's TCP/IP connection */ -/* into the read buffer. Returns FALSE if the connection was closed, or */ -/* if the read buffer's maximum size was reached. */ - ConnBuf *conn; - int CurrentPosition,BytesRead,Error; - conn=&NetBuf->ReadBuf; - CurrentPosition=conn->DataPresent; - while(1) { - if (CurrentPosition>=conn->Length) { - if (conn->Length==MAXREADBUF) { - SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF); - return FALSE; /* drop connection */ - } - if (conn->Length==0) conn->Length=256; else conn->Length*=2; - if (conn->Length>MAXREADBUF) conn->Length=MAXREADBUF; - conn->Data=g_realloc(conn->Data,conn->Length); - } - BytesRead=recv(NetBuf->fd,&conn->Data[CurrentPosition], - conn->Length-CurrentPosition,0); - if (BytesRead==SOCKET_ERROR) { - Error = GetSocketError(); -#ifdef CYGWIN - if (Error==WSAEWOULDBLOCK) break; - else { SetError(&NetBuf->error,ET_WINSOCK,Error); return FALSE; } -#else - if (Error==EAGAIN) break; - else if (Error!=EINTR) { - SetError(&NetBuf->error,ET_ERRNO,Error); - return FALSE; - } -#endif - } else if (BytesRead==0) { - return FALSE; - } else { - CurrentPosition+=BytesRead; - conn->DataPresent=CurrentPosition; - } - } - return TRUE; -} - void QueuePlayerMessageForSend(Player *Play,gchar *data) { QueueMessageForSend(&Play->NetBuf,data); } -void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data) { -/* Writes the null-terminated string "data" to the network buffer, ready */ -/* to be sent to the wire when the network connection becomes free. The */ -/* message is automatically terminated. Fails to write the message without */ -/* error if the buffer reaches its maximum size (although this error will */ -/* be detected when an attempt is made to write the buffer to the wire). */ - int AddLength,NewLength; - ConnBuf *conn; - conn=&NetBuf->WriteBuf; - AddLength=strlen(data)+1; - NewLength=conn->DataPresent+AddLength; - if (NewLength > conn->Length) { - conn->Length*=2; - conn->Length=MAX(conn->Length,NewLength); - if (conn->Length > MAXWRITEBUF) conn->Length=MAXWRITEBUF; - if (NewLength > conn->Length) return; - conn->Data=g_realloc(conn->Data,conn->Length); - } - memcpy(&conn->Data[conn->DataPresent],data,AddLength); - conn->DataPresent=NewLength; - conn->Data[NewLength-1]=NetBuf->Terminator; - -/* If the buffer was empty before, we may need to tell the owner to check - the socket for write-ready status */ - if (NewLength==AddLength) NetBufCallBack(NetBuf); -} - gboolean WritePlayerDataToWire(Player *Play) { return WriteDataToWire(&Play->NetBuf); } -gboolean WriteDataToWire(NetworkBuffer *NetBuf) { -/* Writes any waiting data in the network buffer to the wire. Returns */ -/* TRUE on success, or FALSE if the buffer's maximum length is */ -/* reached, or the remote end has closed the connection. */ - ConnBuf *conn; - int CurrentPosition,BytesSent,Error; - conn=&NetBuf->WriteBuf; - if (!conn->Data || !conn->DataPresent) return TRUE; - if (conn->Length==MAXWRITEBUF) { - SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF); - return FALSE; - } - CurrentPosition=0; - while (CurrentPosition<conn->DataPresent) { - BytesSent=send(NetBuf->fd,&conn->Data[CurrentPosition], - conn->DataPresent-CurrentPosition,0); - if (BytesSent==SOCKET_ERROR) { - Error=GetSocketError(); -#ifdef CYGWIN - if (Error==WSAEWOULDBLOCK) break; - else { SetError(&NetBuf->error,ET_WINSOCK,Error); return FALSE; } -#else - if (Error==EAGAIN) break; - else if (Error!=EINTR) { - SetError(&NetBuf->error,ET_ERRNO,Error); - return FALSE; - } -#endif - } else { - CurrentPosition+=BytesSent; - } - } - if (CurrentPosition>0 && CurrentPosition<conn->DataPresent) { - memmove(&conn->Data[0],&conn->Data[CurrentPosition], - conn->DataPresent-CurrentPosition); - } - conn->DataPresent-=CurrentPosition; - return TRUE; -} - -static void SendHttpRequest(HttpConnection *conn) { - GString *text; - - conn->Tries++; - conn->StatusCode=0; - conn->Status=HS_CONNECTING; - - text=g_string_new(""); - - if (conn->Redirect) { - g_string_sprintf(text,"%s %s HTTP/1.0",conn->Method,conn->Redirect); - g_free(conn->Redirect); conn->Redirect=NULL; - } else { - g_string_sprintf(text,"%s http://%s:%u%s HTTP/1.0", - conn->Method,conn->HostName,conn->Port,conn->Query); - } - QueueMessageForSend(&conn->NetBuf,text->str); - - if (conn->Headers) QueueMessageForSend(&conn->NetBuf,conn->Headers); - - g_string_sprintf(text,"User-Agent: dopewars/%s",VERSION); - QueueMessageForSend(&conn->NetBuf,text->str); - -/* Insert a blank line between headers and body */ - QueueMessageForSend(&conn->NetBuf,""); - - if (conn->Body) QueueMessageForSend(&conn->NetBuf,conn->Body); - - g_string_free(text,TRUE); -} - -static gboolean StartHttpConnect(HttpConnection *conn) { - gchar *ConnectHost; - unsigned ConnectPort; - - if (conn->Proxy) { - ConnectHost=conn->Proxy; ConnectPort=conn->ProxyPort; - } else { - ConnectHost=conn->HostName; ConnectPort=conn->Port; - } - - if (!StartNetworkBufferConnect(&conn->NetBuf,ConnectHost,ConnectPort)) { - CloseHttpConnection(conn); - return FALSE; - } - return TRUE; -} - -HttpConnection *OpenHttpConnection(gchar *HostName,unsigned Port, - gchar *Proxy,unsigned ProxyPort, - gchar *Method,gchar *Query, - gchar *Headers,gchar *Body) { - HttpConnection *conn; - g_assert(HostName && Method && Query); - - conn=g_new0(HttpConnection,1); - InitNetworkBuffer(&conn->NetBuf,'\n','\r'); - conn->HostName=g_strdup(HostName); - if (Proxy && Proxy[0]) conn->Proxy=g_strdup(Proxy); - conn->Method=g_strdup(Method); - conn->Query=g_strdup(Query); - if (Headers && Headers[0]) conn->Headers=g_strdup(Headers); - if (Body && Body[0]) conn->Body=g_strdup(Body); - conn->Port = Port; - conn->ProxyPort = ProxyPort; - - if (!StartHttpConnect(conn)) return NULL; - SendHttpRequest(conn); - - return conn; -} - -HttpConnection *OpenMetaHttpConnection() { +gboolean OpenMetaHttpConnection(HttpConnection **conn) { gchar *query; - HttpConnection *retval; + gboolean retval; query = g_strdup_printf("%s?output=text&getlist=%d", MetaServer.Path,METAVERSION); - retval = OpenHttpConnection(MetaServer.Name,MetaServer.Port, + retval = OpenHttpConnection(conn,MetaServer.Name,MetaServer.Port, MetaServer.ProxyName,MetaServer.ProxyPort, "GET",query,NULL,NULL); - if (retval) g_print("HTTP connection successfully established\n"); g_free(query); return retval; } -void CloseHttpConnection(HttpConnection *conn) { - ShutdownNetworkBuffer(&conn->NetBuf); - g_free(conn->HostName); - g_free(conn->Proxy); - g_free(conn->Method); - g_free(conn->Query); - g_free(conn->Headers); - g_free(conn->Body); - g_free(conn->Redirect); - g_free(conn); -} - -gchar *ReadHttpResponse(HttpConnection *conn) { - gchar *msg,**split; - - msg=GetWaitingMessage(&conn->NetBuf); - if (msg) switch(conn->Status) { - case HS_CONNECTING: /* OK, we should have the HTTP status line */ - conn->Status=HS_READHEADERS; - split=g_strsplit(msg," ",2); - if (split[0] && split[1]) { - conn->StatusCode=atoi(split[1]); - g_print("HTTP status code %d returned\n",conn->StatusCode); - } else g_warning("Invalid HTTP status line %s",msg); - g_strfreev(split); - break; - case HS_READHEADERS: - if (msg[0]==0) conn->Status=HS_READSEPARATOR; - else { - split=g_strsplit(msg," ",1); - if (split[0] && split[1]) { - if (conn->StatusCode==302 && strcmp(split[0],"Location:")==0) { - g_print("Redirect to %s\n",split[1]); - g_free(conn->Redirect); - conn->Redirect = g_strdup(split[1]); - } -/* g_print("Header %s (value %s) read\n",split[0],split[1]);*/ - } - g_strfreev(split); - } - break; - case HS_READSEPARATOR: - conn->Status=HS_READBODY; - break; - case HS_READBODY: /* At present, we do nothing special with the body */ - break; - } - return msg; -} - -gboolean HandleHttpCompletion(HttpConnection *conn) { - NBCallBack CallBack; - gpointer CallBackData; - if (conn->Redirect) { - g_print("Following redirect\n"); - CallBack=conn->NetBuf.CallBack; - CallBackData=conn->NetBuf.CallBackData; - ShutdownNetworkBuffer(&conn->NetBuf); - if (StartHttpConnect(conn)) { - SendHttpRequest(conn); - SetNetworkBufferCallBack(&conn->NetBuf,CallBack,CallBackData); - return FALSE; - } - } - CloseHttpConnection(conn); - return TRUE; -} - gboolean HandleWaitingMetaServerData(HttpConnection *conn,GSList **listpt) { gchar *msg; ServerData *NewServer; t@@ -1250,87 +683,23 @@ price_t GetNextPrice(gchar **Data,price_t Default) { } #if NETWORKING -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"); - - if ((he=gethostbyname(RemoteHost))==NULL) { - return NoHost; - } - *fd=socket(AF_INET,SOCK_STREAM,0); - if (*fd==SOCKET_ERROR) { - return strerror(errno); - } - - ClientAddr.sin_family=AF_INET; - 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(*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(*fd); *fd=-1; - return strerror(errno); - } else { - fcntl(*fd,F_SETFL,O_NONBLOCK); - } - return NULL; -} - -char *FinishConnect(int fd) { - int Error; -#ifdef CYGWIN - Error = GetSocketError(); - if (Error==0) return NULL; - else return strerror(Error); -#else -#ifdef HAVE_SOCKLEN_T - socklen_t optlen; -#else - int optlen; -#endif - - optlen=sizeof(Error); - if (getsockopt(fd,SOL_SOCKET,SO_ERROR,&Error,&optlen)==-1) { - Error = errno; - } - if (Error==0) return NULL; - else return strerror(Error); -#endif /* CYGWIN */ -} - -char *SetupNetwork(gboolean NonBlocking) { +gboolean SetupNetwork(GString *errstr) { /* 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; +/* file descriptor for the newly-opened socket. TRUE is returned. If the */ +/* connection fails, FALSE is returned, and errstr (if non-NULL) is filled */ +/* with a descriptive error message. */ + LastError err; Network=Client=Server=FALSE; - retval=StartConnect(&ClientSock,ServerName,Port,NonBlocking); - if (!retval && !NonBlocking) Client=Network=TRUE; - return retval; -} - -char *FinishSetupNetwork() { - gchar *retval; - retval=FinishConnect(ClientSock); - if (!retval) Client=Network=TRUE; - return retval; + if (StartConnect(&ClientSock,ServerName,Port,FALSE,&err)) { + Client=Network=TRUE; + return TRUE; + } else { + if (errstr) g_string_assign_error(errstr,&err); + return FALSE; + } } - #endif /* NETWORKING */ void SwitchToSinglePlayer(Player *Play) { t@@ -1340,16 +709,7 @@ void SwitchToSinglePlayer(Player *Play) { /* that the game can be continued in single player mode */ Player *NewPlayer; if (!Network || !Client || !FirstClient) return; - if (Play!=FirstClient->data) { - g_error("Oops! FirstClient should be player!"); - } - while (g_slist_next(FirstClient)) { - FirstClient=RemovePlayer((Player *)g_slist_next(FirstClient)->data, - FirstClient); - } -#ifdef NETWORKING - ShutdownNetworkBuffer(&Play->NetBuf); -#endif + ShutdownNetwork(Play); CleanUpServer(); Network=Server=Client=FALSE; InitAbilities(Play); t@@ -1361,12 +721,20 @@ void SwitchToSinglePlayer(Player *Play) { SendEvent(NewPlayer); } -void ShutdownNetwork() { +void ShutdownNetwork(Player *Play) { /* Closes down the client side of the network connection. Clears the list */ -/* of client players, and closes the network socket. */ - while (FirstClient) { - FirstClient=RemovePlayer((Player *)FirstClient->data,FirstClient); +/* of client players (with the exception of "you", the player "Play"), */ +/* and closes the network socket. */ + if (Play!=FirstClient->data) { + g_error("Oops! FirstClient should be player!"); } + while (g_slist_next(FirstClient)) { + FirstClient=RemovePlayer((Player *)g_slist_next(FirstClient)->data, + FirstClient); + } +#ifdef NETWORKING + ShutdownNetworkBuffer(&Play->NetBuf); +#endif Client=Network=Server=FALSE; } (DIR) diff --git a/src/message.h b/src/message.h t@@ -27,7 +27,9 @@ #endif #include <glib.h> +#include "error.h" #include "dopewars.h" +#include "network.h" typedef enum { C_PRINTMESSAGE = 'A', t@@ -49,10 +51,6 @@ typedef enum { C_MEETPLAYER, C_FIGHT, C_FIGHTDONE } AICode; -typedef enum { - E_FULLBUF -} CustomError; - #define DT_LOCATION 'A' #define DT_DRUG 'B' #define DT_GUN 'C' t@@ -76,47 +74,6 @@ void SendPrintMessage(Player *From,AICode AI,Player *To,char *Data); void SendQuestion(Player *From,AICode AI,Player *To,char *Data); #if NETWORKING -/* Keeps track of the progress of an HTTP connection */ -typedef enum { - HS_CONNECTING, HS_READHEADERS, HS_READSEPARATOR, HS_READBODY -} HttpStatus; - -/* A structure used to keep track of an HTTP connection */ -typedef struct _HttpConnection { - gchar *HostName; /* The machine on which the desired page resides */ - unsigned Port; /* The port */ - gchar *Proxy; /* If non-NULL, a web proxy to use */ - unsigned ProxyPort; /* The port to use for talking to the proxy */ - gchar *Method; /* e.g. GET, POST */ - gchar *Query; /* e.g. the path of the desired webpage */ - gchar *Headers; /* if non-NULL, e.g. Content-Type */ - gchar *Body; /* if non-NULL, data to send */ - gchar *Redirect; /* if non-NULL, a URL to redirect to */ - NetworkBuffer NetBuf; /* The actual network connection itself */ - gint Tries; /* Number of requests actually sent so far */ - gint StatusCode; /* 0=no status yet, otherwise an HTTP status code */ - HttpStatus Status; -} HttpConnection; - -char *StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort, - gboolean NonBlocking); -char *FinishConnect(int fd); - -void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator,char StripChar); -void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack, - gpointer CallBackData); -gboolean IsNetworkBufferActive(NetworkBuffer *NetBuf); -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); -gboolean RespondToSelect(NetworkBuffer *NetBuf,fd_set *readfds, - fd_set *writefds,fd_set *errorfds, - gboolean *DoneOK); -gboolean NetBufHandleNetwork(NetworkBuffer *NetBuf,gboolean ReadReady, - gboolean WriteReady,gboolean *DoneOK); gboolean PlayerHandleNetwork(Player *Play,gboolean ReadReady, gboolean WriteReady,gboolean *DoneOK); gboolean ReadPlayerDataFromWire(Player *Play); t@@ -124,28 +81,11 @@ void QueuePlayerMessageForSend(Player *Play,gchar *data); gboolean WritePlayerDataToWire(Player *Play); gchar *GetWaitingPlayerMessage(Player *Play); -gboolean ReadDataFromWire(NetworkBuffer *NetBuf); -gboolean WriteDataToWire(NetworkBuffer *NetBuf); -void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data); -gint CountWaitingMessages(NetworkBuffer *NetBuf); -gchar *GetWaitingMessage(NetworkBuffer *NetBuf); - -HttpConnection *OpenHttpConnection(gchar *HostName,unsigned Port, - gchar *Proxy,unsigned ProxyPort, - gchar *Method,gchar *Query, - gchar *Headers,gchar *Body); -HttpConnection *OpenMetaHttpConnection(void); -void CloseHttpConnection(HttpConnection *conn); -gchar *ReadHttpResponse(HttpConnection *conn); -gboolean HandleHttpCompletion(HttpConnection *conn); +gboolean OpenMetaHttpConnection(HttpConnection **conn); gboolean HandleWaitingMetaServerData(HttpConnection *conn,GSList **listpt); void ClearServerList(GSList **listpt); #endif /* NETWORKING */ -void ClearError(LastError *error); -void SetError(LastError *error,ErrorType type,gint code); -gchar *GetErrorString(LastError *error); - extern GSList *FirstClient; extern void (*ClientMessageHandlerPt) (char *,Player *); t@@ -168,9 +108,8 @@ gchar *GetNextWord(gchar **Data,gchar *Default); void AssignNextWord(gchar **Data,gchar **Dest); int GetNextInt(gchar **Data,int Default); price_t GetNextPrice(gchar **Data,price_t Default); -char *SetupNetwork(gboolean NonBlocking); -char *FinishSetupNetwork(void); -void ShutdownNetwork(void); +gboolean SetupNetwork(GString *errstr); +void ShutdownNetwork(Player *Play); void SwitchToSinglePlayer(Player *Play); int ProcessMessage(char *Msg,Player *Play,Player **Other,AICode *AI, MsgCode *Code,char **Data,GSList *First); t@@ -199,4 +138,5 @@ void SendFightMessage(Player *Attacker,Player *Defender, void FormatFightMessage(Player *To,GString *text,Player *Attacker, Player *Defender,int BitchesKilled,int ArmPercent, FightPoint fp,price_t Loot); -#endif + +#endif /* __MESSAGE_H__ */ (DIR) diff --git a/src/serverside.c b/src/serverside.c t@@ -25,8 +25,18 @@ #include <stdio.h> #include <string.h> -#include <sys/types.h> +#include <sys/types.h> /* For size_t etc. */ #include <sys/stat.h> + +#ifdef CYGWIN +#include <windows.h> /* For datatypes such as BOOL */ +#include <winsock.h> /* For network functions */ +#else +#include <sys/socket.h> /* For struct sockaddr etc. */ +#include <netinet/in.h> /* For struct sockaddr_in etc. */ +#include <arpa/inet.h> /* For socklen_t */ +#endif /* CYGWIN */ + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif t@@ -37,25 +47,15 @@ #include "dopeos.h" #include "dopewars.h" #include "message.h" +#include "network.h" #include "nls.h" #include "serverside.h" #include "tstring.h" -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif - #ifdef GUI_SERVER #include "gtkport.h" #endif -#ifndef SD_SEND -#define SD_SEND 1 -#endif -#ifndef SD_RECV -#define SD_RECV 0 -#endif - static const price_t MINTRENCHPRICE=200,MAXTRENCHPRICE=300; #define ESCAPE 0 t@@ -138,6 +138,17 @@ static void MetaSocketStatus(NetworkBuffer *NetBuf, gboolean Read,gboolean Write); #endif +static gboolean MetaConnectError(HttpConnection *conn) { + GString *errstr; + if (!IsHttpError(conn)) return FALSE; + errstr=g_string_new(""); + g_string_assign_error(errstr,&MetaConn->NetBuf.error); + dopelog(1,_("Failed to connect to metaserver at %s:%u (%s)"), + MetaServer.Name,MetaServer.Port,errstr->str); + g_string_free(errstr,TRUE); + return TRUE; +} + void RegisterWithMetaServer(gboolean Up,gboolean SendData, gboolean RespectTimeout) { /* Sends server details to the metaserver, if specified. If "Up" is */ t@@ -151,6 +162,7 @@ void RegisterWithMetaServer(gboolean Up,gboolean SendData, struct HISCORE MultiScore[NUMHISCORE],AntiqueScore[NUMHISCORE]; GString *headers,*body; gchar *prstr; + gboolean retval; int i; if (!MetaServer.Active || !NotifyMetaServer || WantQuit) return; t@@ -205,16 +217,20 @@ void RegisterWithMetaServer(gboolean Up,gboolean SendData, "Content-Type: application/x-www-form-urlencoded\n" "Content-Length: %d",(int)strlen(body->str)); - MetaConn=OpenHttpConnection(MetaServer.Name,MetaServer.Port, - MetaServer.ProxyName,MetaServer.ProxyPort, - "POST",MetaServer.Path,headers->str,body->str); + retval=OpenHttpConnection(&MetaConn,MetaServer.Name,MetaServer.Port, + MetaServer.ProxyName,MetaServer.ProxyPort, + "POST",MetaServer.Path,headers->str,body->str); g_string_free(headers,TRUE); g_string_free(body,TRUE); - if (MetaConn) { + if (retval) { dopelog(2,_("Waiting for metaserver connect to %s:%u..."), MetaServer.Name,MetaServer.Port); - } else return; + } else { + MetaConnectError(MetaConn); + CloseHttpConnection(MetaConn); MetaConn=NULL; + return; + } #ifdef GUI_SERVER SetNetworkBufferCallBack(&MetaConn->NetBuf,MetaSocketStatus,NULL); #endif t@@ -277,14 +293,13 @@ void HandleServerMessage(gchar *buf,Player *Play) { } SendServerMessage(Play,AI,Code,To,Data); break; - case C_NETMESSAGE: - dopelog(1,"Net:%s\n",Data); -/* shutdown(Play->fd,SD_RECV);*/ +/* case C_NETMESSAGE: + dopelog(1,"Net:%s\n",Data);*/ /* Make sure they do actually disconnect, eventually! */ - if (ConnectTimeout) { +/* if (ConnectTimeout) { Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout; } - break; + break;*/ case C_ABILITIES: ReceiveAbilities(Play,Data); break; t@@ -339,7 +354,6 @@ void HandleServerMessage(gchar *buf,Player *Play) { } SendServerMessage(NULL,C_NONE,C_PRINTMESSAGE,Play,text); g_free(text); -/* shutdown(Play->fd,SD_RECV);*/ /* Make sure they do actually disconnect, eventually! */ if (ConnectTimeout) { Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout; t@@ -657,10 +671,12 @@ void StartServer() { ClientMessageHandlerPt=NULL; ListenSock=socket(AF_INET,SOCK_STREAM,0); if (ListenSock==SOCKET_ERROR) { +/* FIXME +MessageBox(NULL,"Cannot create socket",NULL,MB_OK); */ perror("create socket"); exit(1); } SetReuse(ListenSock); - fcntl(ListenSock,F_SETFL,O_NONBLOCK); + SetBlocking(ListenSock,FALSE); ServerAddr.sin_family=AF_INET; ServerAddr.sin_port=htons(Port); t@@ -783,7 +799,7 @@ Player *HandleNewConnection(void) { &cadsize))==-1) { perror("accept socket"); bgetch(); exit(1); } - fcntl(ClientSock,F_SETFL,O_NONBLOCK); + SetBlocking(ClientSock,FALSE); dopelog(2,_("got connection from %s"),inet_ntoa(ClientAddr.sin_addr)); tmp=g_new(Player,1); FirstServer=AddPlayer(ClientSock,tmp,FirstServer); t@@ -899,8 +915,10 @@ void ServerLoop() { } } if (!DoneOK && HandleHttpCompletion(MetaConn)) { - dopelog(4,"MetaServer: (closed)\n"); - MetaConn=NULL; + if (!MetaConnectError(MetaConn)) { + dopelog(4,"MetaServer: (closed)\n"); + } + CloseHttpConnection(MetaConn); MetaConn=NULL; if (IsServerShutdown()) break; } } t@@ -1016,8 +1034,10 @@ void GuiHandleMeta(gpointer data,gint socket,GdkInputCondition condition) { } } if (!DoneOK && HandleHttpCompletion(MetaConn)) { - dopelog(4,"MetaServer: (closed)\n"); - MetaConn=NULL; + if (!MetaConnectError(MetaConn)) { + dopelog(4,"MetaServer: (closed)\n"); + } + CloseHttpConnection(MetaConn); MetaConn=NULL; if (IsServerShutdown()) GuiQuitServer(); } } t@@ -1136,7 +1156,6 @@ void FinishGame(Player *Play,char *Message) { ClientLeftServer(Play); Play->EventNum=E_FINISH; SendHighScores(Play,TRUE,Message); -/* shutdown(Play->fd,SD_RECV);*/ /* Make sure they do actually disconnect, eventually! */ if (ConnectTimeout) { Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout; t@@ -2657,7 +2676,6 @@ GSList *HandleTimeouts(GSList *First) { dopelog(1,_("Player removed due to idle timeout")); SendPrintMessage(NULL,C_NONE,Play,"Disconnected due to idle timeout"); ClientLeftServer(Play); -/* shutdown(Play->fd,SD_RECV);*/ /* Make sure they do actually disconnect, eventually! */ if (ConnectTimeout) { Play->ConnectTimeout=time(NULL)+(time_t)ConnectTimeout; (DIR) diff --git a/src/winmain.c b/src/winmain.c t@@ -33,7 +33,6 @@ #include "dopewars.h" #include "nls.h" #include "tstring.h" -#include "tstring.h" #include "AIPlayer.h" #include "curses_client.h" #include "gtk_client.h"