OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/base/address_list.h" | 5 #include "net/base/address_list.h" |
6 | 6 |
7 #ifdef OS_WIN | 7 #ifdef OS_WIN |
8 #include <ws2tcpip.h> | 8 #include <ws2tcpip.h> |
9 #include <wspiapi.h> // Needed for Win2k compat. | 9 #include <wspiapi.h> // Needed for Win2k compat. |
10 #else | 10 #else |
11 #include <netdb.h> | 11 #include <netdb.h> |
12 #endif | 12 #endif |
13 | 13 |
| 14 #include "base/logging.h" |
| 15 |
14 namespace net { | 16 namespace net { |
15 | 17 |
| 18 namespace { |
| 19 |
| 20 // Make a deep copy of |info|. This copy should be deleted using |
| 21 // DeleteCopyOfAddrinfo(), and NOT freeaddrinfo(). |
| 22 struct addrinfo* CreateCopyOfAddrinfo(const struct addrinfo* info) { |
| 23 struct addrinfo* copy = new struct addrinfo; |
| 24 |
| 25 // Copy all the fields (some of these are pointers, we will fix that next). |
| 26 memcpy(copy, info, sizeof(addrinfo)); |
| 27 |
| 28 // ai_canonname is a NULL-terminated string. |
| 29 if (info->ai_canonname) { |
| 30 #ifdef OS_WIN |
| 31 copy->ai_canonname = _strdup(info->ai_canonname); |
| 32 #else |
| 33 copy->ai_canonname = strdup(info->ai_canonname); |
| 34 #endif |
| 35 } |
| 36 |
| 37 // ai_addr is a buffer of length ai_addrlen. |
| 38 if (info->ai_addr) { |
| 39 copy->ai_addr = reinterpret_cast<sockaddr *>(new char[info->ai_addrlen]); |
| 40 memcpy(copy->ai_addr, info->ai_addr, info->ai_addrlen); |
| 41 } |
| 42 |
| 43 // Recursive copy. |
| 44 if (info->ai_next) |
| 45 copy->ai_next = CreateCopyOfAddrinfo(info->ai_next); |
| 46 |
| 47 return copy; |
| 48 } |
| 49 |
| 50 // Free an addrinfo that was created by CreateCopyOfAddrinfo(). |
| 51 void FreeMyAddrinfo(struct addrinfo* info) { |
| 52 if (info->ai_canonname) |
| 53 free(info->ai_canonname); // Allocated by strdup. |
| 54 |
| 55 if (info->ai_addr) |
| 56 delete [] reinterpret_cast<char*>(info->ai_addr); |
| 57 |
| 58 struct addrinfo* next = info->ai_next; |
| 59 |
| 60 delete info; |
| 61 |
| 62 // Recursive free. |
| 63 if (next) |
| 64 FreeMyAddrinfo(next); |
| 65 } |
| 66 |
| 67 // Returns the address to port field in |info|. |
| 68 uint16* GetPortField(const struct addrinfo* info) { |
| 69 if (info->ai_family == AF_INET) { |
| 70 DCHECK_EQ(sizeof(sockaddr_in), info->ai_addrlen); |
| 71 struct sockaddr_in* sockaddr = |
| 72 reinterpret_cast<struct sockaddr_in*>(info->ai_addr); |
| 73 return &sockaddr->sin_port; |
| 74 } else if (info->ai_family == AF_INET6) { |
| 75 DCHECK_EQ(sizeof(sockaddr_in6), info->ai_addrlen); |
| 76 struct sockaddr_in6* sockaddr = |
| 77 reinterpret_cast<struct sockaddr_in6*>(info->ai_addr); |
| 78 return &sockaddr->sin6_port; |
| 79 } else { |
| 80 NOTREACHED(); |
| 81 return NULL; |
| 82 } |
| 83 } |
| 84 |
| 85 // Assign the port for all addresses in the list. |
| 86 void SetPortRecursive(struct addrinfo* info, int port) { |
| 87 uint16* port_field = GetPortField(info); |
| 88 *port_field = htons(port); |
| 89 |
| 90 // Assign recursively. |
| 91 if (info->ai_next) |
| 92 SetPortRecursive(info->ai_next, port); |
| 93 } |
| 94 |
| 95 } // namespace |
| 96 |
16 void AddressList::Adopt(struct addrinfo* head) { | 97 void AddressList::Adopt(struct addrinfo* head) { |
17 data_ = new Data(head); | 98 data_ = new Data(head, true /*is_system_created*/); |
| 99 } |
| 100 |
| 101 void AddressList::Copy(const struct addrinfo* head) { |
| 102 data_ = new Data(CreateCopyOfAddrinfo(head), false /*is_system_created*/); |
| 103 } |
| 104 |
| 105 void AddressList::SetPort(int port) { |
| 106 SetPortRecursive(data_->head, port); |
| 107 } |
| 108 |
| 109 int AddressList::GetPort() const { |
| 110 uint16* port_field = GetPortField(data_->head); |
| 111 return ntohs(*port_field); |
| 112 } |
| 113 |
| 114 void AddressList::SetFrom(const AddressList& src, int port) { |
| 115 if (src.GetPort() == port) { |
| 116 // We can reference the data from |src| directly. |
| 117 *this = src; |
| 118 } else { |
| 119 // Otherwise we need to make a copy in order to change the port number. |
| 120 Copy(src.head()); |
| 121 SetPort(port); |
| 122 } |
| 123 } |
| 124 |
| 125 void AddressList::Reset() { |
| 126 data_ = NULL; |
18 } | 127 } |
19 | 128 |
20 AddressList::Data::~Data() { | 129 AddressList::Data::~Data() { |
21 freeaddrinfo(head); | 130 // Call either freeaddrinfo(head), or FreeMyAddrinfo(head), depending who |
| 131 // created the data. |
| 132 if (is_system_created) |
| 133 freeaddrinfo(head); |
| 134 else |
| 135 FreeMyAddrinfo(head); |
22 } | 136 } |
23 | 137 |
24 } // namespace net | 138 } // namespace net |
OLD | NEW |