Sync with 5.4.0
[deliverable/titan.core.git] / common / NetworkHandler.cc
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
8 #include "NetworkHandler.hh"
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include <sys/types.h>
15 #include <arpa/inet.h>
16 #include <netinet/tcp.h>
17
18 #include "memory.h"
19 #include "../core/Textbuf.hh"
20
21 IPAddress::~IPAddress() { }
22
23 NetworkHandler::NetworkHandler() : m_family(ipv4) { }
24
25 void NetworkHandler::set_family(const char *p_addr)
26 {
27 if (!p_addr || IPv4Address::is_valid(p_addr)) m_family = ipv4;
28 #if defined(LINUX) || defined(CYGWIN17)
29 else if (IPv6Address::is_valid(p_addr)) m_family = ipv6;
30 #endif
31 else m_family = ipv0;
32 }
33
34 int NetworkHandler::socket()
35 {
36 return socket(m_family);
37 }
38
39 int NetworkHandler::socket(const NetworkFamily& p_family)
40 {
41 #if defined(LINUX) || defined(CYGWIN17)
42 return ::socket(p_family == ipv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0);
43 #else
44 (void)p_family;
45 return ::socket(AF_INET, SOCK_STREAM, 0);
46 #endif
47 }
48
49 HCNetworkHandler::HCNetworkHandler() : m_mc_addr(NULL), m_local_addr(NULL) { }
50
51 HCNetworkHandler::~HCNetworkHandler()
52 {
53 delete m_mc_addr;
54 delete m_local_addr;
55 }
56
57 bool HCNetworkHandler::set_local_addr(const char *p_addr, unsigned short p_port)
58 {
59 if (!p_addr) return false;
60 switch (m_family) {
61 case ipv4: m_local_addr = new IPv4Address(p_addr, p_port); break;
62 #if defined(LINUX) || defined(CYGWIN17)
63 case ipv6: m_local_addr = new IPv6Address(p_addr, p_port); break;
64 #endif
65 default:
66 break;
67 }
68 return m_local_addr != NULL;
69 }
70
71 bool HCNetworkHandler::set_mc_addr(const char *p_addr, unsigned short p_port)
72 {
73 if (!p_addr) return false;
74 switch (m_family) {
75 case ipv4: m_mc_addr = new IPv4Address(p_addr, p_port); break;
76 #if defined(LINUX) || defined(CYGWIN17)
77 case ipv6: m_mc_addr = new IPv6Address(p_addr, p_port); break;
78 #endif
79 default:
80 break;
81 }
82 return m_mc_addr != NULL;
83 }
84
85 int HCNetworkHandler::getsockname_local_addr(int p_sockfd)
86 {
87 if (m_local_addr != NULL) delete m_local_addr;
88 switch (m_family) {
89 case ipv4: m_local_addr = new IPv4Address(); break;
90 #if defined(LINUX) || defined(CYGWIN17)
91 case ipv6: m_local_addr = new IPv6Address(); break;
92 #endif
93 default: return -1;
94 }
95 return m_local_addr->getsockname(p_sockfd);
96 }
97
98 int HCNetworkHandler::bind_local_addr(int p_sockfd) const
99 {
100 m_local_addr->set_port(0);
101 return ::bind(p_sockfd, m_local_addr->get_addr(), m_local_addr->get_addr_len());
102 }
103
104 #ifdef SOLARIS
105 #define CAST_AWAY_CONST_FOR_SOLARIS6 (sockaddr *)
106 #else
107 #define CAST_AWAY_CONST_FOR_SOLARIS6
108 #endif
109
110 int HCNetworkHandler::connect_to_mc(int p_sockfd) const
111 {
112 return ::connect(p_sockfd, CAST_AWAY_CONST_FOR_SOLARIS6 m_mc_addr->get_addr(),
113 m_mc_addr->get_addr_len());
114 }
115
116 IPAddress *IPAddress::create_addr(const NetworkFamily& p_family)
117 {
118 switch (p_family) {
119 case ipv4:
120 return new IPv4Address();
121 #if defined(LINUX) || defined(CYGWIN17)
122 case ipv6:
123 return new IPv6Address();
124 #endif
125 default:
126 return NULL;
127 }
128 }
129
130 IPAddress *IPAddress::create_addr(const char *p_addr)
131 {
132 if (p_addr == NULL)
133 return NULL;
134 if (IPv4Address::is_valid(p_addr))
135 return new IPv4Address(p_addr);
136 #if defined(LINUX) || defined(CYGWIN17)
137 else if (IPv6Address::is_valid(p_addr))
138 return new IPv6Address(p_addr);
139 #endif
140 else
141 return NULL;
142 }
143
144 IPv4Address::IPv4Address()
145 {
146 clean_up();
147 m_addr.sin_family = AF_INET;
148 m_addr.sin_addr.s_addr = htonl(INADDR_ANY);
149 m_addr.sin_port = htons(0);
150 }
151
152 IPv4Address::IPv4Address(const char *p_addr, unsigned short p_port)
153 {
154 set_addr(p_addr, p_port);
155 }
156
157 IPv4Address::~IPv4Address()
158 {
159 clean_up();
160 }
161
162 bool IPv4Address::is_valid(const char *p_addr)
163 {
164 if (p_addr == NULL) {
165 return false;
166 } else {
167 IPv4Address addr;
168 return addr.set_addr(p_addr);
169 }
170 }
171
172 bool IPv4Address::is_local() const
173 {
174 // Or: (ntohl(m_addr.sin_addr.s_addr) & 0xff000000u) == 0x7f000000u.
175 return m_addr.sin_addr.s_addr == inet_addr("127.0.0.1");
176 }
177
178 bool IPv4Address::set_addr(const char *p_addr, unsigned short p_port)
179 {
180 clean_up();
181 if (p_addr != NULL) {
182 struct hostent *hptr = gethostbyname(p_addr);
183 if (hptr != NULL && (size_t)hptr->h_length == sizeof(struct in_addr)) {
184 m_addr.sin_family = AF_INET;
185 m_addr.sin_port = htons(p_port);
186 memset(m_addr.sin_zero, 0, sizeof(m_addr.sin_zero));
187 memcpy(&m_addr.sin_addr, hptr->h_addr_list[0], hptr->h_length);
188 strncpy(m_addr_str, inet_ntoa(m_addr.sin_addr), sizeof(m_addr_str));
189 strncpy(m_host_str, hptr->h_name, sizeof(m_host_str));
190 return true;
191 }
192 }
193 return false;
194 }
195
196 int IPv4Address::accept(int p_sockfd)
197 {
198 clean_up();
199 socklen_type addrlen = sizeof(m_addr);
200 int fd = ::accept(p_sockfd, (struct sockaddr *)&m_addr, &addrlen);
201 if (fd >= 0) {
202 strncpy(m_addr_str, inet_ntoa(m_addr.sin_addr), sizeof(m_addr_str));
203 if (m_addr.sin_addr.s_addr != htonl(INADDR_ANY)) {
204 struct hostent *hptr =
205 gethostbyaddr((const char *)&m_addr.sin_addr,
206 sizeof(m_addr.sin_addr), m_addr.sin_family);
207 if (hptr != NULL && (size_t)hptr->h_length == sizeof(struct in_addr)) {
208 strncpy(m_host_str, hptr->h_name, sizeof(m_host_str));
209 }
210 }
211 }
212 return fd;
213 }
214
215 int IPv4Address::getsockname(int p_sockfd)
216 {
217 clean_up();
218 socklen_type addrlen = sizeof(m_addr);
219 int s = ::getsockname(p_sockfd, (struct sockaddr *)&m_addr, &addrlen);
220 if (s >= 0) {
221 strncpy(m_addr_str, inet_ntoa(m_addr.sin_addr), sizeof(m_addr_str));
222 if (m_addr.sin_addr.s_addr != htonl(INADDR_ANY)) {
223 struct hostent *hptr =
224 gethostbyaddr((const char *)&m_addr.sin_addr,
225 sizeof(m_addr.sin_addr), m_addr.sin_family);
226 if (hptr != NULL && (size_t)hptr->h_length == sizeof(struct in_addr)) {
227 strncpy(m_host_str, hptr->h_name, sizeof(m_host_str));
228 }
229 }
230 }
231 return s;
232 }
233
234 bool IPv4Address::operator==(const IPAddress& p_addr) const
235 {
236 return memcmp(&m_addr.sin_addr, &(((const IPv4Address&)p_addr).m_addr.sin_addr), sizeof(m_addr.sin_addr)) == 0;
237 }
238
239 bool IPv4Address::operator!=(const IPAddress& p_addr) const
240 {
241 return !(*this == p_addr);
242 }
243
244 IPAddress& IPv4Address::operator=(const IPAddress& p_addr)
245 {
246 clean_up();
247 memcpy(&m_addr, &((const IPv4Address&)p_addr).m_addr, sizeof(m_addr));
248 strncpy(m_host_str, ((const IPv4Address&)p_addr).m_host_str, sizeof(m_host_str));
249 strncpy(m_addr_str, ((const IPv4Address&)p_addr).m_addr_str, sizeof(m_addr_str));
250 return *this;
251 }
252
253 void IPv4Address::push_raw(Text_Buf& p_buf) const
254 {
255 p_buf.push_raw(sizeof(m_addr.sin_family), &m_addr.sin_family);
256 p_buf.push_raw(sizeof(m_addr.sin_port), &m_addr.sin_port);
257 p_buf.push_raw(sizeof(m_addr.sin_addr), &m_addr.sin_addr);
258 p_buf.push_raw(sizeof(m_addr.sin_zero), &m_addr.sin_zero);
259 }
260
261 void IPv4Address::pull_raw(Text_Buf& p_buf)
262 {
263 clean_up();
264 p_buf.pull_raw(sizeof(m_addr.sin_family), &m_addr.sin_family);
265 p_buf.pull_raw(sizeof(m_addr.sin_port), &m_addr.sin_port);
266 p_buf.pull_raw(sizeof(m_addr.sin_addr), &m_addr.sin_addr);
267 p_buf.pull_raw(sizeof(m_addr.sin_zero), &m_addr.sin_zero);
268 }
269
270 void IPv4Address::clean_up()
271 {
272 memset(&m_addr, 0, sizeof(m_addr));
273 memset(m_host_str, 0, sizeof(m_host_str));
274 memset(m_addr_str, 0, sizeof(m_addr_str));
275 }
276
277 #if defined(LINUX) || defined(CYGWIN17)
278 IPv6Address::IPv6Address()
279 {
280 clean_up();
281 m_addr.sin6_family = AF_INET6;
282 m_addr.sin6_addr = in6addr_any;
283 m_addr.sin6_port = htons(0);
284 }
285
286 IPv6Address::IPv6Address(const char *p_addr, unsigned short p_port)
287 {
288 set_addr(p_addr, p_port);
289 }
290
291 IPv6Address::~IPv6Address()
292 {
293 clean_up();
294 }
295
296 const char *IPv6Address::get_addr_str() const
297 {
298 if (strlen(m_addr_str) > 0) {
299 // The host name should always contain the interface's name for link-local addresses.
300 return (strlen(m_host_str) > 0 && strstr(m_host_str, "%") != NULL) ? m_host_str : m_addr_str;
301 } else {
302 return m_host_str;
303 }
304 }
305
306 bool IPv6Address::set_addr(const char *p_addr, unsigned short p_port)
307 {
308 clean_up();
309 struct addrinfo hints, *res;
310 memset(&hints, 0, sizeof(struct addrinfo));
311 hints.ai_flags = AI_CANONNAME | AI_PASSIVE;
312 hints.ai_family = AF_INET6;
313 hints.ai_socktype = SOCK_STREAM;
314 hints.ai_protocol = 0; // Any.
315 char p_port_str[6];
316 memset(p_port_str, 0, sizeof(p_port_str));
317 snprintf(p_port_str, sizeof(p_port_str), "%u", p_port);
318 int s = getaddrinfo(p_addr, p_port_str, &hints, &res);
319 if (s == 0) {
320 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(void*)res->ai_addr;
321 // The (void*) shuts up the "cast increases required alignment" warning.
322 // Hopefully, the res->ai_addr points to a properly aligned sockaddr_in6
323 // and we won't have problems like these if we decide to support Sparc:
324 // http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340384
325 memcpy(&m_addr, addr, sizeof(m_addr));
326 m_addr.sin6_port = htons(p_port);
327 inet_ntop(res->ai_family, &(addr->sin6_addr), m_addr_str, sizeof(m_addr_str));
328 strncpy(m_host_str, res->ai_canonname, sizeof(m_host_str));
329 freeaddrinfo(res);
330 return true;
331 }
332 return false;
333 }
334
335 int IPv6Address::accept(int p_sockfd)
336 {
337 clean_up();
338 socklen_type addrlen = sizeof(m_addr);
339 int fd = ::accept(p_sockfd, (struct sockaddr *)&m_addr, &addrlen);
340 if (fd >= 0) {
341 if (!inet_ntop(AF_INET6, &m_addr.sin6_addr, m_addr_str, sizeof(m_addr_str))) {
342 fprintf(stderr, "IPv6Address::accept(): Unable to convert IPv6 address "
343 "from binary to text form: %s\n", strerror(errno));
344 }
345 int s = getnameinfo((struct sockaddr *)&m_addr, sizeof(m_addr),
346 m_host_str, sizeof(m_host_str), NULL, 0, 0);
347 if (s != 0) {
348 fprintf(stderr, "IPv6Address::accept(): Address to name translation "
349 "failed: %s\n", gai_strerror(s));
350 }
351 }
352 return fd;
353 }
354
355 int IPv6Address::getsockname(int p_sockfd)
356 {
357 clean_up();
358 socklen_type addrlen = sizeof(m_addr);
359 int s1 = ::getsockname(p_sockfd, (struct sockaddr *)&m_addr, &addrlen);
360 if (s1 >= 0) {
361 if (!inet_ntop(AF_INET6, &m_addr.sin6_addr, m_addr_str, sizeof(m_addr_str))) {
362 fprintf(stderr, "IPv6Address::getsockname(): Unable to convert IPv6 "
363 "address from binary to text form: %s\n", strerror(errno));
364 }
365 int s2 = getnameinfo((struct sockaddr *)&m_addr, sizeof(m_addr),
366 m_host_str, sizeof(m_host_str), NULL, 0, 0);
367 if (s2 != 0) {
368 fprintf(stderr, "IPv6Address::getsockname(): Address to name "
369 "translation failed: %s\n", gai_strerror(s2));
370 }
371 }
372 return s1;
373 }
374
375 bool IPv6Address::operator==(const IPAddress& p_addr) const
376 {
377 return memcmp(&m_addr.sin6_addr, &(((const IPv6Address&)p_addr).m_addr.sin6_addr), sizeof(m_addr.sin6_addr)) == 0;
378 }
379
380 bool IPv6Address::operator!=(const IPAddress& p_addr) const
381 {
382 return !(*this == p_addr);
383 }
384
385 IPAddress& IPv6Address::operator=(const IPAddress& p_addr)
386 {
387 clean_up();
388 memcpy(&m_addr, &((const IPv6Address&)p_addr).m_addr, sizeof(m_addr));
389 strncpy(m_host_str, ((const IPv6Address&)p_addr).m_host_str, sizeof(m_host_str));
390 strncpy(m_addr_str, ((const IPv6Address&)p_addr).m_addr_str, sizeof(m_addr_str));
391 return *this;
392 }
393
394 void IPv6Address::push_raw(Text_Buf& p_buf) const
395 {
396 p_buf.push_raw(sizeof(m_addr.sin6_family), &m_addr.sin6_family);
397 p_buf.push_raw(sizeof(m_addr.sin6_port), &m_addr.sin6_port);
398 p_buf.push_raw(sizeof(m_addr.sin6_flowinfo), &m_addr.sin6_flowinfo);
399 p_buf.push_raw(sizeof(m_addr.sin6_addr), &m_addr.sin6_addr);
400 p_buf.push_raw(sizeof(m_addr.sin6_scope_id), &m_addr.sin6_scope_id);
401 }
402
403 void IPv6Address::pull_raw(Text_Buf& p_buf)
404 {
405 clean_up();
406 p_buf.pull_raw(sizeof(m_addr.sin6_family), &m_addr.sin6_family);
407 p_buf.pull_raw(sizeof(m_addr.sin6_port), &m_addr.sin6_port);
408 p_buf.pull_raw(sizeof(m_addr.sin6_flowinfo), &m_addr.sin6_flowinfo);
409 p_buf.pull_raw(sizeof(m_addr.sin6_addr), &m_addr.sin6_addr);
410 p_buf.pull_raw(sizeof(m_addr.sin6_scope_id), &m_addr.sin6_scope_id);
411 }
412
413 void IPv6Address::clean_up()
414 {
415 memset(&m_addr, 0, sizeof(m_addr));
416 memset(m_host_str, 0, sizeof(m_host_str));
417 memset(m_addr_str, 0, sizeof(m_addr_str));
418 }
419
420 bool IPv6Address::is_local() const
421 {
422 const unsigned char localhost_bytes[] =
423 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
424 const unsigned char mapped_ipv4_localhost[] =
425 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1 };
426
427 return (memcmp(m_addr.sin6_addr.s6_addr, localhost_bytes, 16) == 0
428 || memcmp(m_addr.sin6_addr.s6_addr, mapped_ipv4_localhost, 16) == 0);
429 }
430
431 bool IPv6Address::is_valid(const char *p_addr)
432 {
433 if (p_addr == NULL) {
434 return false;
435 } else {
436 IPv6Address addr;
437 return addr.set_addr(p_addr);
438 }
439 }
440 #endif // LINUX || CYGWIN17
This page took 0.041903 seconds and 6 git commands to generate.