Add mechanizm for caching local and peer addresses in AsyncSSLSocket.
[folly.git] / folly / MacAddress.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <iostream>
20
21 #include <boost/operators.hpp>
22
23 #include <folly/Bits.h>
24 #include <folly/Conv.h>
25
26 namespace folly {
27
28 class IPAddressV6;
29
30 /*
31  * MacAddress represents an IEEE 802 MAC address.
32  */
33 class MacAddress : private boost::totally_ordered<MacAddress> {
34  public:
35   static constexpr size_t SIZE = 6;
36   static const MacAddress BROADCAST;
37   static const MacAddress ZERO;
38
39   /*
40    * Construct a zero-initialized MacAddress.
41    */
42   MacAddress() {
43     memset(&bytes_, 0, 8);
44   }
45
46   /*
47    * Parse a MacAddress from a human-readable string.
48    * The string must contain 6 one- or two-digit hexadecimal
49    * numbers, separated by dashes or colons.
50    * Examples: 00:02:C9:C8:F9:68 or 0-2-c9-c8-f9-68
51    */
52   explicit MacAddress(StringPiece str);
53
54   /*
55    * Construct a MAC address from its 6-byte binary value
56    */
57   static MacAddress fromBinary(ByteRange value) {
58     MacAddress ret;
59     ret.setFromBinary(value);
60     return ret;
61   }
62
63   /*
64    * Construct a MacAddress from a uint64_t in network byte order.
65    *
66    * The first two bytes are ignored, and the MAC address is taken from the
67    * latter 6 bytes.
68    *
69    * This is a static method rather than a constructor to avoid confusion
70    * between host and network byte order constructors.
71    */
72   static MacAddress fromNBO(uint64_t value) {
73     return MacAddress(value);
74   }
75
76   /*
77    * Construct a MacAddress from a uint64_t in host byte order.
78    *
79    * The most significant two bytes are ignored, and the MAC address is taken
80    * from the least significant 6 bytes.
81    *
82    * This is a static method rather than a constructor to avoid confusion
83    * between host and network byte order constructors.
84    */
85   static MacAddress fromHBO(uint64_t value) {
86     return MacAddress(Endian::big(value));
87   }
88
89   /*
90    * Construct the multicast MacAddress for the specified multicast IPv6
91    * address.
92    */
93   static MacAddress createMulticast(IPAddressV6 addr);
94
95   /*
96    * Get a pointer to the MAC address' binary value.
97    *
98    * The returned value points to internal storage inside the MacAddress
99    * object.  It is only valid as long as the MacAddress, and its contents may
100    * change if the MacAddress is updated.
101    */
102   const uint8_t* bytes() const {
103     return bytes_ + 2;
104   }
105
106   /*
107    * Return the address as a uint64_t, in network byte order.
108    *
109    * The first two bytes will be 0, and the subsequent 6 bytes will contain
110    * the address in network byte order.
111    */
112   uint64_t u64NBO() const {
113     return packedBytes();
114   }
115
116   /*
117    * Return the address as a uint64_t, in host byte order.
118    *
119    * The two most significant bytes will be 0, and the remaining 6 bytes will
120    * contain the address.  The most significant of these 6 bytes will contain
121    * the first byte that appear on the wire, and the least significant byte
122    * will contain the last byte.
123    */
124   uint64_t u64HBO() const {
125     // Endian::big() does what we want here, even though we are converting
126     // from big-endian to host byte order.  This swaps if and only if
127     // the host byte order is little endian.
128     return Endian::big(packedBytes());
129   }
130
131   /*
132    * Return a human-readable representation of the MAC address.
133    */
134   std::string toString() const;
135
136   /*
137    * Update the current MacAddress object from a human-readable string.
138    */
139   void parse(StringPiece str);
140
141   /*
142    * Update the current MacAddress object from a 6-byte binary representation.
143    */
144   void setFromBinary(ByteRange value);
145
146   bool isBroadcast() const {
147     return *this == BROADCAST;
148   }
149   bool isMulticast() const {
150     return getByte(0) & 0x1;
151   }
152   bool isUnicast() const {
153     return !isMulticast();
154   }
155
156   /*
157    * Return true if this MAC address is locally administered.
158    *
159    * Locally administered addresses are assigned by the local network
160    * administrator, and are not guaranteed to be globally unique.  (It is
161    * similar to IPv4's private address space.)
162    *
163    * Note that isLocallyAdministered() will return true for the broadcast
164    * address, since it has the locally administered bit set.
165    */
166   bool isLocallyAdministered() const {
167     return getByte(0) & 0x2;
168   }
169
170   // Equality and less-than operators.
171   // boost::totally_ordered provides the other comparison operators.
172
173   bool operator==(const MacAddress& other) const {
174     // All constructors and modifying methods make sure padding is 0,
175     // so we don't need to mask these bytes out when comparing here.
176     return packedBytes() == other.packedBytes();
177   }
178
179   bool operator<(const MacAddress& other) const {
180     return u64HBO() < other.u64HBO();
181   }
182
183  private:
184   explicit MacAddress(uint64_t valueNBO) {
185     memcpy(&bytes_, &valueNBO, 8);
186     // Set the pad bytes to 0.
187     // This allows us to easily compare two MacAddresses,
188     // without having to worry about differences in the padding.
189     bytes_[0] = 0;
190     bytes_[1] = 0;
191   }
192
193   /* We store the 6 bytes starting at bytes_[2] (most significant)
194      through bytes_[7] (least).
195      bytes_[0] and bytes_[1] are always equal to 0 to simplify comparisons.
196   */
197   unsigned char bytes_[8];
198
199   inline uint64_t getByte(size_t index) const {
200     return bytes_[index + 2];
201   }
202
203   uint64_t packedBytes() const {
204     uint64_t u64;
205     memcpy(&u64, bytes_, 8);
206     return u64;
207   }
208 };
209
210 /* Define toAppend() so to<string> will work */
211 template <class Tgt>
212 typename std::enable_if<IsSomeString<Tgt>::value>::type
213 toAppend(MacAddress address, Tgt* result) {
214   toAppend(address.toString(), result);
215 }
216
217 std::ostream& operator<<(std::ostream& os, MacAddress address);
218
219 }  // folly