00001
00022 #include "Common/Compat.h"
00023 #include "Common/Serialization.h"
00024
00025 #include <cstdlib>
00026 #include <cstring>
00027
00028 extern "C" {
00029 #include <arpa/inet.h>
00030 #include <netdb.h>
00031 #include <sys/socket.h>
00032 #include <sys/types.h>
00033 #include <sigar.h>
00034 }
00035
00036 #include "Logger.h"
00037 #include "InetAddr.h"
00038 #include "StringExt.h"
00039
00040 namespace Hypertable {
00041
00042 InetAddr::InetAddr() {
00043 HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
00044 memset(this, 0, sizeof(InetAddr));
00045 }
00046
00047 InetAddr::InetAddr(const String &host, uint16_t port) {
00048 HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
00049 HT_EXPECT(initialize(this, host.c_str(), port), Error::BAD_DOMAIN_NAME);
00050 }
00051
00052 InetAddr::InetAddr(const String &endpoint) {
00053 HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
00054 HT_EXPECT(initialize(this, endpoint.c_str()), Error::BAD_DOMAIN_NAME);
00055 }
00056
00057 InetAddr::InetAddr(uint32_t ip32, uint16_t port) {
00058 HT_EXPECT(sizeof(sockaddr_in) == sizeof(InetAddr), Error::UNPOSSIBLE);
00059 initialize(this, ip32, port);
00060 }
00061
00062 bool InetAddr::initialize(sockaddr_in *addr, const char *host, uint16_t port) {
00063 memset(addr, 0, sizeof(struct sockaddr_in));
00064
00065 if (parse_ipv4(host, port, *addr)) {
00066 return true;
00067 }
00068 else {
00069 #if defined(__linux__)
00070
00071 struct hostent hent, *he = 0;
00072 char hbuf[2048];
00073 int err;
00074
00075 if (gethostbyname_r(host, &hent, hbuf, sizeof(hbuf), &he, &err) != 0
00076 || he == 0) {
00077 HT_ERRORF("gethostbyname '%s': error: %d", host, err);
00078 return false;
00079 }
00080 #elif defined(__APPLE__) || defined(__sun__) || defined(__FreeBSD__)
00081
00082
00083 struct hostent *he = gethostbyname(host);
00084
00085 if (he == 0) {
00086 String errmsg = (String)"gethostbyname(\"" + host + "\")";
00087 herror(errmsg.c_str());
00088 HT_THROW(Error::BAD_DOMAIN_NAME, errmsg);
00089 return false;
00090 }
00091 #else
00092 #error TODO
00093 #endif
00094 memcpy(&addr->sin_addr.s_addr, he->h_addr_list[0], sizeof(uint32_t));
00095 if (addr->sin_addr.s_addr == 0) {
00096 uint8_t *ip = (uint8_t *)&addr->sin_addr.s_addr;
00097 ip[0] = 127;
00098 ip[3] = 1;
00099 }
00100 }
00101 addr->sin_family = AF_INET;
00102 addr->sin_port = htons(port);
00103 return true;
00104 }
00105
00106 bool
00107 InetAddr::parse_ipv4(const char *ipin, uint16_t port, sockaddr_in &addr,
00108 int base) {
00109 uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
00110 const char *ipstr = ipin, *end = ipin + strlen(ipin);
00111 char *last;
00112 int64_t n = strtoll(ipstr, &last, base);
00113
00114 addr.sin_family = AF_INET;
00115 addr.sin_port = htons(port);
00116
00117 if (last == end && n > 0 && n < UINT32_MAX) {
00118 addr.sin_addr.s_addr = htonl(n);
00119 return true;
00120 }
00121 *ip++ = n;
00122
00123 if (last > end || *last != '.')
00124 return false;
00125
00126 ipstr = last + 1;
00127 *ip++ = strtol(ipstr, &last, base);
00128
00129 if (last >= end || *last != '.')
00130 return false;
00131
00132 ipstr = last + 1;
00133 *ip++ = strtol(ipstr, &last, base);
00134
00135 if (last >= end || *last != '.')
00136 return false;
00137
00138 ipstr = last + 1;
00139 *ip++ = strtol(ipstr, &last, base);
00140
00141 if (last != end)
00142 return false;
00143
00144 if (addr.sin_addr.s_addr == 0) {
00145 uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
00146 ip[0] = 127;
00147 ip[3] = 1;
00148 }
00149
00150 return true;
00151 }
00152
00153 Endpoint InetAddr::parse_endpoint(const char *endpoint, int default_port) {
00154 const char *colon = strchr(endpoint, ':');
00155
00156 if (colon) {
00157 String host = String(endpoint, colon - endpoint);
00158 return Endpoint(host, atoi(colon + 1));
00159 }
00160 return Endpoint(endpoint, default_port);
00161 }
00162
00163 bool InetAddr::initialize(sockaddr_in *addr, const char *addr_str) {
00164 Endpoint e = parse_endpoint(addr_str);
00165
00166 if (e.port)
00167 return initialize(addr, e.host.c_str(), e.port);
00168
00169 return initialize(addr, "localhost", atoi(addr_str));
00170 }
00171
00172 bool InetAddr::initialize(sockaddr_in *addr, uint32_t haddr, uint16_t port) {
00173 memset(addr, 0 , sizeof(sockaddr_in));
00174 addr->sin_family = AF_INET;
00175 addr->sin_addr.s_addr = htonl(haddr);
00176 addr->sin_port = htons(port);
00177 return true;
00178 }
00179
00180 size_t InetAddr::encoded_length() const {
00181 return 8;
00182 }
00183
00184 void InetAddr::encode(uint8_t **bufp) const {
00185 *(*bufp)++ = sizeof(sockaddr_in);
00186 *(*bufp)++ = sin_family;
00187 Serialization::encode_i16(bufp, sin_port);
00188 Serialization::encode_i32(bufp, sin_addr.s_addr);
00189 }
00190
00191 void InetAddr::decode(const uint8_t **bufp, size_t *remainp) {
00192 Serialization::decode_i8(bufp, remainp);
00193 sin_family = Serialization::decode_i8(bufp, remainp);
00194 sin_port = Serialization::decode_i16(bufp, remainp);
00195 sin_addr.s_addr = Serialization::decode_i32(bufp, remainp);
00196 }
00197
00198
00199 String InetAddr::format(const sockaddr_in &addr, int sep) {
00200
00201 const uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
00202 return Hypertable::format("%d.%d.%d.%d%c%d", (int)ip[0], (int)ip[1],
00203 (int)ip[2],(int)ip[3], sep, (int)ntohs(addr.sin_port));
00204 }
00205
00206 String InetAddr::format_ipaddress(const sockaddr_in &addr) {
00207
00208 const uint8_t *ip = (uint8_t *)&addr.sin_addr.s_addr;
00209 return Hypertable::format("%d.%d.%d.%d", (int)ip[0], (int)ip[1],
00210 (int)ip[2],(int)ip[3]);
00211 }
00212
00213 String InetAddr::hex(const sockaddr_in &addr, int sep) {
00214 return Hypertable::format("%x%c%x", ntohl(addr.sin_addr.s_addr), sep,
00215 ntohs(addr.sin_port));
00216 }
00217
00218 const char *InetAddr::string_format(String &addr_str, const sockaddr_in &addr) {
00219 addr_str = InetAddr::format(addr);
00220 return addr_str.c_str();
00221 }
00222
00223 std::ostream &operator<<(std::ostream &out, const Endpoint &e) {
00224 out << e.host <<':'<< e.port;
00225 return out;
00226 }
00227
00228 std::ostream &operator<<(std::ostream &out, const sockaddr_in &a) {
00229 out << InetAddr::format(a);
00230 return out;
00231 }
00232
00233 }