Merge pull request #10 from egerpil/master
[deliverable/titan.core.git] / common / NetworkHandler.cc
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
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
21IPAddress::~IPAddress() { }
22
23NetworkHandler::NetworkHandler() : m_family(ipv4) { }
24
25void 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
34int NetworkHandler::socket()
35{
36 return socket(m_family);
37}
38
39int 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
49HCNetworkHandler::HCNetworkHandler() : m_mc_addr(NULL), m_local_addr(NULL) { }
50
51HCNetworkHandler::~HCNetworkHandler()
52{
53 delete m_mc_addr;
54 delete m_local_addr;
55}
56
57bool 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
71bool 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
85int 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
98int 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
110int 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
116IPAddress *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
130IPAddress *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
144IPv4Address::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
152IPv4Address::IPv4Address(const char *p_addr, unsigned short p_port)
153{
154 set_addr(p_addr, p_port);
155}
156
157IPv4Address::~IPv4Address()
158{
159 clean_up();
160}
161
162bool 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
172bool 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
178bool 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
196int 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
215int 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
234bool 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
239bool IPv4Address::operator!=(const IPAddress& p_addr) const
240{
241 return !(*this == p_addr);
242}
243
244IPAddress& 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
253void 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
261void 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
270void 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)
278IPv6Address::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
286IPv6Address::IPv6Address(const char *p_addr, unsigned short p_port)
287{
288 set_addr(p_addr, p_port);
289}
290
291IPv6Address::~IPv6Address()
292{
293 clean_up();
294}
295
296const 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
306bool 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
335int 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
355int 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
375bool 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
380bool IPv6Address::operator!=(const IPAddress& p_addr) const
381{
382 return !(*this == p_addr);
383}
384
385IPAddress& 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
394void 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
403void 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
413void 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
420bool 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
431bool 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.041972 seconds and 5 git commands to generate.