tAdd new curl metaserver support to curses client - 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 8254d96a198d6143bcf74d3005cd61fbc1ac60ee
(DIR) parent 1ecfd771226f2a0b1b7b0bf64c8e87aae55f608e
(HTM) Author: Ben Webb <ben@salilab.org>
Date: Fri, 30 Oct 2020 23:01:42 -0700
Add new curl metaserver support to curses client
Diffstat:
M src/curses_client/curses_client.c | 57 +++++++++++++++++--------------
M src/message.c | 121 +++++++++++++------------------
M src/message.h | 5 ++---
M src/network.c | 141 +++++++++++++++++++++++++++++++
M src/network.h | 7 +++++++
M src/serverside.c | 135 -------------------------------
6 files changed, 233 insertions(+), 233 deletions(-)
---
(DIR) diff --git a/src/curses_client/curses_client.c b/src/curses_client/curses_client.c
t@@ -61,6 +61,9 @@ static int Width, Depth;
const static int MaxMessages = 1000;
#ifdef NETWORKING
+/* Data waiting to be sent to/read from the metaserver */
+CurlConnection MetaConn;
+
static enum {
CM_SERVER, CM_PROMPT, CM_META, CM_SINGLE
} ConnectMethod = CM_SERVER;
t@@ -364,14 +367,13 @@ static void SelectServerManually(void)
static gboolean SelectServerFromMetaServer(Player *Play, GString *errstr)
{
int c;
+ const char *merr;
GSList *ListPt;
ServerData *ThisServer;
GString *text;
gint index;
- fd_set readfds, writefds;
+ fd_set readfds, writefds, errorfds;
int maxsock;
- gboolean DoneOK;
- HttpConnection *MetaConn;
int top = get_ui_area_top();
attrset(TextAttr);
t@@ -379,25 +381,28 @@ static gboolean SelectServerFromMetaServer(Player *Play, GString *errstr)
mvaddstr(top + 1, 1, _("Please wait... attempting to contact metaserver..."));
refresh();
- if (OpenMetaHttpConnection(&MetaConn)) {
- SetHttpAuthFunc(MetaConn, HttpAuthFunc, NULL);
- SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf, SocksAuthFunc, NULL);
- } else {
- g_string_assign_error(errstr, MetaConn->NetBuf.error);
- CloseHttpConnection(MetaConn);
+ if ((merr = OpenMetaHttpConnection(&MetaConn))) {
+ g_string_assign(errstr, merr);
return FALSE;
}
ClearServerList(&ServerList);
- do {
+ while(TRUE) {
+ long mintime;
+ struct timeval timeout;
+ int still_running;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
+ FD_ZERO(&errorfds);
FD_SET(0, &readfds);
- maxsock = 1;
- SetSelectForNetworkBuffer(&MetaConn->NetBuf, &readfds, &writefds,
- NULL, &maxsock);
- if (bselect(maxsock, &readfds, &writefds, NULL, NULL) == -1) {
+ curl_multi_fdset(MetaConn.multi, &readfds, &writefds, &errorfds, &maxsock);
+ curl_multi_timeout(MetaConn.multi, &mintime);
+ timeout.tv_sec = mintime < 0 ? 5 : mintime;
+ timeout.tv_usec = 0;
+ maxsock = MAX(maxsock+1, 1);
+
+ if (bselect(maxsock, &readfds, &writefds, &errorfds, &timeout) == -1) {
if (errno == EINTR) {
CheckForResize(Play);
continue;
t@@ -411,20 +416,20 @@ static gboolean SelectServerFromMetaServer(Player *Play, GString *errstr)
if (c == '\f')
wrefresh(curscr);
}
- if (RespondToSelect
- (&MetaConn->NetBuf, &readfds, &writefds, NULL, &DoneOK)) {
- while (HandleWaitingMetaServerData(MetaConn, &ServerList, &DoneOK)) {
- }
- }
- if (!DoneOK && HandleHttpCompletion(MetaConn)) {
- if (IsHttpError(MetaConn)) {
- g_string_assign_error(errstr, MetaConn->NetBuf.error);
- CloseHttpConnection(MetaConn);
+ merr = CurlConnectionPerform(&MetaConn, &still_running);
+ if (merr) {
+ g_string_assign(errstr, merr);
+ return FALSE;
+ } else if (still_running == 0) {
+ merr = HandleWaitingMetaServerData(&MetaConn, &ServerList);
+ CloseCurlConnection(&MetaConn);
+ if (merr) {
+ g_string_assign(errstr, merr);
return FALSE;
}
+ break;
}
- } while (DoneOK);
- CloseHttpConnection(MetaConn);
+ }
text = g_string_new("");
t@@ -2682,6 +2687,7 @@ void CursesLoop(struct CMDLINE *cmdline)
BackupConfig();
start_curses();
+ CurlInit(&MetaConn);
Width = COLS;
Depth = LINES;
t@@ -2712,4 +2718,5 @@ void CursesLoop(struct CMDLINE *cmdline)
} while (c == 'Y');
FirstClient = RemovePlayer(Play, FirstClient);
end_curses();
+ CurlCleanup(&MetaConn);
}
(DIR) diff --git a/src/message.c b/src/message.c
t@@ -427,82 +427,63 @@ static void MetaAppendError(GString *str, LastError *error)
}
}
-static ErrorType ETMeta = { MetaAppendError, NULL };
-
-gboolean OpenMetaHttpConnection(HttpConnection **conn)
+const char *OpenMetaHttpConnection(CurlConnection *conn)
{
- gchar *query;
- gboolean retval;
-
- query = g_strdup_printf("%s?output=text&getlist=%d",
- MetaServer.URL, METAVERSION);
- retval = OpenHttpConnection(conn, MetaServer.URL, 80,
- MetaServer.ProxyName, MetaServer.ProxyPort,
- "",
- UseSocks
- && MetaServer.UseSocks ? &Socks : NULL,
- "GET", query, NULL, NULL);
- g_free(query);
- return retval;
+ const char *errstr;
+ gchar *url;
+
+ url = g_strdup_printf("%s?output=text&getlist=%d",
+ MetaServer.URL, METAVERSION);
+ errstr = OpenCurlConnection(conn, url, NULL);
+ g_free(url);
+ return errstr;
}
-gboolean HandleWaitingMetaServerData(HttpConnection *conn,
- GSList **listpt, gboolean *doneOK)
+const char *HandleWaitingMetaServerData(CurlConnection *conn, GSList **listpt)
{
- gchar *msg;
- ServerData *NewServer;
-
- g_assert(conn && listpt && doneOK);
-
- /* 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 && conn->StatusCode == 200) {
- if (CountWaitingMessages(&conn->NetBuf) < 8)
- return FALSE;
-
- NewServer = g_new0(ServerData, 1);
- NewServer->Name = ReadHttpResponse(conn, doneOK);
- msg = ReadHttpResponse(conn, doneOK);
- NewServer->Port = atoi(msg);
- g_free(msg);
- NewServer->Version = ReadHttpResponse(conn, doneOK);
- msg = ReadHttpResponse(conn, doneOK);
- if (msg[0])
- NewServer->CurPlayers = atoi(msg);
- else
- NewServer->CurPlayers = -1;
- g_free(msg);
- msg = ReadHttpResponse(conn, doneOK);
- NewServer->MaxPlayers = atoi(msg);
- g_free(msg);
- NewServer->Update = ReadHttpResponse(conn, doneOK);
- NewServer->Comment = ReadHttpResponse(conn, doneOK);
- NewServer->UpSince = ReadHttpResponse(conn, doneOK);
- *listpt = g_slist_append(*listpt, NewServer);
- } else if (conn->Status == HS_READSEPARATOR && conn->StatusCode == 200) {
- /* This should be the first line of the body, the "MetaServer:" line */
- msg = ReadHttpResponse(conn, doneOK);
- if (!msg)
- return FALSE;
- if (strlen(msg) >= 14 && strncmp(msg, "FATAL ERROR:", 12) == 0) {
- SetError(&conn->NetBuf.error, &ETMeta, MEC_INTERNAL,
- g_strdup(&msg[13]));
- *doneOK = FALSE;
- return FALSE;
- } else if (strncmp(msg, "MetaServer:", 11) != 0) {
- SetError(&conn->NetBuf.error, &ETMeta, MEC_BADREPLY, g_strdup(msg));
- g_free(msg);
- *doneOK = FALSE;
- return FALSE;
+ char *msg;
+
+ g_assert(conn && listpt);
+
+ msg = conn->data;
+ /* This should be the first line of the body, the "MetaServer:" line */
+ if (!msg) return NULL;
+ if (strlen(msg) >= 14 && strncmp(msg, "FATAL ERROR:", 12) == 0) {
+ //todo
+/* SetError(&conn->NetBuf.error, &ETMeta, MEC_INTERNAL,
+ g_strdup(&msg[13]));*/
+ } else if (strncmp(msg, "MetaServer:", 11) != 0) {
+ //todo
+/* SetError(&conn->NetBuf.error, &ETMeta, MEC_BADREPLY, g_strdup(msg));*/
+ }
+
+ msg = CurlNextLine(conn, msg);
+ while (msg) {
+ char *name, *port, *version, *curplayers, *maxplayers, *update,
+ *comment, *upsince;
+ name = msg;
+ port = CurlNextLine(conn, name);
+ version = CurlNextLine(conn, port);
+ curplayers = CurlNextLine(conn, version);
+ maxplayers = CurlNextLine(conn, curplayers);
+ update = CurlNextLine(conn, maxplayers);
+ comment = CurlNextLine(conn, update);
+ upsince = CurlNextLine(conn, comment);
+ msg = CurlNextLine(conn, upsince);
+ if (msg) {
+ ServerData *NewServer = g_new0(ServerData, 1);
+ NewServer->Name = g_strdup(name);
+ NewServer->Port = atoi(port);
+ NewServer->Version = g_strdup(version);
+ NewServer->CurPlayers = curplayers[0] ? atoi(curplayers) : -1;
+ NewServer->MaxPlayers = atoi(maxplayers);
+ NewServer->Update = g_strdup(update);
+ NewServer->Comment = g_strdup(comment);
+ NewServer->UpSince = g_strdup(upsince);
+ *listpt = g_slist_append(*listpt, NewServer);
}
- g_free(msg);
- } else {
- msg = ReadHttpResponse(conn, doneOK);
- if (!msg)
- return FALSE;
- g_free(msg);
}
- return TRUE;
+ return NULL;
}
void ClearServerList(GSList **listpt)
(DIR) diff --git a/src/message.h b/src/message.h
t@@ -83,9 +83,8 @@ void QueuePlayerMessageForSend(Player *Play, gchar *data);
gboolean WritePlayerDataToWire(Player *Play);
gchar *GetWaitingPlayerMessage(Player *Play);
-gboolean OpenMetaHttpConnection(HttpConnection **conn);
-gboolean HandleWaitingMetaServerData(HttpConnection *conn, GSList **listpt,
- gboolean *doneOK);
+const char *OpenMetaHttpConnection(CurlConnection *conn);
+const char *HandleWaitingMetaServerData(CurlConnection *conn, GSList **listpt);
void ClearServerList(GSList **listpt);
#endif /* NETWORKING */
(DIR) diff --git a/src/network.c b/src/network.c
t@@ -1200,6 +1200,147 @@ static gboolean StartHttpConnect(HttpConnection *conn)
return TRUE;
}
+static size_t MetaConnWriteFunc(void *contents, size_t size, size_t nmemb,
+ void *userp)
+{
+ size_t realsize = size * nmemb;
+ CurlConnection *conn = (CurlConnection *)userp;
+
+ conn->data = g_realloc(conn->data, conn->data_size + realsize + 1);
+ memcpy(&(conn->data[conn->data_size]), contents, realsize);
+ conn->data_size += realsize;
+ conn->data[conn->data_size] = 0;
+
+ return realsize;
+}
+
+static size_t MetaConnHeaderFunc(char *contents, size_t size, size_t nmemb,
+ void *userp)
+{
+ size_t realsize = size * nmemb;
+ CurlConnection *conn = (CurlConnection *)userp;
+
+ gchar *str = g_strchomp(g_strndup(contents, realsize));
+ g_ptr_array_add(conn->headers, (gpointer)str);
+ return realsize;
+}
+
+void CurlInit(CurlConnection *conn)
+{
+ curl_global_init(CURL_GLOBAL_DEFAULT);
+ conn->multi = curl_multi_init();
+ conn->h = curl_easy_init();
+ conn->running = FALSE;
+ conn->Terminator = '\n';
+ conn->StripChar = '\r';
+ conn->data_size = 0;
+ conn->headers = NULL;
+}
+
+void CloseCurlConnection(CurlConnection *conn)
+{
+ curl_multi_remove_handle(conn->multi, conn->h);
+ g_free(conn->data);
+ conn->data_size = 0;
+ conn->running = FALSE;
+ g_ptr_array_free(conn->headers, TRUE);
+ conn->headers = NULL;
+}
+
+void CurlCleanup(CurlConnection *conn)
+{
+ if (conn->running) {
+ CloseCurlConnection(conn);
+ }
+ curl_easy_cleanup(conn->h);
+ curl_multi_cleanup(conn->multi);
+ curl_global_cleanup();
+}
+
+const char *CurlConnectionPerform(CurlConnection *conn, int *still_running)
+{
+ CURLMcode mres;
+ struct CURLMsg *m;
+
+ mres = curl_multi_perform(conn->multi, still_running);
+ if (mres != CURLM_OK && mres != CURLM_CALL_MULTI_PERFORM) {
+ CloseCurlConnection(conn);
+ return curl_multi_strerror(mres);
+ }
+
+ do {
+ int msgq = 0;
+ m = curl_multi_info_read(conn->multi, &msgq);
+ if (m && m->msg == CURLMSG_DONE && m->data.result != CURLE_OK) {
+ CloseCurlConnection(conn);
+ return curl_easy_strerror(m->data.result);
+ }
+ } while(m);
+
+ return NULL;
+}
+
+const char *OpenCurlConnection(CurlConnection *conn, char *URL, char *body)
+{
+ /* If the previous connect hung for so long that it's still active, then
+ * break the connection before we start a new one */
+ if (conn->running) {
+ CloseCurlConnection(conn);
+ }
+
+ if (conn->h) {
+ const char *errstr;
+ int still_running;
+ CURLcode res;
+ CURLMcode mres;
+ if (body) {
+ res = curl_easy_setopt(conn->h, CURLOPT_COPYPOSTFIELDS, body);
+ if (res != CURLE_OK) return curl_easy_strerror(res);
+ }
+ res = curl_easy_setopt(conn->h, CURLOPT_URL, URL);
+ if (res != CURLE_OK) return curl_easy_strerror(res);
+ res = curl_easy_setopt(conn->h, CURLOPT_WRITEFUNCTION, MetaConnWriteFunc);
+ if (res != CURLE_OK) return curl_easy_strerror(res);
+ res = curl_easy_setopt(conn->h, CURLOPT_WRITEDATA, conn);
+ if (res != CURLE_OK) return curl_easy_strerror(res);
+ res = curl_easy_setopt(conn->h, CURLOPT_HEADERFUNCTION, MetaConnHeaderFunc);
+ if (res != CURLE_OK) return curl_easy_strerror(res);
+ res = curl_easy_setopt(conn->h, CURLOPT_HEADERDATA, conn);
+ if (res != CURLE_OK) return curl_easy_strerror(res);
+
+ mres = curl_multi_add_handle(conn->multi, conn->h);
+ if (mres != CURLM_OK && mres != CURLM_CALL_MULTI_PERFORM) {
+ return curl_multi_strerror(mres);
+ }
+ conn->data = g_malloc(1);
+ conn->data_size = 0;
+ conn->headers = g_ptr_array_new_with_free_func(g_free);
+ conn->running = TRUE;
+ errstr = CurlConnectionPerform(conn, &still_running);
+ if (errstr) {
+ return errstr;
+ }
+ return NULL;
+ } else {
+ return "Could not init curl";
+ }
+}
+
+char *CurlNextLine(CurlConnection *conn, char *ch)
+{
+ char *sep_pt;
+ if (!ch) return NULL;
+ sep_pt = strchr(ch, conn->Terminator);
+ if (sep_pt) {
+ *sep_pt = '\0';
+ if (sep_pt > ch && sep_pt[-1] == conn->StripChar) {
+ sep_pt[-1] = '\0';
+ }
+ sep_pt++;
+ }
+ return sep_pt;
+}
+
gboolean OpenHttpConnection(HttpConnection **connpt, gchar *HostName,
unsigned Port, gchar *Proxy,
unsigned ProxyPort, const gchar *bindaddr,
(DIR) diff --git a/src/network.h b/src/network.h
t@@ -226,6 +226,13 @@ gchar *ExpandWriteBuffer(ConnBuf *conn, int numbytes, LastError **error);
void CommitWriteBuffer(NetworkBuffer *NetBuf, ConnBuf *conn, gchar *addpt,
guint addlen);
+void CurlInit(CurlConnection *conn);
+void CurlCleanup(CurlConnection *conn);
+const char *OpenCurlConnection(CurlConnection *conn, char *URL, char *body);
+void CloseCurlConnection(CurlConnection *conn);
+const char *CurlConnectionPerform(CurlConnection *conn, int *still_running);
+char *CurlNextLine(CurlConnection *conn, char *ch);
+
gboolean OpenHttpConnection(HttpConnection **conn, gchar *HostName,
unsigned Port, gchar *Proxy,
unsigned ProxyPort, const gchar *bindaddr,
(DIR) diff --git a/src/serverside.c b/src/serverside.c
t@@ -109,29 +109,6 @@ CurlConnection MetaConn;
static GScanner *Scanner;
-static size_t MetaConnWriteFunc(void *contents, size_t size, size_t nmemb, void *userp)
-{
- size_t realsize = size * nmemb;
- CurlConnection *conn = (CurlConnection *)userp;
-
- conn->data = g_realloc(conn->data, conn->data_size + realsize + 1);
- memcpy(&(conn->data[conn->data_size]), contents, realsize);
- conn->data_size += realsize;
- conn->data[conn->data_size] = 0;
-
- return realsize;
-}
-
-static size_t MetaConnHeaderFunc(char *contents, size_t size, size_t nmemb, void *userp)
-{
- size_t realsize = size * nmemb;
- CurlConnection *conn = (CurlConnection *)userp;
-
- gchar *str = g_strchomp(g_strndup(contents, realsize));
- g_ptr_array_add(conn->headers, (gpointer)str);
- return realsize;
-}
-
#endif
/* Handle to the high score file */
t@@ -185,118 +162,6 @@ static void MetaConnectError(CurlConnection *conn, const char *errstr)
MetaServer.URL, errstr);
}
-void CurlInit(CurlConnection *conn)
-{
- curl_global_init(CURL_GLOBAL_DEFAULT);
- conn->multi = curl_multi_init();
- conn->h = curl_easy_init();
- conn->running = FALSE;
- conn->Terminator = '\n';
- conn->StripChar = '\r';
- conn->data_size = 0;
- conn->headers = NULL;
-}
-
-void CloseCurlConnection(CurlConnection *conn)
-{
- curl_multi_remove_handle(conn->multi, conn->h);
- g_free(conn->data);
- conn->data_size = 0;
- conn->running = FALSE;
- g_ptr_array_free(conn->headers, TRUE);
- conn->headers = NULL;
-}
-
-void CurlCleanup(CurlConnection *conn)
-{
- if (conn->running) {
- CloseCurlConnection(conn);
- }
- curl_easy_cleanup(conn->h);
- curl_multi_cleanup(conn->multi);
- curl_global_cleanup();
-}
-
-const char *CurlConnectionPerform(CurlConnection *conn, int *still_running)
-{
- CURLMcode mres;
- struct CURLMsg *m;
-
- mres = curl_multi_perform(conn->multi, still_running);
- if (mres != CURLM_OK && mres != CURLM_CALL_MULTI_PERFORM) {
- CloseCurlConnection(conn);
- return curl_multi_strerror(mres);
- }
-
- do {
- int msgq = 0;
- m = curl_multi_info_read(conn->multi, &msgq);
- if (m && m->msg == CURLMSG_DONE && m->data.result != CURLE_OK) {
- CloseCurlConnection(conn);
- return curl_easy_strerror(m->data.result);
- }
- } while(m);
-
- return NULL;
-}
-
-const char *OpenCurlConnection(CurlConnection *conn, char *URL, char *body)
-{
- /* If the previous connect hung for so long that it's still active, then
- * break the connection before we start a new one */
- if (conn->running) {
- CloseCurlConnection(conn);
- }
-
- if (conn->h) {
- const char *errstr;
- int still_running;
- CURLcode res;
- CURLMcode mres;
- res = curl_easy_setopt(conn->h, CURLOPT_COPYPOSTFIELDS, body);
- if (res != CURLE_OK) return curl_easy_strerror(res);
- res = curl_easy_setopt(conn->h, CURLOPT_URL, URL);
- if (res != CURLE_OK) return curl_easy_strerror(res);
- res = curl_easy_setopt(conn->h, CURLOPT_WRITEFUNCTION, MetaConnWriteFunc);
- if (res != CURLE_OK) return curl_easy_strerror(res);
- res = curl_easy_setopt(conn->h, CURLOPT_WRITEDATA, conn);
- if (res != CURLE_OK) return curl_easy_strerror(res);
- res = curl_easy_setopt(conn->h, CURLOPT_HEADERFUNCTION, MetaConnHeaderFunc);
- if (res != CURLE_OK) return curl_easy_strerror(res);
- res = curl_easy_setopt(conn->h, CURLOPT_HEADERDATA, conn);
- if (res != CURLE_OK) return curl_easy_strerror(res);
-
- mres = curl_multi_add_handle(conn->multi, conn->h);
- if (mres != CURLM_OK && mres != CURLM_CALL_MULTI_PERFORM) {
- return curl_multi_strerror(mres);
- }
- conn->data = g_malloc(1);
- conn->data_size = 0;
- conn->headers = g_ptr_array_new_with_free_func(g_free);
- conn->running = TRUE;
- errstr = CurlConnectionPerform(conn, &still_running);
- if (errstr) {
- return errstr;
- }
- return NULL;
- } else {
- return "Could not init curl";
- }
-}
-
-char *CurlNextLine(CurlConnection *conn, char *ch)
-{
- char *sep_pt = strchr(ch, conn->Terminator);
- if (sep_pt) {
- *sep_pt = '\0';
- if (sep_pt > ch && sep_pt[-1] == MetaConn.StripChar) {
- sep_pt[-1] = '\0';
- }
- sep_pt++;
- }
- return sep_pt;
-}
-
void log_meta_headers(gpointer data, gpointer user_data)
{
char *header = data;