0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
InetAddr.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 3
9  * of the License, or any later version.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
28 #include "Common/Compat.h"
29 #include "Common/Serialization.h"
30 
31 #include <cstdlib>
32 #include <cstring>
33 
34 extern "C" {
35 #include <arpa/inet.h>
36 #include <netdb.h>
37 #include <sys/socket.h>
38 #include <sys/types.h>
39 #include <sigar.h>
40 }
41 
42 #include "Logger.h"
43 #include "InetAddr.h"
44 #include "StringExt.h"
45 
46 namespace Hypertable {
47 
49  HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
50  memset(this, 0, sizeof(InetAddr));
51 }
52 
53 InetAddr::InetAddr(const String &host, uint16_t port) {
54  HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
55  HT_EXPECT(initialize(this, host.c_str(), port), Error::BAD_DOMAIN_NAME);
56 }
57 
58 InetAddr::InetAddr(const String &endpoint) {
59  HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
60  HT_EXPECT(initialize(this, endpoint.c_str()), Error::BAD_DOMAIN_NAME);
61 }
62 
63 InetAddr::InetAddr(uint32_t ip32, uint16_t port) {
64  HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
65  initialize(this, ip32, port);
66 }
67 
68 bool InetAddr::initialize(sockaddr_in *addr, const char *host, uint16_t port) {
69  memset(addr, 0, sizeof(struct sockaddr_in));
70 
71  if (parse_ipv4(host, port, *addr)) {
72  return true;
73  }
74  else {
75 #if defined(__linux__)
76  // Let's hope this is not broken in the glibc we're using
77  struct hostent hent, *he = 0;
78  char hbuf[2048];
79  int err;
80 
81  if (gethostbyname_r(host, &hent, hbuf, sizeof(hbuf), &he, &err) != 0
82  || he == 0) {
83  HT_ERRORF("gethostbyname '%s': error: %d", host, err);
84  return false;
85  }
86 #elif defined(__APPLE__) || defined(__sun__) || defined(__FreeBSD__)
87  // This is supposed to be safe on Darwin (despite the man page)
88  // and FreeBSD, as it's implemented with thread local storage.
89  struct hostent *he = gethostbyname(host);
90 
91  if (he == 0) {
92  String errmsg = (String)"gethostbyname(\"" + host + "\")";
93  herror(errmsg.c_str());
95  return false;
96  }
97 #else
98 # error TODO please implement me!
99 #endif
100  memcpy(&addr->sin_addr.s_addr, he->h_addr_list[0], sizeof(uint32_t));
101  if (addr->sin_addr.s_addr == 0) {
102  uint8_t *ip = (uint8_t *)&addr->sin_addr.s_addr;
103  ip[0] = 127;
104  ip[3] = 1;
105  }
106  }
107  addr->sin_family = AF_INET;
108  addr->sin_port = htons(port);
109  return true;
110 }
111 
112 bool
113 InetAddr::is_ipv4(const char *ipin) {
114  const char *ptr = ipin, *end = ipin + strlen(ipin);
115  char *last;
116  int component=0;
117  int num_components=0;
118  int base=10;
119 
120  while(ptr < end) {
121  component = strtol(ptr, &last, base);
122  num_components++;
123  if (last == end)
124  break;
125  if (*last != '.' || last > end || component > 255 || component < 0 || num_components > 4)
126  return false;
127  ptr = last + 1;
128  }
129  if (num_components != 4 || component > 255 || component < 0)
130  return false;
131  return true;
132 }
133 
134 bool
135 InetAddr::parse_ipv4(const char *ipin, uint16_t port, sockaddr_in &addr,
136  int base) {
137  uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
138  const char *ipstr = ipin, *end = ipin + strlen(ipin);
139  char *last;
140  int64_t n = strtoll(ipstr, &last, base);
141 
142  addr.sin_family = AF_INET;
143  addr.sin_port = htons(port);
144 
145  if (last == end && n > 0 && n < UINT32_MAX) {
146  addr.sin_addr.s_addr = htonl(n);
147  return true;
148  }
149  *ip++ = n;
150 
151  if (last > end || *last != '.')
152  return false;
153 
154  ipstr = last + 1;
155  *ip++ = strtol(ipstr, &last, base);
156 
157  if (last >= end || *last != '.')
158  return false;
159 
160  ipstr = last + 1;
161  *ip++ = strtol(ipstr, &last, base);
162 
163  if (last >= end || *last != '.')
164  return false;
165 
166  ipstr = last + 1;
167  *ip++ = strtol(ipstr, &last, base);
168 
169  if (last != end)
170  return false;
171 
172  if (addr.sin_addr.s_addr == 0) {
173  uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
174  ip[0] = 127;
175  ip[3] = 1;
176  }
177 
178  return true;
179 }
180 
181 Endpoint InetAddr::parse_endpoint(const char *endpoint, int default_port) {
182  const char *colon = strchr(endpoint, ':');
183 
184  if (colon) {
185  String host = String(endpoint, colon - endpoint);
186  return Endpoint(host, atoi(colon + 1));
187  }
188  return Endpoint(endpoint, default_port);
189 }
190 
191 bool InetAddr::initialize(sockaddr_in *addr, const char *addr_str) {
192  Endpoint e = parse_endpoint(addr_str);
193 
194  if (e.port)
195  return initialize(addr, e.host.c_str(), e.port);
196 
197  return initialize(addr, "localhost", atoi(addr_str));
198 }
199 
200 bool InetAddr::initialize(sockaddr_in *addr, uint32_t haddr, uint16_t port) {
201  memset(addr, 0 , sizeof(sockaddr_in));
202  addr->sin_family = AF_INET;
203  addr->sin_addr.s_addr = htonl(haddr);
204  addr->sin_port = htons(port);
205  return true;
206 }
207 
208 String InetAddr::format(const sockaddr_in &addr, int sep) {
209  // inet_ntoa is not thread safe on many platforms and deprecated
210  const uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
211  return Hypertable::format("%d.%d.%d.%d%c%d", (int)ip[0], (int)ip[1],
212  (int)ip[2],(int)ip[3], sep, (int)ntohs(addr.sin_port));
213 }
214 
215 String InetAddr::format_ipaddress(const sockaddr_in &addr) {
216  // inet_ntoa is not thread safe on many platforms and deprecated
217  const uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
218  return Hypertable::format("%d.%d.%d.%d", (int)ip[0], (int)ip[1],
219  (int)ip[2], (int)ip[3]);
220 }
221 
222 String InetAddr::hex(const sockaddr_in &addr, int sep) {
223  return Hypertable::format("%x%c%x", ntohl(addr.sin_addr.s_addr), sep,
224  ntohs(addr.sin_port));
225 }
226 
227 
228 size_t InetAddr::encoded_length() const {
229  size_t length = encoded_length_internal();
230  return 1 + Serialization::encoded_length_vi32(length) + length;
231 }
232 
255 void InetAddr::encode(uint8_t **bufp) const {
258  encode_internal(bufp);
259 }
260 
261 void InetAddr::decode(const uint8_t **bufp, size_t *remainp) {
262  uint8_t version = Serialization::decode_i8(bufp, remainp);
263  if (version > encoding_version())
264  HT_THROWF(Error::PROTOCOL_ERROR, "Unsupported InetAddr version %d", (int)version);
265  size_t encoding_length = Serialization::decode_vi32(bufp, remainp);
266  const uint8_t *end = *bufp + encoding_length;
267  size_t tmp_remain = encoding_length;
268  decode_internal(version, bufp, &tmp_remain);
269  HT_ASSERT(*bufp <= end);
270  *remainp -= encoding_length;
271  // If encoding is longer than we expect, that means we're decoding a newer
272  // version, so skip the newer portion that we don't know about
273  if (*bufp < end)
274  *bufp = end;
275 }
276 
277 void InetAddr::legacy_decode(const uint8_t **bufp, size_t *remainp) {
278  Serialization::decode_i8(bufp, remainp);
279  sin_family = Serialization::decode_i8(bufp, remainp);
280  sin_port = Serialization::decode_i16(bufp, remainp);
281  sin_addr.s_addr = Serialization::decode_i32(bufp, remainp);
282 }
283 
284 uint8_t InetAddr::encoding_version() const {
285  return 1;
286 }
287 
289  return 8;
290 }
291 
304 void InetAddr::encode_internal(uint8_t **bufp) const {
305  *(*bufp)++ = sizeof(sockaddr_in);
306  *(*bufp)++ = sin_family;
307  Serialization::encode_i16(bufp, sin_port);
308  Serialization::encode_i32(bufp, sin_addr.s_addr);
309 }
310 
311 void InetAddr::decode_internal(uint8_t version, const uint8_t **bufp,
312  size_t *remainp) {
313  Serialization::decode_i8(bufp, remainp);
314  sin_family = Serialization::decode_i8(bufp, remainp);
315  sin_port = Serialization::decode_i16(bufp, remainp);
316  sin_addr.s_addr = Serialization::decode_i32(bufp, remainp);
317 }
318 
319 
320 std::ostream &operator<<(std::ostream &out, const Endpoint &e) {
321  out << e.host <<':'<< e.port;
322  return out;
323 }
324 
325 std::ostream &operator<<(std::ostream &out, const sockaddr_in &a) {
326  out << InetAddr::format(a);
327  return out;
328 }
329 
330 } // namespace Hypertable
String format_ipaddress()
Returns a string with a dotted notation ("127.0.0.1") without! the port.
Definition: InetAddr.h:136
std::string String
A String is simply a typedef to std::string.
Definition: String.h:44
static Endpoint parse_endpoint(const char *endpoint, int defport=0)
Parse an endpoint string in (host:port) format.
Definition: InetAddr.cc:181
String format(const char *fmt,...)
Returns a String using printf like format facilities Vanilla snprintf is about 1.5x faster than this...
Definition: String.cc:37
void decode(const uint8_t **bufp, size_t *remainp)
Reads serialized representation of object from a buffer.
Definition: InetAddr.cc:261
void decode_internal(uint8_t version, const uint8_t **bufp, size_t *remainp)
Reads serialized representation of object from a buffer.
Definition: InetAddr.cc:311
String hex(int sep= ':')
Returns a compact String representation ("0x2387646:80") including the port.
Definition: InetAddr.h:140
uint8_t encoding_version() const
Returns encoding version.
Definition: InetAddr.cc:284
uint32_t decode_i32(const uint8_t **bufp, size_t *remainp)
Decode a 32-bit integer in little-endian order.
#define HT_EXPECT(_e_, _code_)
Definition: Logger.h:388
#define HT_ASSERT(_e_)
Definition: Logger.h:396
uint8_t decode_i8(const uint8_t **bufp, size_t *remainp)
Decode a 8-bit integer (a byte/character)
Definition: Serialization.h:60
int encoded_length_vi32(uint32_t val)
Length of a variable length encoded 32-bit integer (up to 5 bytes)
Encapsulate an internet address.
Definition: InetAddr.h:66
uint16_t decode_i16(const uint8_t **bufp, size_t *remainp)
Decode a 16-bit integer in little-endian order.
static bool is_ipv4(const char *ip)
Tests whether the input string in n.n.n.n format (base 10)
Definition: InetAddr.cc:113
Logging routines and macros.
void encode_i32(uint8_t **bufp, uint32_t val)
Encode a 32-bit integer in little-endian order.
Compatibility Macros for C/C++.
InetAddr()
Constructor creates an empty internet address.
Definition: InetAddr.cc:48
std::ostream & operator<<(std::ostream &os, const crontab_entry &entry)
Helper function to write crontab_entry to an ostream.
Definition: Crontab.cc:301
void encode_i16(uint8_t **bufp, uint16_t val)
Encode a 16-bit integer in little-endian order.
Functions to serialize/deserialize primitives to/from a memory buffer.
void encode(uint8_t **bufp) const
Writes serialized representation of object to a buffer.
Definition: InetAddr.cc:255
String format(int sep= ':') const
Returns a string with a dotted notation ("127.0.0.1:8080") including the port.
Definition: InetAddr.h:132
Hypertable definitions
void encode_vi32(uint8_t **bufp, uint32_t val)
Encode a integer (up to 32-bit) in variable length encoding.
static bool initialize(sockaddr_in *addr, const char *host, uint16_t port)
Initialize a sockaddr_in structure from host:port.
Definition: InetAddr.cc:68
#define HT_THROWF(_code_, _fmt_,...)
Definition: Error.h:490
size_t encoded_length_internal() const
Returns internal serialized length.
Definition: InetAddr.cc:288
size_t encoded_length() const
Returns serialized object length.
Definition: InetAddr.cc:228
Internet address wrapper classes and utility functions.
void legacy_decode(const uint8_t **bufp, size_t *remainp)
Deserializes object from legacy serialization format.
Definition: InetAddr.cc:277
void encode_internal(uint8_t **bufp) const
Writes serialized representation of object to a buffer.
Definition: InetAddr.cc:304
#define HT_ERRORF(msg,...)
Definition: Logger.h:300
static bool parse_ipv4(const char *ip, uint16_t port, sockaddr_in &addr, int base=0)
Parses an ipv4 address string in dotted notiation ("n.n.n.n") or as a number and initializes a sockad...
Definition: InetAddr.cc:135
String extensions and helpers: sets, maps, append operators etc.
#define HT_THROW(_code_, _msg_)
Definition: Error.h:478
uint32_t decode_vi32(const uint8_t **bufp, size_t *remainp)
Decode a variable length encoded integer up to 32-bit.
void encode_i8(uint8_t **bufp, uint8_t val)
Encodes a byte into the given buffer.
Definition: Serialization.h:49
High-level entry point to a service; wraps a host:port pair.
Definition: InetAddr.h:44