2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/util/network.h"
18 #include <netinet/in.h>
19 #include <arpa/nameser.h>
20 #include <arpa/inet.h>
22 #include <sys/utsname.h>
24 #include <folly/String.h>
25 #include <folly/IPAddress.h>
27 #include "hphp/util/lock.h"
28 #include "hphp/util/process.h"
31 ///////////////////////////////////////////////////////////////////////////////
32 // without calling res_init(), any call to getaddrinfo() may leak memory:
33 // http://sources.redhat.com/ml/libc-hacker/2004-02/msg00049.html
35 class ResolverLibInitializer
{
37 ResolverLibInitializer() {
39 // We call sethostent with stayopen = 1 to keep /etc/hosts open across calls
40 // to prevent mmap contention inside the kernel. Two calls are necessary to
41 // properly initialize the stayopen flag in glibc.
46 static ResolverLibInitializer _resolver_lib_initializer
;
47 ///////////////////////////////////////////////////////////////////////////////
48 // thread-safe network functions
50 bool safe_gethostbyname(const char *address
, HostEnt
&result
) {
51 #if defined(__APPLE__) || defined(__CYGWIN__) || defined(__MINGW__) || \
53 // NOTE: on windows gethostbyname is "thread safe"
54 // the hostent is allocated once per thread by winsock2
55 // and cleaned up by winsock when the thread ends
56 struct hostent
*hp
= gethostbyname(address
);
71 size_t hstbuflen
= 1024;
72 result
.tmphstbuf
= (char*)malloc(hstbuflen
);
73 while ((res
= gethostbyname_r(address
, &result
.hostbuf
, result
.tmphstbuf
,
74 hstbuflen
, &hp
, &result
.herr
)) == ERANGE
) {
76 result
.tmphstbuf
= (char*)realloc(result
.tmphstbuf
, hstbuflen
);
82 ///////////////////////////////////////////////////////////////////////////////
83 std::string
GetPrimaryIPImpl(int af
) {
84 const static std::string s_empty
;
86 struct addrinfo hints
;
87 struct addrinfo
*res
= nullptr;
96 uname((struct utsname
*)&buf
);
98 memset(&hints
, 0, sizeof(struct addrinfo
));
101 error
= getaddrinfo(buf
.nodename
, nullptr, &hints
, &res
);
107 return folly::IPAddress(res
->ai_addr
).toFullyQualified();
108 } catch (folly::IPAddressFormatException
&e
) {
113 std::string
GetPrimaryIPv4() {
114 return GetPrimaryIPImpl(AF_INET
);
117 std::string
GetPrimaryIPv6() {
118 return GetPrimaryIPImpl(AF_INET6
);
121 std::string
GetPrimaryIP() {
122 auto ipaddress
= GetPrimaryIPv4();
123 if (!ipaddress
.empty()) {
124 ipaddress
= GetPrimaryIPv6();
129 static std::string
normalizeIPv6Address(const std::string
& address
) {
130 struct in6_addr addr
;
131 if (inet_pton(AF_INET6
, address
.c_str(), &addr
) <= 0) {
132 return std::string();
135 char ipPresentation
[INET6_ADDRSTRLEN
];
136 if (inet_ntop(AF_INET6
, &addr
, ipPresentation
, INET6_ADDRSTRLEN
) == nullptr) {
137 return std::string();
140 return ipPresentation
;
143 HostURL::HostURL(const std::string
&hosturl
, int port
) :
144 m_ipv6(false), m_port(port
) {
147 auto spos
= hosturl
.find("://");
148 if (spos
!= std::string::npos
) {
149 m_hosturl
= m_scheme
= hosturl
.substr(0, spos
);
156 // strip off /EXTRA from prot://addr:port/EXTRA
157 auto extraPos
= hosturl
.find('/', spos
);
158 auto validLen
= extraPos
!= std::string::npos
? extraPos
: hosturl
.size();
161 auto bpos
= hosturl
.find('[');
162 if (bpos
!= std::string::npos
) {
163 // Extract out the IPAddress from [..]
164 // Look for the ending position of ']'
165 auto epos
= hosturl
.rfind(']', validLen
- 1);
166 if (epos
== std::string::npos
) {
167 // This isn't a valid IPv6 address, so bail.
173 // IPv6 address between '[' and ']'
174 auto v6h
= normalizeIPv6Address(hosturl
.substr(bpos
+ 1, epos
- bpos
- 1));
185 // Colon for port. Start after ']';
186 auto cpos
= hosturl
.find(':', epos
);
187 if (cpos
!= std::string::npos
) {
189 auto portLen
= validLen
- cpos
- 1;
190 m_port
= folly::to
<uint16_t>(hosturl
.substr(cpos
+ 1, portLen
));
191 m_hosturl
+= hosturl
.substr(cpos
);
195 } else if (extraPos
!= std::string::npos
) {
196 m_hosturl
+= hosturl
.substr(extraPos
);
199 } else if (m_scheme
== "unix") {
201 m_host
= hosturl
.substr(spos
);
205 auto cpos
= hosturl
.find(':', spos
);
206 if (cpos
!= std::string::npos
) {
207 m_host
= hosturl
.substr(spos
, cpos
- spos
);
210 auto portLen
= validLen
- cpos
- 1;
211 m_port
= folly::to
<uint16_t>(hosturl
.substr(cpos
+ 1, portLen
));
212 m_hosturl
+= hosturl
.substr(cpos
);
217 m_host
= hosturl
.substr(spos
, validLen
- spos
);
218 m_hosturl
+= hosturl
.substr(spos
);
225 ///////////////////////////////////////////////////////////////////////////////