Index: builds/win32/msvc9/fbembed.vcproj =================================================================== --- builds/win32/msvc9/fbembed.vcproj (revision 57120) +++ builds/win32/msvc9/fbembed.vcproj (working copy) @@ -1,7 +1,7 @@ + + + + @@ -410,6 +414,10 @@ > + + Index: builds/win32/msvc9/fb_inet_server.vcproj =================================================================== --- builds/win32/msvc9/fb_inet_server.vcproj (revision 57120) +++ builds/win32/msvc9/fb_inet_server.vcproj (working copy) @@ -1,7 +1,7 @@ + + Index: builds/make.new/config/install-sh =================================================================== --- builds/make.new/config/install-sh (revision 57120) +++ builds/make.new/config/install-sh (working copy) @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2006-12-25.00 +scriptversion=2010-02-06.18; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -200,7 +200,11 @@ fi if test -z "$dir_arg"; then - trap '(exit $?); exit' 1 2 13 15 + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. @@ -515,5 +519,6 @@ # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" # End: Index: src/jrd/isc_file.cpp =================================================================== --- src/jrd/isc_file.cpp (revision 57120) +++ src/jrd/isc_file.cpp (working copy) @@ -82,6 +82,13 @@ #include "../common/config/config.h" +#ifndef WIN_NT +#include /* for inet_pton() see ISC_analyze_tcp */ +#endif +#ifdef WIN_NT +#include "../common/inet_nptopn.h" +#endif + const char INET_FLAG = ':'; /* Unix/NFS specific stuff */ @@ -368,13 +375,31 @@ /* Scan file name looking for separator character */ +/* + * Separator character is : (at the moment) that is also used in + * IPv6 addresses, this has been changed to deal with an IPv6 case + */ + node_name.erase(); - const size p = file_name.find(INET_FLAG); - if (p == npos || p == 0 || p == file_name.length() - 1) - return false; + size p = file_name.find(INET_FLAG); + size pend; + if (file_name[0] == '[' && (pend = file_name.find(']'))) + { + char tmpaddr[16]; + node_name = file_name.substr(1, pend - 1); + if (inet_pton(AF_INET6, node_name.c_str(), tmpaddr) != 1) + { + node_name.erase(); + return false; + } + p = pend + 1; + } + else { + if (p == npos) + return false; + node_name = file_name.substr(0, p); + } - node_name = file_name.substr(0, p); - #ifdef WIN_NT /* For Windows NT, insure that a single character node name does not conflict with an existing drive letter. */ Index: src/include/gen/autoconfig_msvc.h =================================================================== --- src/include/gen/autoconfig_msvc.h (revision 57120) +++ src/include/gen/autoconfig_msvc.h (working copy) @@ -286,6 +286,9 @@ /* Windows platforms support threads */ #define HAVE_MULTI_THREAD 1 +/* Ensure FB is listening on inet6 and inet interfaces */ +#define USE_SPECIAL_IPV6_SOCKET + /* CPU types */ #undef PowerPC #undef sparc @@ -308,6 +311,7 @@ #define WIN_NT #undef SCO_EV + #define FB_PREFIX "c:\\Program Files\\Firebird\\" #define FB_BINDIR "" Index: src/remote/inet.cpp =================================================================== --- src/remote/inet.cpp (revision 57120) +++ src/remote/inet.cpp (working copy) @@ -80,6 +80,9 @@ #ifdef WIN_NT #define FD_SETSIZE 1024 + +#include +#include "../common/inet_nptopn.h" #endif #ifndef WIN_NT @@ -451,8 +454,8 @@ #endif -static in_addr get_bind_address(); -static int get_host_address(const char* name, in_addr* const host_addr_arr, const int arr_size); +static in6_addr * get_bind_address(); +static int get_host_address(const char* name, in6_addr* const host_addr_arr, const int arr_size, const bool includeipv6); static void copy_p_cnct_repeat_array( p_cnct::p_cnct_repeat* pDest, const p_cnct::p_cnct_repeat* pSource, @@ -728,6 +731,19 @@ return port; } +int INET_convertfromv6(struct sockaddr * address) { + struct sockaddr_in6 * addr6; + struct sockaddr_in * addr4; + + addr6 = (struct sockaddr_in6 *)address; + addr4 = (struct sockaddr_in *)address; + + memcpy(&addr4->sin_addr, &addr6->sin6_addr.s6_addr[12], 4); + address->sa_family = AF_INET; + + return 0; +} + rem_port* INET_connect(const TEXT* name, PACKET* packet, ISC_STATUS* status_vector, @@ -767,6 +783,7 @@ status_vector[0] = isc_arg_gds; status_vector[1] = 0; status_vector[2] = isc_arg_end; + bool tryIPv6 = true; Firebird::string host; Firebird::string protocol; @@ -804,46 +821,14 @@ // Set up Inter-Net socket address - struct sockaddr_in address; + struct sockaddr_in6 address; memset(&address, 0, sizeof(address)); // U N I X style sockets + // AF_INET6 may change later if host does not support IPv6 sockets - address.sin_family = AF_INET; + address.sin6_family = AF_INET6; - // define maximum numbers of addresses for a host that we can handle - const int MAX_HOST_ADDRESS_NUMBER = 8; - - in_addr host_addr; - in_addr host_addr_arr[MAX_HOST_ADDRESS_NUMBER]; - int hostAddressNumber = 0; - - if (packet) - { - // client connection - hostAddressNumber = get_host_address(host.c_str(), host_addr_arr, MAX_HOST_ADDRESS_NUMBER); - if (hostAddressNumber > MAX_HOST_ADDRESS_NUMBER) - { - hostAddressNumber = MAX_HOST_ADDRESS_NUMBER; - } - - if (! hostAddressNumber) - { - gds__log("INET/INET_connect: gethostbyname (%s) failed, error code = %d", - host.c_str(), H_ERRNO); - inet_gen_error(port, Arg::Gds(isc_net_lookup_err) << Arg::Gds(isc_host_unknown)); - - disconnect(port); - return NULL; - } - host_addr = host_addr_arr[0]; - } - else - { - // server connection - host_addr = get_bind_address(); - } - const struct servent* service = getservbyname(protocol.c_str(), "tcp"); #ifdef WIN_NT // On Windows NT/9x, getservbyname can only accomodate @@ -880,7 +865,7 @@ if (protocol == FB_SERVICE_NAME) { // apply hardwired translation - address.sin_port = htons(FB_SERVICE_PORT); + address.sin6_port = htons(FB_SERVICE_PORT); } // modification by FSG 23.MAR.2001 else @@ -889,10 +874,10 @@ // The user has supplied something as protocol // let's see whether this is a port number // instead of a service name - address.sin_port = htons(atoi(protocol.c_str())); + address.sin6_port = htons(atoi(protocol.c_str())); } - if (address.sin_port == 0) + if (address.sin6_port == 0) { // end of modification by FSG // this is the original code @@ -907,14 +892,28 @@ // if we have got a service-struct, get port number from there // (in case of hardwired gds_db to 3050 translation, address.sin_port was // already set above - address.sin_port = service->s_port; + address.sin6_port = service->s_port; } // else (service found) // end of modifications by luz // Allocate a port block and initialize a socket for communications - port->port_handle = socket(AF_INET, SOCK_STREAM, 0); + port->port_handle = INVALID_SOCKET; + // if this call is for a server and the SRVR_inet6 flag + // or this is NOT a server call + if (((flag & SRVR_inet6) && (flag & SRVR_server || flag & SRVR_multi_client)) || + !(flag & SRVR_server || flag & SRVR_multi_client)) + { + gds__log("INET/INET_connect: creating a v6 socket"); + port->port_handle = socket(AF_INET6, SOCK_STREAM, 0); + } + // IPv6 may have failed because of underlying operating system support + if (port->port_handle == INVALID_SOCKET) + { + port->port_flags |= PORT_v4; + port->port_handle = socket(AF_INET, SOCK_STREAM, 0); + } if (port->port_handle == INVALID_SOCKET) { @@ -923,9 +922,50 @@ return NULL; } + // Moved from earlier so we know what kind of addresses are acceptable + // IPv6 and IPv4 or just IPv4 + // define maximum numbers of addresses for a host that we can handle + const int MAX_HOST_ADDRESS_NUMBER = 8; + + in6_addr host_addr; + in6_addr host_addr_arr[MAX_HOST_ADDRESS_NUMBER]; + int hostAddressNumber = 0; + + if (packet) + { + // client connection + hostAddressNumber = get_host_address(host.c_str(), host_addr_arr, MAX_HOST_ADDRESS_NUMBER, + port->port_flags & PORT_v4 ? 0 : 1); + if (hostAddressNumber > MAX_HOST_ADDRESS_NUMBER) + { + hostAddressNumber = MAX_HOST_ADDRESS_NUMBER; + } + if (hostAddressNumber == 1 && port->port_flags & PORT_v4) { + const UCHAR loopbkaddr6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + const UCHAR loopbkaddr4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1 }; + + if (memcmp((void *)host_addr_arr, loopbkaddr6, 16) == 0) { + memcpy((void *)host_addr_arr, loopbkaddr4, 16); + } + } + + if (! hostAddressNumber) + { + gds__log("INET/INET_connect: gethostbyname (%s) failed, error code = %d", + host.c_str(), H_ERRNO); + inet_gen_error(port, Arg::Gds(isc_net_lookup_err) << Arg::Gds(isc_host_unknown)); + } + memcpy(&host_addr, &host_addr_arr[0], sizeof(in6_addr)); + } + else + { + // server connection + memcpy(&host_addr, get_bind_address(), sizeof(in6_addr)); + } + // If we're a host, just make the connection - int n; + int n; if (packet) { @@ -947,11 +987,17 @@ int inetErrNo = 0; for (int i = 0; i < hostAddressNumber; i++) { - address.sin_addr = host_addr_arr[i]; + address.sin6_addr = host_addr_arr[i]; // If host has two addresses and the first one failed, // but the second one succeeded - no need to worry + if (port->port_flags & PORT_v4) + { + INET_convertfromv6((struct sockaddr*) &address); + ((struct sockaddr*) &address)->sa_family = AF_INET; + } + n = connect(port->port_handle, (struct sockaddr*) &address, sizeof(address)); inetErrNo = INET_ERRNO; @@ -965,7 +1011,7 @@ // We're a server, so wait for a host to show up - memcpy(&address.sin_addr, &host_addr, sizeof(address.sin_addr)); + memcpy(&address.sin6_addr, &host_addr, sizeof(address.sin6_addr)); if (flag & SRVR_multi_client) { @@ -990,6 +1036,24 @@ return NULL; } #endif +#ifdef USE_SPECIAL_IPV6_SOCKET + if (!(port->port_flags & PORT_v4)) { + // We are a server and want to only bind to the IPv6 addresses + int ipv6only = 1; + setsockopt(port->port_handle, IPPROTO_IPV6, IPV6_V6ONLY, (SCHAR*)&ipv6only, (socklen_t)sizeof(int)); + } +#else + if (!(port->port_flags & PORT_v4)) { + // We are a server and want to bind to IPv6 and IPv4 addresses + int ipv6only = 0; + setsockopt(port->port_handle, IPPROTO_IPV6, IPV6_V6ONLY, (SCHAR*)&ipv6only, (socklen_t)sizeof(int)); + } +#endif + + if (port->port_flags & PORT_v4) { + INET_convertfromv6((struct sockaddr *)&address); + ((struct sockaddr *)&address)->sa_family = AF_INET; + } // Get any values for SO_LINGER so that they can be reset during // disconnect. SO_LINGER should be set by default on the socket @@ -1076,6 +1140,9 @@ } return NULL; } + if (((struct sockaddr *)&address)->sa_family == AF_INET) { + port->port_flags |= PORT_v4; + } #ifdef WIN_NT if (flag & SRVR_debug) #else @@ -1314,24 +1381,28 @@ temp.printf("%s.%ld.%ld", name.c_str(), eff_gid, eff_uid); port->port_user_name = REMOTE_make_string(temp.c_str()); - port->port_protocol_str = REMOTE_make_string("TCPv4"); - - struct sockaddr_in address; + struct sockaddr_in6 address; socklen_t l = sizeof(address); memset(&address, 0, sizeof(address)); int status = getpeername(port->port_handle, (struct sockaddr *) &address, &l); if (status == 0) { - Firebird::string addr_str; - const UCHAR* ip = (UCHAR*) &address.sin_addr; - addr_str.printf( - "%d.%d.%d.%d", - static_cast(ip[0]), - static_cast(ip[1]), - static_cast(ip[2]), - static_cast(ip[3]) ); - port->port_address_str = REMOTE_make_string(addr_str.c_str()); + if (((struct sockaddr *)&address)->sa_family == AF_INET) { + char ipv4pres[INET_ADDRSTRLEN]; + port->port_protocol_str = REMOTE_make_string("TCPv4"); + inet_ntop(AF_INET, + &((struct sockaddr_in *)&address)->sin_addr.s_addr, + ipv4pres, INET_ADDRSTRLEN); + port->port_address_str = REMOTE_make_string(ipv4pres); + port->port_flags |= PORT_v4; + } else if (((struct sockaddr *)&address)->sa_family == AF_INET6) { + char ipv6pres[INET6_ADDRSTRLEN]; + port->port_protocol_str = REMOTE_make_string("TCPv6"); + inet_ntop(AF_INET6, &address.sin6_addr, ipv6pres, + INET6_ADDRSTRLEN); + port->port_address_str = REMOTE_make_string(ipv6pres); + } } return true; @@ -1444,7 +1515,7 @@ * done a successfull connect request ("packet" contains the response). * **************************************/ - struct sockaddr_in address; + struct sockaddr_in6 address; socklen_t l = sizeof(address); // If this is a server, we're got an auxiliary connection. Accept it @@ -1486,6 +1557,10 @@ const SOCKET n = accept(port->port_channel, (struct sockaddr*) &address, &l); inetErrNo = INET_ERRNO; + if (((struct sockaddr *)&address)->sa_family == AF_INET) { + port->port_flags |= PORT_v4; + } + if (n == INVALID_SOCKET) { inet_error(port, "accept", isc_net_event_connect_err, inetErrNo); @@ -1503,13 +1578,21 @@ port->port_async = new_port; new_port->port_dummy_packet_interval = port->port_dummy_packet_interval; new_port->port_dummy_timeout = new_port->port_dummy_packet_interval; - new_port->port_flags = port->port_flags & PORT_no_oob; + new_port->port_flags = port->port_flags & (PORT_no_oob | PORT_v4); new_port->port_flags |= PORT_async; P_RESP* response = &packet->p_resp; // Set up new socket - SOCKET n = socket(AF_INET, SOCK_STREAM, 0); + SOCKET n; + if (new_port->port_flags & PORT_v4) + { + n = socket(AF_INET, SOCK_STREAM, 0); + } + else { + n = socket(AF_INET6, SOCK_STREAM, 0); + } + if (n == INVALID_SOCKET) { inet_error(port, "socket", isc_net_event_connect_err, INET_ERRNO); @@ -1533,9 +1616,18 @@ SOCLOSE(n); return NULL; } - address.sin_family = AF_INET; - address.sin_port = ((struct sockaddr_in *)(response->p_resp_data.cstr_address))->sin_port; +// address.sin_family = AF_INET; +// address.sin_port = ((struct sockaddr_in *)(response->p_resp_data.cstr_address))->sin_port; + // Conversion from an IPv6 struct is not required because this is already an IPv4 (AF_INET / sockaddr_in) struct + // Also, sin6_port and sin_port occupy the same place in the structure... now that was lucky ;-) + address.sin6_port = ((struct sockaddr_in6 *)(response->p_resp_data.cstr_address))->sin6_port; + + if (address.sin6_family == AF_INET6) + { + INET_convertfromv6((struct sockaddr *) &address); + } + int optval = 1; setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, (SCHAR*) &optval, sizeof(optval)); @@ -1567,16 +1659,26 @@ * connection; the server calls aux_request to set up the connection. * **************************************/ - struct sockaddr_in address; + struct sockaddr_in6 address; // Set up new socket - address.sin_family = AF_INET; - in_addr bind_addr = get_bind_address(); - memcpy(&address.sin_addr, &bind_addr, sizeof(address.sin_addr)); - address.sin_port = htons(Config::getRemoteAuxPort()); + address.sin6_family = AF_INET6; + in6_addr bind_addr; + memcpy(&bind_addr, get_bind_address(), sizeof(in6_addr)); + memcpy(&address.sin6_addr, &bind_addr, sizeof(address.sin6_addr)); + address.sin6_port = htons(Config::getRemoteAuxPort()); - SOCKET n = socket(AF_INET, SOCK_STREAM, 0); + SOCKET n; + if (port->port_flags & PORT_v4) + { + INET_convertfromv6((struct sockaddr *)&address); + n = socket(AF_INET, SOCK_STREAM, 0); + } + else { + n = socket(AF_INET6, SOCK_STREAM, 0); + } + if (n == INVALID_SOCKET) { inet_error(port, "socket", isc_net_event_listen_err, INET_ERRNO); @@ -1617,24 +1719,24 @@ return NULL; } - rem_port* const new_port = alloc_port(port->port_parent, PORT_async); + rem_port* const new_port = alloc_port(port->port_parent, PORT_async); port->port_async = new_port; new_port->port_dummy_packet_interval = port->port_dummy_packet_interval; new_port->port_dummy_timeout = new_port->port_dummy_packet_interval; new_port->port_server_flags = port->port_server_flags; new_port->port_channel = (int) n; - new_port->port_flags |= port->port_flags & PORT_no_oob; + new_port->port_flags |= port->port_flags & (PORT_no_oob | PORT_v4); P_RESP* response = &packet->p_resp; - struct sockaddr_in port_address; + struct sockaddr_in6 port_address; if (getsockname(port->port_handle, (struct sockaddr *) &port_address, &length) < 0) { inet_error(port, "getsockname", isc_net_event_listen_err, INET_ERRNO); return NULL; } - memcpy(&address.sin_addr, &port_address.sin_addr, sizeof(address.sin_addr)); + memcpy(&address.sin6_addr, &port_address.sin6_addr, sizeof(address.sin6_addr)); response->p_resp_data.cstr_length = sizeof(address); memcpy(response->p_resp_data.cstr_address, &address, sizeof(address)); @@ -1655,15 +1757,29 @@ * Check the host on the other end of the socket to see if it's localhost * **************************************/ - struct sockaddr_in address; + struct sockaddr_in6 address; + /* this is the IPv6 loopback address */ + const u_int8_t loopbkaddr6[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + const u_int8_t loopbkaddr4[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 127, 0, 0, 1 }; socklen_t length = sizeof(address); if (getpeername(port->port_handle, (struct sockaddr*) &address, &length) == -1) return false; + // is this an IPv4 sockaddr? + if (address.sin6_family == AF_INET) { + return (ntohl(((struct sockaddr_in *)&address)->sin_addr.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET; + } else + // it's IPv6... or 4/6 + // If source address is in the loopback net - trust it + if ( memcmp(loopbkaddr6, &address.sin6_addr, 16) == 0 || memcmp(loopbkaddr4, &address.sin6_addr, 13) == 0) { + return true; + } + return false; + // If source address is in the loopback net - trust it - return (ntohl(address.sin_addr.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET; + //return (ntohl(address.sin_addr.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET; } #endif // WIN_NT @@ -1930,7 +2046,7 @@ namespace { - in_addr config_address; + in6_addr config_address; class GetAddress { @@ -1940,12 +2056,14 @@ const char* config_option = Config::getRemoteBindAddress(); if (config_option) { - int n = get_host_address(config_option, &config_address, 1); + int n = get_host_address(config_option, &config_address, 1, 1); if (n != 1) { // In case when config option is given with error, // bind to loopback interface only - config_address.s_addr = htonl(INADDR_LOOPBACK); + //config_address.s_addr = htonl(INADDR_LOOPBACK); + memset(&config_address, 0, sizeof(in6_addr)); + ((char *)&config_address)[15] = 1; // log warning if (n == 0) { @@ -1961,7 +2079,7 @@ } else // use default to listen all { - config_address.s_addr = INADDR_ANY; + memset(&config_address, 0, sizeof(in6_addr)); } } @@ -1969,7 +2087,7 @@ }; } -static in_addr get_bind_address() +static in6_addr * get_bind_address() { /************************************** * @@ -1985,7 +2103,7 @@ instance.init(); - return config_address; + return &config_address; } @@ -2000,8 +2118,9 @@ static int get_host_address(const char* name, - in_addr* const host_addr_arr, - const int arr_size) + in6_addr* const host_addr_arr, + const int arr_size, + const bool includeipv6) { /************************************** * @@ -2010,16 +2129,23 @@ ************************************** * * Functional description - * Fills array with addresses up to arr_size (must be at least 1). + * Fills array with addresses up to arr_size (must be at least 1). * Returns the required number of elements in array to be able to store * all host addresses (may be less, equal or greater than arr_size). * **************************************/ - if (inet_aton(name, &host_addr_arr[0])) + if (inet_pton(AF_INET, name, (((char *)&host_addr_arr[0]) + 12))) { + memset(&host_addr_arr[0], 0, sizeof(in6_addr) - (4 + 2)); + memset((((char *)&host_addr_arr[0]) + 10), 0xFF, 2); return 1; } + if (includeipv6 && inet_pton(AF_INET6, name, &host_addr_arr[0])) + { + return 1; + } + const hostent* host = gethostbyname(name); // On Windows NT/9x, gethostbyname can only accomodate @@ -2030,33 +2156,58 @@ // retry the operation a few times. // NOTE: This still does not guarantee success, but helps. - if (!host) + struct addrinfo * result; + int res; + + res = getaddrinfo(name, NULL, NULL, &result); + + if (res) { for (int retry = 0; H_ERRNO == INET_RETRY_ERRNO && retry < INET_RETRY_CALL; retry++) { - if ( (host = gethostbyname(name)) ) + if (getaddrinfo(name, NULL, NULL, &result) == 0) break; } } - // We can't work with other types for now. Maybe AF_NETBIOS for MS, too? - if (host && host->h_addrtype == AF_INET) + struct addrinfo *listelement; + listelement = result; + int i = 0; + + // here we prefer IPv6 addresses, they will fail in the connect stage of an IPv4 only server + if (includeipv6) { - const in_addr* const* list = reinterpret_cast(host->h_addr_list); - int i = 0; - while (list[i] != NULL) - { - if (i < arr_size) + while (listelement != NULL) + { + if (listelement->ai_family == AF_INET6 && i < arr_size) { - host_addr_arr[i] = *list[i]; + memcpy(&host_addr_arr[i], + &((struct sockaddr_in6 *)&listelement->ai_addr)->sin6_addr, + sizeof(in6_addr)); + i ++; } - ++i; + listelement = listelement->ai_next; } - return i; } - // give up - return 0; + // put the IPv4 addresses after the IPv6 ones + listelement = result; + while (listelement != NULL) { + if (listelement->ai_family == AF_INET && i < arr_size) { + // little hack to for IPv4 only addresses that will work with IPv4 and IPv6 hosts. + memset(&host_addr_arr[i], 0, sizeof(in6_addr) - (4 + 2)); + memset((((char *)&host_addr_arr[i]) + 10), 0xFF, 2); + memcpy((((char *)&host_addr_arr[i]) + 12), &((struct sockaddr_in *)&listelement->ai_addr)->sin_addr, sizeof(in_addr)); + i++; + } + listelement = listelement->ai_next; + } + + freeaddrinfo(result); + + return i; + + // We can't work with other types for now. Maybe AF_NETBIOS for MS, too? } //____________________________________________________________ @@ -2208,7 +2359,7 @@ * Accept a new connection request. * **************************************/ - struct sockaddr_in address; + struct sockaddr_in6 address; rem_port* const port = alloc_port(main_port); socklen_t l = sizeof(address); Index: src/remote/os/win32/srvr_w32.cpp =================================================================== --- src/remote/os/win32/srvr_w32.cpp (revision 57120) +++ src/remote/os/win32/srvr_w32.cpp (working copy) @@ -367,7 +367,7 @@ while (!server_shutdown) { fb_utils::init_status(status_vector); - rem_port* port = INET_connect(protocol_inet, NULL, status_vector, server_flag, 0); + rem_port* port = INET_connect(protocol_inet, NULL, status_vector, server_flag & ~SRVR_inet6 , 0); if (!port) { @@ -390,7 +390,47 @@ return 0; } +static THREAD_ENTRY_DECLARE inet6_connect_wait_thread(THREAD_ENTRY_PARAM tep) +{ +/************************************** + * + * i n e t 6 _ c o n n e c t _ w a i t _ t h r e a d + * + ************************************** + * + * Functional description + * + **************************************/ + ThreadCounter counter; + ISC_STATUS_ARRAY status_vector; + while (!server_shutdown) + { + fb_utils::init_status(status_vector); + rem_port* port = INET_connect(protocol_inet, NULL, status_vector, server_flag, 0); + + if (!port) + { + if (status_vector[1]) { + gds__log_status(0, status_vector); + } + break; + } + if (server_flag & SRVR_multi_client) + { + SRVR_multi_thread(port, server_flag); + break; + } + if (gds__thread_start(process_connection_thread, port, THREAD_medium, 0, 0)) + { + gds__log("INET6: can't start worker thread, connection terminated"); + port->disconnect(NULL, NULL); + } + } + return 0; +} + + static THREAD_ENTRY_DECLARE wnet_connect_wait_thread(THREAD_ENTRY_PARAM) { /************************************** @@ -488,7 +528,7 @@ } -static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM) +static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM tep) { /************************************** * @@ -501,6 +541,11 @@ **************************************/ ThreadCounter counter; +#ifdef USE_SPECIAL_IPV6_SOCKET + if (server_flag & SRVR_inet6) { + gds__thread_start(inet6_connect_wait_thread, 0, THREAD_medium, 0, 0); + } +#endif if (server_flag & SRVR_inet) { gds__thread_start(inet_connect_wait_thread, 0, THREAD_medium, 0, 0); } @@ -693,6 +738,10 @@ *pserver_flag |= SRVR_xnet; break; + case '6': + *pserver_flag |= SRVR_inet6; + break; + case 'Z': // CVC: printf doesn't work because we don't have a console attached. //printf("Firebird remote server version %s\n", FB_VERSION); @@ -710,11 +759,12 @@ } } - if ((*pserver_flag & (SRVR_inet | SRVR_wnet | SRVR_xnet)) == 0) + if ((*pserver_flag & (SRVR_inet | SRVR_wnet | SRVR_xnet | SRVR_inet6)) == 0) { *pserver_flag |= SRVR_wnet; *pserver_flag |= SRVR_inet; *pserver_flag |= SRVR_xnet; + *pserver_flag |= SRVR_inet6; } return connection_handle; Index: src/remote/remote.h =================================================================== --- src/remote/remote.h (revision 57120) +++ src/remote/remote.h (working copy) @@ -589,6 +589,7 @@ const USHORT PORT_server = 0x0200; // Server (not client) port const USHORT PORT_detached = 0x0400; // op_detach, op_drop_database or op_service_detach was processed const USHORT PORT_rdb_shutdown = 0x0800; // Database is shut down +const USHORT PORT_v4 = 0x1000; // This is an IPv4 only port // Port itself Index: src/remote/remote_def.h =================================================================== --- src/remote/remote_def.h (revision 57120) +++ src/remote/remote_def.h (working copy) @@ -85,5 +85,6 @@ const USHORT SRVR_high_priority = 128; // fork off server at high priority const USHORT SRVR_thread_per_port = 256; // bind thread to a port const USHORT SRVR_no_icon = 512; // tell the server not to show the icon +const USHORT SRVR_inet6 = 1024; // inet6 protocol server #endif /* REMOTE_REMOTE_DEF_H */ Index: src/remote/inet_server.cpp =================================================================== --- src/remote/inet_server.cpp (revision 57120) +++ src/remote/inet_server.cpp (working copy) @@ -370,7 +370,7 @@ } { // scope block ISC_STATUS_ARRAY status_vector; - port = INET_connect(protocol, 0, status_vector, INET_SERVER_flag, 0); + port = INET_connect(protocol, 0, status_vector, INET_SERVER_flag | SRVR_inet6, 0); if (!port) { gds__print_status(status_vector);