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

 - Updated against svn
 - Crude dual-stack implementation (improvements to that will be left
to future tickets)

 I'm still going to commit some parts of this separately as they get
cleaned up enough.


 - ML

diff -Nurd -X.diff_ignore freeciv/client/clinet.c freeciv/client/clinet.c
--- freeciv/client/clinet.c     2008-07-25 00:22:34.000000000 +0300
+++ freeciv/client/clinet.c     2008-07-25 00:22:41.000000000 +0300
@@ -167,8 +167,13 @@
     port = DEFAULT_SOCK_PORT;
 
   /* use name to find TCP/IP address of server */
-  if (!hostname)
+  if (!hostname) {
+#ifdef IPV6_USED
+    hostname = "ip6-localhost";
+#else  /* IPV6 used */
     hostname = "localhost";
+#endif /* IPV6 used */
+  }
 
   if (!net_lookup_service(hostname, port, &server_addr)) {
     (void) mystrlcpy(errbuf, _("Failed looking up host."), errbufsize);
@@ -198,7 +203,7 @@
     (void) mystrlcpy(errbuf, _("Connection in progress."), errbufsize);
     return -1;
   }
-  
+
   if ((client.conn.sock = socket(server_addr.saddr.sa_family,
                                  SOCK_STREAM, 0)) == -1) {
     (void) mystrlcpy(errbuf, mystrerror(), errbufsize);
diff -Nurd -X.diff_ignore freeciv/client/connectdlg_common.c 
freeciv/client/connectdlg_common.c
--- freeciv/client/connectdlg_common.c  2008-07-14 21:49:09.000000000 +0300
+++ freeciv/client/connectdlg_common.c  2008-07-25 00:22:41.000000000 +0300
@@ -206,7 +206,13 @@
   append_output_window(_("Starting server..."));
 
   /* find a free port */ 
-  internal_server_port = find_next_free_port(DEFAULT_SOCK_PORT);
+  internal_server_port = find_next_free_port(DEFAULT_SOCK_PORT,
+#ifdef IPV6_USED
+  TRUE
+#else  /* IPv6 used */
+  FALSE
+#endif /* IPv6 used */
+  );
 
 # ifdef HAVE_WORKING_FORK
   server_pid = fork();
@@ -258,7 +264,7 @@
       fchmod(1, 0644);
     }
 
-    /* If it's still attatched to our terminal, things get messed up, 
+    /* If it's still attached to our terminal, things get messed up, 
       but civserver needs *something* */ 
     fclose(stdin);
     fd = open("/dev/null", O_RDONLY);
diff -Nurd -X.diff_ignore freeciv/client/servers.c freeciv/client/servers.c
--- freeciv/client/servers.c    2008-07-25 00:22:34.000000000 +0300
+++ freeciv/client/servers.c    2008-07-25 00:22:41.000000000 +0300
@@ -413,14 +413,14 @@
     (scan->error_func)(scan, _("Failed looking up metaserver's host"));
     return FALSE;
   }
-  
+
   if ((s = socket(addr.saddr.sa_family, SOCK_STREAM, 0)) == -1) {
     (scan->error_func)(scan, mystrerror());
     return FALSE;
   }
 
   my_nonblock(s);
-  
+
   if (my_connect(s, &addr.saddr, sockaddr_size(&addr)) == -1) {
     if (errno == EINPROGRESS) {
       /* With non-blocking sockets this is the expected result. */
@@ -538,15 +538,27 @@
 #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
+#endif /* WINSOCK */
+
+#ifdef IPV6_USED
+  family = AF_INET6;
+#else  /* IPv6 used */
+  family = AF_INET;
+#endif /* IPv6 used */
 
   /* 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;
   }
@@ -559,9 +571,20 @@
   /* Set the UDP Multicast group IP address. */
   group = get_multicast_group();
   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 +596,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 +610,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 +622,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;
   }
@@ -610,23 +633,50 @@
                  (char *)&opt, sizeof(opt)) == -1) {
     freelog(LOG_ERROR, "SO_REUSEADDR failed: %s", mystrerror());
   }
-                                                                               
+
   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;
