tAuthorisation functions rewritten to avoid modal dialogs popping up during net… | |
git clone git://src.adamsgaard.dk/vaccinewars | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 013c93d79269fed4dfce4b2aa3f6ab1af1d8ba07 | |
parent a407e0d62578bce574706dffda51cdc3ec9eb324 | |
Author: Ben Webb <[email protected]> | |
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 wPar… | |
} | |
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 hPrevInstanc… | |
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 <glib.h> | |
#include <stdarg.h> | |
+#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,NBCall… | |
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 *err… | |
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],d… | |
+ 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 … | |
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… | |
} 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 *H… | |
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); | |