Introduction
Introduction Statistics Contact Development Disclaimer Help
tNew code added for non-blocking communication with the metaserver - vaccinewar…
git clone git://src.adamsgaard.dk/vaccinewars
Log
Files
Refs
README
LICENSE
---
commit 8deb8cf2d3a6cd75cebbefcb6e8b15bc2c6a02b4
parent de7b9a4dd681c475fa9423484288871b71209512
Author: Ben Webb <[email protected]>
Date: Sun, 9 Sep 2001 21:26:38 +0000
New code added for non-blocking communication with the metaserver
Diffstat:
M src/message.c | 157 +++++++++++++++++++++++++++++…
M src/message.h | 31 +++++++++++++++++++++++++++++…
2 files changed, 188 insertions(+), 0 deletions(-)
---
diff --git a/src/message.c b/src/message.c
t@@ -442,6 +442,21 @@ 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 */
t@@ -571,6 +586,148 @@ gboolean WriteDataToWire(NetworkBuffer *NetBuf) {
return TRUE;
}
+HttpConnection *OpenHttpConnection(gchar *HostName,unsigned Port,
+ gchar *Proxy,unsigned ProxyPort,
+ gchar *Method,gchar *Query,
+ gchar *Headers,gchar *Body) {
+ HttpConnection *conn;
+ gchar *ConnectHost;
+ unsigned ConnectPort;
+ GString *text;
+ 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 (conn->Proxy) {
+ ConnectHost=conn->Proxy; ConnectPort=conn->ProxyPort;
+ } else {
+ ConnectHost=conn->HostName; ConnectPort=conn->Port;
+ }
+
+ if (!StartNetworkBufferConnect(&conn->NetBuf,ConnectHost,ConnectPort)) {
+ CloseHttpConnection(conn);
+ return NULL;
+ }
+ conn->Tries++;
+ conn->StatusCode=0;
+ conn->Status=HS_CONNECTING;
+
+ text=g_string_new("");
+
+ 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);
+ QueueMessageForSend(&conn->NetBuf,"\n");
+ if (conn->Body) QueueMessageForSend(&conn->NetBuf,conn->Body);
+
+ g_string_free(text,TRUE);
+
+ return conn;
+}
+
+HttpConnection *OpenMetaHttpConnection() {
+ gchar *query;
+ HttpConnection *retval;
+
+ query = g_strdup_printf("%s?output=text&getlist=%d",
+ MetaServer.Path,METAVERSION);
+ retval = OpenHttpConnection(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);
+}
+
+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;
+ 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 HandleWaitingMetaServerData(HttpConnection *conn) {
+ gchar *msg;
+ ServerData *NewServer;
+
+/* If we're done reading the headers, only read if the data for a whole
+ server is available (8 lines) N.B. "Status" is from the _last_ read */
+ if (conn->Status==HS_READBODY) {
+ if (CountWaitingMessages(&conn->NetBuf)<8) return FALSE;
+
+ 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);
+ msg=ReadHttpResponse(conn);
+ if (msg[0]) NewServer->CurPlayers=atoi(msg);
+ else NewServer->CurPlayers=-1;
+ g_free(msg);
+ msg=ReadHttpResponse(conn);
+ NewServer->MaxPlayers=atoi(msg); g_free(msg);
+ NewServer->Update=ReadHttpResponse(conn);
+ NewServer->Comment=ReadHttpResponse(conn);
+ NewServer->UpSince=ReadHttpResponse(conn);
+ ServerList=g_slist_append(ServerList,NewServer);
+ } else if (conn->Status==HS_READSEPARATOR) {
+ /* This should be the first line of the body, the "MetaServer:" line */
+ msg=ReadHttpResponse(conn);
+ if (!msg) return FALSE;
+ if (strncmp(msg,"MetaServer:",11)!=0) {
+ g_warning("Bad reply from metaserver: %s",msg);
+ }
+ g_free(msg);
+ } else {
+ msg=ReadHttpResponse(conn);
+ if (!msg) return FALSE;
+ g_free(msg);
+ }
+ return TRUE;
+}
+
gchar *bgets(int fd) {
/* Drop-in substitute for fgets; reads a newline-terminated string from */
/* file descriptor fd, into a dynamically-allocated buffer. Returns a */
diff --git a/src/message.h b/src/message.h
t@@ -115,6 +115,27 @@ void SendPrintMessage(Player *From,char AICode,Player *To…
void SendQuestion(Player *From,char AICode,Player *To,char *Data);
#if NETWORKING
+/* Keeps track of the progress of an HTTP connection */
+typedef enum _HttpStatus {
+ 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 */
+ 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);
t@@ -142,8 +163,18 @@ 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 HandleWaitingMetaServerData(HttpConnection *conn);
+
gchar *bgets(int fd);
#endif /* NETWORKING */
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.