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"
14 #include <sys/types.h>
15 #include <arpa/inet.h>
16 #include <netinet/tcp.h>
19 #include "../core/Textbuf.hh"
21 IPAddress::~IPAddress() { }
23 NetworkHandler::NetworkHandler() : m_family(ipv4
) { }
25 void NetworkHandler::set_family(const char *p_addr
)
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
;
34 int NetworkHandler::socket()
36 return socket(m_family
);
39 int NetworkHandler::socket(const NetworkFamily
& p_family
)
41 #if defined(LINUX) || defined(CYGWIN17)
42 return ::socket(p_family
== ipv4
? AF_INET
: AF_INET6
, SOCK_STREAM
, 0);
45 return ::socket(AF_INET
, SOCK_STREAM
, 0);
49 HCNetworkHandler::HCNetworkHandler() : m_mc_addr(NULL
), m_local_addr(NULL
) { }
51 HCNetworkHandler::~HCNetworkHandler()
57 bool HCNetworkHandler::set_local_addr(const char *p_addr
, unsigned short p_port
)
59 if (!p_addr
) return false;
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;
68 return m_local_addr
!= NULL
;
71 bool HCNetworkHandler::set_mc_addr(const char *p_addr
, unsigned short p_port
)
73 if (!p_addr
) return false;
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;
82 return m_mc_addr
!= NULL
;
85 int HCNetworkHandler::getsockname_local_addr(int p_sockfd
)
87 if (m_local_addr
!= NULL
) delete m_local_addr
;
89 case ipv4
: m_local_addr
= new IPv4Address(); break;
90 #if defined(LINUX) || defined(CYGWIN17)
91 case ipv6
: m_local_addr
= new IPv6Address(); break;
95 return m_local_addr
->getsockname(p_sockfd
);
98 int HCNetworkHandler::bind_local_addr(int p_sockfd
) const
100 m_local_addr
->set_port(0);
101 return ::bind(p_sockfd
, m_local_addr
->get_addr(), m_local_addr
->get_addr_len());
105 #define CAST_AWAY_CONST_FOR_SOLARIS6 (sockaddr *)
107 #define CAST_AWAY_CONST_FOR_SOLARIS6
110 int HCNetworkHandler::connect_to_mc(int p_sockfd
) const
112 return ::connect(p_sockfd
, CAST_AWAY_CONST_FOR_SOLARIS6 m_mc_addr
->get_addr(),
113 m_mc_addr
->get_addr_len());
116 IPAddress
*IPAddress::create_addr(const NetworkFamily
& p_family
)
120 return new IPv4Address();
121 #if defined(LINUX) || defined(CYGWIN17)
123 return new IPv6Address();
130 IPAddress
*IPAddress::create_addr(const char *p_addr
)
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
);
144 IPv4Address::IPv4Address()
147 m_addr
.sin_family
= AF_INET
;
148 m_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
149 m_addr
.sin_port
= htons(0);
152 IPv4Address::IPv4Address(const char *p_addr
, unsigned short p_port
)
154 set_addr(p_addr
, p_port
);
157 IPv4Address::~IPv4Address()
162 bool IPv4Address::is_valid(const char *p_addr
)
164 if (p_addr
== NULL
) {
168 return addr
.set_addr(p_addr
);
172 bool IPv4Address::is_local() const
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");
178 bool IPv4Address::set_addr(const char *p_addr
, unsigned short p_port
)
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
));
196 int IPv4Address::accept(int p_sockfd
)
199 socklen_type addrlen
= sizeof(m_addr
);
200 int fd
= ::accept(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
215 int IPv4Address::getsockname(int p_sockfd
)
218 socklen_type addrlen
= sizeof(m_addr
);
219 int s
= ::getsockname(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
234 bool IPv4Address::operator==(const IPAddress
& p_addr
) const
236 return memcmp(&m_addr
.sin_addr
, &(((const IPv4Address
&)p_addr
).m_addr
.sin_addr
), sizeof(m_addr
.sin_addr
)) == 0;
239 bool IPv4Address::operator!=(const IPAddress
& p_addr
) const
241 return !(*this == p_addr
);
244 IPAddress
& IPv4Address::operator=(const IPAddress
& p_addr
)
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
));
253 void IPv4Address::push_raw(Text_Buf
& p_buf
) const
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
);
261 void IPv4Address::pull_raw(Text_Buf
& p_buf
)
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
);
270 void IPv4Address::clean_up()
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
));
277 #if defined(LINUX) || defined(CYGWIN17)
278 IPv6Address::IPv6Address()
281 m_addr
.sin6_family
= AF_INET6
;
282 m_addr
.sin6_addr
= in6addr_any
;
283 m_addr
.sin6_port
= htons(0);
286 IPv6Address::IPv6Address(const char *p_addr
, unsigned short p_port
)
288 set_addr(p_addr
, p_port
);
291 IPv6Address::~IPv6Address()
296 const char *IPv6Address::get_addr_str() const
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
;
306 bool IPv6Address::set_addr(const char *p_addr
, unsigned short p_port
)
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.
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
);
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
));
335 int IPv6Address::accept(int p_sockfd
)
338 socklen_type addrlen
= sizeof(m_addr
);
339 int fd
= ::accept(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
345 int s
= getnameinfo((struct sockaddr
*)&m_addr
, sizeof(m_addr
),
346 m_host_str
, sizeof(m_host_str
), NULL
, 0, 0);
348 fprintf(stderr
, "IPv6Address::accept(): Address to name translation "
349 "failed: %s\n", gai_strerror(s
));
355 int IPv6Address::getsockname(int p_sockfd
)
358 socklen_type addrlen
= sizeof(m_addr
);
359 int s1
= ::getsockname(p_sockfd
, (struct sockaddr
*)&m_addr
, &addrlen
);
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
));
365 int s2
= getnameinfo((struct sockaddr
*)&m_addr
, sizeof(m_addr
),
366 m_host_str
, sizeof(m_host_str
), NULL
, 0, 0);
368 fprintf(stderr
, "IPv6Address::getsockname(): Address to name "
369 "translation failed: %s\n", gai_strerror(s2
));
375 bool IPv6Address::operator==(const IPAddress
& p_addr
) const
377 return memcmp(&m_addr
.sin6_addr
, &(((const IPv6Address
&)p_addr
).m_addr
.sin6_addr
), sizeof(m_addr
.sin6_addr
)) == 0;
380 bool IPv6Address::operator!=(const IPAddress
& p_addr
) const
382 return !(*this == p_addr
);
385 IPAddress
& IPv6Address::operator=(const IPAddress
& p_addr
)
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
));
394 void IPv6Address::push_raw(Text_Buf
& p_buf
) const
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
);
403 void IPv6Address::pull_raw(Text_Buf
& p_buf
)
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
);
413 void IPv6Address::clean_up()
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
));
420 bool IPv6Address::is_local() const
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 };
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);
431 bool IPv6Address::is_valid(const char *p_addr
)
433 if (p_addr
== NULL
) {
437 return addr
.set_addr(p_addr
);
440 #endif // LINUX || CYGWIN17