+    FC_SET_SIN_LEN(&addr.saddr_in6, sizeof(addr.addr_in6));
+  } 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();
@@ -642,7 +692,6 @@
 {
   socklen_t fromlen;
   union my_sockaddr fromend;
-  struct hostent *from;
   char msgbuf[128];
   int type;
   struct data_in din;
@@ -659,7 +708,7 @@
     bool duplicate = FALSE;
 
     dio_input_init(&din, msgbuf, sizeof(msgbuf));
-    fromlen = sizeof(fromend);
+    fromlen = sizeof(&fromend);
 
     /* Try to receive a packet from a server.  No select loop is needed;
      * we just keep on reading until recvfrom returns -1. */
@@ -680,9 +729,46 @@
     dio_get_string(&din, message, sizeof(message));
 
     if (!mystrcasecmp("none", servername)) {
-      from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
+      bool nameinfo = FALSE;
+#ifdef IPV6_SUPPORT
+      char dst[INET6_ADDRSTRLEN];
+#else  /* IPv6 support */
+      const char *dst;
+#endif /* IPv6 support */
+#ifdef HAVE_GETNAMEINFO
+      char host[NI_MAXHOST], service[NI_MAXSERV];
+
+      if (!getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
+                       service, NI_MAXSERV, NI_NUMERICSERV)) {
+        nameinfo = TRUE;
+      }
+#else /* getnameinfo */
+      struct hostent *from;
+      char *host = NULL;
+
+#ifdef IPV6_SUPPORT
+      from = gethostbyaddr((char *) &fromend.saddr_in6.sin6_addr,
+                          sizeof(fromend.saddr_in6.sin6_addr), AF_INET6);
+#else  /* IPv6 support */
+     from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
                           sizeof(fromend.saddr_in4.sin_addr), AF_INET);
-      sz_strlcpy(servername, inet_ntoa(fromend.saddr_in4.sin_addr));
+#endif /* IPv6 support */
+      if (from) {
+        host = from->h_name;
+        nameinfo = TRUE;
+      }
+#endif /* getnameinfo */
+
+      if (!nameinfo) {
+#ifdef IPV6_SUPPORT
+        inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
+                  dst, sizeof(dst));
+#else  /* IPv6 support */
+        dst = inet_ntoa(fromend.saddr_in4.sin_addr);
+#endif /* IPv6 support */
+      }
+
+      sz_strlcpy(servername, nameinfo ? host : dst);
     }
 
     /* UDP can send duplicate or delayed packets. */
diff -Nurd -X.diff_ignore freeciv/common/connection.c 
freeciv/common/connection.c
--- freeciv/common/connection.c 2008-04-17 10:49:41.000000000 +0300
+++ freeciv/common/connection.c 2008-07-25 00:22:41.000000000 +0300
@@ -48,7 +48,11 @@
 /* String used for connection.addr and related cases to indicate
  * blank/unknown/not-applicable address:
  */
+#ifdef IPV6_SUPPORT
+const char blank_addr_str[] = "?:?:?:?:?:?:?:?";
+#else
 const char blank_addr_str[] = "---.---.---.---";
+#endif
 
 /* This is only used by the server.
    If it is set the disconnection of conns is posponed. This is sometimes
diff -Nurd -X.diff_ignore freeciv/server/meta.c freeciv/server/meta.c
--- freeciv/server/meta.c       2008-07-25 00:22:34.000000000 +0300
+++ freeciv/server/meta.c       2008-07-25 00:22:41.000000000 +0300
@@ -397,7 +397,9 @@
     str
   );
 
-  my_writesocket(sock, msg, n);
+  if (my_writesocket(sock, msg, n) < 0) {
+    freelog(LOG_ERROR, "Metaserver write failed: %s", mystrerror());
+  }
 
   my_closesocket(sock);
 
@@ -418,7 +420,7 @@
 bool server_open_meta(void)
 {
   const char *path;
- 
+
   if (metaserver_path) {
     free(metaserver_path);
     metaserver_path = NULL;
@@ -427,7 +429,7 @@
   if (!(path = my_lookup_httpd(metaname, &metaport, srvarg.metaserver_addr))) {
     return FALSE;
   }
-  
+
   metaserver_path = mystrdup(path);
 
   if (!net_lookup_service(metaname, metaport, &meta_addr)) {
diff -Nurd -X.diff_ignore freeciv/server/sernet.c freeciv/server/sernet.c
--- freeciv/server/sernet.c     2008-07-25 00:22:34.000000000 +0300
+++ freeciv/server/sernet.c     2008-07-25 00:22:41.000000000 +0300
@@ -821,7 +821,18 @@
 
   int new_sock;
   union my_sockaddr fromend;
+  bool nameinfo = FALSE;
+#ifdef HAVE_GETNAMEINFO
+  char host[NI_MAXHOST], service[NI_MAXSERV];
+#else
   struct hostent *from;
+  char *host = NULL;
+#endif
+#ifdef IPV6_SUPPORT
+  char dst[INET6_ADDRSTRLEN];
+#else  /* IPv6 support */
+  const char *dst;
+#endif /* IPv6 support */
 
   fromlen = sizeof(fromend);
 
