tAdd basic metaserver support to GUI 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 0eda1a10d2f68195b4e12ec9c938f59100b6099b
 (DIR) parent ac4948ce0b970217f9ea743531da1ee3b963b8fa
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Sun,  1 Nov 2020 23:20:10 -0800
       
       Add basic metaserver support to GUI client
       
       Diffstat:
         M src/gui_client/gtk_client.c         |       9 ++++++++-
         M src/gui_client/newgamedia.c         |     189 +++++++++++++++++++++++++++----
         M src/gui_client/newgamedia.h         |       2 +-
       
       3 files changed, 178 insertions(+), 22 deletions(-)
       ---
 (DIR) diff --git a/src/gui_client/gtk_client.c b/src/gui_client/gtk_client.c
       t@@ -109,6 +109,9 @@ static void GetClientMessage(gpointer data, gint socket,
                                     GdkInputCondition condition);
        void SocketStatus(NetworkBuffer *NetBuf, gboolean Read, gboolean Write,
                          gboolean CallNow);
       +
       +/* Data waiting to be sent to/read from the metaserver */
       +CurlConnection MetaConn;
        #endif /* NETWORKING */
        
        static void HandleClientMessage(char *buf, Player *Play);
       t@@ -264,7 +267,7 @@ void NewGame(GtkWidget *widget, gpointer data)
          BackupConfig();
        
        #ifdef NETWORKING
       -  NewGameDialog(ClientData.Play, SocketStatus);
       +  NewGameDialog(ClientData.Play, SocketStatus, &MetaConn);
        #else
          NewGameDialog(ClientData.Play);
        #endif
       t@@ -2339,8 +2342,12 @@ gboolean GtkLoop(int *argc, char **argv[],
        
          SetIcon(window, dopewars_pill_xpm);
        
       +  CurlInit(&MetaConn);
       +
          gtk_main();
        
       +  CurlCleanup(&MetaConn);
       +
          /* Free the main player */
          FirstClient = RemovePlayer(ClientData.Play, FirstClient);
        
 (DIR) diff --git a/src/gui_client/newgamedia.c b/src/gui_client/newgamedia.c
       t@@ -41,7 +41,7 @@ struct StartGameStruct {
                    *metaserv, *notebook;
          Player *play;
        #ifdef NETWORKING
       -  HttpConnection *MetaConn;
       +  CurlConnection *MetaConn;
          GSList *NewMetaList;
          NBCallBack sockstat;
        #endif
       t@@ -56,6 +56,7 @@ static void MetaSocksAuthDialog(NetworkBuffer *netbuf, gpointer data);
        static void SocksAuthDialog(NetworkBuffer *netbuf, gpointer data);
        static void MetaSocketStatus(NetworkBuffer *NetBuf, gboolean Read,
                                     gboolean Write, gboolean CallNow);
       +static void FillMetaServerList(gboolean UseNewList);
        
        /* List of servers on the metaserver */
        static GSList *MetaList = NULL;
       t@@ -86,15 +87,154 @@ static void SetStartGameStatus(gchar *msg)
        }
        
        #ifdef NETWORKING
       +
       +/* Global information, common to all connections */
       +typedef struct _GlobalData {
       +  CURLM *multi;
       +  guint timer_event;
       +  int still_running;
       +} GlobalData;
       +
       +/* Information associated with a specific socket */
       +typedef struct _SockData {
       +  curl_socket_t sockfd;
       +  CURL *easy;
       +  int action;
       +  long timeout;
       +  GIOChannel *ch;
       +  guint ev;
       +  GlobalData *global;
       +} SockData;
       +
       +GlobalData global_data;
       +
       +/* Called by glib when we get action on a multi socket */
       +static gboolean glib_socket(GIOChannel *ch, GIOCondition condition, gpointer data)
       +{
       +  GlobalData *g = (GlobalData*) data;
       +  CURLMcode rc;
       +  int fd = g_io_channel_unix_get_fd(ch);
       +  fprintf(stderr, "bw> glib socket\n");
       +  int action =
       +    ((condition & G_IO_IN) ? CURL_CSELECT_IN : 0) |
       +    ((condition & G_IO_OUT) ? CURL_CSELECT_OUT : 0);
       +
       +  rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
       +  if (rc != CURLM_OK) fprintf(stderr, "action %d %s\n", rc, curl_multi_strerror(rc));
       +  if (g->still_running) {
       +    return TRUE;
       +  } else {
       +    fprintf(stderr, "got data %s\n", stgam.MetaConn->data);
       +    fprintf(stderr, "last transfer done, kill timeout\n");
       +    if (g->timer_event) {
       +      g_source_remove(g->timer_event);
       +      g->timer_event = 0;
       +    }
       +    HandleWaitingMetaServerData(stgam.MetaConn, &stgam.NewMetaList);
       +    SetStartGameStatus(NULL);
       +    CloseCurlConnection(stgam.MetaConn);
       +    FillMetaServerList(TRUE);
       +    return FALSE;
       +  }
       +}
       +
       +static gboolean glib_timeout(gpointer userp)
       +{
       +  GlobalData *g = userp;
       +  CURLMcode rc;
       +  fprintf(stderr, "bw> glib_timeout\n");
       +  rc = curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0, &g->still_running);
       +  if (rc != CURLM_OK) fprintf(stderr, "action %d %s\n", rc, curl_multi_strerror(rc));
       +  g->timer_event = 0;
       +  return G_SOURCE_REMOVE;
       +}
       +
       +int timer_cb(CURLM *multi, long timeout_ms, void *userp)
       +{
       +  fprintf(stderr, "bw> timer_cb %ld\n", timeout_ms);
       +  GlobalData *g = userp;
       +
       +  if (g->timer_event) {
       +    g_source_remove(g->timer_event);
       +    g->timer_event = 0;
       +  }
       +
       +  /* -1 means we should just delete our timer. */
       +  if (timeout_ms >= 0) {
       +    g->timer_event = g_timeout_add(timeout_ms, glib_timeout, g);
       +  }
       +  return 0;
       +}
       +
       +/* Clean up the SockData structure */
       +static void remsock(SockData *f)
       +{
       +  if (!f) {
       +    return;
       +  }
       +  if (f->ev) {
       +    g_source_remove(f->ev);
       +  }
       +  g_free(f);
       +}
       +
       +/* Assign information to a SockData structure */
       +static void setsock(SockData *f, curl_socket_t s, CURL *e, int act,
       +                    GlobalData *g)
       +{
       +  GIOCondition kind =
       +    ((act & CURL_POLL_IN) ? G_IO_IN : 0) |
       +    ((act & CURL_POLL_OUT) ? G_IO_OUT : 0);
       +
       +  f->sockfd = s;
       +  f->action = act;
       +  f->easy = e;
       +  if (f->ev) {
       +    g_source_remove(f->ev);
       +  }
       +  f->ev = g_io_add_watch(f->ch, kind, glib_socket, g);
       +}
       +
       +/* Initialize a new SockData structure */
       +static void addsock(curl_socket_t s, CURL *easy, int action, GlobalData *g)
       +{
       +  SockData *fdp = g_malloc0(sizeof(SockData));
       +
       +  fdp->global = g;
       +  fdp->ch = g_io_channel_unix_new(s);
       +  setsock(fdp, s, easy, action, g);
       +  curl_multi_assign(g->multi, s, fdp);
       +}
       +
       +int socket_cb(CURL *easy, curl_socket_t s, int  what, void *userp,
       +              void *socketp)
       +{
       +  GlobalData *g = userp;
       +  SockData *fdp = socketp;
       +  static const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
       +  fprintf(stderr, "bw> socket_cb s=%d %d what=%s\n", s, what, whatstr[what]);
       +  if (what == CURL_POLL_REMOVE) {
       +    fprintf(stderr, "remove socket\n");
       +    remsock(fdp);
       +  } else if (!fdp) {
       +    fprintf(stderr, "add socket\n");
       +    addsock(s, easy, what, g);
       +  } else {
       +    fprintf(stderr, "change socket\n");
       +    setsock(fdp, s, easy, what, g);
       +  }
       +  return 0;
       +}
       +
        static void ConnectError(gboolean meta)
        {
          GString *neterr;
          gchar *text;
          LastError *error;
        
       -  if (meta)
       +/*if (meta)
            error = stgam.MetaConn->NetBuf.error;
       -  else
       +  else*/
            error = stgam.play->NetBuf.error;
        
          neterr = g_string_new("");
       t@@ -149,9 +289,8 @@ static void DoConnect(void)
        
          /* Terminate any existing connection attempts */
          ShutdownNetworkBuffer(NetBuf);
       -  if (stgam.MetaConn) {
       -    CloseHttpConnection(stgam.MetaConn);
       -    stgam.MetaConn = NULL;
       +  if (stgam.MetaConn->running) {
       +    CloseCurlConnection(stgam.MetaConn);
          }
        
          oldstatus = NetBuf->status;
       t@@ -242,13 +381,13 @@ void DisplayConnectStatus(gboolean meta,
          NBSocksStatus sockstat;
          gchar *text;
        
       -  if (meta) {
       +/*if (meta) {
            status = stgam.MetaConn->NetBuf.status;
            sockstat = stgam.MetaConn->NetBuf.sockstat;
       -  } else {
       +  } else {*/
            status = stgam.play->NetBuf.status;
            sockstat = stgam.play->NetBuf.sockstat;
       -  }
       +//}
          if (oldstatus == status && sockstat == oldsocks)
            return;
        
       t@@ -293,13 +432,12 @@ void DisplayConnectStatus(gboolean meta,
        
        static void MetaDone(void)
        {
       -  if (IsHttpError(stgam.MetaConn)) {
       +/*if (IsHttpError(stgam.MetaConn)) {
            ConnectError(TRUE);
       -  } else {
       +  } else {*/
            SetStartGameStatus(NULL);
       -  }
       -  CloseHttpConnection(stgam.MetaConn);
       -  stgam.MetaConn = NULL;
       +//}
       +  CloseCurlConnection(stgam.MetaConn);
          FillMetaServerList(TRUE);
        }
        
       t@@ -351,12 +489,12 @@ static void UpdateMetaServerList(GtkWidget *widget)
        {
          GtkWidget *metaserv;
          gchar *text;
       +  const char *merr;
        
          /* Terminate any existing connection attempts */
          ShutdownNetworkBuffer(&stgam.play->NetBuf);
       -  if (stgam.MetaConn) {
       -    CloseHttpConnection(stgam.MetaConn);
       -    stgam.MetaConn = NULL;
       +  if (stgam.MetaConn->running) {
       +    CloseCurlConnection(stgam.MetaConn);
          }
        
          ClearServerList(&stgam.NewMetaList);
       t@@ -367,6 +505,10 @@ static void UpdateMetaServerList(GtkWidget *widget)
          SetStartGameStatus(text);
          g_free(text);
        
       +  if ((merr = OpenMetaHttpConnection(stgam.MetaConn))) {
       +    ConnectError(TRUE);
       +  } else {
       +  }
          /*
          if (OpenMetaHttpConnection(&stgam.MetaConn)) {
            metaserv = stgam.metaserv;
       t@@ -422,7 +564,7 @@ static void CloseNewGameDia(GtkWidget *widget, gpointer data)
            ShutdownNetworkBuffer(&stgam.play->NetBuf);
          }
          if (stgam.MetaConn) {
       -    CloseHttpConnection(stgam.MetaConn);
       +    CloseCurlConnection(stgam.MetaConn);
            stgam.MetaConn = NULL;
          }
          ClearServerList(&stgam.NewMetaList);
       t@@ -445,7 +587,7 @@ static void metalist_row_unselect(GtkWidget *clist, gint row, gint column,
        }
        
        #ifdef NETWORKING
       -void NewGameDialog(Player *play, NBCallBack sockstat)
       +void NewGameDialog(Player *play, NBCallBack sockstat, CurlConnection *MetaConn)
        #else
        void NewGameDialog(Player *play)
        #endif
       t@@ -456,10 +598,17 @@ void NewGameDialog(Player *play)
          guint AccelKey;
        
        #ifdef NETWORKING
       +  global_data.multi = MetaConn->multi;
       +  global_data.timer_event = 0;
          GtkWidget *clist, *scrollwin, *table, *hbbox;
          gchar *server_titles[5], *ServerEntry, *text;
          gboolean UpdateMeta = FALSE;
        
       +  curl_multi_setopt(MetaConn->multi, CURLMOPT_TIMERFUNCTION, timer_cb);
       +  curl_multi_setopt(MetaConn->multi, CURLMOPT_TIMERDATA, &global_data);
       +  curl_multi_setopt(MetaConn->multi, CURLMOPT_SOCKETFUNCTION, socket_cb);
       +  curl_multi_setopt(MetaConn->multi, CURLMOPT_SOCKETDATA, &global_data);
       +
          /* Column titles of metaserver information */
          server_titles[0] = _("Server");
          server_titles[1] = _("Port");
       t@@ -467,7 +616,7 @@ void NewGameDialog(Player *play)
          server_titles[3] = _("Players");
          server_titles[4] = _("Comment");
        
       -  stgam.MetaConn = NULL;
       +  stgam.MetaConn = MetaConn;
          stgam.NewMetaList = NULL;
          stgam.sockstat = sockstat;
        
 (DIR) diff --git a/src/gui_client/newgamedia.h b/src/gui_client/newgamedia.h
       t@@ -32,7 +32,7 @@
        #include "network.h"
        
        #ifdef NETWORKING
       -void NewGameDialog(Player *play, NBCallBack sockstat);
       +void NewGameDialog(Player *play, NBCallBack sockstat, CurlConnection *MetaConn);
        void DisplayConnectStatus(gboolean meta, NBStatus oldstatus,
                                  NBSocksStatus oldsocks);
        void FinishServerConnect(gboolean ConnectOK);