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
15 ******************************************************************************/
16 #include "NetworkHandler.hh"
22 #include <sys/types.h>
23 #include <arpa/inet.h>
24 #include <netinet/tcp.h>
27 #include "../core/Textbuf.hh"
29 IPAddress::~IPAddress() { }
31 NetworkHandler::NetworkHandler() : m_family(ipv4
) { }
33 void NetworkHandler::set_family(const char *p_addr
)
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
;
42 int NetworkHandler::socket()
44 return socket(m_family
);
47 int NetworkHandler::socket(const NetworkFamily
& p_family
)
49 #if defined(LINUX) || defined(CYGWIN17)
50 return ::socket(p_family
== ipv4
? AF_INET
: AF_INET6
, SOCK_STREAM
, 0);
53 return ::socket(AF_INET
, SOCK_STREAM
, 0);
57 HCNetworkHandler::HCNetworkHandler() : m_mc_addr(NULL
), m_local_addr(NULL
) { }
59 HCNetworkHandler::~HCNetworkHandler()
65 bool HCNetworkHandler::set_local_addr(const char *p_addr
, unsigned short p_port
)
67 if (!p_addr
) return false;
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;
76 return m_local_addr
!= NULL
;
79 bool HCNetworkHandler::set_mc_addr(const char *p_addr
, unsigned short p_port
)
81 if (!p_addr
) return false;
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;
90 return m_mc_addr
!= NULL
;
93 int HCNetworkHandler::getsockname_local_addr(int p_sockfd
)
95 if (m_local_addr
!= NULL
) delete m_local_addr
;
97 case ipv4
: m_local_addr
= new IPv4Address(); break;
98 #if defined(LINUX) || defined(CYGWIN17)
99 case ipv6
: m_local_addr
= new IPv6Address(); break;
103 return m_local_addr
->getsockname(p_sockfd
);
106 int HCNetworkHandler::bind_local_addr(int p_sockfd
) const
108 m_local_addr
->set_port(0);
109 return ::bind(p_sockfd
, m_local_addr
->get_addr(), m_local_addr
->get_addr_len());
113 #define CAST_AWAY_CONST_FOR_SOLARIS6 (sockaddr *)
115 #define CAST_AWAY_CONST_FOR_SOLARIS6
118 int HCNetworkHandler::connect_to_mc(int p_sockfd
) const
120 return ::connect(p_sockfd
, CAST_AWAY_CONST_FOR_SOLARIS6 m_mc_addr
->get_addr(),
121 m_mc_addr
->get_addr_len());
124 IPAddress
*IPAddress::create_addr(const NetworkFamily
& p_family
)
128 return new IPv4Address();
129 #if defined(LINUX) || defined(CYGWIN17)
131 return new IPv6Address();
138 IPAddress
*IPAddress::create_addr(const char *p_addr
)
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
);
152 IPv4Address::IPv4Address()
155 m_addr
.sin_family
= AF_INET
;
156 m_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
157 m_addr
.sin_port
= htons(0);
160 IPv4Address::IPv4Address(const char *p_addr
, unsigned short p_port
)
162 set_addr(p_addr
, p_port
);
165 IPv4Address::~IPv4Address()
170 bool IPv4Address::is_valid(const char *p_addr
)
172 if (p_addr
== NULL
) {
176 return addr
.set_addr(p_addr
);
180 bool IPv4Address::is_local() const
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");
186 bool IPv4Address::set_addr(const char *p_addr
, unsigned short p_port
)
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
));
204 int IPv4Address::accept(int p_sockfd
)
207 socklen_type addrlen
= sizeof(m_addr
);
208 int fd
= ::accept(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
223 int IPv4Address::getsockname(int p_sockfd
)
226 socklen_type addrlen
= sizeof(m_addr
);
227 int s
= ::getsockname(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
242 bool IPv4Address::operator==(const IPAddress
& p_addr
) const
244 return memcmp(&m_addr
.sin_addr
, &(((const IPv4Address
&)p_addr
).m_addr
.sin_addr
), sizeof(m_addr
.sin_addr
)) == 0;
247 bool IPv4Address::operator!=(const IPAddress
& p_addr
) const
249 return !(*this == p_addr
);
252 IPAddress
& IPv4Address::operator=(const IPAddress
& p_addr
)
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
));
261 void IPv4Address::push_raw(Text_Buf
& p_buf
) const
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
);
269 void IPv4Address::pull_raw(Text_Buf
& p_buf
)
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
);
278 void IPv4Address::clean_up()
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
));
285 #if defined(LINUX) || defined(CYGWIN17)
286 IPv6Address::IPv6Address()
289 m_addr
.sin6_family
= AF_INET6
;
290 m_addr
.sin6_addr
= in6addr_any
;
291 m_addr
.sin6_port
= htons(0);
294 IPv6Address::IPv6Address(const char *p_addr
, unsigned short p_port
)
296 set_addr(p_addr
, p_port
);
299 IPv6Address::~IPv6Address()
304 const char *IPv6Address::get_addr_str() const
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
;
314 bool IPv6Address::set_addr(const char *p_addr
, unsigned short p_port
)
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.
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
);
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
));
343 int IPv6Address::accept(int p_sockfd
)
346 socklen_type addrlen
= sizeof(m_addr
);
347 int fd
= ::accept(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
353 int s
= getnameinfo((struct sockaddr
*)&m_addr
, sizeof(m_addr
),
354 m_host_str
, sizeof(m_host_str
), NULL
, 0, 0);
356 fprintf(stderr
, "IPv6Address::accept(): Address to name translation "
357 "failed: %s\n", gai_strerror(s
));
363 int IPv6Address::getsockname(int p_sockfd
)
366 socklen_type addrlen
= sizeof(m_addr
);
367 int s1
= ::getsockname(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
373 int s2
= getnameinfo((struct sockaddr
*)&m_addr
, sizeof(m_addr
),
374 m_host_str
, sizeof(m_host_str
), NULL
, 0, 0);
376 fprintf(stderr
, "IPv6Address::getsockname(): Address to name "
377 "translation failed: %s\n", gai_strerror(s2
));
383 bool IPv6Address::operator==(const IPAddress
& p_addr
) const
385 return memcmp(&m_addr
.sin6_addr
, &(((const IPv6Address
&)p_addr
).m_addr
.sin6_addr
), sizeof(m_addr
.sin6_addr
)) == 0;
388 bool IPv6Address::operator!=(const IPAddress
& p_addr
) const
390 return !(*this == p_addr
);
393 IPAddress
& IPv6Address::operator=(const IPAddress
& p_addr
)
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
));
402 void IPv6Address::push_raw(Text_Buf
& p_buf
) const
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
);
411 void IPv6Address::pull_raw(Text_Buf
& p_buf
)
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
);
421 void IPv6Address::clean_up()
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
));
428 bool IPv6Address::is_local() const
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 };
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);
439 bool IPv6Address::is_valid(const char *p_addr
)
441 if (p_addr
== NULL
) {
445 return addr
.set_addr(p_addr
);
448 #endif // LINUX || CYGWIN17