Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2005:
[Freeciv-Dev] (PR#13714) rewrite server-querying code
Home

[Freeciv-Dev] (PR#13714) rewrite server-querying code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#13714) rewrite server-querying code
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 19 Aug 2005 17:45:52 -0700
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=13714 >

This is a preliminary patch to rewrite the interface and backend for the 
server-querying code.

Metaserver queries are now non-blocking.  However in practice this 
doesn't help very much because they still use gethostbyname which blocks 
waiting for DNS resolution.  The only way to get around this is to use a 
resolver library like libadns.

This should use select (gdk_input_add) in the GUI code to avoid polling. 
  However instead we just poll.  This isn't a problem since it's what 
the LAN code does anyway and we poll often (100 ms) and there's nothing 
else going on in the program while the networks tab is open anyway.


It also fixes two major problems in the LAN querying:

1.  Only one new server can be read per second since after the first 
read the function just returns.

2.  Every second the entire list is refreshed, even if nothing happens. 
  This is not a problem if it's only once per second.  However once per 
second is not very good; we should do a query every 100 ms and only 
refresh the list display widget when a new server is actually received.


Despite the blocking on gethostbyname this patch is a major improvement 
I think.  However it will need some more scrutiny and needs to be 
cleaned up a bit.

-jason

Index: client/servers.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/servers.c,v
retrieving revision 1.1
diff -p -u -r1.1 servers.c
--- client/servers.c    19 Aug 2005 20:52:58 -0000      1.1
+++ client/servers.c    20 Aug 2005 00:39:49 -0000
@@ -71,8 +71,26 @@
 
 #include "gui_main_g.h"
 
-static int socklan;
-static struct server_list *lan_servers;
+struct server_scan {
+  enum server_scan_type type;
+  ServerScanErrorFunc error_func;
+
+  struct server_list *servers;
+  int sock;
+
+  /* Only used for metaserver */
+  struct {
+    enum {
+      META_CONNECTING,
+      META_WAITING,
+      META_DONE
+    } state;
+    char name[MAX_LEN_ADDR];
+    int port;
+    const char *urlpath;
+    FILE *fp; /* temp file */
+  } meta;
+};
 
 /**************************************************************************
  The server sends a stream in a registry 'ini' type format.
@@ -150,48 +168,17 @@ static struct server_list *parse_metaser
   return server_list;
 }
 
-/**************************************************************************
- Create the list of servers from the metaserver
- The result must be free'd with delete_server_list() when no
- longer used
-**************************************************************************/
-struct server_list *create_server_list(char *errbuf, int n_errbuf)
+/****************************************************************************
+  Send the request string to the metaserver.
+****************************************************************************/
+static void meta_send_request(struct server_scan *scan)
 {
-  union my_sockaddr addr;
-  int s;
-  fz_FILE *f;
-  const char *urlpath;
-  char metaname[MAX_LEN_ADDR];
-  int metaport;
   const char *capstr;
   char str[MAX_LEN_PACKET];
-  char machine_string[128];
 #ifdef HAVE_UNAME
   struct utsname un;
 #endif 
-
-  urlpath = my_lookup_httpd(metaname, &metaport, METALIST_ADDR);//metaserver);
-  if (!urlpath) {
-    (void) mystrlcpy(errbuf, _("Invalid $http_proxy or metaserver value, must "
-                              "start with 'http://'"), n_errbuf);
-    return NULL;
-  }
-
-  if (!net_lookup_service(metaname, metaport, &addr)) {
-    (void) mystrlcpy(errbuf, _("Failed looking up metaserver's host"), 
n_errbuf);
-    return NULL;
-  }
-  
-  if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
-    (void) mystrlcpy(errbuf, mystrerror(), n_errbuf);
-    return NULL;
-  }
-  
-  if(connect(s, (struct sockaddr *) &addr.sockaddr, sizeof(addr)) == -1) {
-    (void) mystrlcpy(errbuf, mystrerror(), n_errbuf);
-    my_closesocket(s);
-    return NULL;
-  }
+  char machine_string[128];
 
 #ifdef HAVE_UNAME
   uname(&un);
@@ -222,30 +209,186 @@ struct server_list *create_server_list(c
     "Content-Length: %lu\r\n"
     "\r\n"
     "client_cap=%s\r\n",
-    urlpath,
-    metaname, metaport,
+    scan->meta.urlpath,
+    scan->meta.name, scan->meta.port,
     VERSION_STRING, client_string, machine_string,
     (unsigned long) (strlen("client_cap=") + strlen(capstr)),
     capstr);
 
-  f = my_querysocket(s, str, strlen(str));
+  if (my_writesocket(scan->sock, str, strlen(str)) != strlen(str)) {
+    /* Even with non-blocking this shouldn't fail. */
+    (scan->error_func)(scan, mystrerror());
+    return;
+  }
 
-  if (f == NULL) {
-    /* TRANS: This means a network error when trying to connect to
-     * the metaserver.  The message will be shown directly to the user. */
-    (void) mystrlcpy(errbuf, _("Failed querying socket"), n_errbuf);
-    return NULL;
+  scan->meta.state = META_WAITING;
+}
+
+/****************************************************************************
+  Read the request string (or part of it) from the metaserver.
+****************************************************************************/
+static void meta_read_response(struct server_scan *scan)
+{
+  char buf[4096];
+  int result;
+
+  if (!scan->meta.fp) {
+#ifdef WIN32_NATIVE
+    char filename[MAX_PATH];
+
+    GetTempPath(sizeof(filename), filename);
+    cat_snprintf(filename, sizeof(filename) "fctmp%d", myrand());
+
+    scan->meta.fp = fopen(filename, "w+b");
+#else
+    scan->meta.fp = tmpfile();
+#endif
+
+    if (!scan->meta.fp) {
+      (scan->error_func)(scan, _("Could not open temp file."));
+    }
+  }
+
+  while (1) {
+    result = my_readsocket(scan->sock, buf, sizeof(buf));
+
+    if (result < 0) {
+      if (errno == EAGAIN || errno == EINTR) {
+       /* Keep waiting. */
+       return;
+      }
+      (scan->error_func)(scan, mystrerror());
+      return;
+    } else if (result == 0) {
+      fz_FILE *f;
+      char str[4096];
+
+      /* We're done! */
+      rewind(scan->meta.fp);
+
+      f = fz_from_stream(scan->meta.fp);
+      assert(f != NULL);
+
+
+      /* skip HTTP headers */
+      /* XXX: TODO check for magic Content-Type: text/x-ini -vasc */
+      while (fz_fgets(str, sizeof(str), f) && strcmp(str, "\r\n") != 0) {
+       /* nothing */
+      }
+
+      /* XXX: TODO check for magic Content-Type: text/x-ini -vasc */
+
+      /* parse HTTP message body */
+      scan->servers = parse_metaserver_data(f);
+      scan->meta.state = META_DONE;
+      return;
+    } else {
+      if (fwrite(buf, 1, result, scan->meta.fp) < 0) {
+       (scan->error_func)(scan, mystrerror());
+      }
+    }
+  }
+}
+
+/****************************************************************************
+  Begin a metaserver scan for servers.  This just initiates the connection
+  to the metaserver; later get_meta_server_list should be called whenever
+  the socket has data pending to read and parse it.
+
+  Returns FALSE on error (in which case errbuf will contain an error
+  message).
+****************************************************************************/
+static bool begin_metaserver_scan(struct server_scan *scan)
+{
+  union my_sockaddr addr;
+  int s;
+
+  scan->meta.urlpath = my_lookup_httpd(scan->meta.name, &scan->meta.port,
+                                      METALIST_ADDR);
+  if (!scan->meta.urlpath) {
+    (scan->error_func)(scan,
+                      _("Invalid $http_proxy or metaserver value, must "
+                        "start with 'http://'"));
+    return FALSE;
+  }
+
+  if (!net_lookup_service(scan->meta.name, scan->meta.port, &addr)) {
+    (scan->error_func)(scan, _("Failed looking up metaserver's host"));
+    return FALSE;
+  }
+  
+  if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+    (scan->error_func)(scan, mystrerror());
+    return FALSE;
+  }
+
+  my_nonblock(s);
+  
+  if (connect(s, (struct sockaddr *) &addr.sockaddr, sizeof(addr)) == -1) {
+    if (errno == EINPROGRESS) {
+      /* With non-blocking sockets this is the expected result. */
+      scan->meta.state = META_CONNECTING;
+      scan->sock = s;
+    } else {
+      my_closesocket(s);
+      (scan->error_func)(scan, mystrerror());
+      return FALSE;
+    }
+  } else {
+    /* Instant connection?  Whoa. */
+    scan->sock = s;
+    scan->meta.state = META_CONNECTING;
+    meta_send_request(scan);
   }
 
-  /* skip HTTP headers */
-  while (fz_fgets(str, sizeof(str), f) && strcmp(str, "\r\n") != 0) {
-    /* nothing */
+  return TRUE;
+}
+
+/**************************************************************************
+ Create the list of servers from the metaserver
+ The result must be free'd with delete_server_list() when no
+ longer used
+**************************************************************************/
+static struct server_list *get_metaserver_list(struct server_scan *scan)
+{
+  struct timeval tv = {.tv_sec = 0, .tv_usec = 0};
+  fd_set sockset;
+
+  if (scan->sock < 0) {
+    return NULL;
   }
 
-  /* XXX: TODO check for magic Content-Type: text/x-ini -vasc */
+  FD_ZERO(&sockset);
+  FD_SET(scan->sock, &sockset);
 
-  /* parse HTTP message body */
-  return parse_metaserver_data(f);
+  switch (scan->meta.state) {
+  case META_CONNECTING:
+    if (select(scan->sock + 1, NULL, &sockset, NULL, &tv) < 0) {
+      (scan->error_func)(scan, mystrerror());
+    } else if (FD_ISSET(scan->sock, &sockset)) {
+      meta_send_request(scan);
+    } else {
+      /* Keep waiting. */
+    }
+    return NULL;
+  case META_WAITING:
+    if (select(scan->sock + 1, &sockset, NULL, NULL, &tv) < 0) {
+      (scan->error_func)(scan, mystrerror());
+    } else if (FD_ISSET(scan->sock, &sockset)) {
+      meta_read_response(scan);
+      return scan->servers;
+    } else {
+      /* Keep waiting. */
+    }
+    return NULL;
+  case META_DONE:
+    /* We already have a server list but we don't return it since it hasn't
+     * changed. */
+    return NULL;
+  }
+
+  assert(0);
+  return NULL;
 }
 
 /**************************************************************************
@@ -253,7 +396,7 @@ struct server_list *create_server_list(c
  the server list itself (so the server_list is no longer
  valid after calling this function)
 **************************************************************************/
-void delete_server_list(struct server_list *server_list)
+static void delete_server_list(struct server_list *server_list)
 {
   server_list_iterate(server_list, ptmp) {
     int i;
@@ -288,7 +431,7 @@ void delete_server_list(struct server_li
   about the server. The packet is send to all Freeciv servers in the same
   multicast group as the client.
 **************************************************************************/
-int begin_lanserver_scan(void)
+static bool begin_lanserver_scan(struct server_scan *scan)
 {
   union my_sockaddr addr;
   struct data_out dout;
@@ -302,7 +445,7 @@ int begin_lanserver_scan(void)
   /* Create a socket for broadcasting to servers. */
   if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
     freelog(LOG_ERROR, "socket failed: %s", mystrerror());
-    return 0;
+    return FALSE;
   }
 
   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
@@ -322,13 +465,13 @@ int begin_lanserver_scan(void)
   if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, 
                  sizeof(ttl))) {
     freelog(LOG_ERROR, "setsockopt failed: %s", mystrerror());
-    return 0;
+    return FALSE;
   }
 
   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, 
                  sizeof(opt))) {
     freelog(LOG_ERROR, "setsockopt failed: %s", mystrerror());
-    return 0;
+    return FALSE;
   }
 
   dio_output_init(&dout, buffer, sizeof(buffer));
@@ -339,7 +482,7 @@ int begin_lanserver_scan(void)
   if (sendto(sock, buffer, size, 0, &addr.sockaddr,
       sizeof(addr)) < 0) {
     freelog(LOG_ERROR, "sendto failed: %s", mystrerror());
-    return 0;
+    return FALSE;
   } else {
     freelog(LOG_DEBUG, ("Sending request for server announcement on LAN."));
   }
@@ -347,14 +490,14 @@ int begin_lanserver_scan(void)
   my_closesocket(sock);
 
   /* Create a socket for listening for server packets. */
-  if ((socklan = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-    freelog(LOG_ERROR, "socket failed: %s", mystrerror());
-    return 0;
+  if ((scan->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+    (scan->error_func)(scan, mystrerror());
+    return FALSE;
   }
 
-  my_nonblock(socklan);
+  my_nonblock(scan->sock);
 
-  if (setsockopt(socklan, SOL_SOCKET, SO_REUSEADDR,
+  if (setsockopt(scan->sock, SOL_SOCKET, SO_REUSEADDR,
                  (char *)&opt, sizeof(opt)) == -1) {
     freelog(LOG_ERROR, "SO_REUSEADDR failed: %s", mystrerror());
   }
@@ -364,30 +507,30 @@ int begin_lanserver_scan(void)
   addr.sockaddr_in.sin_addr.s_addr = htonl(INADDR_ANY); 
   addr.sockaddr_in.sin_port = htons(SERVER_LAN_PORT + 1);
 
-  if (bind(socklan, &addr.sockaddr, sizeof(addr)) < 0) {
-    freelog(LOG_ERROR, "bind failed: %s", mystrerror());
-    return 0;
+  if (bind(scan->sock, &addr.sockaddr, sizeof(addr)) < 0) {
+    (scan->error_func)(scan, mystrerror());
+    return FALSE;
   }
 
   mreq.imr_multiaddr.s_addr = inet_addr(group);
   mreq.imr_interface.s_addr = htonl(INADDR_ANY);
-  if (setsockopt(socklan, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
+  if (setsockopt(scan->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
                  (const char*)&mreq, sizeof(mreq)) < 0) {
-    freelog(LOG_ERROR, "setsockopt failed: %s", mystrerror());
-    return 0;
+    (scan->error_func)(scan, mystrerror());
+    return FALSE;
   }
 
-  lan_servers = server_list_new();
+  scan->servers = server_list_new();
 
-  return 1;
+  return TRUE;
 }
 
 /**************************************************************************
   Listens for UDP packets broadcasted from a server that responded
   to the request-packet sent from the client. 
 **************************************************************************/
-struct server_list *get_lan_server_list(void) {
-
+static struct server_list *get_lan_server_list(struct server_scan *scan)
+{
 # if defined(__VMS) && !defined(_DECC_V4_SOURCE)
   size_t fromlen;
 # else
@@ -406,85 +549,152 @@ struct server_list *get_lan_server_list(
   char message[1024];
   fd_set readfs, exceptfs;
   struct timeval tv;
+  bool found_new = FALSE;
 
   FD_ZERO(&readfs);
   FD_ZERO(&exceptfs);
-  FD_SET(socklan, &exceptfs);
-  FD_SET(socklan, &readfs);
+  FD_SET(scan->sock, &exceptfs);
+  FD_SET(scan->sock, &readfs);
   tv.tv_sec = 0;
   tv.tv_usec = 0;
 
-  while (select(socklan + 1, &readfs, NULL, &exceptfs, &tv) == -1) {
+  while (select(scan->sock + 1, &readfs, NULL, &exceptfs, &tv) == -1) {
     if (errno != EINTR) {
-      freelog(LOG_ERROR, "select failed: %s", mystrerror());
-      return lan_servers;
+      (scan->error_func)(scan, mystrerror());
+      return NULL;
     }
     /* EINTR can happen sometimes, especially when compiling with -pg.
      * Generally we just want to run select again. */
   }
 
-  if (!FD_ISSET(socklan, &readfs)) {
-    return lan_servers;
+  if (!FD_ISSET(scan->sock, &readfs)) {
+    return NULL;
   }
 
   dio_input_init(&din, msgbuf, sizeof(msgbuf));
   fromlen = sizeof(fromend);
 
-  /* Try to receive a packet from a server. */ 
-  if (0 < recvfrom(socklan, msgbuf, sizeof(msgbuf), 0,
-                   &fromend.sockaddr, &fromlen)) {
-    struct server *pserver;
-
-    dio_get_uint8(&din, &type);
-    if (type != SERVER_LAN_VERSION) {
-      return lan_servers;
-    }
-    dio_get_string(&din, servername, sizeof(servername));
-    dio_get_string(&din, port, sizeof(port));
-    dio_get_string(&din, version, sizeof(version));
-    dio_get_string(&din, status, sizeof(status));
-    dio_get_string(&din, players, sizeof(players));
-    dio_get_string(&din, message, sizeof(message));
-
-    if (!mystrcasecmp("none", servername)) {
-      from = gethostbyaddr((char *) &fromend.sockaddr_in.sin_addr,
-                          sizeof(fromend.sockaddr_in.sin_addr), AF_INET);
-      sz_strlcpy(servername, inet_ntoa(fromend.sockaddr_in.sin_addr));
-    }
-
-    /* UDP can send duplicate or delayed packets. */
-    server_list_iterate(lan_servers, aserver) {
-      if (!mystrcasecmp(aserver->host, servername) 
-          && !mystrcasecmp(aserver->port, port)) {
-        return lan_servers;
-      } 
-    } server_list_iterate_end;
-
-    freelog(LOG_DEBUG,
-            ("Received a valid announcement from a server on the LAN."));
-    
-    pserver =  (struct server*)fc_malloc(sizeof(struct server));
-    pserver->host = mystrdup(servername);
-    pserver->port = mystrdup(port);
-    pserver->version = mystrdup(version);
-    pserver->state = mystrdup(status);
-    pserver->nplayers = mystrdup(players);
-    pserver->message = mystrdup(message);
-    pserver->players = NULL;
+  /* Try to receive a packet from a server. */
+  while (1) {
+    if (0 < recvfrom(scan->sock, msgbuf, sizeof(msgbuf), 0,
+                    &fromend.sockaddr, &fromlen)) {
+      struct server *pserver;
+      bool duplicate = FALSE;
+
+      dio_get_uint8(&din, &type);
+      if (type != SERVER_LAN_VERSION) {
+       continue;
+      }
+      dio_get_string(&din, servername, sizeof(servername));
+      dio_get_string(&din, port, sizeof(port));
+      dio_get_string(&din, version, sizeof(version));
+      dio_get_string(&din, status, sizeof(status));
+      dio_get_string(&din, players, sizeof(players));
+      dio_get_string(&din, message, sizeof(message));
+
+      if (!mystrcasecmp("none", servername)) {
+       from = gethostbyaddr((char *) &fromend.sockaddr_in.sin_addr,
+                            sizeof(fromend.sockaddr_in.sin_addr), AF_INET);
+       sz_strlcpy(servername, inet_ntoa(fromend.sockaddr_in.sin_addr));
+      }
 
-    server_list_prepend(lan_servers, pserver);
-  } else {
-    return lan_servers;
-  }                                       
+      /* UDP can send duplicate or delayed packets. */
+      server_list_iterate(scan->servers, aserver) {
+       if (!mystrcasecmp(aserver->host, servername) 
+           && !mystrcasecmp(aserver->port, port)) {
+         duplicate = TRUE;
+         break;
+       } 
+      } server_list_iterate_end;
+      if (duplicate) {
+       continue;
+      }
 
-  return lan_servers;
+      freelog(LOG_DEBUG,
+             ("Received a valid announcement from a server on the LAN."));
+
+      pserver = fc_malloc(sizeof(*pserver));
+      pserver->host = mystrdup(servername);
+      pserver->port = mystrdup(port);
+      pserver->version = mystrdup(version);
+      pserver->state = mystrdup(status);
+      pserver->nplayers = mystrdup(players);
+      pserver->message = mystrdup(message);
+      pserver->players = NULL;
+
+      server_list_prepend(scan->servers, pserver);
+      found_new = TRUE;
+    } else {
+      return found_new ? scan->servers : NULL;
+    }
+  }
+}
+
+struct server_scan *server_scan_begin(enum server_scan_type type,
+                                     ServerScanErrorFunc error_func)
+{
+  struct server_scan *scan = fc_calloc(sizeof(*scan), 1);
+
+  scan->type = type;
+  scan->error_func = error_func;
+
+  scan->sock = -1;
+
+  switch (type) {
+  case SERVER_SCAN_GLOBAL:
+    if (begin_metaserver_scan(scan)) {
+      return scan;
+    } else {
+      return NULL;
+    }
+  case SERVER_SCAN_LOCAL:
+    if (begin_lanserver_scan(scan)) {
+      return scan;
+    } else {
+      return NULL;
+    }
+  case SERVER_SCAN_LAST:
+    break;
+  }
+
+  assert(0);
+  return NULL;
+}
+
+enum server_scan_type server_scan_get_type(const struct server_scan *scan)
+{
+  return scan->type;
+}
+
+struct server_list *server_scan_get_servers(struct server_scan *scan)
+{
+  switch (scan->type) {
+  case SERVER_SCAN_GLOBAL:
+    return get_metaserver_list(scan);
+  case SERVER_SCAN_LOCAL:
+    return get_lan_server_list(scan);
+  case SERVER_SCAN_LAST:
+    break;
+  }
+
+  assert(0);
+  return NULL;
 }
 
 /**************************************************************************
-  Closes the socket listening on the lan and frees the list of LAN servers.
+  Closes the socket listening on the scan and frees the list of servers.
 **************************************************************************/
-void finish_lanserver_scan(void) 
+void server_scan_finish(struct server_scan *scan)
 {
-  my_closesocket(socklan);
-  delete_server_list(lan_servers);
+  if (scan->sock >= 0) {
+    my_closesocket(scan->sock);
+    scan->sock = -1;
+  }
+
+  if (scan->servers) {
+    delete_server_list(scan->servers);
+    scan->servers = NULL;
+  }
+
+  /* FIXME: do we need to close scan->meta.fp or free scan->meta.urlpath? */
 }
Index: client/servers.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/servers.h,v
retrieving revision 1.1
diff -p -u -r1.1 servers.h
--- client/servers.h    19 Aug 2005 20:52:58 -0000      1.1
+++ client/servers.h    20 Aug 2005 00:39:49 -0000
@@ -50,10 +50,21 @@ struct server
   TYPED_LIST_ITERATE(struct server, serverlist, pserver)
 #define server_list_iterate_end  LIST_ITERATE_END
 
-struct server_list *create_server_list(char *errbuf, int n_errbuf);
-void delete_server_list(struct server_list *server_list);
-int begin_lanserver_scan(void);
-struct server_list *get_lan_server_list(void); 
-void finish_lanserver_scan(void);
+struct server_scan;
+
+enum server_scan_type {
+  SERVER_SCAN_LOCAL, /* Local servers, detected through a LAN scan */
+  SERVER_SCAN_GLOBAL, /* Global servers, read from the metaserver */
+  SERVER_SCAN_LAST
+};
+
+typedef void (*ServerScanErrorFunc)(struct server_scan *scan,
+                                   const char *message);
+
+struct server_scan *server_scan_begin(enum server_scan_type type,
+                                     ServerScanErrorFunc error_func);
+enum server_scan_type server_scan_get_type(const struct server_scan *scan);
+struct server_list *server_scan_get_servers(struct server_scan *scan);
+void server_scan_finish(struct server_scan *scan);
 
 #endif /* FC__SERVERS_H */
Index: client/gui-gtk-2.0/pages.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/pages.c,v
retrieving revision 1.39
diff -p -u -r1.39 pages.c
--- client/gui-gtk-2.0/pages.c  19 Aug 2005 20:52:58 -0000      1.39
+++ client/gui-gtk-2.0/pages.c  20 Aug 2005 00:39:49 -0000
@@ -67,8 +67,8 @@ static enum client_pages old_page;
 static void set_page_callback(GtkWidget *w, gpointer data);
 static void update_nation_page(struct packet_game_load *packet);
 
-static guint lan_timer = 0;
-static int num_lanservers_timer = 0;
+static guint scan_timer = 0;
+struct server_scan *lan, *meta;
 
 static GtkWidget *statusbar, *statusbar_frame;
 static GQueue *statusbar_queue;
@@ -293,45 +293,69 @@ static void update_server_list(GtkTreeSe
 }
 
 /**************************************************************************
-  get the list of servers from the metaserver.
+  this function frees the list of LAN servers on timeout destruction. 
 **************************************************************************/
-static bool get_meta_list(char *errbuf, int n_errbuf)
+static void get_server_scan_destroy(gpointer data)
 {
-  struct server_list *server_list = create_server_list(errbuf, n_errbuf);
-
-  update_server_list(meta_selection, meta_store, server_list);
-
-  if (server_list) {
-    delete_server_list(server_list);
-    return TRUE;
-  } else {
-    return FALSE;
+  if (meta) {
+    server_scan_finish(meta);
+    meta = NULL;
+  }
+  if (lan) {
+    server_scan_finish(lan);
+    lan = NULL;
   }
+  scan_timer = 0;
 }
 
 /**************************************************************************
-  this function frees the list of LAN servers on timeout destruction. 
+  this function updates the list of servers every so often.
 **************************************************************************/
-static void get_lan_destroy(gpointer data)
+static gboolean get_server_scan_list(gpointer data)
 {
-  finish_lanserver_scan();
-  num_lanservers_timer = 0;
-  lan_timer = 0;
+  struct server_list *server_list;
+
+  if (!meta && !lan) {
+    return FALSE;
+  }
+
+  if (lan) {
+    server_list = server_scan_get_servers(lan);
+    if (server_list) {
+      update_server_list(lan_selection, lan_store, server_list);
+    }
+  }
+
+  if (meta) {
+    server_list = server_scan_get_servers(meta);
+    if (server_list) {
+      update_server_list(meta_selection, meta_store, server_list);
+    }
+  }
+
+  return TRUE;
 }
 
 /**************************************************************************
-  this function updates the list of LAN servers every 1000 ms for 5 secs.
+  Callback function for when there's an error in the server scan.
 **************************************************************************/
-static gboolean get_lan_list(gpointer data)
+static void server_scan_error(struct server_scan *scan,
+                             const char *message)
 {
-  struct server_list *server_list = get_lan_server_list();
+  append_output_window(message);
+  freelog(LOG_NORMAL, "%s", message);
 
-  update_server_list(lan_selection, lan_store, server_list);
-  num_lanservers_timer++;
-  if (num_lanservers_timer == 5) {
-    return FALSE;
-  } else {
-    return TRUE;
+  switch (server_scan_get_type(scan)) {
+  case SERVER_SCAN_LOCAL:
+    server_scan_finish(lan);
+    lan = NULL;
+    break;
+  case SERVER_SCAN_GLOBAL:
+    server_scan_finish(meta);
+    meta = NULL;
+    break;
+  case SERVER_SCAN_LAST:
+    break;
   }
 }
 
@@ -340,17 +364,18 @@ static gboolean get_lan_list(gpointer da
 **************************************************************************/
 static void update_network_lists(void)
 {
-  char errbuf[128];
+  if (!meta) {
+    meta = server_scan_begin(SERVER_SCAN_GLOBAL, server_scan_error);
+  }
 
-  if (!get_meta_list(errbuf, sizeof(errbuf)))  {
-    append_output_window(errbuf);
+  if (!lan) {
+    lan = server_scan_begin(SERVER_SCAN_LOCAL, server_scan_error);
   }
 
-  if (lan_timer == 0) { 
-    if (begin_lanserver_scan()) {
-      lan_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, 1000,
-         get_lan_list, NULL, get_lan_destroy);
-    }
+  if (scan_timer == 0) { 
+    scan_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, 100,
+                                   get_server_scan_list,
+                                   NULL, get_server_scan_destroy);
   }
 }
 
@@ -1760,8 +1785,9 @@ void set_client_page(enum client_pages p
     }
     break;
   case PAGE_NETWORK:
-    if (lan_timer != 0) {
-      g_source_remove(lan_timer);
+    if (scan_timer != 0) {
+      g_source_remove(scan_timer);
+      scan_timer = 0;
     }
     break;
   case PAGE_GAME:

[Prev in Thread] Current Thread [Next in Thread]