<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