Complete.Org: Mailing Lists: Archives: freeciv-dev: September 2004:
[Freeciv-Dev] (PR#2757) Patch: New metaserver sample civclient/civserver
Home

[Freeciv-Dev] (PR#2757) Patch: New metaserver sample civclient/civserver

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: _vasc@xxxxxxxxxxx.pt_
Subject: [Freeciv-Dev] (PR#2757) Patch: New metaserver sample civclient/civserver implementation
From: "Vasco Alexandre da Silva Costa" <vasc@xxxxxxxxxxxxxx>
Date: Tue, 21 Sep 2004 15:18:43 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=2757 >

> [vasc - Tue Sep 21 20:38:24 2004]:
> 
> I managed to remove the UTF-8 bugs from the metaserver!
> 
> There is a new metaserver at:
> http://meta.freeciv.org/metaserver.phtml
> 
> It is based on the version at ~kauf with extensive changes.
> 
> There is also a new patch for the Freeciv code, based on
> new_metaserver-091904.2.diff. Turns out the major culprit was
> the my_url_encode function I made ages ago which was horribly
> wrong.

And here is the patch.
Index: client/clinet.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/clinet.c,v
retrieving revision 1.100
diff -u -r1.100 clinet.c
--- client/clinet.c     20 Jul 2004 17:13:52 -0000      1.100
+++ client/clinet.c     21 Sep 2004 20:33:36 -0000
@@ -67,6 +67,7 @@
 #include "mem.h"
 #include "netintf.h"
 #include "packets.h"
+#include "registry.h"
 #include "support.h"
 #include "version.h"
 
@@ -92,7 +93,7 @@
 static struct server_list *lan_servers;
 static union my_sockaddr server_addr;
 
-/**************************************************************************
+/*************************************************************************
   Close socket and cleanup.  This one doesn't print a message, so should
   do so before-hand if necessary.
 **************************************************************************/
@@ -486,6 +487,91 @@
 }
 #endif
 
+/**************************************************************************
+...
+**************************************************************************/
+const char *get_metaserver_state_text(int state_id)
+{
+  switch (state_id) {
+  case 'P': return _("Pregame");
+  case 'S': return _("Waiting");
+  case 'R': return _("Running");
+  case 'E': return _("Endgame");
+  default:  return _("Unknown");
+  }
+}
+
+/**************************************************************************
+...
+**************************************************************************/
+static struct server_list *parse_metaserver_data(fz_FILE *f)
+{
+  struct server_list *server_list;
+  struct section_file the_file, *file = &the_file;
+  int nservers, i, j;
+
+  server_list = fc_malloc(sizeof(struct server_list));
+  server_list_init(server_list);
+
+  /* This call closes f. */
+  if (!section_file_load_from_stream(file, f)) {
+    return server_list;
+  }
+
+  nservers = secfile_lookup_int_default(file, 0, "main.nservers");
+
+  for (i = 0; i < nservers; i++) {
+    char *host, *port, *version, *state, *comment, *nplayers;
+    int n;
+    struct server *pserver = (struct server*)fc_malloc(sizeof(struct server));
+
+    host = secfile_lookup_str(file, "server%d.host", i);
+    pserver->host = mystrdup(host);
+
+    port = secfile_lookup_str(file, "server%d.port", i);
+    pserver->port = mystrdup(port);
+
+    version = secfile_lookup_str(file, "server%d.version", i);
+    pserver->version = mystrdup(version);
+
+    state = secfile_lookup_str(file, "server%d.state", i);
+    pserver->state = mystrdup(state);
+
+    comment = secfile_lookup_str(file, "server%d.comment", i);
+    pserver->comment = mystrdup(comment);
+
+    nplayers = secfile_lookup_str(file, "server%d.nplayers", i);
+    pserver->nplayers = mystrdup(nplayers);
+    n = atoi(nplayers);
+
+    if (n > 0) {
+      pserver->players = fc_malloc(n * sizeof(*pserver->players));
+    } else {
+      pserver->players = NULL;
+    }
+      
+    for (j = 0; j < n; j++) {
+      char *name, *nation, *ai, *host;
+
+      name = secfile_lookup_str(file, "server%d.player%d.name", i, j);
+      pserver->players[j].name = mystrdup(name);
+
+      ai = secfile_lookup_str(file, "server%d.player%d.ai", i, j);
+      pserver->players[j].ai = mystrdup(ai);
+
+      host = secfile_lookup_str(file, "server%d.player%d.host", i, j);
+      pserver->players[j].host = mystrdup(host);
+
+      nation = secfile_lookup_str(file, "server%d.player%d.nation", i, j);
+      pserver->players[j].nation = mystrdup(nation);
+    }
+
+    server_list_insert(server_list, pserver);
+  }
+
+  section_file_free(file);
+  return server_list;
+}
 
 /**************************************************************************
  Create the list of servers from the metaserver
@@ -494,69 +580,27 @@
 **************************************************************************/
 struct server_list *create_server_list(char *errbuf, int n_errbuf)
 {
-  struct server_list *server_list;
   union my_sockaddr addr;
   int s;
   fz_FILE *f;
-  char *proxy_url;
-  char urlbuf[512];
-  char *urlpath;
-  char *server;
-  int port;
-  char str[512];
+  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 
 
-  if ((proxy_url = getenv("http_proxy"))) {
-    if (strncmp(proxy_url, "http://";, strlen("http://";)) != 0) {
-      (void) mystrlcpy(errbuf, _("Invalid $http_proxy value, must "
-                                "start with 'http://'"), n_errbuf);
-      return NULL;
-    }
-    sz_strlcpy(urlbuf, proxy_url);
-  } else {
-    if (strncmp(metaserver, "http://";, strlen("http://";)) != 0) {
-      (void) mystrlcpy(errbuf, _("Invalid metaserver URL, must start "
-                                "with 'http://'"), n_errbuf);
-      return NULL;
-    }
-    sz_strlcpy(urlbuf, metaserver);
-  }
-  server = &urlbuf[strlen("http://";)];
-
-  {
-    char *s;
-    if ((s = strchr(server,':'))) {
-      if (sscanf(&s[1], "%d", &port) != 1) {
-       port = 80;
-      }
-      s[0] = '\0';
-      s++;
-      while (my_isdigit(s[0])) {
-       s++;
-      }
-    } else {
-      port = 80;
-      if (!(s = strchr(server,'/'))) {
-        s = &server[strlen(server)];
-      }
-    }  /* s now points past the host[:port] part */
-
-    if (s[0] == '/') {
-      s[0] = '\0';
-      s++;
-    } else if (s[0] != '\0') {
-      (void) mystrlcpy(errbuf, _("Invalid $http_proxy value, cannot "
-                                "find separating '/'"), n_errbuf);
-      /* which is obligatory if more characters follow */
-      return NULL;
-    }
-    urlpath = s;
+  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(server, port, &addr)) {
+  if (!net_lookup_service(metaname, metaport, &addr)) {
     (void) mystrlcpy(errbuf, _("Failed looking up host"), n_errbuf);
     return NULL;
   }
@@ -566,7 +610,7 @@
     return NULL;
   }
   
-  if(connect(s, &addr.sockaddr, sizeof (addr)) == -1) {
+  if(connect(s, (struct sockaddr *) &addr.sockaddr, sizeof(addr)) == -1) {
     (void) mystrlcpy(errbuf, mystrerror(), n_errbuf);
     my_closesocket(s);
     return NULL;
@@ -590,56 +634,41 @@
 #endif
 #endif /* HAVE_UNAME */
 
-  my_snprintf(str,sizeof(str),
-              "GET %s%s%s HTTP/1.0\r\nUser-Agent: Freeciv/%s %s %s %s\r\n\r\n",
-              proxy_url ? "" : "/",
-              urlpath,
-              proxy_url ? metaserver : "",
-              VERSION_STRING,
-              client_string,
-              machine_string,
-              default_tileset_name);
+  capstr = my_url_encode(our_capability);
 
-  f = my_querysocket(s, str, strlen(str));
+  my_snprintf(str, sizeof(str),
+    "POST %s HTTP/1.1\r\n"
+    "Host: %s:%d\r\n"
+    "User-Agent: Freeciv/%s %s %s\r\n"
+    "Connection: close\r\n"
+    "Content-Type: application/x-www-form-urlencoded; charset=\"utf-8\"\r\n"
+    "Content-Length: %d\r\n"
+    "\r\n"
+    "client_cap=%s\r\n",
+    urlpath,
+    metaname, metaport,
+    VERSION_STRING, client_string, machine_string,
+    strlen("client_cap=")+strlen(capstr),
+    capstr);
 
-#define NEXT_FIELD p=strstr(p,"<TD>"); if(!p) continue; p+=4;
-#define END_FIELD  p=strstr(p,"</TD>"); if(!p) continue; *p++='\0';
-#define GET_FIELD(x) NEXT_FIELD (x)=p; END_FIELD
+  printf("---\n%s", str);
 
-  server_list = fc_malloc(sizeof(struct server_list));
-  server_list_init(server_list);
+  f = my_querysocket(s, str, strlen(str));
 
-  while(fz_fgets(str, 512, f)) {
-    if((0 == strncmp(str, "<TR BGCOLOR",11)) && strchr(str, '\n')) {
-      char *name,*port,*version,*status,*players,*metastring;
-      char *p;
-      struct server *pserver = (struct server*)fc_malloc(sizeof(struct 
server));
-
-      p=strstr(str,"<a"); if(!p) continue;
-      p=strchr(p,'>');    if(!p) continue;
-      name=++p;
-      p=strstr(p,"</a>"); if(!p) continue;
-      *p++='\0';
-
-      GET_FIELD(port);
-      GET_FIELD(version);
-      GET_FIELD(status);
-      GET_FIELD(players);
-      GET_FIELD(metastring);
-
-      pserver->name = mystrdup(name);
-      pserver->port = mystrdup(port);
-      pserver->version = mystrdup(version);
-      pserver->status = mystrdup(status);
-      pserver->players = mystrdup(players);
-      pserver->metastring = mystrdup(metastring);
+  /* skip HTTP headers */
+  while (fz_fgets(str, sizeof(str), f) && strcmp(str, "\r\n") != 0) {
+//    fputs(str, stdout);
+  }
 
-      server_list_insert(server_list, pserver);
-    }
+  printf("\n---\n");
+
+  while (fz_fgets(str, sizeof(str), f)) {
+    fputs(str, stdout);/* DEBUGGING */
   }
-  fz_fclose(f);
+  /* XXX: TODO check for magic Content-Type: text/x-ini -vasc */
 
-  return server_list;
+  /* parse HTTP message body */
+  return parse_metaserver_data(f);
 }
 
 /**************************************************************************
@@ -650,17 +679,32 @@
 void delete_server_list(struct server_list *server_list)
 {
   server_list_iterate(*server_list, ptmp)
-    free(ptmp->name);
+    int i;
+    int n = atoi(ptmp->nplayers);
+
+    free(ptmp->host);
     free(ptmp->port);
     free(ptmp->version);
-    free(ptmp->status);
-    free(ptmp->players);
-    free(ptmp->metastring);
+    free(ptmp->state);
+    free(ptmp->comment);
+
+    for (i = 0; i < n; i++) {
+      free(ptmp->players[i].name);
+      free(ptmp->players[i].ai);
+      free(ptmp->players[i].host);
+      free(ptmp->players[i].nation);
+    }
+    free(ptmp->nplayers);
+
+    if (ptmp->players) {
+      free(ptmp->players);
+    }
+
     free(ptmp);
   server_list_iterate_end;
 
   server_list_unlink_all(server_list);
-       free(server_list);
+  free(server_list);
 }
 
 /**************************************************************************
@@ -830,7 +874,7 @@
 
     /* UDP can send duplicate or delayed packets. */
     server_list_iterate(*lan_servers, aserver) {
-      if (!mystrcasecmp(aserver->name, servername) 
+      if (!mystrcasecmp(aserver->host, servername) 
           && !mystrcasecmp(aserver->port, port)) {
         return lan_servers;
       } 
@@ -840,12 +884,12 @@
             ("Received a valid announcement from a server on the LAN."));
     
     pserver =  (struct server*)fc_malloc(sizeof(struct server));
-    pserver->name = mystrdup(servername);
+    pserver->host = mystrdup(servername);
     pserver->port = mystrdup(port);
     pserver->version = mystrdup(version);
-    pserver->status = mystrdup(status);
-    pserver->players = mystrdup(players);
-    pserver->metastring = mystrdup(metastring);
+    pserver->state = mystrdup(status);
+    pserver->nplayers = mystrdup(players);
+    pserver->comment = mystrdup(metastring);
 
     server_list_insert(lan_servers, pserver);
   } else {
Index: client/clinet.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/clinet.h,v
retrieving revision 1.19
diff -u -r1.19 clinet.h
--- client/clinet.h     13 Apr 2004 16:40:00 -0000      1.19
+++ client/clinet.h     21 Sep 2004 20:33:36 -0000
@@ -14,7 +14,7 @@
 #define FC__CLINET_H
 
 #define DEFAULT_SOCK_PORT 5555
-#define METALIST_ADDR "http://meta.freeciv.org/metaserver/";
+#define METALIST_ADDR "http://meta.freeciv.org/~kauf/metaserver.phtml";
 
 #define SERVER_LAN_PORT 4555
 #define SERVER_LAN_TTL 1
@@ -43,12 +43,21 @@
 
 struct server
 {
-  char *name;
-  char *port;
+  char *host;
+  char * port;
   char *version;
-  char *status;
-  char *players;
-  char *metastring;
+  char *state;
+  char *comment;
+
+  struct players
+  {
+    char *name;
+    char *ai;
+    char *host;
+    char *nation;
+  } *players;
+
+  char *nplayers;
 };
 
 #define SPECLIST_TAG server
@@ -59,6 +68,7 @@
   TYPED_LIST_ITERATE(struct server, serverlist, pserver)
 #define server_list_iterate_end  LIST_ITERATE_END
 
+const char *get_metaserver_state_text(int state_id);
 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);
Index: client/gui-gtk-2.0/connectdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/connectdlg.c,v
retrieving revision 1.48
diff -u -r1.48 connectdlg.c
--- client/gui-gtk-2.0/connectdlg.c     19 Sep 2004 01:00:54 -0000      1.48
+++ client/gui-gtk-2.0/connectdlg.c     21 Sep 2004 20:33:37 -0000
@@ -252,6 +252,7 @@
 static gboolean get_lanservers(gpointer data)
 {
   struct server_list *server_list = get_lan_server_list();
+#if 0
   gchar *row[6];
 
   if (server_list != NULL) {
@@ -281,6 +282,7 @@
     lan_timer = 0;
     return FALSE;
   }
+#endif
   return TRUE;
 }
 
@@ -1143,7 +1145,8 @@
 static int get_meta_list(char *errbuf, int n_errbuf)
 {
   struct server_list *server_list = create_server_list(errbuf, n_errbuf);
-  gchar *row[6];
+#if 0
+  gchar *row[3];
 
   if (!server_list) {
     return -1;
@@ -1169,6 +1172,7 @@
   server_list_iterate_end;
 
   delete_server_list(server_list);
+#endif
   return 0;
 }
 
Index: server/connecthand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/connecthand.c,v
retrieving revision 1.33
diff -u -r1.33 connecthand.c
--- server/connecthand.c        17 Sep 2004 19:04:21 -0000      1.33
+++ server/connecthand.c        21 Sep 2004 20:33:40 -0000
@@ -175,7 +175,7 @@
   send_conn_info(dest, &game.est_connections);
   conn_list_insert_back(&game.est_connections, pconn);
   send_conn_info(&game.est_connections, dest);
-  (void) send_server_info_to_metaserver(TRUE, FALSE);
+  (void) send_server_info_to_metaserver(TRUE, FALSE, META_INFO);
 }
 
 /**************************************************************************
Index: server/meta.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/meta.c,v
retrieving revision 1.60
diff -u -r1.60 meta.c
--- server/meta.c       17 May 2004 02:16:15 -0000      1.60
+++ server/meta.c       21 Sep 2004 20:33:40 -0000
@@ -11,28 +11,11 @@
    GNU General Public License for more details.
 ***********************************************************************/
 
-/*
- * This bit sends "I'm here" packages to the metaserver.
- */
-
-/*
-The desc block should look like this:
-1) GameName   - Freeciv
-2) Version    - 1.5.0
-3) State      - Running(Open for new players)
-4) Host       - Empty
-5) Port       - 5555
-6) NoPlayers  - 3
-7) InfoText   - Warfare - starts at 8:00 EMT
-
-The info string should look like this:
-  GameSpecific text block
-*/
-
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
+#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -57,9 +40,12 @@
 #include <winsock.h>
 #endif
 
+#include "capstr.h"
+#include "connection.h"
 #include "dataio.h"
 #include "fcintl.h"
 #include "log.h"
+#include "mem.h"
 #include "netintf.h"
 #include "support.h"
 #include "timing.h"
@@ -72,9 +58,10 @@
 
 bool server_is_open = FALSE;
 
-static int                     sockfd=0;
 static union my_sockaddr       meta_addr;
-
+static char  metaname[MAX_LEN_ADDR];
+static int   metaport;
+static char *metaserver_path;
 
 /*************************************************************************
   Return static string with default info line to send to metaserver.
@@ -99,11 +86,6 @@
 *************************************************************************/
 void meta_addr_split(void)
 {
-  char *metaserver_port_separator = strchr(srvarg.metaserver_addr, ':');
-
-  if (metaserver_port_separator) {
-    sscanf(metaserver_port_separator + 1, "%hu", &srvarg.metaserver_port);
-  }
 }
 
 /*************************************************************************
@@ -111,122 +93,235 @@
 *************************************************************************/
 char *meta_addr_port(void)
 {
-  static char retstr[300];
+  return srvarg.metaserver_addr;
+}
 
-  if (srvarg.metaserver_port == DEFAULT_META_SERVER_PORT) {
-    sz_strlcpy(retstr, srvarg.metaserver_addr);
-  } else {
-    my_snprintf(retstr, sizeof(retstr),
-               "%s:%d", srvarg.metaserver_addr, srvarg.metaserver_port);
-  }
+/*************************************************************************
+...
+*************************************************************************/
+static void metaserver_failed(void)
+{
+  con_puts(C_METAERROR, _("Not reporting to the metaserver in this game."));
+  con_flush();
 
-  return retstr;
+  server_close_meta();
 }
 
 /*************************************************************************
 ...
-  Returns true if able to send 
 *************************************************************************/
-static bool send_to_metaserver(char *desc, char *info)
+static bool send_to_metaserver(int flags)
 {
-  unsigned char buffer[MAX_LEN_PACKET];
-  struct data_out dout;
-  size_t size;
+  static char msg[8192];
+  static char str[8192];
+  int rest = sizeof(str);
+  int n;
+  char *s = str;
+  const char *host = "somehost.somewhere.net";
+  char state;
+  int sock;
+//  fz_FILE *f;
 
-  dio_output_init(&dout, buffer, sizeof(buffer));
+  if (!server_is_open) {
+    return FALSE;
+  }
 
-  if(sockfd<=0)
+  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+    freelog(LOG_ERROR, "Metaserver: can't open stream socket: %s",
+           mystrerror());
+    metaserver_failed();
     return FALSE;
+  }
 
-  dio_put_uint16(&dout, 0);
-  dio_put_uint8(&dout, PACKET_UDP_PCKT);
-  dio_put_string(&dout, desc);
-  dio_put_string(&dout, info);
+  if (connect(sock, (struct sockaddr *) &meta_addr, sizeof(meta_addr)) == -1) {
+    freelog(LOG_ERROR, "Metaserver: connect failed: %s", mystrerror());
+    metaserver_failed();
+    my_closesocket(sock);
+    return FALSE;
+  }
 
-  size = dio_output_used(&dout);
+  switch(server_state) {
+  case PRE_GAME_STATE:
+    state = 'P';
+    break;
+  case SELECT_RACES_STATE:
+    state = 'S';
+    break;
+  case RUN_GAME_STATE:
+    state = 'R';
+    break;
+  case GAME_OVER_STATE:
+    state = 'E';
+    break;
+  default:
+    state = 'U';
+    break;
+  }
 
-  dio_output_rewind(&dout);
-  dio_put_uint16(&dout, size);
 
-  my_writesocket(sockfd, buffer, size);
-  return TRUE;
-}
+  my_snprintf(s, rest,
+    "host=%s&port=%d&state=%c&",
+    host, srvarg.port, state);
+  s = end_of_strn(s, &rest);
+
+  if (flags & META_GOODBYE) {
+    mystrlcpy(s, "bye=1&", rest);
+    s = end_of_strn(s, &rest);
+  } else {
+    if (flags & META_VERSION) {
+      my_snprintf(s, rest,
+        "version=%s&",
+        my_url_encode(VERSION_STRING));
+      s = end_of_strn(s, &rest);
+
+      my_snprintf(s, rest,
+        "patches=%s&",
+        my_url_encode("none"));
+      s = end_of_strn(s, &rest);
+
+      my_snprintf(s, rest,
+        "capability=%s&",
+        my_url_encode(our_capability));
+      s = end_of_strn(s, &rest);
+    }
 
-/*************************************************************************
-...
-*************************************************************************/
-void server_close_udp(void)
-{
-  server_is_open = FALSE;
+    if (flags & META_COMMENT) {
+      my_snprintf(s, rest,
+        "topic=%s&",
+        my_url_encode(srvarg.extra_metaserver_info));
+      s = end_of_strn(s, &rest);
+
+      my_snprintf(s, rest,
+        "message=%s&",
+        my_url_encode(srvarg.metaserver_info_line));
+      s = end_of_strn(s, &rest);
+    }
 
-  if(sockfd<=0)
-    return;
-  my_closesocket(sockfd);
-  sockfd=0;
+    /* NOTE: send info for ALL players or none at all. */
+    if (get_num_human_and_ai_players() == 0) {
+      mystrlcpy(s, "dropplrs=1&", rest);
+      s = end_of_strn(s, &rest);
+    } else {
+      players_iterate(plr) {
+        char type;
+        struct connection *pconn = find_conn_by_user(plr->username);
+
+        if (is_barbarian(plr)) {
+          type = 'B';
+        } else if (plr->ai.control) {
+          type = 'A';
+        } else {
+          type = 'H';
+        }
+
+        my_snprintf(s, rest,
+          "plu[]=%s&",
+          my_url_encode(plr->username));
+        s = end_of_strn(s, &rest);
+
+        my_snprintf(s, rest,
+           "plt[]=%c&",
+           type);
+        s = end_of_strn(s, &rest);
+
+        my_snprintf(s, rest,
+          "pll[]=%s&",
+          my_url_encode(plr->name));
+        s = end_of_strn(s, &rest);
+
+        my_snprintf(s, rest,
+          "pln[]=%s&",
+           my_url_encode(plr->nation != NO_NATION_SELECTED 
+                         ? get_nation_name_plural(plr->nation) : "none"));
+        s = end_of_strn(s, &rest);
+
+        my_snprintf(s, rest,
+          "plh[]=%s&",
+           pconn ? my_url_encode(pconn->addr) :  my_url_encode("none"));
+        s = end_of_strn(s, &rest);
+      } players_iterate_end;
+    }
+
+    /* send some variables: should be listed in inverted order
+     * FIXME: these should be input from the settings array */
+    my_snprintf(s, rest, "vn[]=%s&vv[]=%d&",
+                my_url_encode("timeout"), game.timeout);
+    s = end_of_strn(s, &rest);
+
+    my_snprintf(s, rest, "vn[]=%s&vv[]=%d&",
+                my_url_encode("endyear"), game.end_year);
+    s = end_of_strn(s, &rest);
+
+    my_snprintf(s, rest, "vn[]=%s&vv[]=%d&",
+                my_url_encode("generator"), map.generator);
+    s = end_of_strn(s, &rest);
+
+    my_snprintf(s, rest, "vn[]=%s&vv[]=%d&",
+                my_url_encode("size"), map.size);
+    s = end_of_strn(s, &rest);
+  }
+
+  n = my_snprintf(msg, sizeof(msg),
+    "POST %s HTTP/1.1\r\n"
+    "Host: %s:%d\r\n"
+    "Content-Type: application/x-www-form-urlencoded; charset=\"utf-8\"\r\n"
+    "Content-Length: %d\r\n"
+    "\r\n"
+    "%s\r\n",
+    metaserver_path,
+    metaname,
+    metaport,
+    sizeof(str)-rest+1,
+    str
+  );
+
+//  printf("---------\n%s\n---\n", msg);
+
+//  printf("---\n");
+
+  my_writesocket(sock, msg, n);
+
+//  f = my_querysocket(sock, msg, n);
+//  while (fz_fgets(msg, sizeof(msg), f))
+//    fputs(msg, stdout);
+
+//  printf("---\n");
+// fz_fclose(f);
+
+  return TRUE;
 }
 
 /*************************************************************************
 ...
 *************************************************************************/
-static void metaserver_failed(void)
+void server_close_meta(void)
 {
-  con_puts(C_METAERROR, _("Not reporting to the metaserver in this game."));
-  con_flush();
+  (void) send_server_info_to_metaserver(TRUE, FALSE, META_GOODBYE);
+
+  server_is_open = FALSE;
 }
 
 /*************************************************************************
 ...
 *************************************************************************/
-void server_open_udp(void)
+void server_open_meta(void)
 {
-  char *metaname = srvarg.metaserver_addr;
-  int metaport;
-  union my_sockaddr bind_addr;
-  
-  /*
-   * Fill in the structure "meta_addr" with the address of the
-   * server that we want to connect with, checks if server address 
-   * is valid, both decimal-dotted and name.
-   */
-  metaport = srvarg.metaserver_port;
-  if (!net_lookup_service(metaname, metaport, &meta_addr)) {
-    freelog(LOG_ERROR, _("Metaserver: bad address: [%s:%d]."),
-      metaname,
-      metaport);
-    metaserver_failed();
-    return;
+  const char *path;
+ 
+  if (metaserver_path) {
+    free(metaserver_path);
+    metaserver_path = NULL;
   }
-
-  /*
-   * Open a UDP socket (an Internet datagram socket).
-   */
-  if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
-    freelog(LOG_ERROR, "Metaserver: can't open datagram socket: %s",
-           mystrerror());
-    metaserver_failed();
+  
+  if (!(path = my_lookup_httpd(metaname, &metaport, srvarg.metaserver_addr))) {
     return;
   }
+  
+  metaserver_path = mystrdup(path);
 
-  /*
-   * Bind any local address for us and
-   * associate datagram socket with server.
-   */
-  if (!net_lookup_service(srvarg.bind_addr, 0, &bind_addr)) {
+  if (!net_lookup_service(metaname, metaport, &meta_addr)) {
     freelog(LOG_ERROR, _("Metaserver: bad address: [%s:%d]."),
-           srvarg.bind_addr, 0);
-    metaserver_failed();
-  }
-
-  /* set source IP */
-  if (bind(sockfd, &bind_addr.sockaddr, sizeof(bind_addr)) == -1) {
-    freelog(LOG_ERROR, "Metaserver: bind failed: %s", mystrerror());
-    metaserver_failed();
-    return;
-  }
-
-  /* no, this is not weird, see man connect(2) --vasc */
-  if (connect(sockfd, &meta_addr.sockaddr, sizeof(meta_addr))==-1) {
-    freelog(LOG_ERROR, "Metaserver: connect failed: %s", mystrerror());
+            metaname, metaport);
     metaserver_failed();
     return;
   }
@@ -234,15 +329,12 @@
   server_is_open = TRUE;
 }
 
-
 /**************************************************************************
 ...
 **************************************************************************/
-bool send_server_info_to_metaserver(bool do_send, bool reset_timer)
+bool send_server_info_to_metaserver(bool do_send, bool reset_timer, int flags)
 {
   static struct timer *time_since_last_send = NULL;
-  char desc[4096], info[4096];
-  int num_nonbarbarians = get_num_human_and_ai_players();
 
   if (reset_timer && time_since_last_send)
   {
@@ -261,59 +353,6 @@
     time_since_last_send = new_timer(TIMER_USER, TIMER_ACTIVE);
   }
 
-  /* build description block */
-  desc[0]='\0';
-  
-  cat_snprintf(desc, sizeof(desc), "Freeciv\n");
-  cat_snprintf(desc, sizeof(desc), VERSION_STRING"\n");
-  /* note: the following strings are not translated here;
-     we mark them so they may be translated when received by a client */
-  switch(server_state) {
-  case PRE_GAME_STATE:
-    cat_snprintf(desc, sizeof(desc), N_("Pregame"));
-    break;
-  case RUN_GAME_STATE:
-    cat_snprintf(desc, sizeof(desc), N_("Running"));
-    break;
-  case GAME_OVER_STATE:
-    cat_snprintf(desc, sizeof(desc), N_("Game over"));
-    break;
-  default:
-    cat_snprintf(desc, sizeof(desc), N_("Waiting"));
-  }
-  cat_snprintf(desc, sizeof(desc), "\n");
-  cat_snprintf(desc, sizeof(desc), "%s\n", "UNSET");
-  cat_snprintf(desc, sizeof(desc), "%d\n", srvarg.port);
-  cat_snprintf(desc, sizeof(desc), "%d\n", num_nonbarbarians);
-  cat_snprintf(desc, sizeof(desc), "%s %s", srvarg.metaserver_info_line,
-              srvarg.extra_metaserver_info);
-
-  /* now build the info block */
-  info[0]='\0';
-  cat_snprintf(info, sizeof(info),
-         "Players:%d  Min players:%d  Max players:%d\n",
-         num_nonbarbarians,  game.min_players, game.max_players);
-  cat_snprintf(info, sizeof(info),
-         "Timeout:%d  Year: %s\n",
-         game.timeout, textyear(game.year));
-    
-    
-  cat_snprintf(info, sizeof(info),
-              "NO:  NAME:               HOST:\n");
-  cat_snprintf(info, sizeof(info),
-              "----------------------------------------\n");
-
-  players_iterate(pplayer) {
-    if (!is_barbarian(pplayer)) {
-      /* Fixme: how should metaserver handle multi-connects?
-       * Uses player_addr_hack() for now.
-       */
-      cat_snprintf(info, sizeof(info), "%2d   %-20s %s\n",
-                  pplayer->player_no, pplayer->name,
-                  player_addr_hack(pplayer));
-    }
-  } players_iterate_end;
-
   clear_timer_start(time_since_last_send);
-  return send_to_metaserver(desc, info);
+  return send_to_metaserver(flags);
 }
Index: server/meta.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/meta.h,v
retrieving revision 1.24
diff -u -r1.24 meta.h
--- server/meta.h       7 Nov 2002 16:04:54 -0000       1.24
+++ server/meta.h       21 Sep 2004 20:33:40 -0000
@@ -15,26 +15,26 @@
 
 #include "shared.h"            /* bool type */
 
-/*
- * Definitions for UDP.
- */
-
 #define DEFAULT_META_SERVER_NO_SEND    TRUE
-#define DEFAULT_META_SERVER_PORT       12245
-#define DEFAULT_META_SERVER_ADDR       "meta.freeciv.org"
+#define DEFAULT_META_SERVER_ADDR       
"http://meta.freeciv.org/~kauf/metaserver.phtml";
 #define METASERVER_UPDATE_INTERVAL     (3*60)
 
-#define PACKET_UDP_PCKT 2
+enum metainfo_type {
+  META_INFO    = 0,
+  META_VERSION = 1,
+  META_COMMENT = 2,
+  META_GOODBYE = 4
+};
 
 const char *default_meta_server_info_string(void);
 
 void meta_addr_split(void);
 char *meta_addr_port(void);
 
-void server_close_udp(void);
-void server_open_udp(void);
+void server_close_meta(void);
+void server_open_meta(void);
 
-bool send_server_info_to_metaserver(bool do_send, bool reset_timer);
+bool send_server_info_to_metaserver(bool do_send, bool reset_timer, int flags);
 
 extern bool server_is_open;
 
Index: server/sernet.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/sernet.c,v
retrieving revision 1.121
diff -u -r1.121 sernet.c
--- server/sernet.c     20 Jul 2004 17:05:26 -0000      1.121
+++ server/sernet.c     21 Sep 2004 20:33:40 -0000
@@ -233,7 +233,7 @@
   }
 #endif
 
-  server_close_udp();
+  server_close_meta();
 
   my_shutdown_network();
 }
@@ -397,7 +397,7 @@
            sz_strlcpy(srvarg.metaserver_info_line,
                       "restarting for lack of players");
            freelog(LOG_NORMAL, srvarg.metaserver_info_line);
-           (void) send_server_info_to_metaserver(TRUE, FALSE);
+           (void) send_server_info_to_metaserver(TRUE, FALSE, META_COMMENT);
 
             server_state = GAME_OVER_STATE;
             force_end_of_sniff = TRUE;
@@ -414,7 +414,7 @@
                      "restarting in %d seconds for lack of players",
                      srvarg.quitidle);
          freelog(LOG_NORMAL, srvarg.metaserver_info_line);
-         (void) send_server_info_to_metaserver(TRUE, FALSE);
+         (void) send_server_info_to_metaserver(TRUE, FALSE, META_COMMENT);
        }
       } else {
         last_noplayers = 0;
@@ -459,7 +459,7 @@
 
     /* Don't wait if timeout == -1 (i.e. on auto games) */
     if (server_state != PRE_GAME_STATE && game.timeout == -1) {
-      (void) send_server_info_to_metaserver(FALSE, FALSE);
+      (void) send_server_info_to_metaserver(FALSE, FALSE, META_INFO);
       return 0;
     }
 
@@ -497,7 +497,7 @@
     con_prompt_off();          /* output doesn't generate a new prompt */
 
     if(select(max_desc+1, &readfs, &writefs, &exceptfs, &tv)==0) { /* timeout 
*/
-      (void) send_server_info_to_metaserver(FALSE, FALSE);
+      (void) send_server_info_to_metaserver(FALSE, FALSE, META_INFO);
       if(game.timeout != 0
        && (time(NULL)>game.turn_start + game.timeout)
        && (server_state == RUN_GAME_STATE)){
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.198
diff -u -r1.198 srv_main.c
--- server/srv_main.c   21 Sep 2004 05:51:12 -0000      1.198
+++ server/srv_main.c   21 Sep 2004 20:33:43 -0000
@@ -177,7 +177,6 @@
   srvarg.metaserver_no_send = DEFAULT_META_SERVER_NO_SEND;
   sz_strlcpy(srvarg.metaserver_info_line, default_meta_server_info_string());
   sz_strlcpy(srvarg.metaserver_addr, DEFAULT_META_SERVER_ADDR);
-  srvarg.metaserver_port = DEFAULT_META_SERVER_PORT;
 
   srvarg.bind_addr = NULL;
   srvarg.port = DEFAULT_SOCK_PORT;
@@ -1379,7 +1378,7 @@
 
     game.nplayers++;
 
-    (void) send_server_info_to_metaserver(TRUE, FALSE);
+    (void) send_server_info_to_metaserver(TRUE, FALSE, META_INFO);
 
     if (!((game.nplayers == old_nplayers+1)
          && strcmp(player_name, pplayer->name)==0)) {
@@ -1400,7 +1399,7 @@
     announce_ai_player(pplayer);
     set_ai_level_direct(pplayer, pplayer->ai.skill_level);
   }
-  (void) send_server_info_to_metaserver(TRUE, FALSE);
+  (void) send_server_info_to_metaserver(TRUE, FALSE, META_INFO);
 }
 
 /*************************************************************************
@@ -1549,7 +1548,7 @@
     end_phase();
     end_turn();
     freelog(LOG_DEBUG, "Sendinfotometaserver");
-    (void) send_server_info_to_metaserver(FALSE, FALSE);
+    (void) send_server_info_to_metaserver(FALSE, FALSE, META_INFO);
 
     conn_list_do_unbuffer(&game.game_connections);
 
@@ -1607,10 +1606,10 @@
   if(!(srvarg.metaserver_no_send)) {
     freelog(LOG_NORMAL, _("Sending info to metaserver [%s]"),
            meta_addr_port());
-    server_open_udp(); /* open socket for meta server */ 
+    server_open_meta(); /* open socket for meta server */ 
   }
 
-  (void) send_server_info_to_metaserver(TRUE, FALSE);
+  (void) send_server_info_to_metaserver(TRUE, FALSE, 
META_VERSION|META_COMMENT);
 
   /* accept new players, wait for serverop to start..*/
   server_state = PRE_GAME_STATE;
@@ -1667,7 +1666,7 @@
     sniff_packets(); /* Accepting commands. */
   }
 
