2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
17 #include "hphp/runtime/ext/std/ext_std_network.h"
18 #include "hphp/runtime/ext/std/ext_std_network-internal.h"
20 #include <folly/IPAddress.h>
21 #include <folly/ScopeGuard.h>
22 #include <folly/portability/Sockets.h>
24 #include "hphp/runtime/base/builtin-functions.h"
25 #include "hphp/runtime/base/file.h"
26 #include "hphp/runtime/base/runtime-option.h"
27 #include "hphp/runtime/ext/sockets/ext_sockets.h"
28 #include "hphp/runtime/ext/std/ext_std_function.h"
29 #include "hphp/runtime/ext/string/ext_string.h"
30 #include "hphp/runtime/server/server-stats.h"
31 #include "hphp/util/lock.h"
32 #include "hphp/util/network.h"
35 ///////////////////////////////////////////////////////////////////////////////
38 static Mutex NetworkMutex
;
40 Variant
HHVM_FUNCTION(gethostname
) {
41 char h_name
[HOST_NAME_MAX
];
43 if (gethostname(h_name
, sizeof(h_name
)) != 0) {
45 "gethostname() failed with errorno=%d: %s", errno
, strerror(errno
));
48 // gethostname may not null-terminate
49 h_name
[sizeof(h_name
) - 1] = '\0';
51 return String(h_name
, CopyString
);
54 Variant
HHVM_FUNCTION(gethostbyaddr
, const String
& ip_address
) {
55 IOStatusHelper
io("gethostbyaddr", ip_address
.data());
56 struct addrinfo hints
, *res
, *res0
;
57 char h_name
[NI_MAXHOST
];
60 memset(&hints
, 0, sizeof(hints
));
61 hints
.ai_family
= PF_UNSPEC
;
62 error
= getaddrinfo(ip_address
.data(), NULL
, &hints
, &res0
);
67 for (res
= res0
; res
; res
= res
->ai_next
) {
68 if (getnameinfo(res
->ai_addr
, res
->ai_addrlen
, h_name
, NI_MAXHOST
,
73 return String(h_name
, CopyString
);
79 const StaticString
s_empty("");
81 String
HHVM_FUNCTION(gethostbyname
, const String
& hostname
) {
82 IOStatusHelper
io("gethostbyname", hostname
.data());
85 if (!safe_gethostbyname(hostname
.data(), result
)) {
90 memcpy(&in
.s_addr
, *(result
.hostbuf
.h_addr_list
), sizeof(in
.s_addr
));
92 return String(folly::IPAddressV4(in
).str());
93 } catch (folly::IPAddressFormatException
&e
) {
98 Variant
HHVM_FUNCTION(gethostbynamel
, const String
& hostname
) {
99 IOStatusHelper
io("gethostbynamel", hostname
.data());
101 if (!safe_gethostbyname(hostname
.data(), result
)) {
106 for (int i
= 0 ; result
.hostbuf
.h_addr_list
[i
] != 0 ; i
++) {
107 struct in_addr in
= *(struct in_addr
*)result
.hostbuf
.h_addr_list
[i
];
109 ret
.append(String(folly::IPAddressV4(in
).str()));
110 } catch (folly::IPAddressFormatException
&e
) {
117 Variant
HHVM_FUNCTION(getprotobyname
, const String
& name
) {
118 Lock
lock(NetworkMutex
);
120 struct protoent
*ent
= getprotobyname(name
.data());
127 Variant
HHVM_FUNCTION(getprotobynumber
, int64_t number
) {
128 Lock
lock(NetworkMutex
);
130 struct protoent
*ent
= getprotobynumber(number
);
134 return String(ent
->p_name
, CopyString
);
137 Variant
HHVM_FUNCTION(getservbyname
, const String
& service
,
138 const String
& protocol
) {
139 Lock
lock(NetworkMutex
);
141 struct servent
*serv
= getservbyname(service
.data(), protocol
.data());
145 return ntohs(serv
->s_port
);
148 Variant
HHVM_FUNCTION(getservbyport
, int64_t port
, const String
& protocol
) {
149 Lock
lock(NetworkMutex
);
151 struct servent
*serv
= getservbyport(htons(port
), protocol
.data());
155 return String(serv
->s_name
, CopyString
);
158 Variant
HHVM_FUNCTION(inet_ntop
, const String
& in_addr
) {
160 if (in_addr
.size() == 16) {
162 } else if (in_addr
.size() != 4) {
163 raise_warning("Invalid in_addr value");
168 if (!inet_ntop(af
, in_addr
.data(), buffer
, sizeof(buffer
))) {
169 raise_warning("An unknown error occurred");
172 return String(buffer
, CopyString
);
175 Variant
HHVM_FUNCTION(inet_pton
, const String
& address
) {
177 const char *saddress
= address
.data();
178 if (strchr(saddress
, ':')) {
180 } else if (!strchr(saddress
, '.')) {
181 raise_warning("Unrecognized address %s", saddress
);
186 memset(buffer
, 0, sizeof(buffer
));
187 int ret
= inet_pton(af
, saddress
, buffer
);
189 raise_warning("Unrecognized address %s", saddress
);
193 return String(buffer
, af
== AF_INET
? 4 : 16, CopyString
);
196 Variant
HHVM_FUNCTION(ip2long
, const String
& ip_address
) {
198 if (ip_address
.empty() ||
199 inet_pton(AF_INET
, ip_address
.data(), &ip
) != 1) {
203 return (int64_t)ntohl(ip
.s_addr
);
206 String
HHVM_FUNCTION(long2ip
, const String
& proper_address
) {
207 unsigned long ul
= strtoul(proper_address
.c_str(), nullptr, 0);
209 return folly::IPAddress::fromLongHBO(ul
).str();
210 } catch (folly::IPAddressFormatException
&e
) {
215 ///////////////////////////////////////////////////////////////////////////////
218 void HHVM_FUNCTION(header
, const String
& str
, bool replace
/* = true */,
219 int http_response_code
/* = 0 */) {
220 if (HHVM_FN(headers_sent
)()) {
221 raise_warning("Cannot modify header information - headers already sent");
224 String header
= HHVM_FN(rtrim
)(str
);
226 // new line safety check
227 if (header
.find('\n') >= 0 || header
.find('\r') >= 0) {
228 raise_error("Header may not contain more than a single header, "
229 "new line detected");
233 Transport
*transport
= g_context
->getTransport();
234 if (transport
&& header
.size()) {
235 const char *header_line
= header
.data();
237 // handle single line of status code
238 if ((header
.size() >= 5 && strncasecmp(header_line
, "HTTP/", 5) == 0) ||
239 (header
.size() >= 7 && strncasecmp(header_line
, "Status:", 7) == 0)) {
241 const char *reason
= nullptr;
242 for (const char *ptr
= header_line
+ 5; *ptr
; ptr
++) {
243 if (*ptr
== ' ' && *(ptr
+ 1) != ' ') {
244 code
= atoi(ptr
+ 1);
245 for (ptr
++; *ptr
; ptr
++) {
246 if (*ptr
== ' ' && *(ptr
+ 1) != ' ') {
255 transport
->setResponse(code
, reason
);
260 const char *colon_offset
= strchr(header_line
, ':');
263 if (!strncasecmp(header_line
, "Content-Type",
264 colon_offset
- header_line
)) {
265 const char *ptr
= colon_offset
+1, *mimetype
= NULL
;
266 while (*ptr
== ' ') ptr
++;
268 if (strncmp(mimetype
, "text/", 5) == 0 &&
269 strstr(mimetype
, "charset=") == NULL
) {
270 newHeader
= header
+ ";charset=utf-8";
275 transport
->replaceHeader(newHeader
.empty() ? header
: newHeader
);
277 transport
->addHeader(newHeader
.empty() ? header
: newHeader
);
279 if (http_response_code
) {
280 transport
->setResponse(http_response_code
);
285 static IMPLEMENT_THREAD_LOCAL(int, s_response_code
);
287 Variant
HHVM_FUNCTION(http_response_code
, int response_code
/* = 0 */) {
288 Transport
*transport
= g_context
->getTransport();
290 *s_response_code
= transport
->getResponseCode();
292 transport
->setResponse(response_code
);
296 int old_code
= *s_response_code
;
298 *s_response_code
= response_code
;
305 return response_code
? true : false;
308 Array
HHVM_FUNCTION(headers_list
) {
309 Transport
*transport
= g_context
->getTransport();
310 Array ret
= Array::Create();
313 transport
->getResponseHeaders(headers
);
314 for (HeaderMap::const_iterator iter
= headers
.begin();
315 iter
!= headers
.end(); ++iter
) {
316 const std::vector
<std::string
> &values
= iter
->second
;
317 for (unsigned int i
= 0; i
< values
.size(); i
++) {
318 ret
.append(String(iter
->first
+ ": " + values
[i
]));
325 bool HHVM_FUNCTION(headers_sent
, VRefParam file
/* = null */,
326 VRefParam line
/* = null */) {
327 Transport
*transport
= g_context
->getTransport();
329 file
.assignIfRef(String(transport
->getFirstHeaderFile()));
330 line
.assignIfRef(transport
->getFirstHeaderLine());
331 return transport
->headersSent();
333 return g_context
->getStdoutBytesWritten() > 0;
338 Variant
HHVM_FUNCTION(header_register_callback
, const Variant
& callback
) {
339 if (!is_callable(callback
)) {
340 raise_warning("First argument is expected to be a valid callback");
344 auto transport
= g_context
->getTransport();
346 // fail if there is no transport
349 if (transport
->headersSent()) {
350 // fail if headers have already been sent
353 return g_context
->setHeaderCallback(callback
);
356 void HHVM_FUNCTION(header_remove
, const Variant
& name
/* = null_string */) {
357 if (HHVM_FN(headers_sent
)()) {
358 raise_warning("Cannot modify header information - headers already sent");
360 Transport
*transport
= g_context
->getTransport();
363 transport
->removeAllHeaders();
365 transport
->removeHeader(name
.toString().data());
370 int64_t HHVM_FUNCTION(get_http_request_size
) {
371 Transport
*transport
= g_context
->getTransport();
373 return transport
->getRequestSize();
379 bool HHVM_FUNCTION(setcookie
, const String
& name
,
380 const String
& value
/* = null_string */,
381 int64_t expire
/* = 0 */,
382 const String
& path
/* = null_string */,
383 const String
& domain
/* = null_string */,
384 bool secure
/* = false */,
385 bool httponly
/* = false */) {
386 Transport
*transport
= g_context
->getTransport();
388 return transport
->setCookie(name
, value
, expire
, path
, domain
, secure
,
394 bool HHVM_FUNCTION(setrawcookie
, const String
& name
,
395 const String
& value
/* = null_string */,
396 int64_t expire
/* = 0 */,
397 const String
& path
/* = null_string */,
398 const String
& domain
/* = null_string */,
399 bool secure
/* = false */,
400 bool httponly
/* = false */) {
401 Transport
*transport
= g_context
->getTransport();
403 return transport
->setCookie(name
, value
, expire
, path
, domain
, secure
,
409 ///////////////////////////////////////////////////////////////////////////////
411 bool HHVM_FUNCTION(openlog
, const String
& ident
, int option
, int facility
) {
412 openlog(ident
.data(), option
, facility
);
416 bool HHVM_FUNCTION(closelog
) {
421 bool HHVM_FUNCTION(syslog
, int priority
, const String
& message
) {
422 syslog(priority
, "%s", message
.data());
426 bool validate_dns_arguments(const String
& host
, const String
& type
,
428 IOStatusHelper
io("dns_check_record", host
.data());
436 throw_invalid_argument("host: [empty]");
439 if (!strcasecmp("A", stype
)) ntype
= DNS_T_A
;
440 else if (!strcasecmp("NS", stype
)) ntype
= DNS_T_NS
;
441 else if (!strcasecmp("MX", stype
)) ntype
= DNS_T_MX
;
442 else if (!strcasecmp("PTR", stype
)) ntype
= DNS_T_PTR
;
443 else if (!strcasecmp("ANY", stype
)) ntype
= DNS_T_ANY
;
444 else if (!strcasecmp("SOA", stype
)) ntype
= DNS_T_SOA
;
445 else if (!strcasecmp("TXT", stype
)) ntype
= DNS_T_TXT
;
446 else if (!strcasecmp("CNAME", stype
)) ntype
= DNS_T_CNAME
;
447 else if (!strcasecmp("AAAA", stype
)) ntype
= DNS_T_AAAA
;
448 else if (!strcasecmp("SRV", stype
)) ntype
= DNS_T_SRV
;
449 else if (!strcasecmp("NAPTR", stype
)) ntype
= DNS_T_NAPTR
;
450 else if (!strcasecmp("A6", stype
)) ntype
= DNS_T_A6
;
452 throw_invalid_argument("type: %s", stype
);
459 void StandardExtension::initNetwork() {
460 HHVM_FE(gethostname
);
461 HHVM_FE(gethostbyaddr
);
462 HHVM_FE(gethostbyname
);
463 HHVM_FE(gethostbynamel
);
464 HHVM_FE(getprotobyname
);
465 HHVM_FE(getprotobynumber
);
466 HHVM_FE(getservbyname
);
467 HHVM_FE(getservbyport
);
473 HHVM_FE(dns_get_record
);
476 HHVM_FE(http_response_code
);
477 HHVM_FE(headers_list
);
478 HHVM_FE(headers_sent
);
479 HHVM_FE(header_register_callback
);
480 HHVM_FE(header_remove
);
481 HHVM_FE(get_http_request_size
);
483 HHVM_FE(setrawcookie
);
488 // These are defined in ext_socket, but Zend has them in network
492 HHVM_RC_INT(DNS_A
, PHP_DNS_A
);
493 HHVM_RC_INT(DNS_A6
, PHP_DNS_A6
);
494 HHVM_RC_INT(DNS_AAAA
, PHP_DNS_AAAA
);
495 HHVM_RC_INT(DNS_ALL
, PHP_DNS_ALL
);
496 HHVM_RC_INT(DNS_ANY
, PHP_DNS_ANY
);
497 HHVM_RC_INT(DNS_CNAME
, PHP_DNS_CNAME
);
498 HHVM_RC_INT(DNS_HINFO
, PHP_DNS_HINFO
);
499 HHVM_RC_INT(DNS_MX
, PHP_DNS_MX
);
500 HHVM_RC_INT(DNS_NAPTR
, PHP_DNS_NAPTR
);
501 HHVM_RC_INT(DNS_NS
, PHP_DNS_NS
);
502 HHVM_RC_INT(DNS_PTR
, PHP_DNS_PTR
);
503 HHVM_RC_INT(DNS_SOA
, PHP_DNS_SOA
);
504 HHVM_RC_INT(DNS_SRV
, PHP_DNS_SRV
);
505 HHVM_RC_INT(DNS_TXT
, PHP_DNS_TXT
);
507 HHVM_RC_INT_SAME(LOG_EMERG
);
508 HHVM_RC_INT_SAME(LOG_ALERT
);
509 HHVM_RC_INT_SAME(LOG_CRIT
);
510 HHVM_RC_INT_SAME(LOG_ERR
);
511 HHVM_RC_INT_SAME(LOG_WARNING
);
512 HHVM_RC_INT_SAME(LOG_NOTICE
);
513 HHVM_RC_INT_SAME(LOG_INFO
);
514 HHVM_RC_INT_SAME(LOG_DEBUG
);
517 HHVM_RC_INT_SAME(LOG_KERN
);
520 HHVM_RC_INT_SAME(LOG_USER
);
523 HHVM_RC_INT_SAME(LOG_MAIL
);
526 HHVM_RC_INT_SAME(LOG_DAEMON
);
529 HHVM_RC_INT_SAME(LOG_AUTH
);
532 HHVM_RC_INT_SAME(LOG_SYSLOG
);
535 HHVM_RC_INT_SAME(LOG_LPR
);
538 HHVM_RC_INT_SAME(LOG_PID
);
541 HHVM_RC_INT_SAME(LOG_CONS
);
544 HHVM_RC_INT_SAME(LOG_ODELAY
);
547 HHVM_RC_INT_SAME(LOG_NDELAY
);
550 HHVM_RC_INT_SAME(LOG_NEWS
);
553 HHVM_RC_INT_SAME(LOG_UUCP
);
556 HHVM_RC_INT_SAME(LOG_CRON
);
559 HHVM_RC_INT_SAME(LOG_AUTHPRIV
);
562 HHVM_RC_INT_SAME(LOG_NOWAIT
);
565 HHVM_RC_INT_SAME(LOG_PERROR
);
569 HHVM_RC_INT_SAME(LOG_LOCAL0
);
570 HHVM_RC_INT_SAME(LOG_LOCAL1
);
571 HHVM_RC_INT_SAME(LOG_LOCAL2
);
572 HHVM_RC_INT_SAME(LOG_LOCAL3
);
573 HHVM_RC_INT_SAME(LOG_LOCAL4
);
574 HHVM_RC_INT_SAME(LOG_LOCAL5
);
575 HHVM_RC_INT_SAME(LOG_LOCAL6
);
576 HHVM_RC_INT_SAME(LOG_LOCAL7
);
579 loadSystemlib("std_network");
582 ///////////////////////////////////////////////////////////////////////////////