diff options
-rw-r--r-- | ACE/NEWS | 10 | ||||
-rw-r--r-- | ACE/ace/INET_Addr.cpp | 156 | ||||
-rw-r--r-- | ACE/ace/INET_Addr.h | 26 | ||||
-rw-r--r-- | ACE/ace/INET_Addr.inl | 2 | ||||
-rw-r--r-- | ACE/ace/Multihomed_INET_Addr.cpp | 81 | ||||
-rw-r--r-- | ACE/tests/INET_Addr_Test.cpp | 51 |
6 files changed, 247 insertions, 79 deletions
@@ -8,6 +8,16 @@ USER VISIBLE CHANGES BETWEEN ACE-6.3.1 and ACE-6.3.2 supported. Please see tests/Chrono_Test.cpp for more details. +. Allow ACE_INET_Addr to hold all addresses associated with a hostname. The + set of addresses always has a "current" address which is accessed by the + usual "get"-type methods on the class. Two new methods are added to deal + with multiple addresses: + - bool next (void): makes the next available address the "current" one. + Returns false if there are no more addresses. + - void reset (void): resets the iteration mechanism to be able to examine + all of the addresses again. + ACE_Multihomed_INET_Addr has also been enhanced so that the get_addresses() + methods copy all available addresses related to each name. USER VISIBLE CHANGES BETWEEN ACE-6.3.0 and ACE-6.3.1 ==================================================== diff --git a/ACE/ace/INET_Addr.cpp b/ACE/ace/INET_Addr.cpp index 1c422fdb899..2367fb2499d 100644 --- a/ACE/ace/INET_Addr.cpp +++ b/ACE/ace/INET_Addr.cpp @@ -152,11 +152,31 @@ ACE_INET_Addr::hash (void) const return this->get_ip_address () + this->get_port_number (); } +bool +ACE_INET_Addr::next (void) +{ + if (this->inet_addrs_.empty () || + this->inet_addrs_iter_ == this->inet_addrs_.end ()) + return false; + + union ip46 next_a = *this->inet_addrs_iter_++; + this->set_addr (&next_a, sizeof (next_a)); + return true; +} + +void +ACE_INET_Addr::reset (void) +{ + this->inet_addrs_iter_ = this->inet_addrs_.begin (); + this->next (); + return; +} + ACE_INET_Addr::ACE_INET_Addr (void) : ACE_Addr (determine_type (), sizeof (inet_addr_)) { // ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); } int @@ -176,6 +196,8 @@ ACE_INET_Addr::set (const ACE_INET_Addr &sa) this->set_type (sa.get_type()); this->set_size (sa.get_size()); + this->inet_addrs_ = sa.inet_addrs_; + this->reset (); } return 0; @@ -266,7 +288,7 @@ ACE_INET_Addr::ACE_INET_Addr (const char address[], int address_family) : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); this->set (address, address_family); } @@ -275,7 +297,7 @@ ACE_INET_Addr::ACE_INET_Addr (const wchar_t address[], int address_family) : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); this->set (address, address_family); } @@ -287,7 +309,7 @@ ACE_INET_Addr::ACE_INET_Addr (const ACE_INET_Addr &sa) : ACE_Addr (sa.get_type (), sa.get_size()) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); this->set (sa); } @@ -354,15 +376,22 @@ ACE_INET_Addr::set (u_short port_number, { if (hp != 0) { - struct sockaddr_in6 v6; - ACE_OS::memset (&v6, 0, sizeof (v6)); - v6.sin6_family = AF_INET6; - (void) ACE_OS::memcpy ((void *) &v6.sin6_addr, - hp->h_addr, - hp->h_length); this->set_type (hp->h_addrtype); - this->set_addr (&v6, hp->h_length); - this->set_port_number (port_number, encode); + for (size_t i = 0; hp->h_addr_list[i]; ++i) + { + union ip46 next_addr; + struct sockaddr_in6 *next_addr_in6 = (struct sockaddr_in6 *)&next_addr.in6_; + (void) ACE_OS::memset (&next_addr, sizeof (next_addr), 0); + next_addr_in6->sin6_family = AF_INET6; + next_addr_in6->sin6_port = + encode ? ACE_NTOHS (port_number) : port_number; + (void) ACE_OS::memcpy ((void *) &next_addr_in6->sin6_addr, + hp->h_addr_list[i], + hp->h_length); + this->inet_addrs_.push_back (next_addr); + } + this->reset (); + return 0; } } @@ -371,16 +400,35 @@ ACE_INET_Addr::set (u_short port_number, return -1; # else struct addrinfo hints; - struct addrinfo *res = 0; + struct addrinfo *res = 0, *curr = 0; int error = 0; ACE_OS::memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_INET6; if ((error = ::getaddrinfo (host_name, 0, &hints, &res)) == 0) { this->set_type (res->ai_family); - this->set_addr (res->ai_addr, - ACE_Utils::truncate_cast<int>(res->ai_addrlen)); - this->set_port_number (port_number, encode); + for (curr = res; curr; curr = curr->ai_next) + { + union ip46 next_addr; + if (curr->ai_family == AF_INET6) + { + ACE_OS::memcpy (&next_addr.in6_, + curr->ai_addr, + curr->ai_addrlen); + next_addr.in6_.sin6_port = + encode ? ACE_NTOHS (port_number) : port_number; + } + else + { + ACE_OS::memcpy (&next_addr.in4_, + curr->ai_addr, + curr->ai_addrlen); + next_addr.in4_.sin_port = + encode ? ACE_NTOHS (port_number) : port_number; + } + this->inet_addrs_.push_back (next_addr); + } + this->reset (); ::freeaddrinfo (res); return 0; } @@ -406,34 +454,40 @@ ACE_INET_Addr::set (u_short port_number, struct in_addr addrv4; if (ACE_OS::inet_aton (host_name, &addrv4) == 1) - return this->set (port_number, - encode ? ACE_NTOHL (addrv4.s_addr) : addrv4.s_addr, - encode); - else { - hostent hentry; - ACE_HOSTENT_DATA buf; - int h_error = 0; // Not the same as errno! + this->inet_addrs_iter_ = this->inet_addrs_.end (); + return this->set (port_number, + encode ? ACE_NTOHL (addrv4.s_addr) : addrv4.s_addr, + encode); + } - hostent *hp = ACE_OS::gethostbyname_r (host_name, &hentry, - buf, &h_error); - if (hp == 0) - errno = h_error; + hostent hentry; + ACE_HOSTENT_DATA buf; + int h_error = 0; // Not the same as errno! - if (hp == 0) - { - return -1; - } - else - { - (void) ACE_OS::memcpy ((void *) &addrv4.s_addr, - hp->h_addr, - hp->h_length); - return this->set (port_number, - encode ? ACE_NTOHL (addrv4.s_addr) : addrv4.s_addr, - encode); - } + hostent *hp = ACE_OS::gethostbyname_r (host_name, &hentry, + buf, &h_error); + if (hp == 0) + { + errno = h_error; + return -1; } + + this->set_type (hp->h_addrtype); + for (size_t i = 0; hp->h_addr_list[i]; ++i) + { + union ip46 next_addr; + struct sockaddr_in *next_addr_in = (struct sockaddr_in *)&next_addr.in4_; + (void) ACE_OS::memset (&next_addr, sizeof (next_addr), 0); + next_addr_in->sin_family = AF_INET; + next_addr_in->sin_port = encode ? ACE_NTOHS (port_number) : port_number; + (void) ACE_OS::memcpy ((void *) &next_addr_in->sin_addr, + hp->h_addr_list[i], + hp->h_length); + this->inet_addrs_.push_back (next_addr); + } + this->reset (); + return 0; } // Helper function to get a port number from a port name. @@ -609,17 +663,18 @@ ACE_INET_Addr::get_addr (void) const } void -ACE_INET_Addr::set_addr (void *addr, int len) +ACE_INET_Addr::set_addr (const void *addr, int len) { this->set_addr (addr, len, 0); } // Set a pointer to the address. void -ACE_INET_Addr::set_addr (void *addr, int /* len */, int map) +ACE_INET_Addr::set_addr (const void *addr, int /* len */, int map) { ACE_TRACE ("ACE_INET_Addr::set_addr"); - struct sockaddr_in *getfamily = static_cast<struct sockaddr_in *> (addr); + const struct sockaddr_in *getfamily = + static_cast<const struct sockaddr_in *> (addr); if (getfamily->sin_family == AF_INET) { @@ -637,7 +692,8 @@ ACE_INET_Addr::set_addr (void *addr, int /* len */, int map) #if defined (ACE_HAS_IPV6) else if (getfamily->sin_family == AF_INET6) { - struct sockaddr_in6 *in6 = static_cast<struct sockaddr_in6*> (addr); + const struct sockaddr_in6 *in6 = + static_cast<const struct sockaddr_in6*> (addr); this->set_port_number (in6->sin6_port, 0); this->set_address (reinterpret_cast<const char*> (&in6->sin6_addr), sizeof (in6->sin6_addr), @@ -653,7 +709,7 @@ ACE_INET_Addr::ACE_INET_Addr (const sockaddr_in *addr, int len) : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); this->set (addr, len); } @@ -664,7 +720,7 @@ ACE_INET_Addr::ACE_INET_Addr (u_short port_number, : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); if (this->set (port_number, inet_address) == -1) ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), @@ -680,7 +736,7 @@ ACE_INET_Addr::ACE_INET_Addr (const char port_name[], : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); if (this->set (port_name, host_name, protocol) == -1) @@ -695,7 +751,7 @@ ACE_INET_Addr::ACE_INET_Addr (const wchar_t port_name[], : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); if (this->set (port_name, host_name, protocol) == -1) @@ -712,7 +768,7 @@ ACE_INET_Addr::ACE_INET_Addr (const char port_name[], : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); if (this->set (port_name, ACE_HTONL (inet_address), protocol) == -1) @@ -727,7 +783,7 @@ ACE_INET_Addr::ACE_INET_Addr (const wchar_t port_name[], : ACE_Addr (determine_type (), sizeof (inet_addr_)) { ACE_TRACE ("ACE_INET_Addr::ACE_INET_Addr"); - this->reset (); + this->reset_i (); if (this->set (port_name, ACE_HTONL (inet_address), protocol) == -1) diff --git a/ACE/ace/INET_Addr.h b/ACE/ace/INET_Addr.h index 0c21df7b75b..357eac3f0d2 100644 --- a/ACE/ace/INET_Addr.h +++ b/ACE/ace/INET_Addr.h @@ -19,6 +19,7 @@ #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "ace/Addr.h" +#include <vector> ACE_BEGIN_VERSIONED_NAMESPACE_DECL @@ -27,6 +28,10 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL * * @brief Defines a C++ wrapper facade for the Internet domain address * family format. + * + * ACE_INET_Addr can hold all of the IP addresses assigned to a single name. + * By default it refers only to the first, if there is more than one. The + * next() method can make the others available in turn. */ class ACE_Export ACE_INET_Addr : public ACE_Addr { @@ -189,14 +194,14 @@ public: int get_addr_size(void) const; /// Set a pointer to the address. - virtual void set_addr (void *, int len); + virtual void set_addr (const void *, int len); /// Set a pointer to the address. - virtual void set_addr (void *, int len, int map); + virtual void set_addr (const void *, int len, int map); /** * Transform the current ACE_INET_Addr address into string format. - * If @a ipaddr_format is ttrue this produces "ip-number:port-number" + * If @a ipaddr_format is true this produces "ip-number:port-number" * (e.g., "128.252.166.57:1234"), whereas if @a ipaddr_format is false * this produces "ip-name:port-number" (e.g., * "tango.cs.wustl.edu:1234"). Returns -1 if the @a size of the @@ -347,6 +352,13 @@ public: /// Computes and returns hash value. virtual u_long hash (void) const; + /// If there is another address to examine, move to it and return true; + /// else return false. + bool next (void); + + /// Reset the set of address so they can be scanned again using next(). + void reset (void); + /// Dump the state of an object. void dump (void) const; @@ -364,18 +376,22 @@ private: int determine_type (void) const; /// Initialize underlying inet_addr_ to default values - void reset (void); + void reset_i (void); /// Underlying representation. /// This union uses the knowledge that the two structures share the /// first member, sa_family (as all sockaddr structures do). - union + union ip46 { sockaddr_in in4_; #if defined (ACE_HAS_IPV6) sockaddr_in6 in6_; #endif /* ACE_HAS_IPV6 */ } inet_addr_; + // If there is more than one address assigned to a given name, this + // holds all of them; one is always copied to inet_addr_. + std::vector<union ip46> inet_addrs_; + std::vector<union ip46>::iterator inet_addrs_iter_; }; ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/ACE/ace/INET_Addr.inl b/ACE/ace/INET_Addr.inl index 6cc14c97558..2532bb9cb6f 100644 --- a/ACE/ace/INET_Addr.inl +++ b/ACE/ace/INET_Addr.inl @@ -7,7 +7,7 @@ ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_INLINE void -ACE_INET_Addr::reset (void) +ACE_INET_Addr::reset_i (void) { ACE_OS::memset (&this->inet_addr_, 0, sizeof (this->inet_addr_)); if (this->get_type() == AF_INET) diff --git a/ACE/ace/Multihomed_INET_Addr.cpp b/ACE/ace/Multihomed_INET_Addr.cpp index a734beb1ae2..1acc40c1053 100644 --- a/ACE/ace/Multihomed_INET_Addr.cpp +++ b/ACE/ace/Multihomed_INET_Addr.cpp @@ -243,21 +243,40 @@ void ACE_Multihomed_INET_Addr::get_addresses(sockaddr_in *addrs, size_t size) const { - // Copy primary address to the first slot of the user-supplied array - if (size > 0) { - addrs[0] = *reinterpret_cast<sockaddr_in*> (this->get_addr ()); - } + if (size == 0) + return; + // Copy primary address(es) to the first slot(s) of the user-supplied array + ACE_INET_Addr me (*this); + size_t i = 0; + for (i = 0; i < size; ++i) + { + sockaddr_in *in4 = reinterpret_cast<sockaddr_in*> (me.get_addr ()); + if (in4->sin_family == AF_INET) + { + addrs[i] = *in4; + ++i; + } + if (!me.next ()) + break; + } // Copy secondary addresses to remaining slots of the user-supplied // array. Secondary address [i] is copied to slot [i+1] - - size_t top = size - 1 < this->secondaries_.size() ? - size - 1 : this->secondaries_.size(); - - for (size_t i = 0; i < top; ++i) { - addrs[i+1] = - *reinterpret_cast<sockaddr_in*> (this->secondaries_[i].get_addr()); - } + for (size_t j = 0; j < this->secondaries_.size (); ++j) + { + ACE_INET_Addr copy (this->secondaries_[j]); + for (; i < size; ++i) + { + sockaddr_in *in4 = reinterpret_cast<sockaddr_in*> (copy.get_addr ()); + if (in4->sin_family == AF_INET) + { + addrs[i] = *in4; + ++i; + } + if (!copy.next ()) + break; + } + } } #if defined (ACE_HAS_IPV6) @@ -265,22 +284,40 @@ void ACE_Multihomed_INET_Addr::get_addresses(sockaddr_in6 *addrs, size_t size) const { - // Copy primary address to the first slot of the user-supplied array - if (size > 0) + if (size == 0) + return; + // Copy primary address(es) to the first slot(s) of the user-supplied array + ACE_INET_Addr me (*this); + size_t i = 0; + for (i = 0; i < size; ++i) { - addrs[0] = *reinterpret_cast<sockaddr_in6*> (this->get_addr ()); + sockaddr_in6 *in6 = reinterpret_cast<sockaddr_in6*> (me.get_addr ()); + if (in6->sin6_family == AF_INET6) + { + addrs[i] = *in6; + ++i; + } + if (!me.next ()) + break; } // Copy secondary addresses to remaining slots of the user-supplied // array. Secondary address [i] is copied to slot [i+1] - size_t top = - size - 1 < this->secondaries_.size() ? - size - 1 : this->secondaries_.size(); - - for (size_t i = 0; i < top; ++i) + for (size_t j = 0; j < this->secondaries_.size (); ++j) { - addrs[i+1] = - *reinterpret_cast<sockaddr_in6*> (this->secondaries_[i].get_addr()); + ACE_INET_Addr copy (this->secondaries_[j]); + for (; i < size; ++i) + { + sockaddr_in6 *in6 = + reinterpret_cast<sockaddr_in6*> (copy.get_addr ()); + if (in6->sin6_family == AF_INET6) + { + addrs[i] = *in6; + ++i; + } + if (!copy.next ()) + break; + } } } #endif /* ACE_HAS_IPV6 */ diff --git a/ACE/tests/INET_Addr_Test.cpp b/ACE/tests/INET_Addr_Test.cpp index 4743b2894f3..9e2cfc7a4a9 100644 --- a/ACE/tests/INET_Addr_Test.cpp +++ b/ACE/tests/INET_Addr_Test.cpp @@ -20,7 +20,7 @@ // Make sure that ACE_Addr::addr_type_ is the same // as the family of the inet_addr_. -int check_type_consistency (const ACE_INET_Addr &addr) +static int check_type_consistency (const ACE_INET_Addr &addr) { int family = -1; @@ -49,6 +49,52 @@ int check_type_consistency (const ACE_INET_Addr &addr) return 0; } +static bool test_multiple (void) +{ + + bool success = true; + + // Check the behavior when there are multiple addresses assigned to a name. + // The NTP pool should always return multiples, though always different. + ACE_INET_Addr ntp; + if (ntp.set (123, ACE_TEXT ("pool.ntp.org")) == -1) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("pool.ntp.org"))); + return false; + } + size_t count = 0; + ACE_TCHAR addr_string[256]; + do + { + ++count; // If lookup succeeded, there's at least one + ntp.addr_to_string (addr_string, sizeof (addr_string)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("IPv4 %B: %s\n"), count, addr_string)); + } + while (ntp.next ()); + success = count > 1; + +#if defined (ACE_HAS_IPV6) + ACE_INET_Addr ntp6; + if (ntp6.set (123, ACE_TEXT ("2.pool.ntp.org"), 1, AF_INET6) == -1) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("2.pool.ntp.org"))); + return false; + } + count = 0; + do + { + ++count; // If lookup succeeded, there's at least one + ntp6.addr_to_string (addr_string, sizeof (addr_string)); + ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("IPv6 %B: %s\n"), count, addr_string)); + } + while (ntp6.next ()); + if (count <= 1) + success = false; +#endif /* ACE_HAS_IPV6 */ + + return success; +} + struct Address { const char* name; bool loopback; @@ -273,6 +319,9 @@ int run_main (int, ACE_TCHAR *[]) status = 1; } + if (!test_multiple ()) + status = 1; + ACE_END_TEST; return status; |