-  (void) send_server_info_to_metaserver(TRUE, FALSE);
+  (void) send_server_info_to_metaserver(TRUE, FALSE, META_INFO);
 
   if (game.is_new_game) {
     load_rulesets();
@@ -1788,7 +1787,7 @@
   /* start the game */
 
   server_state = RUN_GAME_STATE;
-  (void) send_server_info_to_metaserver(TRUE, FALSE);
+  (void) send_server_info_to_metaserver(TRUE, FALSE, META_INFO);
 
   if(game.is_new_game) {
     /* Before the player map is allocated (and initiailized)! */
Index: server/stdinhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
retrieving revision 1.351
diff -u -r1.351 stdinhand.c
--- server/stdinhand.c  20 Sep 2004 22:06:52 -0000      1.351
+++ server/stdinhand.c  21 Sep 2004 20:33:44 -0000
@@ -496,8 +496,8 @@
 **************************************************************************/
 static void open_metaserver_connection(struct connection *caller)
 {
-  server_open_udp();
-  if (send_server_info_to_metaserver(TRUE, FALSE)) {
+  server_open_meta();
+  if (send_server_info_to_metaserver(TRUE, FALSE, META_VERSION|META_COMMENT)) {
     notify_player(NULL, _("Open metaserver connection to [%s]."),
                  meta_addr_port());
   }
@@ -508,8 +508,8 @@
 **************************************************************************/
 static void close_metaserver_connection(struct connection *caller)
 {
-  if (send_server_info_to_metaserver(TRUE, TRUE)) {
-    server_close_udp();
+  if (send_server_info_to_metaserver(TRUE, TRUE, META_INFO)) {
+    server_close_meta();
     notify_player(NULL, _("Close metaserver connection to [%s]."),
                  meta_addr_port());
   }
@@ -569,7 +569,7 @@
     return TRUE;
   }
   sz_strlcpy(srvarg.metaserver_info_line, arg);
-  if (!send_server_info_to_metaserver(TRUE, FALSE)) {
+  if (!send_server_info_to_metaserver(TRUE, FALSE, META_COMMENT)) {
     cmd_reply(CMD_METAINFO, caller, C_METAERROR,
              _("Not reporting to the metaserver."));
   } else {
@@ -824,7 +824,7 @@
 
   notify_player(NULL, _("Game: %s has been added as an AI-controlled player."),
                 arg);
-  (void) send_server_info_to_metaserver(TRUE, FALSE);
+  (void) send_server_info_to_metaserver(TRUE, FALSE, META_INFO);
 
   pplayer = find_player_by_name(arg);
   if (!pplayer)
@@ -955,8 +955,7 @@
                                        "experimental");
 
     if (*srvarg.metaserver_addr != '\0' &&
-       ((0 != strcmp(srvarg.metaserver_addr, DEFAULT_META_SERVER_ADDR)) ||
-        (srvarg.metaserver_port != DEFAULT_META_SERVER_PORT))) {
+       ((0 != strcmp(srvarg.metaserver_addr, DEFAULT_META_SERVER_ADDR)))) {
       fprintf(script_file, "metaserver %s\n", meta_addr_port());
     }
 
Index: utility/netintf.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/utility/netintf.c,v
retrieving revision 1.21
diff -u -r1.21 netintf.c
--- utility/netintf.c   17 May 2004 02:16:15 -0000      1.21
+++ utility/netintf.c   21 Sep 2004 20:33:44 -0000
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #ifdef HAVE_ARPA_INET_H
@@ -226,6 +227,108 @@
   return fz_from_stream(fp);
 }
 
+/*************************************************************************
+  Returns a valid httpd server and port, plus the path to the resource
+  at the url location.
+*************************************************************************/
+const char *my_lookup_httpd(char *server, int *port, const char *url)
+{
+  const char *purl, *str, *ppath, *pport;
+
+  if ((purl = getenv("http_proxy"))) {
+    if (strncmp(purl, "http://";, strlen("http://";)) != 0) {
+      return NULL;
+    }
+    str = purl;
+  } else {
+    if (strncmp(url, "http://";, strlen("http://";)) != 0) {
+      return NULL;
+    }
+    str = url;
+  }
+
+  str += strlen("http://";);
+  
+  pport = strchr(str, ':');
+  ppath = strchr(str, '/');
+
+  /* snarf server. */
+  server[0] = '\0';
+
+  if (pport) {
+    strncat(server, str, MIN(MAX_LEN_ADDR, pport-str));
+  } else {
+    if (ppath) {
+      strncat(server, str, MIN(MAX_LEN_ADDR, ppath-str));
+    } else {
+      strncat(server, str, MAX_LEN_ADDR);
+    }
+  }
+
+  /* snarf port. */
+  if (!pport || sscanf(pport+1, "%d", port) != 1) {
+    *port = 80;
+  }
+
+  /* snarf path. */
+  if (!ppath) {
+    ppath = "/";
+  }
+
+  return (purl ? url : ppath);
+}
+
+/*************************************************************************
+  Returns TRUE if ch is an unreserved ASCII character.
+*************************************************************************/
+static bool is_url_safe(unsigned ch)
+{
+  const char *unreserved = "-_.!~*'|";
+
+  if ((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9')) {
+    return TRUE;
+  } else {
+    return (strchr(unreserved, ch) != NULL);
+  }
+}
+
+/***************************************************************
+  URL-encode a string as per RFC 2396.
+  Should work for all ASCII based charsets: including UTF-8.
+***************************************************************/
+const char *my_url_encode(const char *txt)
+{
+  static char buf[2048];
+  int  pos;
+  unsigned ch;
+  char *ptr;
+
+  /* in a worst case scenario every character needs "% HEX HEX" encoding. */
+  if (sizeof(buf) <= (3*strlen(txt))) {
+    return "";
+  }
+  
+  ptr = buf;
+  for (ptr = buf; *txt != '\0'; txt++) {
+    ch = (unsigned char) *txt;
+
+    if (is_url_safe(ch)) {
+      *ptr++ = *txt;
+      pos++;
+    } else if (ch == ' ') {
+      *ptr++ = '+';
+      pos++;
+    } else {
+      sprintf(ptr, "%%%2.2X", ch);
+      ptr += 3;
+      pos += 3;
+    }
+  }
+  *ptr++ = '\0';
+
+  return buf;
+}
+
 /************************************************************************** 
   Finds the next (lowest) free port.
 **************************************************************************/ 
Index: utility/netintf.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/utility/netintf.h,v
retrieving revision 1.11
diff -u -r1.11 netintf.h
--- utility/netintf.h   8 May 2004 19:21:01 -0000       1.11
+++ utility/netintf.h   21 Sep 2004 20:33:44 -0000
@@ -66,4 +66,7 @@
 fz_FILE *my_querysocket(int sock, void *buf, size_t size);
 int find_next_free_port(int starting_port);
 
+const char *my_lookup_httpd(char *server, int *port, const char *url);
+const char *my_url_encode(const char *txt);
+
 #endif  /* FC__NETINTF_H */

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