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"