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