tAuthorisation functions rewritten to avoid modal dialogs popping up during networking - vaccinewars - be a doctor and try to vaccinate the world
git clone git://src.adamsgaard.dk/vaccinewars
Log
Files
Refs
README
LICENSE
---
commit 013c93d79269fed4dfce4b2aa3f6ab1af1d8ba07
parent a407e0d62578bce574706dffda51cdc3ec9eb324
Author: Ben Webb 
Date:   Thu, 11 Oct 2001 18:49:47 +0000

Authorisation functions rewritten to avoid modal dialogs popping up during
networking


Diffstat:
  M src/gtk_client.c                    |      46 ++++++++++++++++++++-----------
  M src/gtkport.c                       |      24 ++++++++++++++++++++----
  M src/gtkport.h                       |       2 ++
  M src/network.c                       |     103 +++++++++++++++++++++++--------
  M src/network.h                       |      29 +++++++++++++++++++----------

5 files changed, 147 insertions(+), 57 deletions(-)
---
diff --git a/src/gtk_client.c b/src/gtk_client.c
t@@ -95,7 +95,8 @@ static void NewGameDialog(void);
 static void StartGame(void);
 static void EndGame(void);
 static void UpdateMenus(void);
-static gboolean AuthDialog(HttpConnection *conn,gchar *realm);
+static void AuthDialog(HttpConnection *conn,
+                       gboolean proxyauth,gchar *realm);
 
 #ifdef NETWORKING
 static void GetClientMessage(gpointer data,gint socket,
t@@ -2161,7 +2162,9 @@ static void CloseNewGameDia(GtkWidget *widget,
                             struct StartGameStruct *widgets) {
 #ifdef NETWORKING
 /* Terminate any existing connection attempts */
-   ShutdownNetworkBuffer(&ClientData.Play->NetBuf);
+   if (ClientData.Play->NetBuf.status!=NBS_CONNECTED) {
+      ShutdownNetworkBuffer(&ClientData.Play->NetBuf);
+   }
    if (widgets->MetaConn) {
       CloseHttpConnection(widgets->MetaConn); widgets->MetaConn=NULL;
    }
t@@ -3126,42 +3129,56 @@ void DisplaySpyReports(Player *Play) {
 static void OKAuthDialog(GtkWidget *widget,GtkWidget *window) {
    GtkWidget *userentry,*passwdentry;
    gchar *username,*password;
+   gpointer proxy;
    HttpConnection *conn;
-   gboolean *retval;
 
+   proxy = gtk_object_get_data(GTK_OBJECT(window),"proxy");
    userentry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window),"username");
    passwdentry = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(window),
                                                   "password");
-   retval = (gboolean *)gtk_object_get_data(GTK_OBJECT(window),"retval");
    conn = (HttpConnection *)gtk_object_get_data(GTK_OBJECT(window),"httpconn");
-   g_assert(userentry && passwdentry && retval && conn);
-
-   *retval = TRUE;
+   g_assert(userentry && passwdentry && conn);
 
    username = gtk_editable_get_chars(GTK_EDITABLE(userentry),0,-1);
    password = gtk_editable_get_chars(GTK_EDITABLE(passwdentry),0,-1);
 
-   SetHttpAuthentication(conn,username,password);
+   gtk_object_set_data(GTK_OBJECT(window),"authdone",GINT_TO_POINTER(TRUE));
+
+   if (!SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),username,password)) {
+      g_print("FIXME: Connect error on setauth\n");
+   }
    g_free(username); g_free(password);
 
    gtk_widget_destroy(window);
 }
 
 void DestroyAuthDialog(GtkWidget *widget,gpointer data) {
-   gtk_main_quit();
+   HttpConnection *conn;
+   gpointer authdone,proxy;
+
+   authdone = gtk_object_get_data(GTK_OBJECT(widget),"authdone");
+   conn = (HttpConnection *)gtk_object_get_data(GTK_OBJECT(widget),"httpconn");
+   proxy = gtk_object_get_data(GTK_OBJECT(widget),"proxy");
+
+   if (authdone) {
+      g_print("Auth already done, thanks\n");
+   } else {
+      if (!SetHttpAuthentication(conn,GPOINTER_TO_INT(proxy),NULL,NULL)) {
+         g_print("FIXME: Connect error on unsetauth\n");
+      }
+   }
 }
 
