Home | History | Annotate | Download | only in base
      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 
     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.
     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 
     51 AddressList::AddressList() {
     52 }
     53 
     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 
    101 AddressList::AddressList(const AddressList& addresslist)
    102     : data_(addresslist.data_) {
    103 }
    104 
    105 AddressList::~AddressList() {
    106 }
    107 
    108 AddressList& AddressList::operator=(const AddressList& addresslist) {
    109   data_ = addresslist.data_;
    110   return *this;
    111 }
    112 
    113 void AddressList::Adopt(struct addrinfo* head) {
    114   data_ = new Data(head, true /*is_system_created*/);
    115 }
    116 
    117 void AddressList::Copy(const struct addrinfo* head, bool recursive) {
    118   data_ = new Data(CreateCopyOfAddrinfo(head, recursive),
    119                    false /*is_system_created*/);
    120 }
    121 
    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 
    149 void AddressList::SetPort(int port) {
    150   SetPortRecursive(data_->head, port);
    151 }
    152 
    153 int AddressList::GetPort() const {
    154   return GetPortFromAddrinfo(data_->head);
    155 }
    156 
    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 
    168 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 
    176 void AddressList::Reset() {
    177   data_ = NULL;
    178 }
    179 
    180 const struct addrinfo* AddressList::head() const {
    181   if (!data_)
    182     return NULL;
    183   return data_->head;
    184 }
    185 
    186 AddressList::AddressList(Data* data) : data_(data) {}
    187 
    188 // static
    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 
    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 
    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