1/*******************************************************************************
2 * Copyright (C) 2004-2008 Intel Corp. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 *  - Redistributions of source code must retain the above copyright notice,
8 *    this list of conditions and the following disclaimer.
9 *
10 *  - Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 *  - Neither the name of Intel Corp. nor the names of its
15 *    contributors may be used to endorse or promote products derived from this
16 *    software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *******************************************************************************/
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include "ATNetworkTool.h"
36#include <sstream>
37#include <algorithm>
38#include <cerrno>
39#include <net/if.h>
40#include <netdb.h>
41
42#ifdef __sun
43#include <arpa/inet.h>
44#include <sys/sockio.h>
45#include <stdio.h>
46#include <stropts.h>
47#else
48#include <ifaddrs.h>
49#endif // __sun
50
51#include <unistd.h>
52#include <fcntl.h>
53
54bool ATNetworkTool::GetHostNameDomain(const char *name, std::string &domain)
55{
56	const char *domp = strchr(name, '.');
57	if (domp) {
58		domp++;
59		if (*domp) {
60#ifdef LMS_NET_DEBUG
61			printf("D:  %s\n", domp);
62#endif
63			domain = domp;
64			return true;
65		}
66	}
67	return false;
68}
69
70bool ATNetworkTool::GetHentDomain(struct hostent *hent, std::string &domain)
71{
72	if (NULL == hent) {
73		return false;
74	}
75	if (NULL == hent->h_name) {
76		return false;
77	}
78
79#ifdef LMS_NET_DEBUG
80	printf("N:  %s\n", hent->h_name);
81#endif
82	if (ATNetworkTool::GetHostNameDomain(hent->h_name, domain)) {
83		return true;
84	}
85
86	if (NULL != hent->h_aliases) {
87		for (char **ssx = hent->h_aliases; ssx && *ssx; ssx++) {
88#ifdef LMS_NET_DEBUG
89			printf("A:  %s\n", *ssx);
90#endif
91			if (ATNetworkTool::GetHostNameDomain(*ssx, domain)) {
92				return true;
93			}
94		}
95	}
96	return false;
97}
98
99bool ATNetworkTool::GetIPDomain(const ATAddress &ip, std::string &domain, int &error)
100{
101	char hbuf[NI_MAXHOST];
102
103	if (0 != (error = getnameinfo(ip.addr(), ip.size(),
104				      hbuf, sizeof(hbuf),
105				      NULL, 0,
106				      NI_NAMEREQD))) {
107		return false;
108	}
109
110	return ATNetworkTool::GetHostNameDomain(hbuf, domain);
111}
112
113int ATNetworkTool::GetLocalIPs(ATAddressList &addresses, int &error, int family, bool withloopback)
114{
115	struct ifaddrs *ifap;
116
117#ifdef __sun
118
119	char          buf[1024];
120	struct ifconf ifc;
121	struct ifreq *ifr;
122	int           sock;
123	int           nInterfaces;
124	int           i;
125
126	addresses.clear();
127
128	sock = socket(AF_INET, SOCK_DGRAM, 0);
129	if(sock < 0)
130	{
131		perror("socket");
132		return 1;
133	}
134
135	/* Query available interfaces. */
136	ifc.ifc_len = sizeof(buf);
137	ifc.ifc_buf = buf;
138	if(ioctl(sock, SIOCGIFCONF, &ifc) < 0)
139	{
140		perror("ioctl(SIOCGIFCONF)");
141		close(sock);
142		return 1;
143	}
144
145	/* Iterate through the list of interfaces. */
146	ifr         = ifc.ifc_req;
147	nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
148	for(i = 0; i < nInterfaces; i++)
149	{
150		struct ifreq *item = &ifr[i];
151
152		if (item->ifr_flags & IFF_LOOPBACK)
153			continue;
154
155		addresses.insert(&item->ifr_addr);
156	}
157
158	close(sock);
159
160#else // ! __sun
161
162	if (0 != getifaddrs(&ifap)) {
163		error = errno;
164		return -1;
165	}
166
167	addresses.clear();
168	for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) {
169		if (NULL == ifa->ifa_addr) {
170			continue;
171		}
172		if ((ifa->ifa_flags & IFF_UP) == 0) {
173			continue;
174		}
175		if ((!withloopback) &&
176		    (((ifa->ifa_flags & IFF_LOOPBACK) != 0) ||
177		    ((ifa->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0))) {
178			continue;
179		}
180
181		if (AF_UNSPEC != family) {
182			if (ATNetworkTool::AF_XINETX == family) {
183				if (!ATAddress::saIsInet(ifa->ifa_addr)) {
184					continue;
185				}
186			} else {
187				if (ifa->ifa_addr->sa_family != family) {
188					continue;
189				}
190			}
191		}
192
193		addresses.insert(ifa->ifa_addr);
194	}
195	freeifaddrs(ifap);
196
197#endif // __sun
198
199	return 0;
200}
201
202int ATNetworkTool::GetLocalNetDomains(ATDomainMap &domains, int &error, int family)
203{
204	int ret;
205	ATAddressList addresses;
206
207	if (0 != (ret = ATNetworkTool::GetLocalIPs(addresses, error, family))) {
208		return ret;
209	}
210
211	domains.clear();
212	ATAddressList::iterator aend = addresses.end();
213	for (ATAddressList::iterator ait = addresses.begin();
214	    ait != aend;
215	    ait++)
216	{
217		std::string domain;
218		if (ATNetworkTool::GetIPDomain(*ait, domain, error)) {
219			domains[*ait] = domain;
220		}
221	}
222	return 0;
223}
224
225int ATNetworkTool::GetSockDomain(int sock, std::string &domain, int &error)
226{
227	struct sockaddr_storage ss;
228	socklen_t salen = sizeof(ss);
229	struct sockaddr *sa;
230
231	sa = (struct sockaddr *)&ss;
232
233	if (getsockname(sock, sa, &salen) != 0) {
234		error = errno;
235		return -1;
236	}
237
238	if (ATNetworkTool::GetIPDomain(sa, domain, error)) {
239		return 1;
240	}
241	return 0;
242}
243
244int ATNetworkTool::GetSockPeerIPs(int sock, ATAddressList &addresses, int &error,
245				  int family, bool zeroport)
246{
247	struct sockaddr_storage ss;
248	socklen_t salen = sizeof(ss);
249	struct sockaddr *sa;
250	struct addrinfo hints, *paddr, *paddrp;
251
252	sa = (struct sockaddr *)&ss;
253
254	if (getpeername(sock, sa, &salen) != 0) {
255		error = errno;
256		return -1;
257	}
258
259	char hbuf[NI_MAXHOST];
260	char pbuf[NI_MAXSERV];
261	if (0 != (error = getnameinfo(sa, salen,
262				      hbuf, sizeof(hbuf),
263				      pbuf, sizeof(pbuf),
264				      0))) {
265		return -1;
266	}
267
268	memset(&hints, 0, sizeof(hints));
269	if (ATNetworkTool::AF_XINETX == family) {
270		hints.ai_family = PF_UNSPEC;
271	} else {
272		hints.ai_family = family;
273	}
274	hints.ai_socktype = SOCK_STREAM;
275	if (0 != (error = getaddrinfo(hbuf, pbuf, &hints, &paddrp))) {
276		return -1;
277	}
278	addresses.clear();
279	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
280		if (ATNetworkTool::AF_XINETX == family) {
281			if (!ATAddress::saIsInet(paddr->ai_addr)) {
282				continue;
283			}
284		}
285		if (zeroport) {
286			addresses.insert(ATAddress(paddr->ai_addr, 0));
287		} else {
288			addresses.insert(paddr->ai_addr);
289		}
290	}
291	freeaddrinfo(paddrp);
292	return 0;
293}
294
295int ATNetworkTool::IsSockPeerLocal(int sock, int &error, int family)
296{
297	ATAddressList localAddresses;
298	ATAddressList targAddresses;
299
300	if (0 != ATNetworkTool::GetSockPeerIPs(sock, targAddresses, error,
301						family, true)) {
302		return -1;
303	}
304	if (0 != ATNetworkTool::GetLocalIPs(localAddresses, error,
305						family, true)) {
306		return -1;
307	}
308	if (std::includes(localAddresses.begin(), localAddresses.end(),
309			  targAddresses.begin(), targAddresses.end())) {
310		return 1;
311	}
312	return 0;
313}
314
315int ATNetworkTool::CloseSocket(int s)
316{
317	shutdown(s, SHUT_RDWR);
318	return close(s);
319}
320
321int ATNetworkTool::CreateSocket(const struct addrinfo *addr, int &error)
322{
323	return ATNetworkTool::CreateSocket(addr->ai_addr, addr->ai_addrlen,
324					    error,
325					    addr->ai_family, addr->ai_socktype,
326					    addr->ai_protocol);
327}
328
329int ATNetworkTool::CreateSocket(const struct sockaddr *addr, socklen_t addrlen,
330				int &error,
331				int family, int socktype, int protocol)
332{
333	int s = socket(family, socktype, protocol);
334	if (s < 0) {
335		error = errno;
336		return -1;
337	}
338
339	if (socktype != SOCK_DGRAM) {
340		linger l;
341		l.l_onoff = 0;
342		l.l_linger = 0;
343		if (setsockopt(s, SOL_SOCKET, SO_LINGER,
344			       (char *)&l, sizeof(l)) == -1) {
345			error = errno;
346			close(s);
347			return -1;
348		}
349	}
350
351	if (bind(s, addr, addrlen) == -1) {
352		error = errno;
353		close(s);
354		return -1;
355	}
356
357	return s;
358}
359
360int ATNetworkTool::ConnectSocket(struct addrinfo *addr,
361				 int &error, bool loopback)
362{
363	return ATNetworkTool::ConnectSocket(addr->ai_addr, addr->ai_addrlen,
364					    error, loopback,
365					    addr->ai_family, addr->ai_socktype,
366					    addr->ai_protocol);
367}
368
369int ATNetworkTool::ConnectSocket(const struct sockaddr *addr, socklen_t addrlen,
370				 int &error, bool loopback,
371				 int family, int socktype, int protocol)
372{
373	struct addrinfo hints, *paddr, *paddrp;
374	int oks = -1;
375
376	memset(&hints, 0, sizeof(hints));
377	if (ATNetworkTool::AF_XINETX == family) {
378		hints.ai_family = PF_UNSPEC;
379	} else {
380		hints.ai_family = family;
381	}
382	hints.ai_socktype = socktype;
383	hints.ai_protocol = protocol;
384#ifdef AI_NUMERICSERV
385	hints.ai_flags   |= AI_NUMERICSERV;
386#endif
387	if (!loopback) {
388		hints.ai_flags |= AI_PASSIVE;
389	}
390	if ((error = getaddrinfo(NULL, "0", &hints, &paddrp)) != 0) {
391		return -1;
392	}
393	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
394		if (ATNetworkTool::AF_XINETX == family) {
395			if (!ATAddress::saIsInet(paddr->ai_addr)) {
396				continue;
397			}
398		}
399
400		int s = ATNetworkTool::CreateSocket(paddr, error);
401		if (s < 0) {
402			continue;
403		}
404
405		if (connect(s, addr, addrlen) != 0) {
406			error = errno;
407			ATNetworkTool::CloseSocket(s);
408			continue;
409		}
410
411		oks = s;
412		break;
413	}
414	freeaddrinfo(paddrp);
415	return oks;
416}
417
418int ATNetworkTool::CreateServerSocket(in_port_t port,
419					int &error,
420					bool loopback, bool nonblocking,
421					int family, int socktype, int protocol,
422					int backlog)
423{
424	std::stringstream ssport;
425
426	ssport << port;
427	return ATNetworkTool::CreateServerSocket(ssport.str().c_str(),
428						 error,
429						 loopback, nonblocking,
430						 family, socktype, protocol,
431						 backlog);
432}
433
434int ATNetworkTool::CreateServerSocket(const char *port,
435					int &error,
436					bool loopback, bool nonblocking,
437					int family, int socktype, int protocol,
438					int backlog)
439{
440	ATSocketList sockets;
441	int s = -1;
442
443	int num = ATNetworkTool::CreateServerSockets(sockets, port,
444						     error,
445						     loopback, nonblocking,
446						     family, socktype, protocol,
447						     backlog, true);
448	if ((num > 0) && (sockets.size() > 0)) {
449		s = sockets[0];
450	}
451	sockets.clear();
452	return s;
453}
454
455
456int ATNetworkTool::CreateServerSockets(ATSocketList &sockets, in_port_t port,
457					int &error,
458					bool loopback, bool nonblocking,
459					int family, int socktype, int protocol,
460					int backlog, bool one)
461{
462	std::stringstream ssport;
463
464	ssport << port;
465	return ATNetworkTool::CreateServerSockets(sockets, ssport.str().c_str(),
466						  error,
467						  loopback, nonblocking,
468						  family, socktype, protocol,
469						  backlog, one);
470}
471
472int ATNetworkTool::CreateServerSockets(ATSocketList &sockets, const char *port,
473					int &error,
474					bool loopback, bool nonblocking,
475					int family, int socktype, int protocol,
476					int backlog, bool one)
477{
478	struct addrinfo hints, *paddr, *paddrp;
479	int num = 0;
480
481	memset(&hints, 0, sizeof(hints));
482	if (ATNetworkTool::AF_XINETX == family) {
483		hints.ai_family = PF_UNSPEC;
484	} else {
485		hints.ai_family = family;
486	}
487	hints.ai_socktype = socktype;
488	hints.ai_protocol = protocol;
489#ifdef AI_NUMERICSERV
490	hints.ai_flags   |= AI_NUMERICSERV;
491#endif
492	if (!loopback) {
493		hints.ai_flags |= AI_PASSIVE;
494	}
495	if ((error = getaddrinfo(NULL, port, &hints, &paddrp)) != 0) {
496		return -1;
497	}
498	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
499		if (ATNetworkTool::AF_XINETX == family) {
500			if (!ATAddress::saIsInet(paddr->ai_addr)) {
501				continue;
502			}
503		}
504
505		int s = ATNetworkTool::CreateServerSocket(paddr, error,
506							  nonblocking,
507							  backlog);
508		if (s < 0) {
509			continue;
510		}
511		sockets.push_back(s);
512		num++;
513		if (one) {
514			break;
515		}
516	}
517	freeaddrinfo(paddrp);
518	return num;
519}
520
521int ATNetworkTool::CreateServerSocket(const struct addrinfo *addr, int &error,
522					bool nonblocking, int backlog)
523{
524	int s = ATNetworkTool::CreateSocket(addr, error);
525	if (s < 0) {
526		return -1;
527	}
528
529	if (nonblocking) {
530		ATNetworkTool::SetNonBlocking(s);
531	}
532
533	if (listen(s, backlog) == -1) {
534		error = errno;
535		ATNetworkTool::CloseSocket(s);
536		return -1;
537	}
538
539	return s;
540}
541
542int ATNetworkTool::SetNonBlocking(int s, bool block)
543{
544	if (block) {
545		return fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
546	} else {
547		return fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK);
548	}
549}
550
551int ATNetworkTool::ConnectToSocket(int sock, int &error, bool loopback,
552				    int socktype, int protocol)
553{
554	struct sockaddr_storage ss;
555	socklen_t addrLen = sizeof(ss);
556	struct sockaddr *sa = (struct sockaddr *)&ss;
557
558	if (getsockname(sock, sa, &addrLen) != 0) {
559		error = errno;
560		return -1;
561	}
562	int s = ATNetworkTool::ConnectSocket(sa, addrLen,
563					     error, loopback,
564					     sa->sa_family,
565					     socktype, protocol);
566	if (s < 0) {
567		return -1;
568	}
569	return s;
570}
571
572int ATNetworkTool::Connect(const char *host, in_port_t port,
573				int &error,
574				int family, int socktype, int protocol)
575{
576	std::stringstream ssport;
577
578	ssport << port;
579
580	return ATNetworkTool::Connect(host, ssport.str().c_str(), error,
581					family, socktype, protocol);
582}
583
584int ATNetworkTool::Connect(const char *host, const char *port,
585				int &error,
586				int family, int socktype, int protocol)
587{
588	struct addrinfo hints, *paddr, *paddrp;
589	int oks = -1;
590
591	if (socktype != SOCK_DGRAM) {
592		socktype = SOCK_STREAM;
593	}
594
595	memset(&hints, 0, sizeof(hints));
596	if (ATNetworkTool::AF_XINETX == family) {
597		hints.ai_family = PF_UNSPEC;
598	} else {
599		hints.ai_family = family;
600	}
601	hints.ai_socktype = socktype;
602	hints.ai_protocol = protocol;
603	hints.ai_flags    = AI_NUMERICHOST;
604#ifdef AI_NUMERICSERV
605	hints.ai_flags   |= AI_NUMERICSERV;
606#endif
607	if ((error = getaddrinfo(host, port, &hints, &paddrp)) != 0) {
608		memset(&hints, 0, sizeof(hints));
609		if (ATNetworkTool::AF_XINETX == family) {
610			hints.ai_family = PF_UNSPEC;
611		} else {
612			hints.ai_family = family;
613		}
614		hints.ai_socktype = socktype;
615		hints.ai_protocol = protocol;
616#ifdef AI_NUMERICSERV
617		hints.ai_flags   |= AI_NUMERICSERV;
618#endif
619		if ((error = getaddrinfo(host, port, &hints, &paddrp)) != 0) {
620			return -1;
621		}
622	}
623	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
624		if (ATNetworkTool::AF_XINETX == family) {
625			if (!ATAddress::saIsInet(paddr->ai_addr)) {
626				continue;
627			}
628		}
629
630		int s = ATNetworkTool::ConnectSocket(paddr, error);
631		if (s < 0) {
632			continue;
633		}
634		oks = s;
635		break;
636	}
637	freeaddrinfo(paddrp);
638	return oks;
639}
640
641int ATNetworkTool::ConnectLoopback(in_port_t port,
642				int &error,
643				int family, int socktype, int protocol)
644{
645	std::stringstream ssport;
646
647	ssport << port;
648
649	return ATNetworkTool::ConnectLoopback(ssport.str().c_str(), error,
650					family, socktype, protocol);
651}
652
653int ATNetworkTool::ConnectLoopback(const char *port,
654				int &error,
655				int family, int socktype, int protocol)
656{
657	struct addrinfo hints, *paddr, *paddrp;
658	int oks = -1;
659
660	if (socktype != SOCK_DGRAM) {
661		socktype = SOCK_STREAM;
662	}
663
664	memset(&hints, 0, sizeof(hints));
665	if (ATNetworkTool::AF_XINETX == family) {
666		hints.ai_family = PF_UNSPEC;
667	} else {
668		hints.ai_family = family;
669	}
670	hints.ai_socktype = socktype;
671	hints.ai_protocol = protocol;
672#ifdef AI_NUMERICSERV
673	hints.ai_flags   |= AI_NUMERICSERV;
674#endif
675	if ((error = getaddrinfo(NULL, port, &hints, &paddrp)) != 0) {
676		return -1;
677	}
678	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
679		if (ATNetworkTool::AF_XINETX == family) {
680			if (!ATAddress::saIsInet(paddr->ai_addr)) {
681				continue;
682			}
683		}
684
685		int s = ATNetworkTool::ConnectSocket(paddr, error, true);
686		if (s < 0) {
687			continue;
688		}
689		oks = s;
690		break;
691	}
692	freeaddrinfo(paddrp);
693	return oks;
694}
695
696unsigned int ATNetworkTool::GetLocalPort(int sock)
697{
698	struct sockaddr_storage ss;
699	socklen_t addrLen = sizeof(ss);
700	struct sockaddr *sa = (struct sockaddr *)&ss;
701
702	if (getsockname(sock, sa, &addrLen) != 0) {
703		return 0;
704	}
705	switch (sa->sa_family) {
706	case AF_INET6:
707		return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
708		break;
709	case AF_INET:
710		return ntohs(((struct sockaddr_in *)sa)->sin_port);
711		break;
712	}
713	return 0;
714}
715
716int ATNetworkTool::Accept(int s, ATAddress &address,
717			  int &error, bool nonblocking)
718{
719	struct sockaddr_storage saddr;
720	socklen_t addrLen = sizeof(saddr);
721	struct sockaddr *addr = (struct sockaddr *)&saddr;
722
723	int s_new = accept(s, addr, &addrLen);
724	if (s_new == -1) {
725		error = errno;
726		return -1;
727	}
728
729	address = addr;
730
731	ATNetworkTool::SetNonBlocking(s_new, nonblocking);
732
733	return s_new;
734}
735
736