-gboolean AuthDialog(HttpConnection *conn,gchar *realm) {
+void AuthDialog(HttpConnection *conn,gboolean proxy,gchar *realm) {
    GtkWidget *window,*button,*hsep,*vbox,*label,*entry,*table,*hbbox;
-   gboolean retval=FALSE;
 
    window=gtk_window_new(GTK_WINDOW_DIALOG);
    gtk_signal_connect(GTK_OBJECT(window),"destroy",
                       GTK_SIGNAL_FUNC(DestroyAuthDialog),NULL);
-   gtk_object_set_data(GTK_OBJECT(window),"retval",(gpointer)&retval);
+   gtk_object_set_data(GTK_OBJECT(window),"proxy",GINT_TO_POINTER(proxy));
    gtk_object_set_data(GTK_OBJECT(window),"httpconn",(gpointer)conn);
 
-   if (conn->proxyauth) {
+   if (proxy) {
       gtk_window_set_title(GTK_WINDOW(window),
 /* Title of dialog for authenticating with a proxy server */
                            _("Proxy Authentication Required"));
t@@ -3229,9 +3246,6 @@ gboolean AuthDialog(HttpConnection *conn,gchar *realm) {
 
    gtk_container_add(GTK_CONTAINER(window),vbox);
    gtk_widget_show_all(window);
-
-   gtk_main();
-   return retval;
 }
 
 #else
diff --git a/src/gtkport.c b/src/gtkport.c
t@@ -44,6 +44,8 @@
 
 #define WM_SOCKETDATA (WM_USER+100)
 
+static gint RecurseLevel=0;
+
 static const gchar *WC_GTKSEP    = "WC_GTKSEP";
 static const gchar *WC_GTKVPANED = "WC_GTKVPANED";
 static const gchar *WC_GTKHPANED = "WC_GTKHPANED";
t@@ -922,9 +924,13 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) {
          }
          break;
       case WM_SOCKETDATA:
+/* Ignore network messages if in recursive message loops, to avoid dodgy
+   race conditions */
+         if (RecurseLevel<=1) {
 /* Make any error available by the usual WSAGetLastError() mechanism */
-         WSASetLastError(WSAGETSELECTERROR(lParam));
-         DispatchSocketEvent((SOCKET)wParam,WSAGETSELECTEVENT(lParam));
+            WSASetLastError(WSAGETSELECTERROR(lParam));
+            DispatchSocketEvent((SOCKET)wParam,WSAGETSELECTEVENT(lParam));
+         }
          break;
       case WM_TIMER:
          DispatchTimeoutEvent((UINT)wParam);
t@@ -963,6 +969,7 @@ void win32_init(HINSTANCE hInstance,HINSTANCE hPrevInstance,char *MainIcon) {
    hInst=hInstance;
    hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
    WindowList=NULL;
+   RecurseLevel=0;
    if (!hPrevInstance) {
       wc.style                = CS_HREDRAW|CS_VREDRAW;
       wc.lpfnWndProc        = MainWndProc;
t@@ -2896,6 +2903,8 @@ void gtk_main() {
    GtkWidget *widget;
    HACCEL hAccel;
 
+   RecurseLevel++;
+
    while (GetMessage(&msg,NULL,0,0)) {
       MsgDone=FALSE;
       for (list=WindowList;list && !MsgDone;list=g_slist_next(list)) {
t@@ -2913,6 +2922,7 @@ void gtk_main() {
          DispatchMessage(&msg);
       }
    }
+   RecurseLevel--;
 }
 
 typedef struct _GtkSignal GtkSignal;
t@@ -4416,8 +4426,14 @@ void gtk_progress_bar_realize(GtkWidget *widget) {
 
 gint GtkMessageBox(GtkWidget *parent,const gchar *Text,
                    const gchar *Title,gint Options) {
-   return MessageBox(parent && parent->hWnd ? parent->hWnd : NULL,
-                     Text,Title,Options);
+   gint retval;
+
+   RecurseLevel++;
+   retval = MessageBox(parent && parent->hWnd ? parent->hWnd : NULL,
+                       Text,Title,Options);
+   RecurseLevel--;
+
+   return retval;
 }
 
 guint gtk_timeout_add(guint32 interval,GtkFunction function,gpointer data) {
diff --git a/src/gtkport.h b/src/gtkport.h
t@@ -33,6 +33,8 @@
 #include 
 #include 
 
+#define MB_IMMRETURN 0
+
 typedef enum {
    GTK_WINDOW_TOPLEVEL, GTK_WINDOW_DIALOG, GTK_WINDOW_POPUP
 } GtkWindowType;
diff --git a/src/network.c b/src/network.c
t@@ -129,7 +129,9 @@ static void NetBufCallBack(NetworkBuffer *NetBuf) {
 }
 
 static void NetBufCallBackStop(NetworkBuffer *NetBuf) {
-   if (NetBuf && NetBuf->CallBack) (*NetBuf->CallBack)(NetBuf,FALSE,FALSE);
+   if (NetBuf && NetBuf->CallBack) {
+      (*NetBuf->CallBack)(NetBuf,FALSE,FALSE);
+   }
 }
 
 static void InitConnBuf(ConnBuf *buf) {
t@@ -176,6 +178,8 @@ void SetNetworkBufferCallBack(NetworkBuffer *NetBuf,NBCallBack CallBack,
 
 void SetNetworkBufferUserPasswdFunc(NetworkBuffer *NetBuf,
                                     NBUserPasswd userpasswd) {
+/* Sets the function used to obtain a username and password for SOCKS5 */
+/* username/password authentication                                    */
    NetBuf->userpasswd=userpasswd;
 }
 
t@@ -320,20 +324,28 @@ static void SocksAppendError(GString *str,LastError *error) {
 static ErrorType ETSocks = { SocksAppendError };
 
 static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
-   gchar *user,*password;
-   gchar *addpt;
-   guint addlen;
-   ConnBuf *conn;
-
    if (!NetBuf->userpasswd) {
       SetError(&NetBuf->error,&ETSocks,SEC_NOMETHODS);
       return FALSE;
+   } else {
+/* Request a username and password (the callback function should in turn
+   call SendSocks5UserPasswd when it's done) */
+      NetBuf->sockstat = NBSS_USERPASSWD;
+      (*NetBuf->userpasswd)(NetBuf);
+      return TRUE;
    }
-   if (!(*NetBuf->userpasswd)(NetBuf,&user,&password)) {
+}
+
+gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
+                              gchar *password) {
+   gchar *addpt;
+   guint addlen;
+   ConnBuf *conn;
+
+   if (!user || !password) {
       SetError(&NetBuf->error,&ETSocks,SEC_USERCANCEL);
       return FALSE;
    }
-
    conn=&NetBuf->negbuf;
    addlen = 3 + strlen(user) + strlen(password);
    addpt = ExpandWriteBuffer(conn,addlen);
t@@ -347,7 +359,6 @@ static gboolean Socks5UserPasswd(NetworkBuffer *NetBuf) {
    strcpy(&addpt[3+strlen(user)],password);
    g_free(user); g_free(password);
 
-   NetBuf->sockstat = NBSS_USERPASSWD;
    conn->DataPresent+=addlen;
 
 /* If the buffer was empty before, we may need to tell the owner to check
t@@ -457,7 +468,10 @@ g_print("FIXME: SOCKS5 connect reply\n");
                else replylen+=data[4];   /* FQDN */
                data = GetWaitingData(NetBuf,replylen);
                if (data) {
-                  g_print("FIXME: SOCKS5 sucessful connect\n");
+                  g_print("FIXME: SOCKS5 successful connect\n");
+               if (addrtype==1) g_print("IPv4 address %d.%d.%d.%d\n",data[4],data[5],data[6],data[7]);
+               else if (addrtype==4) g_print("IPv6 address\n");
+               else g_print("FQDN\n");
                   NetBuf->status = NBS_CONNECTED;
                   g_free(data);
                   NetBufCallBack(NetBuf); /* status has changed */
t@@ -896,7 +910,6 @@ static void SendHttpRequest(HttpConnection *conn) {
    conn->Tries++;
    conn->StatusCode=0;
    conn->Status=HS_CONNECTING;
-   conn->authsupplied=FALSE;
 
    text=g_string_new("");
 
t@@ -908,9 +921,14 @@ static void SendHttpRequest(HttpConnection *conn) {
 
    if (conn->user && conn->password) {
       userpasswd = g_strdup_printf("%s:%s",conn->user,conn->password);
-      g_string_assign(text,conn->proxyauth ? "Proxy-Authenticate" :
-                                             "Authorization");
-      g_string_append(text,": Basic ");
+      g_string_assign(text,"Authorization: Basic ");
+      AddB64Enc(text,userpasswd);
+      g_free(userpasswd);
+      QueueMessageForSend(&conn->NetBuf,text->str);
+   }
+   if (conn->proxyuser && conn->proxypassword) {
+      userpasswd = g_strdup_printf("%s:%s",conn->proxyuser,conn->proxypassword);
+      g_string_assign(text,"Proxy-Authenticate: Basic ");
       AddB64Enc(text,userpasswd);
       g_free(userpasswd);
       QueueMessageForSend(&conn->NetBuf,text->str);
t@@ -961,7 +979,6 @@ gboolean OpenHttpConnection(HttpConnection **connpt,gchar *HostName,
    if (Body && Body[0]) conn->Body=g_strdup(Body);
    conn->Port = Port;
    conn->ProxyPort = ProxyPort;
-   conn->user = conn->password = NULL;
    *connpt = conn;
 
    if (StartHttpConnect(conn)) {
t@@ -982,9 +999,10 @@ void CloseHttpConnection(HttpConnection *conn) {
    g_free(conn->Body);
    g_free(conn->RedirHost);
    g_free(conn->RedirQuery);
-   g_free(conn->realm);
    g_free(conn->user);
    g_free(conn->password);
+   g_free(conn->proxyuser);
+   g_free(conn->proxypassword);
    g_free(conn);
 }
 
t@@ -992,12 +1010,25 @@ gboolean IsHttpError(HttpConnection *conn) {
    return IsError(&conn->NetBuf.error);
 }
 
-void SetHttpAuthentication(HttpConnection *conn,gchar *user,gchar *password) {
-   g_assert(conn && user && password);
-   g_free(conn->user);
-   g_free(conn->password);
-   conn->user = g_strdup(user);
-   conn->password = g_strdup(password);
+gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
+                               gchar *user,gchar *password) {
+   gchar **ptuser,**ptpassword;
+   g_assert(conn);
+   if (proxy) {
+      ptuser=&conn->proxyuser; ptpassword=&conn->proxypassword;
+   } else {
+      ptuser=&conn->user; ptpassword=&conn->password;
+   }
+   g_free(*ptuser); g_free(*ptpassword);
+   if (user && password) {
+      *ptuser = g_strdup(user);
+      *ptpassword = g_strdup(password);
+   } else {
+      *ptuser = *ptpassword = NULL;
+   }
+   conn->waitinput=FALSE;
+   if (conn->Status==HS_WAITCOMPLETE) return !HandleHttpCompletion(conn);
+   else return TRUE;
 }
 
 void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc) {
t@@ -1062,15 +1093,19 @@ static void ParseHtmlHeader(gchar *line,HttpConnection *conn) {
     } else if (g_strcasecmp(split[0],"WWW-Authenticate:")==0 &&
                conn->StatusCode==401) {
       g_print("FIXME: Authentication %s required\n",split[1]);
-      conn->proxyauth=FALSE;
-      if (conn->authfunc) conn->authsupplied=(*conn->authfunc)(conn,split[1]);
+      if (conn->authfunc) {
+         conn->waitinput=TRUE;
+         (*conn->authfunc)(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==407) {
       g_print("FIXME: Proxy authentication %s required\n",split[1]);
-      conn->proxyauth=TRUE;
-      if (conn->authfunc) conn->authsupplied=(*conn->authfunc)(conn,split[1]);
+      if (conn->authfunc) {
+         conn->waitinput=TRUE;
+         (*conn->authfunc)(conn,TRUE,split[1]);
+      }
     }
   }
   g_strfreev(split);
t@@ -1099,6 +1134,9 @@ gchar *ReadHttpResponse(HttpConnection *conn) {
          break;
       case HS_READBODY:   /* At present, we do nothing special with the body */
          break;
+      case HS_WAITCOMPLETE: /* Well, we shouldn't be here at all... */
+         g_free(msg); msg=NULL;
+         break;
    }
    return msg;
 }
t@@ -1109,6 +1147,13 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
    NBUserPasswd userpasswd;
    gboolean retry=FALSE;
 
+/* If we're still waiting for authentication etc., then signal that the
+   connection shouldn't be closed yet, and go into the "WAITCOMPLETE" state */
+   if (conn->waitinput) {
+      conn->Status = HS_WAITCOMPLETE;
+      return FALSE;
+   }
+
    if (conn->Tries>=5) {
       g_print("FIXME: Number of tries exceeded\n");
       return TRUE;
t@@ -1123,10 +1168,14 @@ gboolean HandleHttpCompletion(HttpConnection *conn) {
       conn->RedirHost = conn->RedirQuery = NULL;
       retry = TRUE;
    }
-   if (conn->authsupplied && conn->user && conn->password) {
+   if (conn->StatusCode==401 && conn->user && conn->password) {
       g_print("Trying again with authentication\n");
       retry = TRUE;
    }
+   if (conn->StatusCode==407 && conn->proxyuser && conn->proxypassword) {
+      g_print("Trying again with proxy authentication\n");
+      retry = TRUE;
+   }
 
    if (retry) {
       CallBack=conn->NetBuf.CallBack;
diff --git a/src/network.h b/src/network.h
t@@ -65,8 +65,7 @@ typedef struct _NetworkBuffer NetworkBuffer;
 
 typedef void (*NBCallBack)(NetworkBuffer *NetBuf,gboolean Read,gboolean Write);
 
-typedef gboolean (*NBUserPasswd)(NetworkBuffer *NetBuf,
-                                 gchar **user,gchar **password);
+typedef void (*NBUserPasswd)(NetworkBuffer *NetBuf);
 
 /* Information about a SOCKS server */
 typedef struct _SocksServer {
t@@ -114,12 +113,18 @@ struct _NetworkBuffer {
 
 /* Keeps track of the progress of an HTTP connection */
 typedef enum {
-   HS_CONNECTING, HS_READHEADERS, HS_READSEPARATOR, HS_READBODY
+   HS_CONNECTING,    /* Waiting for connect() to complete */
+   HS_READHEADERS,   /* Reading HTTP headers */
+   HS_READSEPARATOR, /* Reading the header/body separator line */
+   HS_READBODY,      /* Reading HTTP body */
+   HS_WAITCOMPLETE   /* Done reading, now waiting for authentication etc.
+                        before closing and/or retrying the connection */
 } HttpStatus;
 
 typedef struct _HttpConnection HttpConnection;
 
-typedef gboolean (*HCAuthFunc)(struct _HttpConnection *conn,gchar *realm);
+typedef void (*HCAuthFunc)(struct _HttpConnection *conn,
+                           gboolean proxyauth,gchar *realm);
 
 /* A structure used to keep track of an HTTP connection */
 struct _HttpConnection {
t@@ -135,11 +140,12 @@ struct _HttpConnection {
    gchar *RedirQuery;     /* if non-NULL, the path to redirect to */
    unsigned RedirPort;    /* The port on the host to redirect to */
    HCAuthFunc authfunc;   /* Callback function for authentication */
-   gboolean proxyauth;    /* TRUE if the authentication is with a proxy */
-   gboolean authsupplied; /* TRUE if the request should be retried with auth */
-   gchar *realm;          /* The realm for basic HTTP authentication */
-   gchar *user;           /* The supplied username */
-   gchar *password;       /* The supplied password */
+   gboolean waitinput;    /* TRUE if we're waiting for auth etc.
+                             to be supplied */
+   gchar *user;           /* The supplied username for HTTP auth */
+   gchar *password;       /* The supplied password for HTTP auth */
+   gchar *proxyuser;      /* The supplied username for HTTP proxy auth */
+   gchar *proxypassword;  /* The supplied password for HTTP proxy auth */
    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 */
t@@ -169,6 +175,8 @@ gboolean WriteDataToWire(NetworkBuffer *NetBuf);
 void QueueMessageForSend(NetworkBuffer *NetBuf,gchar *data);
 gint CountWaitingMessages(NetworkBuffer *NetBuf);
 gchar *GetWaitingMessage(NetworkBuffer *NetBuf);
+gboolean SendSocks5UserPasswd(NetworkBuffer *NetBuf,gchar *user,
+                              gchar *password);
 
 gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
                             unsigned Port,gchar *Proxy,unsigned ProxyPort,
t@@ -178,7 +186,8 @@ gboolean OpenHttpConnection(HttpConnection **conn,gchar *HostName,
 void CloseHttpConnection(HttpConnection *conn);
 gboolean IsHttpError(HttpConnection *conn);
 gchar *ReadHttpResponse(HttpConnection *conn);
-void SetHttpAuthentication(HttpConnection *conn,gchar *user,gchar *password);
+gboolean SetHttpAuthentication(HttpConnection *conn,gboolean proxy,
+                               gchar *user,gchar *password);
 void SetHttpAuthFunc(HttpConnection *conn,HCAuthFunc authfunc);
 gboolean HandleHttpCompletion(HttpConnection *conn);