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

 This patch adds IPv6 LAN announcement multicasting. Commandline
parameters control if LAN announcements are done using IPv4 or IPv6 or
not at all.

 You need to enable IPv6 support at configure time to use this.


 - ML

diff -Nurd -X.diff_ignore freeciv/client/civclient.c freeciv/client/civclient.c
--- freeciv/client/civclient.c  2008-06-24 01:37:58.000000000 +0300
+++ freeciv/client/civclient.c  2008-08-14 03:56:50.000000000 +0300
@@ -90,6 +90,7 @@
 int  server_port = -1;
 bool auto_connect = FALSE; /* TRUE = skip "Connect to Freeciv Server" dialog */
 bool in_ggz = FALSE;
+enum announce_type announce;
 
 struct civclient client;
 
@@ -231,6 +232,8 @@
 
   i = 1;
 
+  announce = ANNOUNCE_DEFAULT;
+
   while (i < argc) {
     if (ui_separator) {
       argv[1 + ui_options] = argv[i];
@@ -238,6 +241,7 @@
     } else if (is_option("--help", argv[i])) {
       fc_fprintf(stderr, _("Usage: %s [option ...]\n"
                           "Valid options are:\n"), argv[0]);
+      fc_fprintf(stderr, _("  -A, --Announce PROTO\tAnnounce game in LAN using 
protocol PROTO (IPv4/IPv6/none)\n"));
       fc_fprintf(stderr, _("  -a, --autoconnect\tSkip connect dialog\n"));
 #ifdef DEBUG
       fc_fprintf(stderr, _("  -d, --debug NUM\tSet debug log level (0 to 4,"
@@ -321,6 +325,20 @@
       sz_strlcpy(tileset_name, option);
       free(option);
       user_tileset = TRUE;
+    } else if ((option = get_option_malloc("--Announce", argv, &i, argc))) {
+      if (!strcasecmp(option, "ipv4")) {
+        announce = ANNOUNCE_IPV4;
+      } else if (!strcasecmp(option, "none")) {
+        announce = ANNOUNCE_NONE;
+#ifdef IPV6_SUPPORT
+      } else if(!strcasecmp(option, "ipv6")) {
+        announce = ANNOUNCE_IPV6;
+#endif /* IPv6 support */
+      } else {
+        fc_fprintf(stderr, _("Invalid announce protocol \"%s\".\n"), option);
+        exit(EXIT_FAILURE);
+      }
+      free(option);
     } else if (is_option("--", argv[i])) {
       ui_separator = TRUE;
     } else {
diff -Nurd -X.diff_ignore freeciv/client/servers.c freeciv/client/servers.c
--- freeciv/client/servers.c    2008-07-31 23:27:49.000000000 +0300
+++ freeciv/client/servers.c    2008-08-14 04:14:45.000000000 +0300
@@ -96,6 +96,8 @@
   } meta;
 };
 
+extern enum announce_type announce;
+
 /**************************************************************************
  The server sends a stream in a registry 'ini' type format.
  Read it using secfile functions and fill the server_list structs.
@@ -538,15 +540,35 @@
 #else  /* HAVE_WINSOCK */
   char buffer[MAX_LEN_PACKET];
 #endif /* HAVE_WINSOCK */
-  struct ip_mreq mreq;
+  struct ip_mreq mreq4;
   const char *group;
   size_t size;
+  int family;
+
+#ifdef IPV6_SUPPORT
+  struct ipv6_mreq mreq6;
+#endif
+
 #ifndef HAVE_WINSOCK
   unsigned char ttl;
 #endif
 
+  if (announce == ANNOUNCE_NONE) {
+    /* Succeeded in doing nothing */
+    return TRUE;
+  }
+
+#ifdef IPV6_SUPPORT
+  if (announce == ANNOUNCE_IPV6) {
+    family = AF_INET6;
+  } else
+#endif
+  {
+    family = AF_INET;
+  }
+
   /* Create a socket for broadcasting to servers. */
-  if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+  if ((sock = socket(family, SOCK_DGRAM, 0)) < 0) {
     freelog(LOG_ERROR, "socket failed: %s", mystrerror());
     return FALSE;
   }
@@ -557,11 +579,23 @@
   }
 
   /* Set the UDP Multicast group IP address. */
-  group = get_multicast_group();
+  group = get_multicast_group(announce == ANNOUNCE_IPV6);
   memset(&addr, 0, sizeof(addr));
-  addr.saddr_in4.sin_family = AF_INET;
-  addr.saddr_in4.sin_addr.s_addr = inet_addr(get_multicast_group());
-  addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
+
+#ifndef IPV6_SUPPORT
+  {
+    inet_aton(group, &addr.saddr_in4.sin_addr);
+#else  /* IPv6 support */
+  if (family == AF_INET6) {
+    addr.saddr.sa_family = AF_INET6;
+    inet_pton(AF_INET6, group, &addr.saddr_in6.sin6_addr);
+    addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
+  } else {
+    inet_pton(AF_INET, group, &addr.saddr_in4.sin_addr);
+#endif /* IPv6 support */
+    addr.saddr.sa_family = AF_INET;
+    addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
+  }
 
 /* this setsockopt call fails on Windows 98, so we stick with the default
  * value of 1 on Windows, which should be fine in most cases */
@@ -573,7 +607,7 @@
     freelog(LOG_ERROR, "setsockopt failed: %s", mystrerror());
     return FALSE;
   }
-#endif
+#endif /* HAVE_WINSOCK */
 
   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, 
                  sizeof(opt))) {
@@ -587,7 +621,7 @@
  
 
   if (sendto(sock, buffer, size, 0, &addr.saddr,
-      sockaddr_size(&addr)) < 0) {
+             sockaddr_size(&addr)) < 0) {
     /* This can happen when there's no network connection - it should
      * give an in-game message. */
     freelog(LOG_ERROR, "lanserver scan sendto failed: %s", mystrerror());
@@ -599,7 +633,7 @@
   my_closesocket(sock);
 
   /* Create a socket for listening for server packets. */
-  if ((scan->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+  if ((scan->sock = socket(family, SOCK_DGRAM, 0)) < 0) {
     (scan->error_func)(scan, mystrerror());
     return FALSE;
   }
@@ -612,21 +646,47 @@
   }
                                                                                
   memset(&addr, 0, sizeof(addr));
-  addr.saddr_in4.sin_family = AF_INET;
-  addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY); 
-  addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
+
+#ifdef IPV6_SUPPORT
+  if (family == AF_INET6) {
+    addr.saddr.sa_family = AF_INET6;
+    addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT + 1);
+    addr.saddr_in6.sin6_addr = in6addr_any;
+  } else
+#endif /* IPv6 support */
+  {
+    addr.saddr.sa_family = AF_INET;
+    addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
+    addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
+  }
 
   if (bind(scan->sock, &addr.saddr, sockaddr_size(&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(scan->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
-                 (const char*)&mreq, sizeof(mreq)) < 0) {
-    (scan->error_func)(scan, mystrerror());
-    return FALSE;
+#ifndef IPV6_SUPPORT
+  {
+    inet_aton(group, &mreq4.imr_multiaddr);
+#else
+  if (family == AF_INET6) {
+    inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
+    mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
+
+    if (setsockopt(scan->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
+                   (const char*)&mreq6, sizeof(mreq6)) < 0) {
+      (scan->error_func)(scan, mystrerror());
+    }
+  } else {
+    inet_pton(AF_INET, group, &mreq4.imr_multiaddr.s_addr);
+#endif /* IPv6 support */
+    mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
+
+    if (setsockopt(scan->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                   (const char*)&mreq4, sizeof(mreq4)) < 0) {
+      (scan->error_func)(scan, mystrerror());
+      return FALSE;
+    }
   }
 
   scan->servers = server_list_new();
diff -Nurd -X.diff_ignore freeciv/server/civserver.c freeciv/server/civserver.c
--- freeciv/server/civserver.c  2008-03-08 16:32:28.000000000 +0200
+++ freeciv/server/civserver.c  2008-08-14 03:56:30.000000000 +0300
@@ -123,6 +123,8 @@
 #ifdef GENERATING_MAC
   Mac_options(argc);
 #endif
+  srvarg.announce = ANNOUNCE_DEFAULT;
+
   /* no  we don't use GNU's getopt or even the "standard" getopt */
   /* yes we do have reasons ;)                                   */
   inx = 1;
@@ -190,9 +192,22 @@
       free(option);
     } else if ((option = get_option_malloc("--saves", argv, &inx, argc))) {
       srvarg.saves_pathname = option; /* Never freed. */
-    } else if (is_option("--version", argv[inx]))
+    } else if (is_option("--version", argv[inx])) {
       showvers = TRUE;
-    else {
+    } else if ((option = get_option_malloc("--Announce", argv, &inx, argc))) {
+      if (!strcasecmp(option, "ipv4")) {
+        srvarg.announce = ANNOUNCE_IPV4;
+      } else if(!strcasecmp(option, "none")) {
+        srvarg.announce= ANNOUNCE_NONE;
+#ifdef IPV6_SUPPORT
+      } else if (!strcasecmp(option, "ipv6")) {
+        srvarg.announce = ANNOUNCE_IPV6;
+#endif /* IPv6 support */
+      } else {
+        freelog(LOG_ERROR, _("Illegal value \"%s\" for --Announce"), option);
+      }
+      free(option);
+    } else {
       fc_fprintf(stderr, _("Error: unknown option '%s'\n"), argv[inx]);
       showhelp = TRUE;
       break;
@@ -212,6 +227,7 @@
   if (showhelp) {
     fc_fprintf(stderr,
               _("Usage: %s [option ...]\nValid options are:\n"), argv[0]);
+    fc_fprintf(stderr, _("  -A  --announce PROTO\tAnnounce game in LAN using 
protocol PROTO (IPv4/IPv6/none)\n"));
 #ifdef HAVE_AUTH
     fc_fprintf(stderr, _("  -a  --auth FILE\tEnable server authentication "
                          "with configuration from FILE.\n"));
diff -Nurd -X.diff_ignore freeciv/server/sernet.c freeciv/server/sernet.c
--- freeciv/server/sernet.c     2008-07-27 14:15:10.000000000 +0300
+++ freeciv/server/sernet.c     2008-08-14 04:13:57.000000000 +0300
@@ -926,12 +926,17 @@
   /* setup socket address */
   union my_sockaddr src;
   union my_sockaddr addr;
-  struct ip_mreq mreq;
+  struct ip_mreq mreq4;
   const char *group;
   int opt;
+  int lan_family;
+
+#ifdef IPV6_SUPPORT
+  struct ipv6_mreq mreq6;
+#endif
 
   if (!net_lookup_service(srvarg.bind_addr, srvarg.port, &src)) {
-    freelog(LOG_FATAL, _("Server: bad address: [%s:%d]."),
+    freelog(LOG_FATAL, _("Server: bad address: <%s:%d>."),
            srvarg.bind_addr, srvarg.port);
     exit(EXIT_FAILURE);
   }
@@ -958,8 +963,21 @@
     exit(EXIT_FAILURE);
   }
 
+  if (srvarg.announce == ANNOUNCE_NONE) {
+    return 0;
+  }
+
+#ifdef IPV6_SUPPORT
+  if (srvarg.announce == ANNOUNCE_IPV6) {
+    lan_family = AF_INET6;
+  } else
+#endif /* IPV6 used */
+  {
+    lan_family = AF_INET;
+  }
+
   /* Create socket for server LAN announcements */
-  if ((socklan = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+  if ((socklan = socket(lan_family, SOCK_DGRAM, 0)) < 0) {
      freelog(LOG_ERROR, "socket failed: %s", mystrerror());
   }
 
@@ -970,26 +988,55 @@
 
   my_nonblock(socklan);
 
-  group = get_multicast_group();
+  group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
 
   memset(&addr, 0, sizeof(addr));
-  addr.saddr_in4.sin_family = AF_INET;
-  addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
-  addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
+
+  addr.saddr.sa_family = lan_family;
+
+#ifdef IPV6_SUPPORT
+  if (addr.saddr.sa_family == AF_INET6) {
+    addr.saddr_in6.sin6_family = AF_INET6;
+    addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
+    addr.saddr_in6.sin6_addr = in6addr_any;
+  } else
+#endif /* IPv6 support */
+  {
+    addr.saddr_in4.sin_family = AF_INET;
+    addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
+    addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
+  }
 
   if (bind(socklan, &addr.saddr, sockaddr_size(&addr)) < 0) {
     freelog(LOG_ERROR, "Lan bind failed: %s", mystrerror());
   }
 
-  mreq.imr_multiaddr.s_addr = inet_addr(group);
-  mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+#ifndef IPV6_SUPPORT
+  {
+    inet_aton(group, &mreq4.imr_multiaddr);
+#else
+  if (addr.saddr.sa_family == AF_INET6) {
+    inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
+    mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
+    if (setsockopt(socklan, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
+                   (const char*)&mreq6, sizeof(mreq6)) < 0) {
+      freelog(LOG_ERROR, "IPV6_ADD_MEMBERSHIP (%s) failed: %s",
+              group, mystrerror());
+    }
+  } else {
+    inet_pton(AF_INET, group, &mreq4.imr_multiaddr.s_addr);
+#endif /* IPv6 support */
+    mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
 
-  if (setsockopt(socklan, IPPROTO_IP, IP_ADD_MEMBERSHIP,
-                 (const char*)&mreq, sizeof(mreq)) < 0) {
-    freelog(LOG_ERROR, "setsockopt failed: %s", mystrerror());
+    if (setsockopt(socklan, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                   (const char*)&mreq4, sizeof(mreq4)) < 0) {
+      freelog(LOG_ERROR, "IP_ADD_MEMBERSHIP (%s) failed: %s",
+              group, mystrerror());
+    }
   }
 
   close_socket_set_callback(close_socket_callback);
+
   return 0;
 }
 
@@ -1183,7 +1230,7 @@
   }
 
   /* Set the UDP Multicast group IP address of the packet. */
-  group = get_multicast_group();
+  group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
   memset(&addr, 0, sizeof(addr));
   addr.saddr_in4.sin_family = AF_INET;
   addr.saddr_in4.sin_addr.s_addr = inet_addr(group);
diff -Nurd -X.diff_ignore freeciv/server/srv_main.h freeciv/server/srv_main.h
--- freeciv/server/srv_main.h   2008-07-18 22:08:35.000000000 +0300
+++ freeciv/server/srv_main.h   2008-08-14 03:47:14.000000000 +0300
@@ -13,6 +13,10 @@
 #ifndef FC__SRV_MAIN_H
 #define FC__SRV_MAIN_H
 
+/* utility */
+#include "netintf.h"
+
+/* common */
 #include "fc_types.h"
 
 struct conn_list;
@@ -46,6 +50,7 @@
   char *auth_conf;              /* auth configuration file */
   bool auth_allow_guests;       /* defaults to TRUE */
   bool auth_allow_newusers;     /* defaults to TRUE */
+  enum announce_type announce;
 };
 
 /* used in savegame values */
diff -Nurd -X.diff_ignore freeciv/utility/netintf.h freeciv/utility/netintf.h
--- freeciv/utility/netintf.h   2008-07-31 23:27:48.000000000 +0300
+++ freeciv/utility/netintf.h   2008-08-14 03:55:59.000000000 +0300
@@ -75,6 +75,15 @@
 #endif
 };
 
+/* Which protocol will be used for LAN announcements */
+enum announce_type {
+  ANNOUNCE_NONE,
+  ANNOUNCE_IPV4,
+  ANNOUNCE_IPV6
+};
+
+#define ANNOUNCE_DEFAULT ANNOUNCE_IPV4
+
 int my_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t 
addrlen);
 int my_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
               struct timeval *timeout);
diff -Nurd -X.diff_ignore freeciv/utility/shared.c freeciv/utility/shared.c
--- freeciv/utility/shared.c    2008-07-14 21:49:06.000000000 +0300
+++ freeciv/utility/shared.c    2008-08-14 04:18:59.000000000 +0300
@@ -1596,18 +1596,29 @@
   servers on the LAN, as specified by $FREECIV_MULTICAST_GROUP.
   Gets value once, and then caches result.
 ***************************************************************************/
-char *get_multicast_group(void)
+char *get_multicast_group(bool ipv6_prefered)
 {
   static bool init = FALSE;
   static char *group = NULL;
-  static char *default_multicast_group = "225.1.1.1";
-  
+  static char *default_multicast_group_ipv4 = "225.1.1.1";
+#ifdef IPV6_SUPPORT
+  /* TODO: Get useful group (this is node local) */
+  static char *default_multicast_group_ipv6 = "FF31::8000:15B4";
+#endif
+
   if (!init) {
     char *env = getenv("FREECIV_MULTICAST_GROUP");
     if (env) {
       group = mystrdup(env);           
     } else {
-      group = mystrdup(default_multicast_group);
+#ifdef IPV6_SUPPORT
+      if (ipv6_prefered) {
+        group = mystrdup(default_multicast_group_ipv6);
+      } else
+#endif /* IPv6 support */
+      {
+        group = mystrdup(default_multicast_group_ipv4);
+      }
     }
     init = TRUE;
   }
diff -Nurd -X.diff_ignore freeciv/utility/shared.h freeciv/utility/shared.h
--- freeciv/utility/shared.h    2008-04-17 10:49:41.000000000 +0300
+++ freeciv/utility/shared.h    2008-08-14 04:11:29.000000000 +0300
@@ -235,7 +235,7 @@
                               const char *prefix,
                               int *ind_result);
 
-char *get_multicast_group(void);
+char *get_multicast_group(bool ipv6_prefered);
 void interpret_tilde(char* buf, size_t buf_size, const char* filename);
 char *interpret_tilde_alloc(const char* filename);
 
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to