X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FIPAddressV6.h;h=a1d0c7cbd3a9cd20d1e5cca951dccd64119fc939;hb=c9cbfdb7254cef993316a53e8ad11e8cf1c6f33f;hp=6ef438d58b39d9cc6302ddf5fe0ad0212a12441c;hpb=ce64f0f685111ac24c7a321ea56d0c3524621df1;p=folly.git diff --git a/folly/IPAddressV6.h b/folly/IPAddressV6.h index 6ef438d5..a1d0c7cb 100644 --- a/folly/IPAddressV6.h +++ b/folly/IPAddressV6.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,16 @@ #pragma once +#include + +#include #include -#include +#include #include #include -#include - #include +#include #include #include @@ -51,8 +53,19 @@ typedef std::array ByteArray16; * isTeredo, isIPv4Mapped, tryCreateIPv4, type * * @see IPAddress + * + * Notes on scope ID parsing: + * + * getaddrinfo() uses if_nametoindex() to convert interface names + * into a numerical index. For instance, + * "fe80::202:c9ff:fec1:ee08%eth0" may return scope ID 2 on some + * hosts, but other numbers on other hosts. It will fail entirely on + * hosts without an eth0 interface. + * + * Serializing / Deserializing IPAddressB6's on different hosts + * that use link-local scoping probably won't work. */ -class IPAddressV6 : boost::totally_ordered { +class IPAddressV6 { public: // V6 Address Type enum Type { @@ -71,6 +84,13 @@ class IPAddressV6 : boost::totally_ordered { // Binary prefix for 6to4 networks static const uint32_t PREFIX_6TO4; + // Size of std::string returned by toFullyQualified. + static constexpr size_t kToFullyQualifiedSize = + 8 /*words*/ * 4 /*hex chars per word*/ + 7 /*separators*/; + + // returns true iff the input string can be parsed as an ipv6-address + static bool validate(StringPiece ip); + /** * Create a new IPAddress instance from the provided binary data. * @throws IPAddressFormatException if the input length is not 16 bytes. @@ -81,6 +101,13 @@ class IPAddressV6 : boost::totally_ordered { return addr; } + /** + * Returns the address as a Range. + */ + ByteRange toBinary() const { + return ByteRange((const unsigned char *) &addr_.in6Addr_.s6_addr, 16); + } + /** * Default constructor for IPAddressV6. * @@ -90,6 +117,7 @@ class IPAddressV6 : boost::totally_ordered { // Create an IPAddressV6 from a string // @throws IPAddressFormatException + // explicit IPAddressV6(StringPiece ip); // ByteArray16 constructor @@ -98,6 +126,9 @@ class IPAddressV6 : boost::totally_ordered { // in6_addr constructor explicit IPAddressV6(const in6_addr& src); + // sockaddr_in6 constructor + explicit IPAddressV6(const sockaddr_in6& src); + /** * Create a link-local IPAddressV6 from the specified ethernet MAC address. */ @@ -179,6 +210,16 @@ class IPAddressV6 : boost::totally_ordered { */ bool isLinkLocal() const; + /** + * Return the mac address if this is a link-local IPv6 address. + * + * @return an Optional union representing the mac address. + * + * If the address is not a link-local one it will return an empty Optional. + * You can use Optional::value() to check whether the mac address is not null. + */ + Optional getMacAddressFromLinkLocal() const; + /** * Return true if this is a multicast address. */ @@ -198,7 +239,8 @@ class IPAddressV6 : boost::totally_ordered { // @see IPAddress#isZero bool isZero() const { - return detail::Bytes::isZero(bytes(), 16); + constexpr auto zero = ByteArray16{{}}; + return 0 == std::memcmp(bytes(), zero.data(), zero.size()); } bool isLinkLocalBroadcast() const; @@ -209,10 +251,16 @@ class IPAddressV6 : boost::totally_ordered { // return underlying in6_addr structure in6_addr toAddr() const { return addr_.in6Addr_; } + uint16_t getScopeId() const { return scope_; } + void setScopeId(uint16_t scope) { + scope_ = scope; + } + sockaddr_in6 toSockAddr() const { sockaddr_in6 addr; memset(&addr, 0, sizeof(sockaddr_in6)); addr.sin6_family = AF_INET6; + addr.sin6_scope_id = scope_; memcpy(&addr.sin6_addr, &addr_.in6Addr_, sizeof(in6_addr)); return addr; } @@ -230,7 +278,7 @@ class IPAddressV6 : boost::totally_ordered { std::string str() const; // @see IPAddress#version - size_t version() const { return 6; } + uint8_t version() const { return 6; } /** * Return the solicited-node multicast address for this address. @@ -248,13 +296,9 @@ class IPAddressV6 : boost::totally_ordered { static const ByteArray16 fetchMask(size_t numBits); // Given 2 IPAddressV6,mask pairs extract the longest common IPAddress, // mask pair - static CIDRNetworkV6 longestCommonPrefix(const CIDRNetworkV6& one, - const CIDRNetworkV6& two) { - auto prefix = detail::Bytes::longestCommonPrefix( - one.first.addr_.bytes_, one.second, - two.first.addr_.bytes_, two.second); - return {IPAddressV6(prefix.first), prefix.second}; - } + static CIDRNetworkV6 longestCommonPrefix( + const CIDRNetworkV6& one, + const CIDRNetworkV6& two); // Number of bytes in the address representation. static constexpr size_t byteCount() { return 16; } @@ -294,6 +338,10 @@ class IPAddressV6 : boost::totally_ordered { explicit AddressStorage(MacAddress mac); } addr_; + // Link-local scope id. This should always be 0 for IPAddresses that + // are *not* link-local. + uint16_t scope_{0}; + static const std::array masks_; /** @@ -315,11 +363,31 @@ void toAppend(IPAddressV6 addr, fbstring* result); * Return true if two addresses are equal. */ inline bool operator==(const IPAddressV6& addr1, const IPAddressV6& addr2) { - return (std::memcmp(addr1.toAddr().s6_addr, addr2.toAddr().s6_addr, 16) == 0); + return (std::memcmp(addr1.toAddr().s6_addr, addr2.toAddr().s6_addr, 16) == 0) + && addr1.getScopeId() == addr2.getScopeId(); } // Return true if addr1 < addr2 inline bool operator<(const IPAddressV6& addr1, const IPAddressV6& addr2) { - return (std::memcmp(addr1.toAddr().s6_addr, addr2.toAddr().s6_addr, 16) < 0); + auto cmp = std::memcmp(addr1.toAddr().s6_addr, + addr2.toAddr().s6_addr, 16) < 0; + if (!cmp) { + return addr1.getScopeId() < addr2.getScopeId(); + } else { + return cmp; + } +} +// Derived operators +inline bool operator!=(const IPAddressV6& a, const IPAddressV6& b) { + return !(a == b); +} +inline bool operator>(const IPAddressV6& a, const IPAddressV6& b) { + return b < a; +} +inline bool operator<=(const IPAddressV6& a, const IPAddressV6& b) { + return !(a > b); +} +inline bool operator>=(const IPAddressV6& a, const IPAddressV6& b) { + return !(a < b); } } // folly