@@ -830,14 +841,36 @@
     return -1;
   }
 
+#ifdef HAVE_GETNAMEINFO
+  if (!getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
+                   service, NI_MAXSERV, NI_NUMERICSERV)) {
+    nameinfo = TRUE;
+  }
+#else  /* getnameinfo */
+#ifdef IPV6_SUPPORT
   from =
-      gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
-                   sizeof(fromend.saddr_in4.sin_addr), AF_INET);
+    gethostbyaddr((char *) &fromend.saddr_in6.sin6_addr,
+                  sizeof(fromend.saddr_in6.sin6_addr), AF_INET6);
+#else  /* IPv6 support */
+  from =
+    gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
+                  sizeof(fromend.saddr_in4.sin_addr), AF_INET);
+#endif /* IPv6 support */
+  if (from) {
+    host = from->h_name;
+    nameinfo = TRUE;
+  }
+#endif /* getnameinfo */
+
+#ifdef IPV6_SUPPORT
+  inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
+            dst, sizeof(dst));
+#else  /* IPv6 support */
+  dst = inet_ntoa(fromend.saddr_in4.sin_addr);
+#endif /* IPv6 support */
 
   return server_make_connection(new_sock,
-                               (from ? from->h_name
-                                 : inet_ntoa(fromend.saddr_in4.sin_addr)),
-                               inet_ntoa(fromend.saddr_in4.sin_addr));
+                               (nameinfo ? host : dst), dst);
 }
 
 /********************************************************************
@@ -902,12 +935,22 @@
   /* 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
+
+#ifdef IPV6_USED
+  lan_family = AF_INET6;
+#else  /* IPV6 used */
+  lan_family = AF_INET;
+#endif /* IPV6 used */
 
   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);
   }
@@ -935,7 +978,7 @@
   }
 
   /* 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());
   }
 
@@ -949,20 +992,50 @@
   group = get_multicast_group();
 
   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;
+    FC_SET_SIN_LEN(&addr.saddr_in6, sizeof(addr));
+  } 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_IP, IP_ADD_MEMBERSHIP,
-                 (const char*)&mreq, sizeof(mreq)) < 0) {
-    freelog(LOG_ERROR, "setsockopt failed: %s", mystrerror());
+    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*)&mreq4, sizeof(mreq4)) < 0) {
+      freelog(LOG_ERROR, "IP_ADD_MEMBERSHIP (%s) failed: %s",
+              group, mystrerror());
+    }
   }
 
   close_socket_set_callback(close_socket_callback);
@@ -1148,12 +1221,20 @@
   int socksend, setting = 1;
   const char *group;
   size_t size;
+  int family;
+
 #ifndef HAVE_WINSOCK
   unsigned char ttl;
 #endif
 
+#ifdef IPV6_USED
+  family = AF_INET6;
+#else  /* IPv6 used */
+  family = AF_INET;
+#endif /* IPv6 used */
+
   /* Create a socket to broadcast to client. */
-  if ((socksend = socket(AF_INET,SOCK_DGRAM, 0)) < 0) {
+  if ((socksend = socket(family, SOCK_DGRAM, 0)) < 0) {
     freelog(LOG_ERROR, "socket failed: %s", mystrerror());
     return;
   }
@@ -1161,9 +1242,20 @@
   /* Set the UDP Multicast group IP address of the packet. */
   group = get_multicast_group();
   memset(&addr, 0, sizeof(addr));
-  addr.saddr_in4.sin_family = AF_INET;
-  addr.saddr_in4.sin_addr.s_addr = inet_addr(group);
-  addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
+#ifndef IPV6_SUPPORT
+  {
+    inet_aton(group, &addr.saddr_in4.sin_addr);
+#else  /* IPv6 support */
+  if (family == AF_INET6) {
+    addr.saddr_in6.sin6_family = AF_INET6;
+    inet_pton(AF_INET6, group, &addr.saddr_in6.sin6_addr);
+    addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT + 1);
+  } else {
+    inet_pton(AF_INET, group, &addr.saddr_in4.sin_addr);
+#endif /* IPv6 support */
+    addr.saddr_in4.sin_family = AF_INET;
+    addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
+  }
 
 /* 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 */
@@ -1226,8 +1318,8 @@
 
   /* Sending packet to client with the information gathered above. */
   if (sendto(socksend, buffer,  size, 0, &addr.saddr,
-      sockaddr_size(&addr)) < 0) {
-    freelog(LOG_ERROR, "landserver response sendto failed: %s", mystrerror());
+             sockaddr_size(&addr)) < 0) {
+    freelog(LOG_ERROR, "lanserver response sendto failed: %s", mystrerror());
     return;
   }
 
