// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/base/address_list.h" #include #include "base/logging.h" #include "net/base/net_util.h" #include "net/base/sys_addrinfo.h" namespace net { namespace { char* do_strdup(const char* src) { #if defined(OS_WIN) return _strdup(src); #else return strdup(src); #endif } struct addrinfo* CreateAddrInfo(const IPAddressNumber& address, bool canonicalize_name) { struct addrinfo* ai = new addrinfo; memset(ai, 0, sizeof(addrinfo)); ai->ai_socktype = SOCK_STREAM; switch (address.size()) { case kIPv4AddressSize: { ai->ai_family = AF_INET; const size_t sockaddr_in_size = sizeof(struct sockaddr_in); ai->ai_addrlen = sockaddr_in_size; struct sockaddr_in* addr = reinterpret_cast( new char[sockaddr_in_size]); memset(addr, 0, sockaddr_in_size); addr->sin_family = AF_INET; #if defined(SIN6_LEN) addr->sin_len = sockaddr_in_size; #endif memcpy(&addr->sin_addr, &address[0], kIPv4AddressSize); ai->ai_addr = reinterpret_cast(addr); break; } case kIPv6AddressSize: { ai->ai_family = AF_INET6; const size_t sockaddr_in6_size = sizeof(struct sockaddr_in6); ai->ai_addrlen = sockaddr_in6_size; struct sockaddr_in6* addr6 = reinterpret_cast( new char[sockaddr_in6_size]); memset(addr6, 0, sockaddr_in6_size); addr6->sin6_family = AF_INET6; #if defined(SIN6_LEN) addr6->sin6_len = sockaddr_in6_size; #endif memcpy(&addr6->sin6_addr, &address[0], kIPv6AddressSize); ai->ai_addr = reinterpret_cast(addr6); break; } default: { NOTREACHED() << "Bad IP address"; break; } } if (canonicalize_name) { std::string name = NetAddressToString(ai); ai->ai_canonname = do_strdup(name.c_str()); } return ai; } } // namespace struct AddressList::Data : public base::RefCountedThreadSafe { Data(struct addrinfo* ai, bool is_system_created); // This variable is const since it should NOT be mutated. Since // Data is reference counted, this |head| could be shared by multiple // instances of AddressList, hence we need to be careful not to mutate // it from any one instance. const struct addrinfo * const head; // Indicates which free function to use for |head|. bool is_system_created; private: friend class base::RefCountedThreadSafe; ~Data(); }; AddressList::AddressList() { } AddressList::AddressList(const AddressList& addresslist) : data_(addresslist.data_) { } AddressList::~AddressList() { } AddressList& AddressList::operator=(const AddressList& addresslist) { data_ = addresslist.data_; return *this; } // static AddressList AddressList::CreateFromIPAddressList( const IPAddressList& addresses, uint16 port) { DCHECK(!addresses.empty()); struct addrinfo* head = NULL; struct addrinfo* next = NULL; for (IPAddressList::const_iterator it = addresses.begin(); it != addresses.end(); ++it) { if (head == NULL) { head = next = CreateAddrInfo(*it, false); } else { next->ai_next = CreateAddrInfo(*it, false); next = next->ai_next; } } SetPortForAllAddrinfos(head, port); return AddressList(new Data(head, false)); } // static AddressList AddressList::CreateFromIPAddress( const IPAddressNumber& address, uint16 port) { return CreateFromIPAddressWithCname(address, port, false); } // static AddressList AddressList::CreateFromIPAddressWithCname( const IPAddressNumber& address, uint16 port, bool canonicalize_name) { struct addrinfo* ai = CreateAddrInfo(address, canonicalize_name); SetPortForAllAddrinfos(ai, port); return AddressList(new Data(ai, false /*is_system_created*/)); } // static AddressList AddressList::CreateByAdoptingFromSystem(struct addrinfo* head) { return AddressList(new Data(head, true /*is_system_created*/)); } // static AddressList AddressList::CreateByCopying(const struct addrinfo* head) { return AddressList(new Data(CreateCopyOfAddrinfo(head, true /*recursive*/), false /*is_system_created*/)); } // static AddressList AddressList::CreateByCopyingFirstAddress( const struct addrinfo* head) { return AddressList(new Data(CreateCopyOfAddrinfo(head, false /*recursive*/), false /*is_system_created*/)); } // static AddressList AddressList::CreateFromSockaddr( const struct sockaddr* address, socklen_t address_length, int socket_type, int protocol) { // Do sanity checking on socket_type and protocol. DCHECK(socket_type == SOCK_DGRAM || socket_type == SOCK_STREAM); DCHECK(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP); struct addrinfo* ai = new addrinfo; memset(ai, 0, sizeof(addrinfo)); switch (address_length) { case sizeof(struct sockaddr_in): { const struct sockaddr_in* sin = reinterpret_cast(address); ai->ai_family = sin->sin_family; DCHECK_EQ(AF_INET, ai->ai_family); } break; case sizeof(struct sockaddr_in6): { const struct sockaddr_in6* sin6 = reinterpret_cast(address); ai->ai_family = sin6->sin6_family; DCHECK_EQ(AF_INET6, ai->ai_family); } break; default: NOTREACHED() << "Bad IP address"; break; } ai->ai_socktype = socket_type; ai->ai_protocol = protocol; ai->ai_addrlen = address_length; ai->ai_addr = reinterpret_cast(new char[address_length]); memcpy(ai->ai_addr, address, address_length); return AddressList(new Data(ai, false /*is_system_created*/)); } void AddressList::Append(const struct addrinfo* head) { DCHECK(head); // Always create a copy, since the Data might be shared across instances. struct addrinfo* new_head = CreateCopyOfAddrinfo(data_->head, true); data_ = new Data(new_head, false /*is_system_created*/); // Find the end of current linked list and append new data there. struct addrinfo* copy_ptr = new_head; while (copy_ptr->ai_next) copy_ptr = copy_ptr->ai_next; copy_ptr->ai_next = CreateCopyOfAddrinfo(head, true); // Only the head of the list should have a canonname. Strip any // canonical name in the appended data. copy_ptr = copy_ptr->ai_next; while (copy_ptr) { if (copy_ptr->ai_canonname) { free(copy_ptr->ai_canonname); copy_ptr->ai_canonname = NULL; } copy_ptr = copy_ptr->ai_next; } } void AddressList::SetPort(uint16 port) { // NOTE: we need to be careful not to mutate the reference-counted data, // since it might be shared by other AddressLists. struct addrinfo* head = CreateCopyOfAddrinfo(data_->head, true); SetPortForAllAddrinfos(head, port); data_ = new Data(head, false /*is_system_created*/); } uint16 AddressList::GetPort() const { return GetPortFromAddrinfo(data_->head); } bool AddressList::GetCanonicalName(std::string* canonical_name) const { DCHECK(canonical_name); if (!data_ || !data_->head->ai_canonname) return false; canonical_name->assign(data_->head->ai_canonname); return true; } const struct addrinfo* AddressList::head() const { if (!data_) return NULL; return data_->head; } AddressList::AddressList(Data* data) : data_(data) {} AddressList::Data::Data(struct addrinfo* ai, bool is_system_created) : head(ai), is_system_created(is_system_created) { DCHECK(head); } AddressList::Data::~Data() { // Casting away the const is safe, since upon destruction we know that // no one holds a reference to the data any more. struct addrinfo* mutable_head = const_cast(head); // Call either freeaddrinfo(head), or FreeMyAddrinfo(head), depending who // created the data. if (is_system_created) freeaddrinfo(mutable_head); else FreeCopyOfAddrinfo(mutable_head); } AddressList CreateAddressListUsingPort(const AddressList& src, int port) { if (src.GetPort() == port) return src; AddressList out = src; out.SetPort(port); return out; } } // namespace net