tLow-level error and network handling abstracted out - vaccinewars - be a docto… | |
git clone git://src.adamsgaard.dk/vaccinewars | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 75487908600e5379fe2f8412948355e8df683006 | |
parent b561f151374a4e7b19c84e2eb4ec514bffe352fa | |
Author: Ben Webb <[email protected]> | |
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(-) | |
--- | |
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)); | |
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@ | |
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 … | |
+dopewars_SOURCES = AIPlayer.c curses_client.c dopeos.c dopewars.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) $(TEXINFO… | |
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) | |
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(); | |
} | |
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… | |
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; | |
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 | |
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; | |
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,gboo… | |
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 ReturnOnF… | |
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 ReturnOnFa… | |
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 … | |
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 StartGam… | |
} | |
#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 Sta… | |
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 … | |
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); | |
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 wPara… | |
} | |
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 hPrevInstanc… | |
hInst=hInstance; | |
hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT); | |
WindowList=NULL; | |
- AsyncSocketError=0; | |
if (!hPrevInstance) { | |
wc.style = CS_HREDRAW|CS_VREDRAW; | |
wc.lpfnWndProc = MainWndProc; | |
diff --git a/src/gtkport.h b/src/gtkport.h | |
t@@ -700,8 +700,6 @@ void gtk_progress_bar_update(GtkProgressBar *pbar,gfloat p… | |
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 */ | |
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; | |
} | |
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,cha… | |
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__ */ | |
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 SendDat… | |
"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,GdkInputCo… | |
} | |
} | |
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; | |
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" |