tFirst attempt using libcurl to connect to metaserver - 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 8b75b68f07617cbf489a17154c034c0e53353469
 (DIR) parent e7209ec919eb016fb80517108c65feb26a3d5179
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Thu, 29 Oct 2020 00:48:46 -0700
       
       First attempt using libcurl to connect to metaserver
       
       Diffstat:
         M src/Makefile.am                     |       2 +-
         M src/dopewars.c                      |      18 +++++-------------
         M src/dopewars.h                      |       5 ++---
         M src/message.c                       |       4 ++--
         M src/serverside.c                    |     148 ++++++++++++++++++++++---------
         M src/serverside.h                    |       2 +-
       
       6 files changed, 119 insertions(+), 60 deletions(-)
       ---
 (DIR) diff --git a/src/Makefile.am b/src/Makefile.am
       t@@ -21,7 +21,7 @@ CURSESPORTSUBDIR = cursesport
        endif
        
        SUBDIRS = $(GUISUBDIR) $(CURSESSUBDIR) $(GTKPORTSUBDIR) $(CURSESPORTSUBDIR) plugins
       -dopewars_LDADD = @GUILIB@ @CURSESLIB@ @GTKPORTLIB@ @CURSESPORTLIB@ @GTK_LIBS@ @LTLIBINTL@ @WNDRES@ @PLUGOBJS@ @PLUGLIBS@ @GLIB_LIBS@
       +dopewars_LDADD = @GUILIB@ @CURSESLIB@ @GTKPORTLIB@ @CURSESPORTLIB@ @GTK_LIBS@ @LTLIBINTL@ @WNDRES@ @PLUGOBJS@ @PLUGLIBS@ @GLIB_LIBS@ -lcurl
        dopewars_DEPENDENCIES = @GUILIB@ @CURSESLIB@ @GTKPORTLIB@ @CURSESPORTLIB@ @WNDRES@ @PLUGOBJS@
        
        bin_PROGRAMS = dopewars
 (DIR) diff --git a/src/dopewars.c b/src/dopewars.c
       t@@ -210,12 +210,12 @@ struct BITCH Bitch = {
        
        #ifdef NETWORKING
        struct METASERVER MetaServer = {
       -  FALSE, NULL, 0, NULL, 0, NULL, NULL, NULL,
       +  FALSE, NULL, NULL, 0, NULL, NULL,
          NULL, FALSE, NULL, NULL, NULL, NULL
        };
        
        struct METASERVER DefaultMetaServer = {
       -  TRUE, "dopewars.sourceforge.net", 80, "", 8080, "/metaserver.php",
       +  TRUE, "https://dopewars.sourceforge.io/metaserver.php", "", 8080,
          "", "", "dopewars server", FALSE, "", "", "", ""
        };
        
       t@@ -277,21 +277,15 @@ struct GLOBALS Globals[] = {
          {NULL, &MetaServer.Active, NULL, NULL, NULL, "MetaServer.Active",
           N_("TRUE if server should report to a metaserver"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0, 0},
       -  {NULL, NULL, NULL, &MetaServer.Name, NULL, "MetaServer.Name",
       -   N_("Metaserver name to report/get server details to/from"),
       +  {NULL, NULL, NULL, &MetaServer.URL, NULL, "MetaServer.URL",
       +   N_("Metaserver URL to report/get server details to/from"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0, 0},
       -  {&MetaServer.Port, NULL, NULL, NULL, NULL, "MetaServer.Port",
       -   N_("Port for metaserver communication"),
       -   NULL, NULL, 0, "", NULL, NULL, FALSE, 0, 65535},
          {NULL, NULL, NULL, &MetaServer.ProxyName, NULL, "MetaServer.ProxyName",
           N_("Name of a proxy for metaserver communication"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0, 0},
          {&MetaServer.ProxyPort, NULL, NULL, NULL, NULL, "MetaServer.ProxyPort",
           N_("Port for communicating with the proxy server"),
           NULL, NULL, 0, "", NULL, NULL, FALSE, 0, 65535},
       -  {NULL, NULL, NULL, &MetaServer.Path, NULL, "MetaServer.Path",
       -   N_("Path of the script on the metaserver"),
       -   NULL, NULL, 0, "", NULL, NULL, FALSE, 0, 0},
          {NULL, NULL, NULL, &MetaServer.LocalName, NULL, "MetaServer.LocalName",
           N_("Preferred hostname of your server machine"), NULL, NULL, 0, "",
           NULL, NULL, FALSE, 0, 0},
       t@@ -1682,12 +1676,10 @@ void CopyNames(struct NAMES *dest, struct NAMES *src)
        void CopyMetaServer(struct METASERVER *dest, struct METASERVER *src)
        {
          dest->Active = src->Active;
       -  dest->Port = src->Port;
          dest->ProxyPort = src->ProxyPort;
          dest->UseSocks = src->UseSocks;
       -  AssignName(&dest->Name, src->Name);
       +  AssignName(&dest->URL, src->URL);
          AssignName(&dest->ProxyName, src->ProxyName);
       -  AssignName(&dest->Path, src->Path);
          AssignName(&dest->LocalName, src->LocalName);
          AssignName(&dest->Password, src->Password);
          AssignName(&dest->Comment, src->Comment);
 (DIR) diff --git a/src/dopewars.h b/src/dopewars.h
       t@@ -100,11 +100,10 @@ struct SOUNDS {
        
        struct METASERVER {
          gboolean Active;
       -  gchar *Name;
       -  unsigned Port;
       +  gchar *URL;
          gchar *ProxyName;
          unsigned ProxyPort;
       -  gchar *Path, *LocalName, *Password, *Comment;
       +  gchar *LocalName, *Password, *Comment;
          gboolean UseSocks;
          gchar *authuser, *authpassword, *proxyuser, *proxypassword;
        };
 (DIR) diff --git a/src/message.c b/src/message.c
       t@@ -435,8 +435,8 @@ gboolean OpenMetaHttpConnection(HttpConnection **conn)
          gboolean retval;
        
          query = g_strdup_printf("%s?output=text&getlist=%d",
       -                          MetaServer.Path, METAVERSION);
       -  retval = OpenHttpConnection(conn, MetaServer.Name, MetaServer.Port,
       +                          MetaServer.URL, METAVERSION);
       +  retval = OpenHttpConnection(conn, MetaServer.URL, 80,
                                      MetaServer.ProxyName, MetaServer.ProxyPort,
                                      "",
                                      UseSocks
 (DIR) diff --git a/src/serverside.c b/src/serverside.c
       t@@ -28,6 +28,7 @@
        #include <string.h>
        #include <sys/types.h>          /* For size_t etc. */
        #include <sys/stat.h>
       +#include <curl/curl.h>
        
        #ifdef CYGWIN
        #include <windows.h>            /* For datatypes such as BOOL */
       t@@ -90,7 +91,7 @@ static char *attackquestiontr = N_("AE");
        int TerminateRequest, ReregisterRequest, RelogRequest;
        
        int MetaUpdateTimeout;
       -int MetaMinTimeout;
       +long MetaMinTimeout;
        gboolean WantQuit = FALSE;
        
        #ifdef CYGWIN
       t@@ -107,7 +108,38 @@ GSList *FirstServer = NULL;
        static GScanner *Scanner;
        
        /* Data waiting to be sent to/read from the metaserver */
       -HttpConnection *MetaConn = NULL;
       +CURLM *MetaConnM = NULL;
       +
       +struct _MetaServerConnection {
       +  CURL *h;
       +  gchar *data;
       +  size_t data_size;
       +  char Terminator;              /* Character that separates messages */
       +  char StripChar;               /* Char that should be removed
       +                                 * from messages */
       +};
       +
       +struct _MetaServerConnection MetaConn;
       +
       +static size_t MetaConnWriteFunc(void *contents, size_t size, size_t nmemb, void *userp)
       +{
       +  size_t realsize = size * nmemb;
       +  struct _MetaServerConnection *conn = (struct _MetaServerConnection *)userp;
       + 
       +  char *ptr = realloc(conn->data, conn->data_size + realsize + 1);
       +  if(ptr == NULL) {
       +    /* out of memory! */ 
       +    printf("not enough memory (realloc returned NULL)\n");
       +    return 0;
       +  }
       + 
       +  conn->data = ptr;
       +  memcpy(&(conn->data[conn->data_size]), contents, realsize);
       +  conn->data_size += realsize;
       +  conn->data[conn->data_size] = 0;
       + 
       +  return realsize;
       +}
        #endif
        
        /* Handle to the high score file */
       t@@ -155,9 +187,9 @@ static void MetaSocketStatus(NetworkBuffer *NetBuf,
        #endif
        
        #ifdef NETWORKING
       -static gboolean MetaConnectError(HttpConnection *conn)
       +static gboolean MetaConnectError(CURL *conn)
        {
       -  GString *errstr;
       +/*GString *errstr;
        
          if (!IsHttpError(conn))
            return FALSE;
       t@@ -165,7 +197,7 @@ static gboolean MetaConnectError(HttpConnection *conn)
          g_string_assign_error(errstr, MetaConn->NetBuf.error);
          dopelog(1, LF_SERVER, _("Failed to connect to metaserver at %s:%u (%s)"),
                  MetaServer.Name, MetaServer.Port, errstr->str);
       -  g_string_free(errstr, TRUE);
       +  g_string_free(errstr, TRUE);*/
          return TRUE;
        }
        
       t@@ -227,7 +259,7 @@ void RegisterWithMetaServer(gboolean Up, gboolean SendData,
        {
        #ifdef NETWORKING
          struct HISCORE MultiScore[NUMHISCORE], AntiqueScore[NUMHISCORE];
       -  GString *headers, *body;
       +  GString *body;
          gchar *prstr;
          gboolean retval;
          int i;
       t@@ -246,10 +278,13 @@ void RegisterWithMetaServer(gboolean Up, gboolean SendData,
        
          /* If the previous connect hung for so long that it's still active, then
           * break the connection before we start a new one */
       -  if (MetaConn)
       -    CloseHttpConnection(MetaConn);
       +  if (MetaConn.h) {
       +    curl_multi_remove_handle(MetaConnM, MetaConn.h);
       +    curl_easy_cleanup(MetaConn.h);
       +    MetaConn.h = NULL;
       +    free(MetaConn.data);
       +  }
        
       -  headers = g_string_new("");
          body = g_string_new("");
        
          g_string_assign(body, "output=text&");
       t@@ -284,35 +319,36 @@ void RegisterWithMetaServer(gboolean Up, gboolean SendData,
            }
          }
        
       -  g_string_printf(headers,
       -                   "Content-Type: application/x-www-form-urlencoded\n"
       -                   "Content-Length: %d", (int)strlen(body->str));
       -
       -  retval = OpenHttpConnection(&MetaConn, MetaServer.Name, MetaServer.Port,
       -                              MetaServer.ProxyName, MetaServer.ProxyPort,
       -                              BindAddress,
       -                              UseSocks && MetaServer.UseSocks ? &Socks : NULL,
       -                              "POST", MetaServer.Path, headers->str,
       -                              body->str);
       -  g_string_free(headers, TRUE);
       +  MetaConn.h = curl_easy_init();
       +  MetaConn.data = malloc(1);
       +  MetaConn.Terminator = '\n';
       +  MetaConn.StripChar = '\r';
       +  MetaConn.data_size = 0;
       +  if (MetaConn.h) {
       +    int still_running;
       +    curl_easy_setopt(MetaConn.h, CURLOPT_COPYPOSTFIELDS, body->str);
       +    curl_easy_setopt(MetaConn.h, CURLOPT_URL, MetaServer.URL);
       +    curl_easy_setopt(MetaConn.h, CURLOPT_WRITEFUNCTION, MetaConnWriteFunc);
       +    curl_easy_setopt(MetaConn.h, CURLOPT_WRITEDATA, &MetaConn);
       + 
       +    curl_multi_add_handle(MetaConnM, MetaConn.h);
       +    curl_multi_perform(MetaConnM, &still_running);
       +    dopelog(2, LF_SERVER, _("Waiting for connect to metaserver at %s..."),
       +            MetaServer.URL);
       +  }
          g_string_free(body, TRUE);
        
       -  if (retval) {
       -    dopelog(2, LF_SERVER, _("Waiting for connect to metaserver at %s:%u..."),
       -            MetaServer.Name, MetaServer.Port);
       -  } else {
       -    MetaConnectError(MetaConn);
       +/*  MetaConnectError(MetaConn);
            CloseHttpConnection(MetaConn);
            MetaConn = NULL;
       -    return;
       -  }
       -  SetHttpAuthFunc(MetaConn, ServerHttpAuth, NULL);
       +    return;*/
       +/*SetHttpAuthFunc(MetaConn, ServerHttpAuth, NULL);
        
          if (Socks.authuser && Socks.authuser[0] &&
              Socks.authpassword && Socks.authpassword[0]) {
            SetNetworkBufferUserPasswdFunc(&MetaConn->NetBuf, ServerNetBufAuth,
                                           NULL);
       -  }
       +  }*/
        #ifdef GUI_SERVER
          SetNetworkBufferCallBack(&MetaConn->NetBuf, MetaSocketStatus, NULL);
        #endif
       t@@ -952,7 +988,7 @@ void RequestServerShutdown(void)
         */
        gboolean IsServerShutdown(void)
        {
       -  return (WantQuit && !FirstServer && !MetaConn);
       +  return (WantQuit && !FirstServer && !MetaConn.h);
        }
        
        static GPrintFunc StartServerReply(NetworkBuffer *netbuf)
       t@@ -1182,6 +1218,9 @@ void ServerLoop(struct CMDLINE *cmdline)
        
          InitConfiguration(cmdline);
        
       +  curl_global_init(CURL_GLOBAL_DEFAULT);
       +  MetaConnM = curl_multi_init();
       +
          if (!StartServer())
            return;
        
       t@@ -1207,9 +1246,10 @@ void ServerLoop(struct CMDLINE *cmdline)
            FD_ZERO(&readfs);
            FD_ZERO(&writefs);
            FD_ZERO(&errorfs);
       +    curl_multi_fdset(MetaConnM, &readfs, &writefs, &errorfs, &topsock);
            FD_SET(ListenSock, &readfs);
            FD_SET(ListenSock, &errorfs);
       -    topsock = ListenSock + 1;
       +    topsock = MAX(topsock + 1, ListenSock + 1);
        #ifndef CYGWIN
            if (localsock >= 0) {
              FD_SET(localsock, &readfs);
       t@@ -1223,10 +1263,6 @@ void ServerLoop(struct CMDLINE *cmdline)
                                        &topsock);
            }
        #endif
       -    if (MetaConn) {
       -      SetSelectForNetworkBuffer(&MetaConn->NetBuf, &readfs, &writefs,
       -                                &errorfs, &topsock);
       -    }
            for (list = FirstServer; list; list = g_slist_next(list)) {
              tmp = (Player *)list->data;
              if (!IsCop(tmp)) {
       t@@ -1311,8 +1347,11 @@ void ServerLoop(struct CMDLINE *cmdline)
            if (IsServerShutdown())
              break;
        #endif
       -    if (MetaConn) {
       -      if (RespondToSelect(&MetaConn->NetBuf, &readfs, &writefs,
       +    if (MetaConn.h) {
       +      int still_running;
       +      curl_multi_perform(MetaConnM, &still_running);
       +//    dopelog(2, LF_SERVER, "MetaServer multi_perform: %d", still_running);
       +/*    if (RespondToSelect(&MetaConn->NetBuf, &readfs, &writefs,
                                  &errorfs, &DoneOK)) {
                while ((buf = ReadHttpResponse(MetaConn, &DoneOK))) {
                  gboolean ReadingBody = (MetaConn->Status == HS_READBODY);
       t@@ -1331,6 +1370,30 @@ void ServerLoop(struct CMDLINE *cmdline)
                MetaConn = NULL;
                if (IsServerShutdown())
                  break;
       +      } */
       +      if (still_running == 0) {
       +        char *ch = MetaConn.data;
       +        while(ch && *ch) {
       +          char *sep_pt = strchr(ch, MetaConn.Terminator);
       +          if (sep_pt) {
       +            *sep_pt = '\0';
       +            if (sep_pt > ch && sep_pt[-1] == MetaConn.StripChar) {
       +              sep_pt[-1] = '\0';
       +            }
       +            sep_pt++;
       +          }
       +          if (*ch) {
       +            dopelog(2, LF_SERVER, "MetaServer: %s", ch);
       +          }
       +          ch = sep_pt;
       +        }
       +        dopelog(4, LF_SERVER, "MetaServer: (closed)\n");
       +        curl_multi_remove_handle(MetaConnM, MetaConn.h);
       +        curl_easy_cleanup(MetaConn.h);
       +        MetaConn.h = NULL;
       +        free(MetaConn.data);
       +        if (IsServerShutdown())
       +          break;
              }
            }
        
       t@@ -1365,6 +1428,10 @@ void ServerLoop(struct CMDLINE *cmdline)
        #endif
          StopServer();
          g_string_free(LineBuf, TRUE);
       +
       +  curl_multi_cleanup(MetaConnM);
       +
       +  curl_global_cleanup();
        }
        
        #ifdef GUI_SERVER
       t@@ -3703,7 +3770,7 @@ void ClearFightTimeout(Player *Play)
         * unless "mintime" is already smaller (as long as it's not -1, which
         * means "uninitialized"). Returns 1 if the timeout has already expired.
         */
       -int AddTimeout(time_t timeout, time_t timenow, int *mintime)
       +long AddTimeout(time_t timeout, time_t timenow, long *mintime)
        {
          if (timeout == 0)
            return 0;
       t@@ -3721,14 +3788,15 @@ int AddTimeout(time_t timeout, time_t timenow, int *mintime)
         * an event has already expired, returns 0. If no events are pending,
         * returns -1. "First" should point to a list of valid players.
         */
       -int GetMinimumTimeout(GSList *First)
       +long GetMinimumTimeout(GSList *First)
        {
          Player *Play;
          GSList *list;
       -  int mintime = -1;
       +  long mintime = -1;
          time_t timenow;
        
          timenow = time(NULL);
       +  curl_multi_timeout(MetaConnM, &mintime);
          if (AddTimeout(MetaMinTimeout, timenow, &mintime))
            return 0;
          if (AddTimeout(MetaUpdateTimeout, timenow, &mintime))
 (DIR) diff --git a/src/serverside.h b/src/serverside.h
       t@@ -52,7 +52,7 @@ int LoseBitch(Player *Play, Inventory *Guns, Inventory *Drugs);
        void GainBitch(Player *Play);
        void SetFightTimeout(Player *Play);
        void ClearFightTimeout(Player *Play);
       -int GetMinimumTimeout(GSList *First);
       +long GetMinimumTimeout(GSList *First);
        GSList *HandleTimeouts(GSList *First);
        void ConvertHighScoreFile(const gchar *convertfile);
        void OpenHighScoreFile(void);