diff -Nurd -X.diff_ignore freeciv/utility/netintf.c freeciv/utility/netintf.c
--- freeciv/utility/netintf.c   2008-07-22 17:57:14.000000000 +0300
+++ freeciv/utility/netintf.c   2008-07-25 00:22:41.000000000 +0300
@@ -52,8 +52,8 @@
 
 #include "fcintl.h"
 #include "log.h"
-#include "shared.h"            /* TRUE, FALSE */
-#include "support.h"
+#include "shared.h"
+#include "support.h"           /* TRUE, FALSE */
 
 #include "netintf.h"
 
@@ -149,7 +149,7 @@
 int my_writesocket(int sock, const void *buf, size_t size)
 {
   int result;
-        
+
 #ifdef HAVE_WINSOCK
   result = send(sock, buf, size, 0);
   if (result == -1) {
@@ -295,7 +295,7 @@
 #endif /* IPv6 support */
   {
     return FALSE;
- }
+  }
 }
 
 /***************************************************************************
@@ -304,31 +304,74 @@
 bool net_lookup_service(const char *name, int port, union my_sockaddr *addr)
 {
   struct hostent *hp;
-  struct sockaddr_in *sock = &addr->saddr_in4;
+  struct sockaddr_in *sock4;
+#ifdef IPV6_SUPPORT
+  struct sockaddr_in6 *sock6;
+#endif /* IPv6 support */
 
-  sock->sin_family = AF_INET;
-  sock->sin_port = htons(port);
+  sock4 = &addr->saddr_in4;
+
+#ifdef IPV6_SUPPORT
+  sock6 = &addr->saddr_in6;
+
+  addr->saddr.sa_family = AF_INET6;
+  sock6->sin6_port = htons(port);
+  FC_SET_SIN_LEN(sock6, sizeof(*sock6));
+#else /* IPv6 support */
+  addr->saddr.sa_family = AF_INET;
+  sock4->sin_port = htons(port);
+#endif /* IPv6 support */
 
   if (!name) {
-    sock->sin_addr.s_addr = htonl(INADDR_ANY);
+#ifdef IPV6_SUPPORT
+    sock6->sin6_addr = in6addr_any;
+#else  /* IPv6 support */
+    sock4->sin_addr.s_addr = htonl(INADDR_ANY);
+#endif /* IPv6 support */
     return TRUE;
   }
 
