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
29namespace butil {
30
31// Type of an IP address
32typedef struct in_addr ip_t;
33
34static const ip_t IP_ANY = { INADDR_ANY };
35static const ip_t IP_NONE = { INADDR_NONE };
36
37// Convert |ip| to an integral
38inline in_addr_t ip2int(ip_t ip) { return ip.s_addr; }
39
40// Convert integral |ip_value| to an IP
41inline 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.
49int str2ip(const char* ip_str, ip_t* ip);
50
51struct 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());
59IPStr 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.
65int hostname2ip(const char* hostname, ip_t* ip);
66
67// Convert `ip' to `hostname'.
68// Returns 0 on success, -1 otherwise and errno is set.
69int ip2hostname(ip_t ip, char* hostname, size_t hostname_len);
70int ip2hostname(ip_t ip, std::string* hostname);
71
72// Hostname of this machine, "" on error.
73// NOTE: This function caches result on first call.
74const char* my_hostname();
75
76// IP of this machine, IP_ANY on error.
77// NOTE: This function caches result on first call.
78ip_t my_ip();
79// String form.
80const char* my_ip_cstr();
81
82// ipv4 + port
83struct 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
93struct 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());
102EndPointStr endpoint2str(const EndPoint&);
103
104// Convert string `ip_and_port_str' to a EndPoint *point.
105// Returns 0 on success, -1 otherwise.
106int str2endpoint(const char* ip_and_port_str, EndPoint* point);
107int 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.
111int hostname2endpoint(const char* ip_and_port_str, EndPoint* point);
112int 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.
116int endpoint2hostname(const EndPoint& point, char* hostname, size_t hostname_len);
117int 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.
122int 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.
128int tcp_listen(EndPoint ip_and_port);
129
130// Get the local end of a socket connection
131int get_local_side(int fd, EndPoint *out);
132
133// Get the other end of a socket connection
134int 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.
140inline bool operator<(butil::ip_t lhs, butil::ip_t rhs) {
141 return butil::ip2int(lhs) < butil::ip2int(rhs);
142}
143inline bool operator>(butil::ip_t lhs, butil::ip_t rhs) {
144 return rhs < lhs;
145}
146inline bool operator>=(butil::ip_t lhs, butil::ip_t rhs) {
147 return !(lhs < rhs);
148}
149inline bool operator<=(butil::ip_t lhs, butil::ip_t rhs) {
150 return !(rhs < lhs);
151}
152inline bool operator==(butil::ip_t lhs, butil::ip_t rhs) {
153 return butil::ip2int(lhs) == butil::ip2int(rhs);
154}
155inline bool operator!=(butil::ip_t lhs, butil::ip_t rhs) {
156 return !(lhs == rhs);
157}
158
159inline std::ostream& operator<<(std::ostream& os, const butil::IPStr& ip_str) {
160 return os << ip_str.c_str();
161}
162inline std::ostream& operator<<(std::ostream& os, butil::ip_t ip) {
163 return os << butil::ip2str(ip);
164}
165
166namespace butil {
167// Overload operators for EndPoint in the same namespace due to ADL.
168inline bool operator<(EndPoint p1, EndPoint p2) {
169 return (p1.ip != p2.ip) ? (p1.ip < p2.ip) : (p1.port < p2.port);
170}
171inline bool operator>(EndPoint p1, EndPoint p2) {
172 return p2 < p1;
173}
174inline bool operator<=(EndPoint p1, EndPoint p2) {
175 return !(p2 < p1);
176}
177inline bool operator>=(EndPoint p1, EndPoint p2) {
178 return !(p1 < p2);
179}
180inline bool operator==(EndPoint p1, EndPoint p2) {
181 return p1.ip == p2.ip && p1.port == p2.port;
182}
183inline bool operator!=(EndPoint p1, EndPoint p2) {
184 return !(p1 == p2);
185}
186
187inline std::ostream& operator<<(std::ostream& os, const EndPoint& ep) {
188 return os << ep.ip << ':' << ep.port;
189}
190inline std::ostream& operator<<(std::ostream& os, const EndPointStr& ep_str) {
191 return os << ep_str.c_str();
192}
193
194} // namespace butil
195
196
197namespace 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
204inline 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)
209template <>
210struct 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