3 ** \author grymse@alhem.net
6 Copyright (C) 2004-2007 Anders Hedstrom
8 This library is made available under the terms of the GNU GPL.
10 If you would like to use this library in a closed-source application,
11 a separate license agreement is available. For information about
12 the closed-source license agreement for the C++ sockets library,
13 please visit http://www.alhem.net/Sockets/license.html and/or
14 email license@alhem.net.
16 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License
18 as published by the Free Software Foundation; either version 2
19 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include "Ipv4Address.h"
33 #include "Ipv6Address.h"
34 #include "RandomNumber.h"
44 #ifdef SOCKETS_NAMESPACE
45 namespace SOCKETS_NAMESPACE
{
50 std::string
Utility::m_host
;
51 bool Utility::m_local_resolved
= false;
52 ipaddr_t
Utility::m_ip
= 0;
53 std::string
Utility::m_addr
;
56 struct in6_addr
Utility::m_local_ip6
;
57 std::string
Utility::m_local_addr6
;
62 std::string
Utility::base64(const std::string
& str_in
)
66 m_b
.encode(str_in
, str
, false); // , false == do not add cr/lf
71 std::string
Utility::base64d(const std::string
& str_in
)
75 m_b
.decode(str_in
, str
);
80 std::string
Utility::l2string(long l
)
90 std::string
Utility::bigint2string(uint64_t l
)
96 uint64_t a
= tmp
% 10;
97 str
= (char)(a
+ 48) + str
;
108 uint64_t Utility::atoi64(const std::string
& str
)
111 for (size_t i
= 0; i
< str
.size(); i
++)
113 l
= l
* 10 + str
[i
] - 48;
119 unsigned int Utility::hex2unsigned(const std::string
& str
)
122 for (size_t i
= 0; i
< str
.size(); i
++)
124 r
= r
* 16 + str
[i
] - 48 - ((str
[i
] >= 'A') ? 7 : 0) - ((str
[i
] >= 'a') ? 32 : 0);
131 * Encode string per RFC1738 URL encoding rules
134 std::string
Utility::rfc1738_encode(const std::string
& src
)
136 static char hex
[] = "0123456789ABCDEF";
138 for (size_t i
= 0; i
< src
.size(); i
++)
151 unsigned char c
= static_cast<unsigned char>(src
[i
]);
162 * Decode string per RFC1738 URL encoding rules
165 std::string
Utility::rfc1738_decode(const std::string
& src
)
168 for (size_t i
= 0; i
< src
.size(); i
++)
170 if (src
[i
] == '%' && isxdigit(src
[i
+ 1]) && isxdigit(src
[i
+ 2]))
174 c1
= c1
- 48 - ((c1
>= 'A') ? 7 : 0) - ((c1
>= 'a') ? 32 : 0);
175 c2
= c2
- 48 - ((c2
>= 'A') ? 7 : 0) - ((c2
>= 'a') ? 32 : 0);
176 dst
+= (char)(c1
* 16 + c2
);
192 bool Utility::isipv4(const std::string
& str
)
196 for (size_t i
= 0; i
< str
.size(); i
++)
201 if (!isdigit(str
[i
]))
210 bool Utility::isipv6(const std::string
& str
)
214 for (size_t i
= 0; i
< str
.size(); i
++)
216 qc
+= (str
[i
] == ':') ? 1 : 0;
217 qd
+= (str
[i
] == '.') ? 1 : 0;
228 std::string tmp
= pa
.getword();
235 for (size_t i
= 0; i
< tmp
.size(); i
++)
237 if (tmp
[i
] < '0' || (tmp
[i
] > '9' && tmp
[i
] < 'A') ||
238 (tmp
[i
] > 'F' && tmp
[i
] < 'a') || tmp
[i
] > 'f')
250 bool Utility::u2ip(const std::string
& str
, ipaddr_t
& l
)
252 struct sockaddr_in sa
;
253 bool r
= Utility::u2ip(str
, sa
);
254 memcpy(&l
, &sa
.sin_addr
, sizeof(l
));
261 bool Utility::u2ip(const std::string
& str
, struct in6_addr
& l
)
263 struct sockaddr_in6 sa
;
264 bool r
= Utility::u2ip(str
, sa
);
272 void Utility::l2ip(const ipaddr_t ip
, std::string
& str
)
274 struct sockaddr_in sa
;
275 memset(&sa
, 0, sizeof(sa
));
276 sa
.sin_family
= AF_INET
;
277 memcpy(&sa
.sin_addr
, &ip
, sizeof(sa
.sin_addr
));
278 Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), str
, NI_NUMERICHOST
);
282 void Utility::l2ip(const in_addr
& ip
, std::string
& str
)
284 struct sockaddr_in sa
;
285 memset(&sa
, 0, sizeof(sa
));
286 sa
.sin_family
= AF_INET
;
288 Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), str
, NI_NUMERICHOST
);
294 void Utility::l2ip(const struct in6_addr
& ip
, std::string
& str
,bool mixed
)
296 char slask
[100]; // l2ip temporary
298 unsigned int prev
= 0;
299 bool skipped
= false;
300 bool ok_to_skip
= true;
304 unsigned short addr16
[8];
305 memcpy(addr16
, &ip
, sizeof(addr16
));
306 for (size_t i
= 0; i
< 6; i
++)
308 x
= ntohs(addr16
[i
]);
309 if (*slask
&& (x
|| !ok_to_skip
|| prev
))
311 if (x
|| !ok_to_skip
)
313 sprintf(slask
+ strlen(slask
),"%x", x
);
323 x
= ntohs(addr16
[6]);
324 sprintf(slask
+ strlen(slask
),":%u.%u",x
/ 256,x
& 255);
325 x
= ntohs(addr16
[7]);
326 sprintf(slask
+ strlen(slask
),".%u.%u",x
/ 256,x
& 255);
330 struct sockaddr_in6 sa
;
331 memset(&sa
, 0, sizeof(sa
));
332 sa
.sin6_family
= AF_INET6
;
334 Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), str
, NI_NUMERICHOST
);
341 int Utility::in6_addr_compare(in6_addr a
,in6_addr b
)
343 for (size_t i
= 0; i
< 16; i
++)
345 if (a
.s6_addr
[i
] < b
.s6_addr
[i
])
347 if (a
.s6_addr
[i
] > b
.s6_addr
[i
])
356 void Utility::ResolveLocal()
360 // get local hostname and translate into ip-address
364 if (Utility::u2ip(h
, m_ip
))
366 Utility::l2ip(m_ip
, m_addr
);
371 memset(&m_local_ip6
, 0, sizeof(m_local_ip6
));
373 if (Utility::u2ip(h
, m_local_ip6
))
375 Utility::l2ip(m_local_ip6
, m_local_addr6
);
381 m_local_resolved
= true;
385 const std::string
& Utility::GetLocalHostname()
387 if (!m_local_resolved
)
395 ipaddr_t
Utility::GetLocalIP()
397 if (!m_local_resolved
)
405 const std::string
& Utility::GetLocalAddress()
407 if (!m_local_resolved
)
417 const struct in6_addr
& Utility::GetLocalIP6()
419 if (!m_local_resolved
)
427 const std::string
& Utility::GetLocalAddress6()
429 if (!m_local_resolved
)
433 return m_local_addr6
;
439 void Utility::SetEnv(const std::string
& var
,const std::string
& value
)
441 #if (defined(SOLARIS8) || defined(SOLARIS))
443 static std::map
<std::string
, char *> vmap
;
444 if (vmap
.find(var
) != vmap
.end())
448 vmap
[var
] = new char[var
.size() + 1 + value
.size() + 1];
449 sprintf(vmap
[var
], "%s=%s", var
.c_str(), value
.c_str());
454 std::string slask
= var
+ "=" + value
;
455 _putenv( (char *)slask
.c_str());
458 setenv(var
.c_str(), value
.c_str(), 1);
463 std::string
Utility::Sa2String(struct sockaddr
*sa
)
467 if (sa
-> sa_family
== AF_INET6
)
469 struct sockaddr_in6
*sa6
= (struct sockaddr_in6
*)sa
;
471 Utility::l2ip(sa6
-> sin6_addr
, tmp
);
472 return tmp
+ ":" + Utility::l2string(ntohs(sa6
-> sin6_port
));
476 if (sa
-> sa_family
== AF_INET
)
478 struct sockaddr_in
*sa4
= (struct sockaddr_in
*)sa
;
480 memcpy(&a
, &sa4
-> sin_addr
, 4);
482 Utility::l2ip(a
, tmp
);
483 return tmp
+ ":" + Utility::l2string(ntohs(sa4
-> sin_port
));
489 void Utility::GetTime(struct timeval
*p
)
492 FILETIME ft
; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
493 GetSystemTimeAsFileTime(&ft
);
495 memcpy(&tt
, &ft
, sizeof(tt
));
496 tt
/= 10; // make it usecs
497 p
->tv_sec
= (long)tt
/ 1000000;
498 p
->tv_usec
= (long)tt
% 1000000;
500 gettimeofday(p
, NULL
);
505 std::auto_ptr
<SocketAddress
> Utility::CreateAddress(struct sockaddr
*sa
,socklen_t sa_len
)
507 switch (sa
-> sa_family
)
510 if (sa_len
== sizeof(struct sockaddr_in
))
512 struct sockaddr_in
*p
= (struct sockaddr_in
*)sa
;
513 return std::auto_ptr
<SocketAddress
>(new Ipv4Address(*p
));
519 if (sa_len
== sizeof(struct sockaddr_in6
))
521 struct sockaddr_in6
*p
= (struct sockaddr_in6
*)sa
;
522 return std::auto_ptr
<SocketAddress
>(new Ipv6Address(*p
));
528 return std::auto_ptr
<SocketAddress
>(NULL
);
532 bool Utility::u2ip(const std::string
& host
, struct sockaddr_in
& sa
, int ai_flags
)
534 memset(&sa
, 0, sizeof(sa
));
535 sa
.sin_family
= AF_INET
;
536 #ifdef NO_GETADDRINFO
537 if ((ai_flags
& AI_NUMERICHOST
) != 0 || isipv4(host
))
539 Parse
pa((char *)host
.c_str(), ".");
549 u
.a
.b1
= static_cast<unsigned char>(pa
.getvalue());
550 u
.a
.b2
= static_cast<unsigned char>(pa
.getvalue());
551 u
.a
.b3
= static_cast<unsigned char>(pa
.getvalue());
552 u
.a
.b4
= static_cast<unsigned char>(pa
.getvalue());
553 memcpy(&sa
.sin_addr
, &u
.l
, sizeof(sa
.sin_addr
));
557 struct hostent
*he
= gethostbyname( host
.c_str() );
562 memcpy(&sa
.sin_addr
, he
-> h_addr
, sizeof(sa
.sin_addr
));
565 struct hostent
*result
;
568 int n
= gethostbyname_r(host
.c_str(), &he
, buf
, sizeof(buf
), &result
, &myerrno
);
573 memcpy(&sa
.sin_addr
, he
.h_addr
, 4);
577 struct addrinfo hints
;
578 memset(&hints
, 0, sizeof(hints
));
581 // AI_PASSIVE - server
586 hints
.ai_flags
= ai_flags
;
587 hints
.ai_family
= AF_INET
;
588 hints
.ai_socktype
= 0;
589 hints
.ai_protocol
= 0;
590 struct addrinfo
*res
;
591 if (Utility::isipv4(host
))
592 hints
.ai_flags
|= AI_NUMERICHOST
;
593 int n
= getaddrinfo(host
.c_str(), NULL
, &hints
, &res
);
596 static RandomNumber
prng( true );
597 std::vector
<struct addrinfo
*> vec
;
598 struct addrinfo
*ai
= res
;
601 if (ai
-> ai_addrlen
== sizeof(sa
))
609 ai
= vec
[prng
.next() % vec
.size()];
611 memcpy(&sa
, ai
-> ai_addr
, ai
-> ai_addrlen
);
616 std::string error
= "Error: ";
618 error
+= gai_strerror(n
);
621 #endif // NO_GETADDRINFO
627 bool Utility::u2ip(const std::string
& host
, struct sockaddr_in6
& sa
, int ai_flags
)
629 memset(&sa
, 0, sizeof(sa
));
630 sa
.sin6_family
= AF_INET6
;
631 #ifdef NO_GETADDRINFO
632 if ((ai_flags
& AI_NUMERICHOST
) != 0 || isipv6(host
))
634 std::list
<std::string
> vec
;
636 for (size_t i
= 0; i
<= host
.size(); i
++)
638 if (i
== host
.size() || host
[i
] == ':')
640 std::string s
= host
.substr(x
, i
- x
);
642 if (strstr(s
.c_str(),".")) // x.x.x.x
645 char slask
[100]; // u2ip temporary hex2string conversion
646 unsigned long b0
= static_cast<unsigned long>(pa
.getvalue());
647 unsigned long b1
= static_cast<unsigned long>(pa
.getvalue());
648 unsigned long b2
= static_cast<unsigned long>(pa
.getvalue());
649 unsigned long b3
= static_cast<unsigned long>(pa
.getvalue());
650 sprintf(slask
,"%lx",b0
* 256 + b1
);
651 vec
.push_back(slask
);
652 sprintf(slask
,"%lx",b2
* 256 + b3
);
653 vec
.push_back(slask
);
663 size_t sz
= vec
.size(); // number of byte pairs
664 size_t i
= 0; // index in in6_addr.in6_u.u6_addr16[] ( 0 .. 7 )
665 unsigned short addr16
[8];
666 for (std::list
<std::string
>::iterator it
= vec
.begin(); it
!= vec
.end(); it
++)
668 std::string bytepair
= *it
;
671 addr16
[i
++] = htons(Utility::hex2unsigned(bytepair
));
682 memcpy(&sa
.sin6_addr
, addr16
, sizeof(addr16
));
687 struct hostent
*he
= getipnodebyname( host
.c_str(), AF_INET6
, 0, &errnum
);
689 struct hostent
*he
= gethostbyname2( host
.c_str(), AF_INET6
);
695 memcpy(&sa
.sin6_addr
,he
-> h_addr_list
[0],he
-> h_length
);
701 struct addrinfo hints
;
702 memset(&hints
, 0, sizeof(hints
));
703 hints
.ai_flags
= ai_flags
;
704 hints
.ai_family
= AF_INET6
;
705 hints
.ai_socktype
= 0;
706 hints
.ai_protocol
= 0;
707 struct addrinfo
*res
;
708 if (Utility::isipv6(host
))
709 hints
.ai_flags
|= AI_NUMERICHOST
;
710 int n
= getaddrinfo(host
.c_str(), NULL
, &hints
, &res
);
713 static RandomNumber
prng( true );
714 std::vector
<struct addrinfo
*> vec
;
715 struct addrinfo
*ai
= res
;
718 if (ai
-> ai_addrlen
== sizeof(sa
))
726 ai
= vec
[prng
.next() % vec
.size()];
728 memcpy(&sa
, ai
-> ai_addr
, ai
-> ai_addrlen
);
733 std::string error
= "Error: ";
735 error
+= gai_strerror(n
);
738 #endif // NO_GETADDRINFO
740 #endif // IPPROTO_IPV6
741 #endif // ENABLE_IPV6
744 bool Utility::reverse(struct sockaddr
*sa
, socklen_t sa_len
, std::string
& hostname
, int flags
)
747 return Utility::reverse(sa
, sa_len
, hostname
, service
, flags
);
751 bool Utility::reverse(struct sockaddr
*sa
, socklen_t sa_len
, std::string
& hostname
, std::string
& service
, int flags
)
755 #ifdef NO_GETADDRINFO
756 switch (sa
-> sa_family
)
759 if (flags
& NI_NUMERICHOST
)
770 struct sockaddr_in
*sa_in
= (struct sockaddr_in
*)sa
;
771 memcpy(&u
.l
, &sa_in
-> sin_addr
, sizeof(u
.l
));
773 sprintf(tmp
, "%u.%u.%u.%u", u
.a
.b1
, u
.a
.b2
, u
.a
.b3
, u
.a
.b4
);
779 struct sockaddr_in
*sa_in
= (struct sockaddr_in
*)sa
;
780 struct hostent
*h
= gethostbyaddr( (const char *)&sa_in
-> sin_addr
, sizeof(sa_in
-> sin_addr
), AF_INET
);
783 hostname
= h
-> h_name
;
790 if (flags
& NI_NUMERICHOST
)
792 char slask
[100]; // l2ip temporary
794 unsigned int prev
= 0;
795 bool skipped
= false;
796 bool ok_to_skip
= true;
798 unsigned short addr16
[8];
799 struct sockaddr_in6
*sa_in6
= (struct sockaddr_in6
*)sa
;
800 memcpy(addr16
, &sa_in6
-> sin6_addr
, sizeof(addr16
));
801 for (size_t i
= 0; i
< 8; i
++)
803 unsigned short x
= ntohs(addr16
[i
]);
804 if (*slask
&& (x
|| !ok_to_skip
|| prev
))
806 if (x
|| !ok_to_skip
)
808 sprintf(slask
+ strlen(slask
),"%x", x
);
826 // %! TODO: ipv6 reverse lookup
827 struct sockaddr_in6
*sa_in
= (struct sockaddr_in6
*)sa
;
828 struct hostent
*h
= gethostbyaddr( (const char *)&sa_in
-> sin6_addr
, sizeof(sa_in
-> sin6_addr
), AF_INET6
);
831 hostname
= h
-> h_name
;
840 char host
[NI_MAXHOST
];
841 char serv
[NI_MAXSERV
];
847 int n
= getnameinfo(sa
, sa_len
, host
, sizeof(host
), serv
, sizeof(serv
), flags
);
863 #endif // NO_GETADDRINFO
867 bool Utility::u2service(const std::string
& name
, int& service
, int ai_flags
)
869 #ifdef NO_GETADDRINFO
873 struct addrinfo hints
;
875 memset(&hints
, 0, sizeof(hints
));
878 // AI_PASSIVE - server
883 hints
.ai_flags
= ai_flags
;
884 hints
.ai_family
= AF_UNSPEC
;
885 hints
.ai_socktype
= 0;
886 hints
.ai_protocol
= 0;
887 struct addrinfo
*res
;
888 int n
= getaddrinfo(NULL
, name
.c_str(), &hints
, &res
);
891 service
= res
-> ai_protocol
;
896 #endif // NO_GETADDRINFO
900 unsigned long Utility::ThreadID()
903 return GetCurrentThreadId();
905 return (unsigned long)pthread_self();
910 std::string
Utility::ToLower(const std::string
& str
)
913 for (size_t i
= 0; i
< str
.size(); i
++)
915 if (str
[i
] >= 'A' && str
[i
] <= 'Z')
924 std::string
Utility::ToUpper(const std::string
& str
)
927 for (size_t i
= 0; i
< str
.size(); i
++)
929 if (str
[i
] >= 'a' && str
[i
] <= 'z')
930 r
+= (char)(str
[i
] - 32);
938 std::string
Utility::ToString(double d
)
941 sprintf(tmp
, "%f", d
);
946 #ifdef SOCKETS_NAMESPACE