• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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