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"
45 #ifdef SOCKETS_NAMESPACE
46 namespace SOCKETS_NAMESPACE
{
51 std::string
Utility::m_host
;
52 bool Utility::m_local_resolved
= false;
53 ipaddr_t
Utility::m_ip
= 0;
54 std::string
Utility::m_addr
;
57 struct in6_addr
Utility::m_local_ip6
;
58 std::string
Utility::m_local_addr6
;
63 std::string
Utility::base64(const std::string
& str_in
)
67 m_b
.encode(str_in
, str
, false); // , false == do not add cr/lf
72 std::string
Utility::base64d(const std::string
& str_in
)
76 m_b
.decode(str_in
, str
);
81 std::string
Utility::l2string(long l
)
91 std::string
Utility::bigint2string(uint64_t l
)
97 uint64_t a
= tmp
% 10;
98 str
= (char)(a
+ 48) + str
;
109 uint64_t Utility::atoi64(const std::string
& str
)
112 for (size_t i
= 0; i
< str
.size(); i
++)
114 l
= l
* 10 + str
[i
] - 48;
120 unsigned int Utility::hex2unsigned(const std::string
& str
)
123 for (size_t i
= 0; i
< str
.size(); i
++)
125 r
= r
* 16 + str
[i
] - 48 - ((str
[i
] >= 'A') ? 7 : 0) - ((str
[i
] >= 'a') ? 32 : 0);
132 * Encode string per RFC1738 URL encoding rules
135 std::string
Utility::rfc1738_encode(const std::string
& src
)
137 static char hex
[] = "0123456789ABCDEF";
139 for (size_t i
= 0; i
< src
.size(); i
++)
152 unsigned char c
= static_cast<unsigned char>(src
[i
]);
163 * Decode string per RFC1738 URL encoding rules
166 std::string
Utility::rfc1738_decode(const std::string
& src
)
169 for (size_t i
= 0; i
< src
.size(); i
++)
171 if (src
[i
] == '%' && isxdigit(src
[i
+ 1]) && isxdigit(src
[i
+ 2]))
175 c1
= c1
- 48 - ((c1
>= 'A') ? 7 : 0) - ((c1
>= 'a') ? 32 : 0);
176 c2
= c2
- 48 - ((c2
>= 'A') ? 7 : 0) - ((c2
>= 'a') ? 32 : 0);
177 dst
+= (char)(c1
* 16 + c2
);
193 bool Utility::isipv4(const std::string
& str
)
197 for (size_t i
= 0; i
< str
.size(); i
++)
202 if (!isdigit(str
[i
]))
211 bool Utility::isipv6(const std::string
& str
)
215 for (size_t i
= 0; i
< str
.size(); i
++)
217 qc
+= (str
[i
] == ':') ? 1 : 0;
218 qd
+= (str
[i
] == '.') ? 1 : 0;
229 std::string tmp
= pa
.getword();
236 for (size_t i
= 0; i
< tmp
.size(); i
++)
238 if (tmp
[i
] < '0' || (tmp
[i
] > '9' && tmp
[i
] < 'A') ||
239 (tmp
[i
] > 'F' && tmp
[i
] < 'a') || tmp
[i
] > 'f')
251 bool Utility::u2ip(const std::string
& str
, ipaddr_t
& l
)
253 struct sockaddr_in sa
;
254 bool r
= Utility::u2ip(str
, sa
);
255 memcpy(&l
, &sa
.sin_addr
, sizeof(l
));
262 bool Utility::u2ip(const std::string
& str
, struct in6_addr
& l
)
264 struct sockaddr_in6 sa
;
265 bool r
= Utility::u2ip(str
, sa
);
273 void Utility::l2ip(const ipaddr_t ip
, std::string
& str
)
275 struct sockaddr_in sa
;
276 memset(&sa
, 0, sizeof(sa
));
277 sa
.sin_family
= AF_INET
;
278 memcpy(&sa
.sin_addr
, &ip
, sizeof(sa
.sin_addr
));
279 Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), str
, NI_NUMERICHOST
);
283 void Utility::l2ip(const in_addr
& ip
, std::string
& str
)
285 struct sockaddr_in sa
;
286 memset(&sa
, 0, sizeof(sa
));
287 sa
.sin_family
= AF_INET
;
289 Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), str
, NI_NUMERICHOST
);
295 void Utility::l2ip(const struct in6_addr
& ip
, std::string
& str
,bool mixed
)
297 char slask
[100]; // l2ip temporary
299 unsigned int prev
= 0;
300 bool skipped
= false;
301 bool ok_to_skip
= true;
305 unsigned short addr16
[8];
306 memcpy(addr16
, &ip
, sizeof(addr16
));
307 for (size_t i
= 0; i
< 6; i
++)
309 x
= ntohs(addr16
[i
]);
310 if (*slask
&& (x
|| !ok_to_skip
|| prev
))
312 if (x
|| !ok_to_skip
)
314 sprintf(slask
+ strlen(slask
),"%x", x
);
324 x
= ntohs(addr16
[6]);
325 sprintf(slask
+ strlen(slask
),":%u.%u",x
/ 256,x
& 255);
326 x
= ntohs(addr16
[7]);
327 sprintf(slask
+ strlen(slask
),".%u.%u",x
/ 256,x
& 255);
331 struct sockaddr_in6 sa
;
332 memset(&sa
, 0, sizeof(sa
));
333 sa
.sin6_family
= AF_INET6
;
335 Utility::reverse( (struct sockaddr
*)&sa
, sizeof(sa
), str
, NI_NUMERICHOST
);
342 int Utility::in6_addr_compare(in6_addr a
,in6_addr b
)
344 for (size_t i
= 0; i
< 16; i
++)
346 if (a
.s6_addr
[i
] < b
.s6_addr
[i
])
348 if (a
.s6_addr
[i
] > b
.s6_addr
[i
])
357 void Utility::ResolveLocal()
361 // get local hostname and translate into ip-address
365 if (Utility::u2ip(h
, m_ip
))
367 Utility::l2ip(m_ip
, m_addr
);
372 memset(&m_local_ip6
, 0, sizeof(m_local_ip6
));
374 if (Utility::u2ip(h
, m_local_ip6
))
376 Utility::l2ip(m_local_ip6
, m_local_addr6
);
382 m_local_resolved
= true;
386 const std::string
& Utility::GetLocalHostname()
388 if (!m_local_resolved
)
396 ipaddr_t
Utility::GetLocalIP()
398 if (!m_local_resolved
)
406 const std::string
& Utility::GetLocalAddress()
408 if (!m_local_resolved
)
418 const struct in6_addr
& Utility::GetLocalIP6()
420 if (!m_local_resolved
)
428 const std::string
& Utility::GetLocalAddress6()
430 if (!m_local_resolved
)
434 return m_local_addr6
;
440 void Utility::SetEnv(const std::string
& var
,const std::string
& value
)
442 #if (defined(SOLARIS8) || defined(SOLARIS))
444 static std::map
<std::string
, char *> vmap
;
445 if (vmap
.find(var
) != vmap
.end())
449 vmap
[var
] = new char[var
.size() + 1 + value
.size() + 1];
450 sprintf(vmap
[var
], "%s=%s", var
.c_str(), value
.c_str());
455 std::string slask
= var
+ "=" + value
;
456 _putenv( (char *)slask
.c_str());
459 setenv(var
.c_str(), value
.c_str(), 1);
464 std::string
Utility::Sa2String(struct sockaddr
*sa
)
468 if (sa
-> sa_family
== AF_INET6
)
470 struct sockaddr_in6
*sa6
= (struct sockaddr_in6
*)sa
;
472 Utility::l2ip(sa6
-> sin6_addr
, tmp
);
473 return tmp
+ ":" + Utility::l2string(ntohs(sa6
-> sin6_port
));
477 if (sa
-> sa_family
== AF_INET
)
479 struct sockaddr_in
*sa4
= (struct sockaddr_in
*)sa
;
481 memcpy(&a
, &sa4
-> sin_addr
, 4);
483 Utility::l2ip(a
, tmp
);
484 return tmp
+ ":" + Utility::l2string(ntohs(sa4
-> sin_port
));
490 void Utility::GetTime(struct timeval
*p
)
493 FILETIME ft
; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
494 GetSystemTimeAsFileTime(&ft
);
496 memcpy(&tt
, &ft
, sizeof(tt
));
497 tt
/= 10; // make it usecs
498 p
->tv_sec
= (long)tt
/ 1000000;
499 p
->tv_usec
= (long)tt
% 1000000;
501 gettimeofday(p
, NULL
);
506 std::auto_ptr
<SocketAddress
> Utility::CreateAddress(struct sockaddr
*sa
,socklen_t sa_len
)
508 switch (sa
-> sa_family
)
511 if (sa_len
== sizeof(struct sockaddr_in
))
513 struct sockaddr_in
*p
= (struct sockaddr_in
*)sa
;
514 return std::auto_ptr
<SocketAddress
>(new Ipv4Address(*p
));
520 if (sa_len
== sizeof(struct sockaddr_in6
))
522 struct sockaddr_in6
*p
= (struct sockaddr_in6
*)sa
;
523 return std::auto_ptr
<SocketAddress
>(new Ipv6Address(*p
));
529 return std::auto_ptr
<SocketAddress
>(NULL
);
533 bool Utility::u2ip(const std::string
& host
, struct sockaddr_in
& sa
, int ai_flags
)
535 memset(&sa
, 0, sizeof(sa
));
536 sa
.sin_family
= AF_INET
;
537 #ifdef NO_GETADDRINFO
538 if ((ai_flags
& AI_NUMERICHOST
) != 0 || isipv4(host
))
540 Parse
pa((char *)host
.c_str(), ".");
550 u
.a
.b1
= static_cast<unsigned char>(pa
.getvalue());
551 u
.a
.b2
= static_cast<unsigned char>(pa
.getvalue());
552 u
.a
.b3
= static_cast<unsigned char>(pa
.getvalue());
553 u
.a
.b4
= static_cast<unsigned char>(pa
.getvalue());
554 memcpy(&sa
.sin_addr
, &u
.l
, sizeof(sa
.sin_addr
));
558 struct hostent
*he
= gethostbyname( host
.c_str() );
563 memcpy(&sa
.sin_addr
, he
-> h_addr
, sizeof(sa
.sin_addr
));
566 struct hostent
*result
= NULL
;
569 int n
= gethostbyname_r(host
.c_str(), &he
, buf
, sizeof(buf
), &result
, &myerrno
);
574 if (he
.h_addr_list
&& he
.h_addr_list
[0])
575 memcpy(&sa
.sin_addr
, he
.h_addr
, 4);
581 struct addrinfo hints
;
582 memset(&hints
, 0, sizeof(hints
));
585 // AI_PASSIVE - server
590 hints
.ai_flags
= ai_flags
;
591 hints
.ai_family
= AF_INET
;
592 hints
.ai_socktype
= 0;
593 hints
.ai_protocol
= 0;
594 struct addrinfo
*res
;
595 if (Utility::isipv4(host
))
596 hints
.ai_flags
|= AI_NUMERICHOST
;
597 int n
= getaddrinfo(host
.c_str(), NULL
, &hints
, &res
);
600 static RandomNumber
prng( true );
601 std::vector
<struct addrinfo
*> vec
;
602 struct addrinfo
*ai
= res
;
605 if (ai
-> ai_addrlen
== sizeof(sa
))
613 ai
= vec
[prng
.next() % vec
.size()];
615 memcpy(&sa
, ai
-> ai_addr
, ai
-> ai_addrlen
);
620 std::string error
= "Error: ";
622 error
+= gai_strerror(n
);
625 #endif // NO_GETADDRINFO
631 bool Utility::u2ip(const std::string
& host
, struct sockaddr_in6
& sa
, int ai_flags
)
633 memset(&sa
, 0, sizeof(sa
));
634 sa
.sin6_family
= AF_INET6
;
635 #ifdef NO_GETADDRINFO
636 if ((ai_flags
& AI_NUMERICHOST
) != 0 || isipv6(host
))
638 std::list
<std::string
> vec
;
640 for (size_t i
= 0; i
<= host
.size(); i
++)
642 if (i
== host
.size() || host
[i
] == ':')
644 std::string s
= host
.substr(x
, i
- x
);
646 if (strstr(s
.c_str(),".")) // x.x.x.x
649 char slask
[100]; // u2ip temporary hex2string conversion
650 unsigned long b0
= static_cast<unsigned long>(pa
.getvalue());
651 unsigned long b1
= static_cast<unsigned long>(pa
.getvalue());
652 unsigned long b2
= static_cast<unsigned long>(pa
.getvalue());
653 unsigned long b3
= static_cast<unsigned long>(pa
.getvalue());
654 sprintf(slask
,"%lx",b0
* 256 + b1
);
655 vec
.push_back(slask
);
656 sprintf(slask
,"%lx",b2
* 256 + b3
);
657 vec
.push_back(slask
);
667 size_t sz
= vec
.size(); // number of byte pairs
668 size_t i
= 0; // index in in6_addr.in6_u.u6_addr16[] ( 0 .. 7 )
669 unsigned short addr16
[8];
670 for (std::list
<std::string
>::iterator it
= vec
.begin(); it
!= vec
.end(); it
++)
672 std::string bytepair
= *it
;
675 addr16
[i
++] = htons(Utility::hex2unsigned(bytepair
));
686 memcpy(&sa
.sin6_addr
, addr16
, sizeof(addr16
));
691 struct hostent
*he
= getipnodebyname( host
.c_str(), AF_INET6
, 0, &errnum
);
693 struct hostent
*he
= gethostbyname2( host
.c_str(), AF_INET6
);
699 memcpy(&sa
.sin6_addr
,he
-> h_addr_list
[0],he
-> h_length
);
705 struct addrinfo hints
;
706 memset(&hints
, 0, sizeof(hints
));
707 hints
.ai_flags
= ai_flags
;
708 hints
.ai_family
= AF_INET6
;
709 hints
.ai_socktype
= 0;
710 hints
.ai_protocol
= 0;
711 struct addrinfo
*res
;
712 if (Utility::isipv6(host
))
713 hints
.ai_flags
|= AI_NUMERICHOST
;
714 int n
= getaddrinfo(host
.c_str(), NULL
, &hints
, &res
);
717 static RandomNumber
prng( true );
718 std::vector
<struct addrinfo
*> vec
;
719 struct addrinfo
*ai
= res
;
722 if (ai
-> ai_addrlen
== sizeof(sa
))
730 ai
= vec
[prng
.next() % vec
.size()];
732 memcpy(&sa
, ai
-> ai_addr
, ai
-> ai_addrlen
);
737 std::string error
= "Error: ";
739 error
+= gai_strerror(n
);
742 #endif // NO_GETADDRINFO
744 #endif // IPPROTO_IPV6
745 #endif // ENABLE_IPV6
748 bool Utility::reverse(struct sockaddr
*sa
, socklen_t sa_len
, std::string
& hostname
, int flags
)
751 return Utility::reverse(sa
, sa_len
, hostname
, service
, flags
);
755 bool Utility::reverse(struct sockaddr
*sa
, socklen_t sa_len
, std::string
& hostname
, std::string
& service
, int flags
)
759 #ifdef NO_GETADDRINFO
760 switch (sa
-> sa_family
)
763 if (flags
& NI_NUMERICHOST
)
774 struct sockaddr_in
*sa_in
= (struct sockaddr_in
*)sa
;
775 memcpy(&u
.l
, &sa_in
-> sin_addr
, sizeof(u
.l
));
777 sprintf(tmp
, "%u.%u.%u.%u", u
.a
.b1
, u
.a
.b2
, u
.a
.b3
, u
.a
.b4
);
783 struct sockaddr_in
*sa_in
= (struct sockaddr_in
*)sa
;
784 struct hostent
*h
= gethostbyaddr( (const char *)&sa_in
-> sin_addr
, sizeof(sa_in
-> sin_addr
), AF_INET
);
787 hostname
= h
-> h_name
;
794 if (flags
& NI_NUMERICHOST
)
796 char slask
[100]; // l2ip temporary
798 unsigned int prev
= 0;
799 bool skipped
= false;
800 bool ok_to_skip
= true;
802 unsigned short addr16
[8];
803 struct sockaddr_in6
*sa_in6
= (struct sockaddr_in6
*)sa
;
804 memcpy(addr16
, &sa_in6
-> sin6_addr
, sizeof(addr16
));
805 for (size_t i
= 0; i
< 8; i
++)
807 unsigned short x
= ntohs(addr16
[i
]);
808 if (*slask
&& (x
|| !ok_to_skip
|| prev
))
810 if (x
|| !ok_to_skip
)
812 sprintf(slask
+ strlen(slask
),"%x", x
);
830 // %! TODO: ipv6 reverse lookup
831 struct sockaddr_in6
*sa_in
= (struct sockaddr_in6
*)sa
;
832 struct hostent
*h
= gethostbyaddr( (const char *)&sa_in
-> sin6_addr
, sizeof(sa_in
-> sin6_addr
), AF_INET6
);
835 hostname
= h
-> h_name
;
844 char host
[NI_MAXHOST
];
845 char serv
[NI_MAXSERV
];
851 int n
= getnameinfo(sa
, sa_len
, host
, sizeof(host
), serv
, sizeof(serv
), flags
);
867 #endif // NO_GETADDRINFO
871 bool Utility::u2service(const std::string
& name
, int& service
, int ai_flags
)
873 #ifdef NO_GETADDRINFO
877 struct addrinfo hints
;
879 memset(&hints
, 0, sizeof(hints
));
882 // AI_PASSIVE - server
887 hints
.ai_flags
= ai_flags
;
888 hints
.ai_family
= AF_UNSPEC
;
889 hints
.ai_socktype
= 0;
890 hints
.ai_protocol
= 0;
891 struct addrinfo
*res
;
892 int n
= getaddrinfo(NULL
, name
.c_str(), &hints
, &res
);
895 service
= res
-> ai_protocol
;
900 #endif // NO_GETADDRINFO
904 unsigned long Utility::ThreadID()
907 return GetCurrentThreadId();
909 return (unsigned long)pthread_self();
914 std::string
Utility::ToLower(const std::string
& str
)
917 for (size_t i
= 0; i
< str
.size(); i
++)
919 if (str
[i
] >= 'A' && str
[i
] <= 'Z')
928 std::string
Utility::ToUpper(const std::string
& str
)
931 for (size_t i
= 0; i
< str
.size(); i
++)
933 if (str
[i
] >= 'a' && str
[i
] <= 'z')
934 r
+= (char)(str
[i
] - 32);
942 std::string
Utility::ToString(double d
)
945 sprintf(tmp
, "%f", d
);
950 #ifdef SOCKETS_NAMESPACE