1 | // Licensed to the Apache Software Foundation (ASF) under one |
2 | // or more contributor license agreements. See the NOTICE file |
3 | // distributed with this work for additional information |
4 | // regarding copyright ownership. The ASF licenses this file |
5 | // to you under the Apache License, Version 2.0 (the |
6 | // "License"); you may not use this file except in compliance |
7 | // with the License. You may obtain a copy of the License at |
8 | // |
9 | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | // |
11 | // Unless required by applicable law or agreed to in writing, |
12 | // software distributed under the License is distributed on an |
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | // KIND, either express or implied. See the License for the |
15 | // specific language governing permissions and limitations |
16 | // under the License. |
17 | |
18 | // Date: Mon. Nov 7 14:47:36 CST 2011 |
19 | |
20 | // Wrappers of IP and port. |
21 | |
22 | #ifndef BUTIL_ENDPOINT_H |
23 | #define BUTIL_ENDPOINT_H |
24 | |
25 | #include <netinet/in.h> // in_addr |
26 | #include <iostream> // std::ostream |
27 | #include "butil/containers/hash_tables.h" // hashing functions |
28 | |
29 | namespace butil { |
30 | |
31 | // Type of an IP address |
32 | typedef struct in_addr ip_t; |
33 | |
34 | static const ip_t IP_ANY = { INADDR_ANY }; |
35 | static const ip_t IP_NONE = { INADDR_NONE }; |
36 | |
37 | // Convert |ip| to an integral |
38 | inline in_addr_t ip2int(ip_t ip) { return ip.s_addr; } |
39 | |
40 | // Convert integral |ip_value| to an IP |
41 | inline ip_t int2ip(in_addr_t ip_value) { |
42 | const ip_t ip = { ip_value }; |
43 | return ip; |
44 | } |
45 | |
46 | // Convert string `ip_str' to ip_t *ip. |
47 | // `ip_str' is in IPv4 dotted-quad format: `127.0.0.1', `10.23.249.73' ... |
48 | // Returns 0 on success, -1 otherwise. |
49 | int str2ip(const char* ip_str, ip_t* ip); |
50 | |
51 | struct IPStr { |
52 | const char* c_str() const { return _buf; } |
53 | char _buf[INET_ADDRSTRLEN]; |
54 | }; |
55 | |
56 | // Convert IP to c-style string. Notice that you can serialize ip_t to |
57 | // std::ostream directly. Use this function when you don't have streaming log. |
58 | // Example: printf("ip=%s\n", ip2str(some_ip).c_str()); |
59 | IPStr ip2str(ip_t ip); |
60 | |
61 | // Convert `hostname' to ip_t *ip. If `hostname' is NULL, use hostname |
62 | // of this machine. |
63 | // `hostname' is typically in this form: `tc-cm-et21.tc' `db-cos-dev.db01' ... |
64 | // Returns 0 on success, -1 otherwise. |
65 | int hostname2ip(const char* hostname, ip_t* ip); |
66 | |
67 | // Convert `ip' to `hostname'. |
68 | // Returns 0 on success, -1 otherwise and errno is set. |
69 | int ip2hostname(ip_t ip, char* hostname, size_t hostname_len); |
70 | int ip2hostname(ip_t ip, std::string* hostname); |
71 | |
72 | // Hostname of this machine, "" on error. |
73 | // NOTE: This function caches result on first call. |
74 | const char* my_hostname(); |
75 | |
76 | // IP of this machine, IP_ANY on error. |
77 | // NOTE: This function caches result on first call. |
78 | ip_t my_ip(); |
79 | // String form. |
80 | const char* my_ip_cstr(); |
81 | |
82 | // ipv4 + port |
83 | struct EndPoint { |
84 | EndPoint() : ip(IP_ANY), port(0) {} |
85 | EndPoint(ip_t ip2, int port2) : ip(ip2), port(port2) {} |
86 | explicit EndPoint(const sockaddr_in& in) |
87 | : ip(in.sin_addr), port(ntohs(in.sin_port)) {} |
88 | |
89 | ip_t ip; |
90 | int port; |
91 | }; |
92 | |
93 | struct EndPointStr { |
94 | const char* c_str() const { return _buf; } |
95 | char _buf[INET_ADDRSTRLEN + 16]; |
96 | }; |
97 | |
98 | // Convert EndPoint to c-style string. Notice that you can serialize |
99 | // EndPoint to std::ostream directly. Use this function when you don't |
100 | // have streaming log. |
101 | // Example: printf("point=%s\n", endpoint2str(point).c_str()); |
102 | EndPointStr endpoint2str(const EndPoint&); |
103 | |
104 | // Convert string `ip_and_port_str' to a EndPoint *point. |
105 | // Returns 0 on success, -1 otherwise. |
106 | int str2endpoint(const char* ip_and_port_str, EndPoint* point); |
107 | int str2endpoint(const char* ip_str, int port, EndPoint* point); |
108 | |
109 | // Convert `hostname_and_port_str' to a EndPoint *point. |
110 | // Returns 0 on success, -1 otherwise. |
111 | int hostname2endpoint(const char* ip_and_port_str, EndPoint* point); |
112 | int hostname2endpoint(const char* name_str, int port, EndPoint* point); |
113 | |
114 | // Convert `endpoint' to `hostname'. |
115 | // Returns 0 on success, -1 otherwise and errno is set. |
116 | int endpoint2hostname(const EndPoint& point, char* hostname, size_t hostname_len); |
117 | int endpoint2hostname(const EndPoint& point, std::string* host); |
118 | |
119 | // Create a TCP socket and connect it to `server'. Write port of this side |
120 | // into `self_port' if it's not NULL. |
121 | // Returns the socket descriptor, -1 otherwise and errno is set. |
122 | int tcp_connect(EndPoint server, int* self_port); |
123 | |
124 | // Create and listen to a TCP socket bound with `ip_and_port'. |
125 | // To enable SO_REUSEADDR for the whole program, enable gflag -reuse_addr |
126 | // To enable SO_REUSEPORT for the whole program, enable gflag -reuse_port |
127 | // Returns the socket descriptor, -1 otherwise and errno is set. |
128 | int tcp_listen(EndPoint ip_and_port); |
129 | |
130 | // Get the local end of a socket connection |
131 | int get_local_side(int fd, EndPoint *out); |
132 | |
133 | // Get the other end of a socket connection |
134 | int get_remote_side(int fd, EndPoint *out); |
135 | |
136 | } // namespace butil |
137 | |
138 | // Since ip_t is defined from in_addr which is globally defined, due to ADL |
139 | // we have to put overloaded operators globally as well. |
140 | inline bool operator<(butil::ip_t lhs, butil::ip_t rhs) { |
141 | return butil::ip2int(lhs) < butil::ip2int(rhs); |
142 | } |
143 | inline bool operator>(butil::ip_t lhs, butil::ip_t rhs) { |
144 | return rhs < lhs; |
145 | } |
146 | inline bool operator>=(butil::ip_t lhs, butil::ip_t rhs) { |
147 | return !(lhs < rhs); |
148 | } |
149 | inline bool operator<=(butil::ip_t lhs, butil::ip_t rhs) { |
150 | return !(rhs < lhs); |
151 | } |
152 | inline bool operator==(butil::ip_t lhs, butil::ip_t rhs) { |
153 | return butil::ip2int(lhs) == butil::ip2int(rhs); |
154 | } |
155 | inline bool operator!=(butil::ip_t lhs, butil::ip_t rhs) { |
156 | return !(lhs == rhs); |
157 | } |
158 | |
159 | inline std::ostream& operator<<(std::ostream& os, const butil::IPStr& ip_str) { |
160 | return os << ip_str.c_str(); |
161 | } |
162 | inline std::ostream& operator<<(std::ostream& os, butil::ip_t ip) { |
163 | return os << butil::ip2str(ip); |
164 | } |
165 | |
166 | namespace butil { |
167 | // Overload operators for EndPoint in the same namespace due to ADL. |
168 | inline bool operator<(EndPoint p1, EndPoint p2) { |
169 | return (p1.ip != p2.ip) ? (p1.ip < p2.ip) : (p1.port < p2.port); |
170 | } |
171 | inline bool operator>(EndPoint p1, EndPoint p2) { |
172 | return p2 < p1; |
173 | } |
174 | inline bool operator<=(EndPoint p1, EndPoint p2) { |
175 | return !(p2 < p1); |
176 | } |
177 | inline bool operator>=(EndPoint p1, EndPoint p2) { |
178 | return !(p1 < p2); |
179 | } |
180 | inline bool operator==(EndPoint p1, EndPoint p2) { |
181 | return p1.ip == p2.ip && p1.port == p2.port; |
182 | } |
183 | inline bool operator!=(EndPoint p1, EndPoint p2) { |
184 | return !(p1 == p2); |
185 | } |
186 | |
187 | inline std::ostream& operator<<(std::ostream& os, const EndPoint& ep) { |
188 | return os << ep.ip << ':' << ep.port; |
189 | } |
190 | inline std::ostream& operator<<(std::ostream& os, const EndPointStr& ep_str) { |
191 | return os << ep_str.c_str(); |
192 | } |
193 | |
194 | } // namespace butil |
195 | |
196 | |
197 | namespace BUTIL_HASH_NAMESPACE { |
198 | |
199 | // Implement methods for hashing a pair of integers, so they can be used as |
200 | // keys in STL containers. |
201 | |
202 | #if defined(COMPILER_MSVC) |
203 | |
204 | inline std::size_t hash_value(const butil::EndPoint& ep) { |
205 | return butil::HashPair(butil::ip2int(ep.ip), ep.port); |
206 | } |
207 | |
208 | #elif defined(COMPILER_GCC) |
209 | template <> |
210 | struct hash<butil::EndPoint> { |
211 | std::size_t operator()(const butil::EndPoint& ep) const { |
212 | return butil::HashPair(butil::ip2int(ep.ip), ep.port); |
213 | } |
214 | }; |
215 | |
216 | #else |
217 | #error define hash<EndPoint> for your compiler |
218 | #endif // COMPILER |
219 | |
220 | } |
221 | |
222 | #endif // BUTIL_ENDPOINT_H |
223 | |