1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/address_list.h"
6
7 #include <stdlib.h>
8
9 #include "base/logging.h"
10 #include "net/base/net_util.h"
11 #include "net/base/sys_addrinfo.h"
12
13 namespace net {
14
15 namespace {
16
do_strdup(const char * src)17 char* do_strdup(const char* src) {
18 #if defined(OS_WIN)
19 return _strdup(src);
20 #else
21 return strdup(src);
22 #endif
23 }
24
25 // Assign the port for all addresses in the list.
SetPortRecursive(struct addrinfo * info,int port)26 void SetPortRecursive(struct addrinfo* info, int port) {
27 uint16* port_field = GetPortFieldFromAddrinfo(info);
28 if (port_field)
29 *port_field = htons(port);
30
31 // Assign recursively.
32 if (info->ai_next)
33 SetPortRecursive(info->ai_next, port);
34 }
35
36 } // namespace
37
38 struct AddressList::Data : public base::RefCountedThreadSafe<Data> {
39 Data(struct addrinfo* ai, bool is_system_created);
40 struct addrinfo* head;
41
42 // Indicates which free function to use for |head|.
43 bool is_system_created;
44
45 private:
46 friend class base::RefCountedThreadSafe<Data>;
47
48 ~Data();
49 };
50
AddressList()51 AddressList::AddressList() {
52 }
53
AddressList(const IPAddressNumber & address,int port,bool canonicalize_name)54 AddressList::AddressList(const IPAddressNumber& address, int port,
55 bool canonicalize_name) {
56 struct addrinfo* ai = new addrinfo;
57 memset(ai, 0, sizeof(addrinfo));
58 ai->ai_socktype = SOCK_STREAM;
59
60 switch (address.size()) {
61 case 4: {
62 ai->ai_family = AF_INET;
63 const size_t sockaddr_in_size = sizeof(struct sockaddr_in);
64 ai->ai_addrlen = sockaddr_in_size;
65
66 struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(
67 new char[sockaddr_in_size]);
68 memset(addr, 0, sockaddr_in_size);
69 addr->sin_family = AF_INET;
70 memcpy(&addr->sin_addr, &address[0], 4);
71 ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr);
72 break;
73 }
74 case 16: {
75 ai->ai_family = AF_INET6;
76 const size_t sockaddr_in6_size = sizeof(struct sockaddr_in6);
77 ai->ai_addrlen = sockaddr_in6_size;
78
79 struct sockaddr_in6* addr6 = reinterpret_cast<struct sockaddr_in6*>(
80 new char[sockaddr_in6_size]);
81 memset(addr6, 0, sockaddr_in6_size);
82 addr6->sin6_family = AF_INET6;
83 memcpy(&addr6->sin6_addr, &address[0], 16);
84 ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr6);
85 break;
86 }
87 default: {
88 NOTREACHED() << "Bad IP address";
89 break;
90 }
91 }
92
93 if (canonicalize_name) {
94 std::string name = NetAddressToString(ai);
95 ai->ai_canonname = do_strdup(name.c_str());
96 }
97 data_ = new Data(ai, false /*is_system_created*/);
98 SetPort(port);
99 }
100
AddressList(const AddressList & addresslist)101 AddressList::AddressList(const AddressList& addresslist)
102 : data_(addresslist.data_) {
103 }
104
~AddressList()105 AddressList::~AddressList() {
106 }
107
operator =(const AddressList & addresslist)108 AddressList& AddressList::operator=(const AddressList& addresslist) {
109 data_ = addresslist.data_;
110 return *this;
111 }
112
Adopt(struct addrinfo * head)113 void AddressList::Adopt(struct addrinfo* head) {
114 data_ = new Data(head, true /*is_system_created*/);
115 }
116
Copy(const struct addrinfo * head,bool recursive)117 void AddressList::Copy(const struct addrinfo* head, bool recursive) {
118 data_ = new Data(CreateCopyOfAddrinfo(head, recursive),
119 false /*is_system_created*/);
120 }
121
Append(const struct addrinfo * head)122 void AddressList::Append(const struct addrinfo* head) {
123 DCHECK(head);
124 struct addrinfo* new_head;
125 if (data_->is_system_created) {
126 new_head = CreateCopyOfAddrinfo(data_->head, true);
127 data_ = new Data(new_head, false /*is_system_created*/);
128 } else {
129 new_head = data_->head;
130 }
131 // Find the end of current linked list and append new data there.
132 struct addrinfo* copy_ptr = new_head;
133 while (copy_ptr->ai_next)
134 copy_ptr = copy_ptr->ai_next;
135 copy_ptr->ai_next = CreateCopyOfAddrinfo(head, true);
136
137 // Only the head of the list should have a canonname. Strip any
138 // canonical name in the appended data.
139 copy_ptr = copy_ptr->ai_next;
140 while (copy_ptr) {
141 if (copy_ptr->ai_canonname) {
142 free(copy_ptr->ai_canonname);
143 copy_ptr->ai_canonname = NULL;
144 }
145 copy_ptr = copy_ptr->ai_next;
146 }
147 }
148
SetPort(int port)149 void AddressList::SetPort(int port) {
150 SetPortRecursive(data_->head, port);
151 }
152
GetPort() const153 int AddressList::GetPort() const {
154 return GetPortFromAddrinfo(data_->head);
155 }
156
SetFrom(const AddressList & src,int port)157 void AddressList::SetFrom(const AddressList& src, int port) {
158 if (src.GetPort() == port) {
159 // We can reference the data from |src| directly.
160 *this = src;
161 } else {
162 // Otherwise we need to make a copy in order to change the port number.
163 Copy(src.head(), true);
164 SetPort(port);
165 }
166 }
167
GetCanonicalName(std::string * canonical_name) const168 bool AddressList::GetCanonicalName(std::string* canonical_name) const {
169 DCHECK(canonical_name);
170 if (!data_ || !data_->head->ai_canonname)
171 return false;
172 canonical_name->assign(data_->head->ai_canonname);
173 return true;
174 }
175
Reset()176 void AddressList::Reset() {
177 data_ = NULL;
178 }
179
head() const180 const struct addrinfo* AddressList::head() const {
181 if (!data_)
182 return NULL;
183 return data_->head;
184 }
185
AddressList(Data * data)186 AddressList::AddressList(Data* data) : data_(data) {}
187
188 // static
CreateAddressListFromSockaddr(const struct sockaddr * address,socklen_t address_length,int socket_type,int protocol)189 AddressList* AddressList::CreateAddressListFromSockaddr(
190 const struct sockaddr* address,
191 socklen_t address_length,
192 int socket_type,
193 int protocol) {
194 // Do sanity checking on socket_type and protocol.
195 DCHECK(socket_type == SOCK_DGRAM || socket_type == SOCK_STREAM);
196 DCHECK(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP);
197
198 struct addrinfo* ai = new addrinfo;
199 memset(ai, 0, sizeof(addrinfo));
200 switch (address_length) {
201 case sizeof(struct sockaddr_in):
202 {
203 const struct sockaddr_in* sin =
204 reinterpret_cast<const struct sockaddr_in*>(address);
205 ai->ai_family = sin->sin_family;
206 DCHECK_EQ(AF_INET, ai->ai_family);
207 }
208 break;
209 case sizeof(struct sockaddr_in6):
210 {
211 const struct sockaddr_in6* sin6 =
212 reinterpret_cast<const struct sockaddr_in6*>(address);
213 ai->ai_family = sin6->sin6_family;
214 DCHECK_EQ(AF_INET6, ai->ai_family);
215 }
216 break;
217 default:
218 NOTREACHED() << "Bad IP address";
219 break;
220 }
221 ai->ai_socktype = socket_type;
222 ai->ai_protocol = protocol;
223 ai->ai_addrlen = address_length;
224 ai->ai_addr = reinterpret_cast<struct sockaddr*>(new char[address_length]);
225 memcpy(ai->ai_addr, address, address_length);
226 return new AddressList(new Data(ai, false /*is_system_created*/));
227 }
228
229
Data(struct addrinfo * ai,bool is_system_created)230 AddressList::Data::Data(struct addrinfo* ai, bool is_system_created)
231 : head(ai), is_system_created(is_system_created) {
232 DCHECK(head);
233 }
234
~Data()235 AddressList::Data::~Data() {
236 // Call either freeaddrinfo(head), or FreeCopyOfAddrinfo(head), depending on
237 // who created the data.
238 if (is_system_created)
239 freeaddrinfo(head);
240 else
241 FreeCopyOfAddrinfo(head);
242 }
243
244 } // namespace net
245