Index: net/base/address_list.cc |
=================================================================== |
--- net/base/address_list.cc (revision 18213) |
+++ net/base/address_list.cc (working copy) |
@@ -11,14 +11,128 @@ |
#include <netdb.h> |
#endif |
+#include "base/logging.h" |
+ |
namespace net { |
+namespace { |
+ |
+// Make a deep copy of |info|. This copy should be deleted using |
+// DeleteCopyOfAddrinfo(), and NOT freeaddrinfo(). |
+struct addrinfo* CreateCopyOfAddrinfo(const struct addrinfo* info) { |
+ struct addrinfo* copy = new struct addrinfo; |
+ |
+ // Copy all the fields (some of these are pointers, we will fix that next). |
+ memcpy(copy, info, sizeof(addrinfo)); |
+ |
+ // ai_canonname is a NULL-terminated string. |
+ if (info->ai_canonname) { |
+#ifdef OS_WIN |
+ copy->ai_canonname = _strdup(info->ai_canonname); |
+#else |
+ copy->ai_canonname = strdup(info->ai_canonname); |
+#endif |
+ } |
+ |
+ // ai_addr is a buffer of length ai_addrlen. |
+ if (info->ai_addr) { |
+ copy->ai_addr = reinterpret_cast<sockaddr *>(new char[info->ai_addrlen]); |
+ memcpy(copy->ai_addr, info->ai_addr, info->ai_addrlen); |
+ } |
+ |
+ // Recursive copy. |
+ if (info->ai_next) |
+ copy->ai_next = CreateCopyOfAddrinfo(info->ai_next); |
+ |
+ return copy; |
+} |
+ |
+// Free an addrinfo that was created by CreateCopyOfAddrinfo(). |
+void FreeMyAddrinfo(struct addrinfo* info) { |
+ if (info->ai_canonname) |
+ free(info->ai_canonname); // Allocated by strdup. |
+ |
+ if (info->ai_addr) |
+ delete [] reinterpret_cast<char*>(info->ai_addr); |
+ |
+ struct addrinfo* next = info->ai_next; |
+ |
+ delete info; |
+ |
+ // Recursive free. |
+ if (next) |
+ FreeMyAddrinfo(next); |
+} |
+ |
+// Returns the address to port field in |info|. |
+uint16* GetPortField(const struct addrinfo* info) { |
+ if (info->ai_family == AF_INET) { |
+ DCHECK_EQ(sizeof(sockaddr_in), info->ai_addrlen); |
+ struct sockaddr_in* sockaddr = |
+ reinterpret_cast<struct sockaddr_in*>(info->ai_addr); |
+ return &sockaddr->sin_port; |
+ } else if (info->ai_family == AF_INET6) { |
+ DCHECK_EQ(sizeof(sockaddr_in6), info->ai_addrlen); |
+ struct sockaddr_in6* sockaddr = |
+ reinterpret_cast<struct sockaddr_in6*>(info->ai_addr); |
+ return &sockaddr->sin6_port; |
+ } else { |
+ NOTREACHED(); |
+ return NULL; |
+ } |
+} |
+ |
+// Assign the port for all addresses in the list. |
+void SetPortRecursive(struct addrinfo* info, int port) { |
+ uint16* port_field = GetPortField(info); |
+ *port_field = htons(port); |
+ |
+ // Assign recursively. |
+ if (info->ai_next) |
+ SetPortRecursive(info->ai_next, port); |
+} |
+ |
+} // namespace |
+ |
void AddressList::Adopt(struct addrinfo* head) { |
- data_ = new Data(head); |
+ data_ = new Data(head, true /*is_system_created*/); |
} |
+void AddressList::Copy(const struct addrinfo* head) { |
+ data_ = new Data(CreateCopyOfAddrinfo(head), false /*is_system_created*/); |
+} |
+ |
+void AddressList::SetPort(int port) { |
+ SetPortRecursive(data_->head, port); |
+} |
+ |
+int AddressList::GetPort() const { |
+ uint16* port_field = GetPortField(data_->head); |
+ return ntohs(*port_field); |
+} |
+ |
+void AddressList::SetFrom(const AddressList& src, int port) { |
+ if (src.GetPort() == port) { |
+ // We can reference the data from |src| directly. |
+ *this = src; |
+ } else { |
+ // Otherwise we need to make a copy in order to change the port number. |
+ Copy(src.head()); |
+ SetPort(port); |
+ } |
+} |
+ |
+void AddressList::Reset() { |
+ data_ = NULL; |
+} |
+ |
AddressList::Data::~Data() { |
- freeaddrinfo(head); |
+ // Call either freeaddrinfo(head), or FreeMyAddrinfo(head), depending who |
+ // created the data. |
+ if (is_system_created) |
+ freeaddrinfo(head); |
+ else |
+ FreeMyAddrinfo(head); |
} |
} // namespace net |