-#ifdef HAVE_INET_ATON
-  if (inet_aton(name, &sock->sin_addr) != 0) {
+#ifdef IPV6_SUPPORT
+  if (inet_pton(AF_INET6, name, &sock6->sin6_addr)) {
     return TRUE;
   }
-#else
-  if ((sock->sin_addr.s_addr = inet_addr(name)) != INADDR_NONE) {
+  /* TODO: Replace gethostbyname2() with getaddrinfo() */
+  hp = gethostbyname2(name, AF_INET6);
+  if (!hp || hp->h_addrtype != AF_INET6) {
+    /* Try to fallback to IPv4 */
+    freelog(LOG_DEBUG, "Falling back to IPv4");
+    hp = gethostbyname2(name, AF_INET);
+    if (!hp || hp->h_addrtype != AF_INET) {
+      return FALSE;
+    }
+    addr->saddr.sa_family = AF_INET;
+    sock4->sin_port = htons(port);
+  }
+#else  /* IPV6 support */
+#if defined(HAVE_INET_ATON)
+  if (inet_aton(name, &sock4->sin_addr) != 0) {
     return TRUE;
   }
-#endif
+#else  /* HAVE_INET_ATON */
+  if ((sock4->sin_addr.s_addr = inet_addr(name)) != INADDR_NONE) {
+    return TRUE;
+  }
+#endif /* HAVE_INET_ATON */
   hp = gethostbyname(name);
   if (!hp || hp->h_addrtype != AF_INET) {
     return FALSE;
   }
+#endif /* IPv6 support */
+
+#ifdef IPV6_SUPPORT
+  if (addr->saddr.sa_family == AF_INET6) {
+    memcpy(&sock6->sin6_addr, hp->h_addr, hp->h_length);
+  } else
+#endif /* IPv6 support */
+  {
+    memcpy(&sock4->sin_addr, hp->h_addr, hp->h_length);
+  }
 
-  memcpy(&sock->sin_addr, hp->h_addr, hp->h_length);
   return TRUE;
 }
 
@@ -508,19 +551,48 @@
 /************************************************************************** 
   Finds the next (lowest) free port.
 **************************************************************************/ 
-int find_next_free_port(int starting_port)
+int find_next_free_port(int starting_port, bool IPv6)
 {
-  int port, s = socket(AF_INET, SOCK_STREAM, 0);
+  int port;
+  int family;
+  int s;
+
+#ifdef IPV6_SUPPORT
+  if (IPv6) {
+    family = AF_INET6;
+  } else
+#endif  /* IPv6 used */
+  {
+    family = AF_INET;
+  }
+
+  s = socket(family, SOCK_STREAM, 0);
 
   for (port = starting_port;; port++) {
     union my_sockaddr tmp;
-    struct sockaddr_in *sock = &tmp.saddr_in4;
+    struct sockaddr_in *sock4;
+
+#ifdef IPV6_SUPPORT
+    struct sockaddr_in6 *sock6;
+#endif /* IPV6 support */
 
     memset(&tmp, 0, sizeof(tmp));
 
-    sock->sin_family = AF_INET;
-    sock->sin_port = htons(port);
-    sock->sin_addr.s_addr = htonl(INADDR_ANY);
+#ifdef IPV6_SUPPORT
+    if (IPv6) {
+      sock6 = &tmp.saddr_in6;
+      sock6->sin6_family = AF_INET6;
+      sock6->sin6_port = htons(port);
+      sock6->sin6_addr = in6addr_any;
+      FC_SET_SIN_LEN(sock, sizeof(*sock6));
+    } else
+#endif /* IPV6 support */
+    {
+      sock4 = &tmp.saddr_in4;
+      sock4->sin_family = AF_INET;
+      sock4->sin_port = htons(port);
+      sock4->sin_addr.s_addr = htonl(INADDR_ANY);
+    }
 
     if (bind(s, &tmp.saddr, sockaddr_size(&tmp)) == 0) {
       break;
diff -Nurd -X.diff_ignore freeciv/utility/netintf.h freeciv/utility/netintf.h
--- freeciv/utility/netintf.h   2008-07-22 17:57:14.000000000 +0300
+++ freeciv/utility/netintf.h   2008-07-25 00:22:41.000000000 +0300
@@ -43,6 +43,11 @@
 #include "ioz.h"
 #include "shared.h"            /* bool type */
 
+/* Define macros for IPv6 compatibility or not. */
+#ifdef IPV6_SUPPORT
+#define FC_SET_SIN_LEN(a, b)
+#endif /* IPV6_SUPPORT */
+
 /* map symbolic Winsock error names to symbolic errno names */
 #ifdef HAVE_WINSOCK
 #undef EINTR
@@ -81,14 +86,13 @@
 int my_readsocket(int sock, void *buf, size_t size);
 int my_writesocket(int sock, const void *buf, size_t size); 
 void my_closesocket(int sock);
-void my_init_network(void);         
+void my_init_network(void);
 void my_shutdown_network(void);
 
 void my_nonblock(int sockfd);
-bool net_lookup_service(const char *name, int port, 
-                        union my_sockaddr *addr);
+bool net_lookup_service(const char *name, int port, union my_sockaddr *addr);
 fz_FILE *my_querysocket(int sock, void *buf, size_t size);
-int find_next_free_port(int starting_port);
+int find_next_free_port(int starting_port, bool IPv6);
 
 const char *my_lookup_httpd(char *server, int *port, const char *url);
 const char *my_url_encode(const char *txt);
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-07-25 00:22:41.000000000 +0300
@@ -1600,12 +1600,17 @@
 {
   static bool init = FALSE;
   static char *group = NULL;
+#ifdef IPV6_USED
+  /* TODO: Get useful group (this is node local) */
+  static char *default_multicast_group = "FF31::8000:15B4";
+#else
   static char *default_multicast_group = "225.1.1.1";
-  
+#endif
+
   if (!init) {
     char *env = getenv("FREECIV_MULTICAST_GROUP");
     if (env) {
-      group = mystrdup(env);           
+      group = mystrdup(env);
     } else {
       group = mystrdup(default_multicast_group);
     }
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to