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
13namespace net {
14
15namespace {
16
17char* 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.
26void 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
38struct 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
51AddressList::AddressList() {
52}
53
54AddressList::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
101AddressList::AddressList(const AddressList& addresslist)
102    : data_(addresslist.data_) {
103}
104
105AddressList::~AddressList() {
106}
107
108AddressList& AddressList::operator=(const AddressList& addresslist) {
109  data_ = addresslist.data_;
110  return *this;
111}
112
113void AddressList::Adopt(struct addrinfo* head) {
114  data_ = new Data(head, true /*is_system_created*/);
115}
116
117void AddressList::Copy(const struct addrinfo* head, bool recursive) {
118  data_ = new Data(CreateCopyOfAddrinfo(head, recursive),
119                   false /*is_system_created*/);
120}
121
122void 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
149void AddressList::SetPort(int port) {
150  SetPortRecursive(data_->head, port);
151}
152
153int AddressList::GetPort() const {
154  return GetPortFromAddrinfo(data_->head);
155}
156
157void 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
168bool 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
176void AddressList::Reset() {
177  data_ = NULL;
178}
179
180const struct addrinfo* AddressList::head() const {
181  if (!data_)
182    return NULL;
183  return data_->head;
184}
185
186AddressList::AddressList(Data* data) : data_(data) {}
187
188// static
189AddressList* 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
230AddressList::Data::Data(struct addrinfo* ai, bool is_system_created)
231    : head(ai), is_system_created(is_system_created) {
232  DCHECK(head);
233}
234
235AddressList::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