tImproved metaserver error reporting - 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 0bc279db8ad5c1ec9856ea8135ee3959249ffb5a
 (DIR) parent a09e6292bf62e8174a499e147c5d9f276ed2b466
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Fri, 12 Oct 2001 19:35:27 +0000
       
       Improved metaserver error reporting
       
       
       Diffstat:
         M src/curses_client.c                 |       4 ++--
         M src/error.c                         |      36 +++++++++++++++++++++----------
         M src/error.h                         |       8 +++++---
         M src/gtk_client.c                    |      11 +++++------
         M src/message.c                       |      34 +++++++++++++++++++++++++------
         M src/network.c                       |     121 ++++++++++++++-----------------
         M src/network.h                       |      10 +++++-----
         M src/serverside.c                    |      36 +++++++++++++++++++------------
       
       8 files changed, 145 insertions(+), 115 deletions(-)
       ---
 (DIR) diff --git a/src/curses_client.c b/src/curses_client.c
       t@@ -237,7 +237,7 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
           refresh();
        
           if (!OpenMetaHttpConnection(&MetaConn)) {
       -      g_string_assign_error(errstr,&MetaConn->NetBuf.error);
       +      g_string_assign_error(errstr,MetaConn->NetBuf.error);
              CloseHttpConnection(MetaConn);
              return FALSE;
           }
       t@@ -265,7 +265,7 @@ static gboolean SelectServerFromMetaServer(Player *Play,GString *errstr) {
              }
              if (!DoneOK && HandleHttpCompletion(MetaConn)) {
                 if (IsHttpError(MetaConn)) {
       -            g_string_assign_error(errstr,&MetaConn->NetBuf.error);
       +            g_string_assign_error(errstr,MetaConn->NetBuf.error);
                    CloseHttpConnection(MetaConn);
                    return FALSE;
                 }
 (DIR) diff --git a/src/error.c b/src/error.c
       t@@ -35,17 +35,31 @@
        #include "error.h"
        #include "nls.h"
        
       -void ClearError(LastError *error) {
       -  error->type=NULL;
       +void FreeError(LastError *error) {
       +  if (!error) return;
       +  if (error->type && error->type->FreeErrorData) {
       +    (*error->type->FreeErrorData)(error);
       +  } else {
       +    g_free(error->data);
       +  }
       +  g_free(error);
        }
        
       -gboolean IsError(LastError *error) {
       -  return (error->type!=NULL);
       -}
       +LastError *NewError(ErrorType *type,gint code,gpointer data) {
       +  LastError *error;
        
       -void SetError(LastError *error,ErrorType *type,gint code) {
       +  error = g_new0(LastError,1);
          error->type=type;
          error->code=code;
       +  error->data=data;
       +
       +  return error;
       +}
       +
       +void SetError(LastError **error,ErrorType *type,gint code,gpointer data) {
       +  if (!error) return;
       +  if (*error) FreeError(*error);
       +  *error = NewError(type,code,data);
        }
        
        void LookupErrorCode(GString *str,gint code,ErrTable *table,
       t@@ -69,7 +83,7 @@ void CustomAppendError(GString *str,LastError *error) {
          LookupErrorCode(str,error->code,CustomErrStr,_("Internal error code %d"));
        }
        
       -static ErrorType ETCustom = { CustomAppendError };
       +static ErrorType ETCustom = { CustomAppendError,NULL };
        ErrorType *ET_CUSTOM = &ETCustom;
        
        /* "errno" error handling */
       t@@ -77,7 +91,7 @@ void ErrnoAppendError(GString *str,LastError *error) {
          g_string_append(str,strerror(error->code));
        }
        
       -static ErrorType ETErrno = { ErrnoAppendError };
       +static ErrorType ETErrno = { ErrnoAppendError,NULL };
        ErrorType *ET_ERRNO = &ETErrno;
        
        #ifdef CYGWIN
       t@@ -110,7 +124,7 @@ void WinsockAppendError(GString *str,LastError *error) {
          LookupErrorCode(str,error->code,WSAErrStr,_("Network error code %d"));
        }
        
       -static ErrorType ETWinsock = { WinsockAppendError };
       +static ErrorType ETWinsock = { WinsockAppendError,NULL };
        ErrorType *ET_WINSOCK = &ETWinsock;
        
        /* Standard Win32 "GetLastError" handling */
       t@@ -124,7 +138,7 @@ void Win32AppendError(GString *str,LastError *error) {
          LocalFree(lpMsgBuf);
        }
        
       -static ErrorType ETWin32 = { Win32AppendError };
       +static ErrorType ETWin32 = { Win32AppendError,NULL };
        ErrorType *ET_WIN32 = &ETWin32;
        
        #else
       t@@ -141,7 +155,7 @@ void HErrnoAppendError(GString *str,LastError *error) {
          LookupErrorCode(str,error->code,DNSErrStr,_("Name server error code %d"));
        }
        
       -static ErrorType ETHErrno = { HErrnoAppendError };
       +static ErrorType ETHErrno = { HErrnoAppendError,NULL };
        ErrorType *ET_HERRNO = &ETHErrno;
        
        #endif /* CYGWIN */
 (DIR) diff --git a/src/error.h b/src/error.h
       t@@ -31,11 +31,13 @@
        struct _LastError;
        typedef struct _ErrorType {
           void (*AppendErrorString)(GString *str,struct _LastError *error);
       +   void (*FreeErrorData)(struct _LastError *error);
        } ErrorType;
        
        typedef struct _LastError {
          gint code;
          ErrorType *type;
       +  gpointer data;
        } LastError;
        
        extern ErrorType *ET_CUSTOM,*ET_ERRNO;
       t@@ -54,9 +56,9 @@ typedef struct _ErrTable {
          gchar *string;
        } ErrTable;
        
       -void ClearError(LastError *error);
       -gboolean IsError(LastError *error);
       -void SetError(LastError *error,ErrorType *type,gint code);
       +void FreeError(LastError *error);
       +LastError *NewError(ErrorType *type,gint code,gpointer data);
       +void SetError(LastError **error,ErrorType *type,gint code,gpointer data);
        void LookupErrorCode(GString *str,gint code,ErrTable *table,
                             gchar *fallbackstr);
        void g_string_assign_error(GString *str,LastError *error);
 (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c
       t@@ -1945,10 +1945,10 @@ static void ConnectError(struct StartGameStruct *widgets,gboolean meta) {
           gchar *text;
           LastError *error;
        
       -   if (meta) error=&widgets->MetaConn->NetBuf.error;
       -   else error=&ClientData.Play->NetBuf.error;
       +   if (meta) error=widgets->MetaConn->NetBuf.error;
       +   else error=ClientData.Play->NetBuf.error;
        
       -   if (!IsError(error)) return;
       +   if (!error) return;
        
           neterr = g_string_new("");
           g_string_assign_error(neterr,error);
       t@@ -2108,9 +2108,9 @@ static void HandleMetaSock(gpointer data,gint socket,
           NBStatus oldstatus;
           NBSocksStatus oldsocks;
        
       -g_print("HandleMetaSock: read %d, write %d\n",
       +/*g_print("HandleMetaSock: read %d, write %d\n",
                condition&GDK_INPUT_READ,
       -        condition&GDK_INPUT_WRITE);
       +        condition&GDK_INPUT_WRITE);*/
           widgets=(struct StartGameStruct *)data;
           if (!widgets->MetaConn) return;
        
       t@@ -3201,7 +3201,6 @@ static void DestroyAuthDialog(GtkWidget *window,gpointer data) {
           oldsocks = widgets->MetaConn->NetBuf.sockstat;
        
           if (!SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),username,password)) {
       -      g_print("FIXME: Connect error on setauth\n");
              MetaDone(widgets);
           } else {
              DisplayConnectStatus(widgets,TRUE,oldstatus,oldsocks);
 (DIR) diff --git a/src/message.c b/src/message.c
       t@@ -303,6 +303,29 @@ gboolean WritePlayerDataToWire(Player *Play) {
           return WriteDataToWire(&Play->NetBuf);
        }
        
       +typedef enum {
       +  MEC_INTERNAL,
       +  MEC_BADREPLY
       +} MetaErrorCode;
       +
       +static void MetaAppendError(GString *str,LastError *error) {
       +  switch (error->code) {
       +    case MEC_INTERNAL:
       +      g_string_sprintfa(str,_("Internal metaserver error \"%s\""),
       +                        (gchar *)error->data);
       +      break;
       +    case MEC_BADREPLY:
       +      g_string_sprintfa(str,_("Bad metaserver reply \"%s\""),
       +                        (gchar *)error->data);
       +      break;
       +    default:
       +      g_string_sprintfa(str,_("Unknown metaserver error code %d"),error->code);
       +      break;
       +  }
       +}
       +
       +static ErrorType ETMeta = { MetaAppendError, NULL };
       +
        gboolean OpenMetaHttpConnection(HttpConnection **conn) {
           gchar *query;
           gboolean retval;
       t@@ -330,7 +353,6 @@ gboolean HandleWaitingMetaServerData(HttpConnection *conn,GSList **listpt,
        
              NewServer=g_new0(ServerData,1);
              NewServer->Name=ReadHttpResponse(conn);
       -      g_print("Server name %s read from metaserver\n",NewServer->Name);
              msg=ReadHttpResponse(conn);
              NewServer->Port=atoi(msg); g_free(msg);
              NewServer->Version=ReadHttpResponse(conn);
       t@@ -349,12 +371,11 @@ gboolean HandleWaitingMetaServerData(HttpConnection *conn,GSList **listpt,
              msg=ReadHttpResponse(conn);
              if (!msg) return FALSE;
              if (strlen(msg)>=14 && strncmp(msg,"FATAL ERROR:",12)==0) {
       -         g_warning("Metaserver error: %s",&msg[13]);
       -         g_free(msg);
       +         SetError(&conn->NetBuf.error,&ETMeta,MEC_INTERNAL,g_strdup(&msg[13]));
                 *doneOK=FALSE;
                 return FALSE;
              } else if (strncmp(msg,"MetaServer:",11)!=0) {
       -         g_warning("Bad reply from metaserver: %s",msg);
       +         SetError(&conn->NetBuf.error,&ETMeta,MEC_BADREPLY,g_strdup(msg));
                 g_free(msg);
                 *doneOK=FALSE;
                 return FALSE;
       t@@ -700,14 +721,15 @@ gboolean SetupNetwork(GString *errstr) {
        /* 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;
       +   LastError *err;
        
           Network=Client=Server=FALSE;
           if (StartConnect(&ClientSock,ServerName,Port,FALSE,&err)) {
             Client=Network=TRUE;
             return TRUE;
           } else {
       -     if (errstr) g_string_assign_error(errstr,&err);
       +     if (errstr) g_string_assign_error(errstr,err);
       +     FreeError(err);
             return FALSE;
           }
        }
 (DIR) diff --git a/src/network.c b/src/network.c
       t@@ -115,18 +115,10 @@ void SetBlocking(int sock,gboolean blocking) {
        
        #endif /* CYGWIN */
        
       -static gboolean FinishConnect(int fd,LastError *error);
       +static gboolean FinishConnect(int fd,LastError **error);
        
        static void NetBufCallBack(NetworkBuffer *NetBuf) {
           if (NetBuf && NetBuf->CallBack) {
       -g_print("status = %d, read = %d, write = %d\n",
       -NetBuf->status,
       -NetBuf->status!=NBS_PRECONNECT,
       -                          (NetBuf->status==NBS_CONNECTED &&
       -                           NetBuf->WriteBuf.DataPresent) ||
       -                          (NetBuf->status==NBS_SOCKSCONNECT &&
       -                           NetBuf->negbuf.DataPresent) ||
       -                          NetBuf->WaitConnect);
              (*NetBuf->CallBack)(NetBuf,NetBuf->status!=NBS_PRECONNECT,
                                  (NetBuf->status==NBS_CONNECTED &&
                                   NetBuf->WriteBuf.DataPresent) ||
       t@@ -173,7 +165,7 @@ void InitNetworkBuffer(NetworkBuffer *NetBuf,char Terminator,char StripChar,
           NetBuf->socks = socks;
           NetBuf->host = NULL;
           NetBuf->userpasswd = NULL;
       -   ClearError(&NetBuf->error);
       +   NetBuf->error = NULL;
        }
        
        void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
       t@@ -253,6 +245,8 @@ void ShutdownNetworkBuffer(NetworkBuffer *NetBuf) {
           FreeConnBuf(&NetBuf->WriteBuf);
           FreeConnBuf(&NetBuf->negbuf);
        
       +   FreeError(NetBuf->error); NetBuf->error=NULL;
       +
           g_free(NetBuf->host);
        
           InitNetworkBuffer(NetBuf,NetBuf->Terminator,NetBuf->StripChar,NetBuf->socks);
       t@@ -329,7 +323,7 @@ static void SocksAppendError(GString *str,LastError *error) {
           LookupErrorCode(str,error->code,SocksErrStr,_("SOCKS error code %d"));
        }
        
       -static ErrorType ETSocks = { SocksAppendError };
       +static ErrorType ETSocks = { SocksAppendError,NULL };
        
        typedef enum {
          HEC_TRIESEX   = 1,
       t@@ -379,11 +373,11 @@ static void HTTPAppendError(GString *str,LastError *error) {
          }
        }
        
       -static ErrorType ETHTTP = { HTTPAppendError };
       +static ErrorType ETHTTP = { HTTPAppendError,NULL };
        
        static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
           if (!NetBuf->userpasswd) {
       -      SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS);
       +      SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS,NULL);
              return FALSE;
           } else {
        /* Request a username and password (the callback function should in turn
       t@@ -401,14 +395,14 @@ gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
           ConnBuf *conn;
        
           if (!user || !password) {
       -      SetError(&NetBuf->error,&ETSocks,SEC_USERCANCEL);
       +      SetError(&NetBuf->error,&ETSocks,SEC_USERCANCEL,NULL);
              return FALSE;
           }
           conn=&NetBuf->negbuf;
           addlen = 3 + strlen(user) + strlen(password);
           addpt = ExpandWriteBuffer(conn,addlen);
           if (!addpt || strlen(user)>255 || strlen(password)>255) {
       -      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       +      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
              return FALSE;
           }
           addpt[0] = 1;  /* Subnegotiation version code */
       t@@ -444,7 +438,7 @@ static gboolean Socks5Connect(NetworkBuffer *NetBuf) {
           addlen = hostlen + 7;
           addpt = ExpandWriteBuffer(conn,addlen);
           if (!addpt) {
       -      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       +      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
              return FALSE;
           }
           addpt[0] = 5;       /* SOCKS version 5 */
       t@@ -480,9 +474,9 @@ g_print("Handling SOCKS5 reply\n");
                    retval=FALSE;
                    g_print("FIXME: Reply from SOCKS5 server: %d %d\n",data[0],data[1]);
                    if (data[0]!=5) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_VERSION);
       +               SetError(&NetBuf->error,&ETSocks,SEC_VERSION,NULL);
                    } else if (data[1]!=0 && data[1]!=2) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS);
       +               SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS,NULL);
                    } else {
                       g_print("FIXME: Using SOCKS5 method %d\n",data[1]);
                       if (data[1]==SM_NOAUTH) {
       t@@ -498,9 +492,9 @@ g_print("Handling SOCKS5 reply\n");
                 if (data) {
                    retval=FALSE;
                    if (data[0]!=5) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_VERSION);
       +               SetError(&NetBuf->error,&ETSocks,SEC_VERSION,NULL);
                    } else if (data[1]!=0) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_AUTHFAILED);
       +               SetError(&NetBuf->error,&ETSocks,SEC_AUTHFAILED,NULL);
                    } else {
                       retval=Socks5Connect(NetBuf);
                    }
       t@@ -513,13 +507,13 @@ g_print("FIXME: SOCKS5 connect reply\n");
                    retval=FALSE;
                    addrtype = data[3];
                    if (data[0]!=5) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_VERSION);
       +               SetError(&NetBuf->error,&ETSocks,SEC_VERSION,NULL);
                    } else if (data[1]>8) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_UNKNOWN);
       +               SetError(&NetBuf->error,&ETSocks,SEC_UNKNOWN,NULL);
                    } else if (data[1]!=0) {
       -               SetError(&NetBuf->error,&ETSocks,data[1]);
       +               SetError(&NetBuf->error,&ETSocks,data[1],NULL);
                    } else if (addrtype!=1 && addrtype!=3 && addrtype!=4) {
       -               SetError(&NetBuf->error,&ETSocks,SEC_ADDRTYPE);
       +               SetError(&NetBuf->error,&ETSocks,SEC_ADDRTYPE,NULL);
                    } else {
                       retval=TRUE;
                       replylen = 6;
       t@@ -545,16 +539,16 @@ g_print("FIXME: SOCKS5 connect reply\n");
              if (data) {
                 retval=FALSE;
                 if (data[0]!=0) {
       -            SetError(&NetBuf->error,&ETSocks,SEC_REPLYVERSION);
       +            SetError(&NetBuf->error,&ETSocks,SEC_REPLYVERSION,NULL);
                 } else {
                    if (data[1]==90) {
                       NetBuf->status = NBS_CONNECTED;
                       NetBufCallBack(NetBuf); /* status has changed */
                       retval=TRUE;
                    } else if (data[1]>=SEC_REJECT && data[1]<=SEC_IDMISMATCH) {
       -               SetError(&NetBuf->error,&ETSocks,data[1]);
       +               SetError(&NetBuf->error,&ETSocks,data[1],NULL);
                    } else {
       -               SetError(&NetBuf->error,&ETSocks,SEC_UNKNOWN);
       +               SetError(&NetBuf->error,&ETSocks,SEC_UNKNOWN,NULL);
                    }
                 }
                 g_free(data);
       t@@ -743,7 +737,7 @@ gboolean ReadDataFromWire(NetworkBuffer *NetBuf) {
           while(1) {
              if (CurrentPosition>=conn->Length) {
                 if (conn->Length==MAXREADBUF) {
       -            SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       +            SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
                    return FALSE; /* drop connection */
                 }
                 if (conn->Length==0) conn->Length=256; else conn->Length*=2;
       t@@ -756,11 +750,11 @@ gboolean ReadDataFromWire(NetworkBuffer *NetBuf) {
        #ifdef CYGWIN
                 int Error = WSAGetLastError();
                 if (Error==WSAEWOULDBLOCK) break;
       -         else { SetError(&NetBuf->error,ET_WINSOCK,Error); return FALSE; }
       +         else { SetError(&NetBuf->error,ET_WINSOCK,Error,NULL); return FALSE; }
        #else
                 if (errno==EAGAIN) break;
                 else if (errno!=EINTR) {
       -            SetError(&NetBuf->error,ET_ERRNO,errno);
       +            SetError(&NetBuf->error,ET_ERRNO,errno,NULL);
                    return FALSE;
                 }
        #endif
       t@@ -768,7 +762,6 @@ gboolean ReadDataFromWire(NetworkBuffer *NetBuf) {
                 return FALSE;
              } else {
                 CurrentPosition+=BytesRead;
       -g_print("%d bytes read from wire\n",BytesRead);
                 conn->DataPresent=CurrentPosition;
              }
           }
       t@@ -814,13 +807,13 @@ void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data) {
           if (addpt==conn->Data) NetBufCallBack(NetBuf);
        }
        
       -static struct hostent *LookupHostname(gchar *host,LastError *error) {
       +static struct hostent *LookupHostname(gchar *host,LastError **error) {
           struct hostent *he;
           if ((he=gethostbyname(host))==NULL) {
        #ifdef CYGWIN
       -      if (error) SetError(error,ET_WINSOCK,WSAGetLastError());
       +      if (error) SetError(error,ET_WINSOCK,WSAGetLastError(),NULL);
        #else
       -      if (error) SetError(error,ET_HERRNO,h_errno);
       +      if (error) SetError(error,ET_HERRNO,h_errno,NULL);
        #endif
           }
           return he;
       t@@ -850,7 +843,7 @@ gboolean StartSocksNegotiation(NetworkBuffer *NetBuf,gchar *RemoteHost,
              addlen=2+num_methods;
              addpt = ExpandWriteBuffer(conn,addlen);
              if (!addpt) {
       -         SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       +         SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
                 return FALSE;
              }
              addpt[0] = 5;   /* SOCKS version 5 */
       t@@ -881,12 +874,12 @@ gboolean StartSocksNegotiation(NetworkBuffer *NetBuf,gchar *RemoteHost,
           bufsize=0;
           WNetGetUser(NULL,username,&bufsize);
           if (GetLastError()!=ERROR_MORE_DATA) {
       -     SetError(&NetBuf->error,ET_WIN32,GetLastError());
       +     SetError(&NetBuf->error,ET_WIN32,GetLastError(),NULL);
             return FALSE;
           } else {
             username=g_malloc(bufsize);
             if (WNetGetUser(NULL,username,&bufsize)!=NO_ERROR) {
       -       SetError(&NetBuf->error,ET_WIN32,GetLastError());
       +       SetError(&NetBuf->error,ET_WIN32,GetLastError(),NULL);
               return FALSE;
             }
           }
       t@@ -907,7 +900,7 @@ g_print("username %s\n",pwd->pw_name);
        
           addpt = ExpandWriteBuffer(conn,addlen);
           if (!addpt) {
       -      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       +      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
              return FALSE;
           }
        
       t@@ -936,7 +929,7 @@ static gboolean WriteBufToWire(NetworkBuffer *NetBuf,ConnBuf *conn) {
           int CurrentPosition,BytesSent;
           if (!conn->Data || !conn->DataPresent) return TRUE;
           if (conn->Length==MAXWRITEBUF) {
       -      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF);
       +      SetError(&NetBuf->error,ET_CUSTOM,E_FULLBUF,NULL);
              return FALSE;
           }
           CurrentPosition=0;
       t@@ -947,16 +940,15 @@ static gboolean WriteBufToWire(NetworkBuffer *NetBuf,ConnBuf *conn) {
        #ifdef CYGWIN
                 int Error=WSAGetLastError();
                 if (Error==WSAEWOULDBLOCK) break;
       -         else { SetError(&NetBuf->error,ET_WINSOCK,Error); return FALSE; }
       +         else { SetError(&NetBuf->error,ET_WINSOCK,Error,NULL); return FALSE; }
        #else
                 if (errno==EAGAIN) break;
                 else if (errno!=EINTR) {
       -            SetError(&NetBuf->error,ET_ERRNO,errno);
       +            SetError(&NetBuf->error,ET_ERRNO,errno,NULL);
                    return FALSE;
                 }
        #endif
              } else {
       -g_print("%d bytes written to wire\n",BytesSent);
                 CurrentPosition+=BytesSent;
              }
           }
       t@@ -973,10 +965,8 @@ gboolean WriteDataToWire(NetworkBuffer *NetBuf) {
        /* TRUE on success, or FALSE if the buffer's maximum length is        */
        /* reached, or the remote end has closed the connection.              */
           if (NetBuf->status==NBS_SOCKSCONNECT) {
       -g_print("Writing negbuf\n");
              return WriteBufToWire(NetBuf,&NetBuf->negbuf);
           } else {
       -g_print("Writing WriteBuf\n");
              return WriteBufToWire(NetBuf,&NetBuf->WriteBuf);
           }
        }
       t@@ -1084,10 +1074,6 @@ void CloseHttpConnection(HttpConnection *conn) {
           g_free(conn);
        }
        
       -gboolean IsHttpError(HttpConnection *conn) {
       -   return IsError(&conn->NetBuf.error);
       -}
       -
        gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
                                       gchar *user,gchar *password) {
           gchar **ptuser,**ptpassword;
       t@@ -1190,13 +1176,11 @@ static void ParseHtmlHeader(gchar *line,HttpConnection *conn) {
              }
            } else if (g_strcasecmp(split[0],"WWW-Authenticate:")==0 &&
                       conn->StatusCode==HEC_AUTHREQ) {
       -      g_print("FIXME: Authentication %s required\n",split[1]);
              StartHttpAuth(conn,FALSE,split[1]);
        /* Proxy-Authenticate is, strictly speaking, an HTTP/1.1 thing, but some
           HTTP/1.0 proxies seem to support it anyway */
            } else if (g_strcasecmp(split[0],"Proxy-Authenticate:")==0 &&
                       conn->StatusCode==HEC_PROXYAUTH) {
       -      g_print("FIXME: Proxy authentication %s required\n",split[1]);
              StartHttpAuth(conn,TRUE,split[1]);
            }
          }
       t@@ -1237,7 +1221,7 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
           gpointer CallBackData;
           NBUserPasswd userpasswd;
           gboolean retry=FALSE;
       -   LastError *error;
       +   LastError **error;
        
           error=&conn->NetBuf.error;
        
       t@@ -1249,12 +1233,11 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
           }
        
           if (conn->Tries>=5) {
       -      SetError(error,&ETHTTP,HEC_TRIESEX);
       +      SetError(error,&ETHTTP,HEC_TRIESEX,NULL);
              return TRUE;
           }
        
           if (conn->RedirHost) {
       -      g_print("Following redirect to %s\n",conn->RedirHost);
              g_free(conn->HostName); g_free(conn->Query);
              conn->HostName = conn->RedirHost;
              conn->Query = conn->RedirQuery;
       t@@ -1263,12 +1246,10 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
              retry = TRUE;
           }
           if (conn->StatusCode==HEC_AUTHREQ && conn->user && conn->password) {
       -      g_print("Trying again with authentication\n");
              retry = TRUE;
           }
           if (conn->StatusCode==HEC_PROXYAUTH && conn->proxyuser &&
               conn->proxypassword) {
       -      g_print("Trying again with proxy authentication\n");
              retry = TRUE;
           }
        
       t@@ -1284,28 +1265,32 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
                 return FALSE;
              }
           } else if (conn->StatusCode>=300) {
       -     SetError(error,&ETHTTP,conn->StatusCode);
       +     SetError(error,&ETHTTP,conn->StatusCode,NULL);
           }
           return TRUE;
        }
        
       -int CreateTCPSocket(LastError *error) {
       +gboolean IsHttpError(HttpConnection *conn) {
       +  return (conn->NetBuf.error!=NULL);
       +}
       +
       +int CreateTCPSocket(LastError **error) {
          int fd;
        
          fd=socket(AF_INET,SOCK_STREAM,0);
        
          if (fd==SOCKET_ERROR && error) {
        #ifdef CYGWIN
       -    SetError(error,ET_WINSOCK,WSAGetLastError());
       +    SetError(error,ET_WINSOCK,WSAGetLastError(),NULL);
        #else
       -    SetError(error,ET_ERRNO,errno);
       +    SetError(error,ET_ERRNO,errno,NULL);
        #endif
          }
        
          return fd;
        }
          
       -gboolean BindTCPSocket(int sock,unsigned port,LastError *error) {
       +gboolean BindTCPSocket(int sock,unsigned port,LastError **error) {
          struct sockaddr_in bindaddr;
          int retval;
        
       t@@ -1318,9 +1303,9 @@ gboolean BindTCPSocket(int sock,unsigned port,LastError *error) {
        
          if (retval==SOCKET_ERROR && error) {
        #ifdef CYGWIN
       -    SetError(error,ET_WINSOCK,WSAGetLastError());
       +    SetError(error,ET_WINSOCK,WSAGetLastError(),NULL);
        #else
       -    SetError(error,ET_ERRNO,errno);
       +    SetError(error,ET_ERRNO,errno,NULL);
        #endif
          }
        
       t@@ -1328,7 +1313,7 @@ gboolean BindTCPSocket(int sock,unsigned port,LastError *error) {
        }
        
        gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
       -                      gboolean NonBlocking,LastError *error) {
       +                      gboolean NonBlocking,LastError **error) {
           struct sockaddr_in ClientAddr;
           struct hostent *he;
        
       t@@ -1350,10 +1335,10 @@ gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
        #ifdef CYGWIN
              int errcode=WSAGetLastError();
              if (errcode==WSAEWOULDBLOCK) return TRUE;
       -      else if (error) SetError(error,ET_WINSOCK,errcode);
       +      else if (error) SetError(error,ET_WINSOCK,errcode,NULL);
        #else
              if (errno==EINPROGRESS) return TRUE;
       -      else if (error) SetError(error,ET_ERRNO,errno);
       +      else if (error) SetError(error,ET_ERRNO,errno,NULL);
        #endif
              CloseSocket(*fd); *fd=-1;
              return FALSE;
       t@@ -1363,13 +1348,13 @@ gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
           return TRUE;
        }
        
       -gboolean FinishConnect(int fd,LastError *error) {
       +gboolean FinishConnect(int fd,LastError **error) {
           int errcode;
        #ifdef CYGWIN
           errcode = WSAGetLastError();
           if (errcode==0) return TRUE;
           else {
       -     if (error) { SetError(error,ET_WINSOCK,errcode); }
       +     if (error) { SetError(error,ET_WINSOCK,errcode,NULL); }
             return FALSE;
           }
        #else
       t@@ -1385,7 +1370,7 @@ gboolean FinishConnect(int fd,LastError *error) {
           }
           if (errcode==0) return TRUE;
           else {
       -     if (error) { SetError(error,ET_ERRNO,errcode); }
       +     if (error) { SetError(error,ET_ERRNO,errcode,NULL); }
             return FALSE;
           }
        #endif /* CYGWIN */
 (DIR) diff --git a/src/network.h b/src/network.h
       t@@ -108,7 +108,7 @@ struct _NetworkBuffer {
                                       SOCKS5 authentication */  
           gchar *host;             /* If non-NULL, the host to connect to */
           unsigned port;           /* If non-NULL, the port to connect to */
       -   LastError error;         /* Any error from the last operation */
       +   LastError *error;        /* Any error from the last operation */
        };
        
        /* Keeps track of the progress of an HTTP connection */
       t@@ -185,17 +185,17 @@ gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
                                    gchar *Method,gchar *Query,
                                    gchar *Headers,gchar *Body);
        void CloseHttpConnection(HttpConnection *conn);
       -gboolean IsHttpError(HttpConnection *conn);
        gchar *ReadHttpResponse(HttpConnection *conn);
        gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
                                       gchar *user,gchar *password);
        void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc,gpointer data);
        gboolean HandleHttpCompletion(HttpConnection *conn);
       +gboolean IsHttpError(HttpConnection *conn);
        
       -int CreateTCPSocket(LastError *error);
       -gboolean BindTCPSocket(int sock,unsigned port,LastError *error);
       +int CreateTCPSocket(LastError **error);
       +gboolean BindTCPSocket(int sock,unsigned port,LastError **error);
        gboolean StartConnect(int *fd,gchar *RemoteHost,unsigned RemotePort,
       -                      gboolean NonBlocking,LastError *error);
       +                      gboolean NonBlocking,LastError **error);
        void StartNetworking(void);
        void StopNetworking(void);
        
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -142,7 +142,7 @@ static gboolean MetaConnectError(HttpConnection *conn) {
           GString *errstr;
           if (!IsHttpError(conn)) return FALSE;
           errstr=g_string_new("");
       -   g_string_assign_error(errstr,&MetaConn->NetBuf.error);
       +   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);
       t@@ -648,7 +648,8 @@ gboolean ReadServerKey(GString *LineBuf,gboolean *EndOfLine) {
        }
        
        void StartServer() {
       -   struct sockaddr_in ServerAddr;
       +   LastError *sockerr;
       +   GString *errstr;
        #ifndef CYGWIN
           struct sigaction sact;
        #endif
       t@@ -670,22 +671,29 @@ void StartServer() {
           Network=TRUE;
           FirstServer=NULL;
           ClientMessageHandlerPt=NULL;
       -   ListenSock=socket(AF_INET,SOCK_STREAM,0);
       +   ListenSock=CreateTCPSocket(&sockerr);
           if (ListenSock==SOCKET_ERROR) {
       -/* FIXME
       -MessageBox(NULL,"Cannot create socket",NULL,MB_OK); */
       -      perror("create socket"); exit(1);
       +     errstr=g_string_new("");
       +     g_string_assign_error(errstr,sockerr);
       +     g_log(NULL,G_LOG_LEVEL_CRITICAL,
       +           _("Cannot create server (listening) socket (%s) Aborting."),
       +           errstr->str);
       +     g_string_free(errstr,TRUE);
       +     FreeError(sockerr);
       +     exit(1);
           }
           SetReuse(ListenSock);
           SetBlocking(ListenSock,FALSE);
       -  
       -   ServerAddr.sin_family=AF_INET;
       -   ServerAddr.sin_port=htons(Port);
       -   ServerAddr.sin_addr.s_addr=INADDR_ANY;
       -   memset(ServerAddr.sin_zero,0,sizeof(ServerAddr.sin_zero));
       -   if (bind(ListenSock,(struct sockaddr *)&ServerAddr,
       -       sizeof(struct sockaddr)) == SOCKET_ERROR) {
       -      perror("bind socket"); exit(1);
       +
       +   if (!BindTCPSocket(ListenSock,Port,&sockerr)) {
       +     errstr=g_string_new("");
       +     g_string_assign_error(errstr,sockerr);
       +     g_log(NULL,G_LOG_LEVEL_CRITICAL,
       +           _("Cannot listen on port %u (%s) Aborting."),
       +           Port,errstr->str);
       +     g_string_free(errstr,TRUE);
       +     FreeError(sockerr);
       +     exit(1);
           }
        
        /* Initial startup message for the server */