codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / ext / std / ext_std_network.cpp
blobf3cd79c7e9d7f917dc3d85e11f128c5d0c94093d
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
34 namespace HPHP {
35 ///////////////////////////////////////////////////////////////////////////////
36 // DNS
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) {
44 raise_warning(
45 "gethostname() failed with errorno=%d: %s", errno, strerror(errno));
46 return false;
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];
58 int error;
60 memset(&hints, 0, sizeof(hints));
61 hints.ai_family = PF_UNSPEC;
62 error = getaddrinfo(ip_address.data(), NULL, &hints, &res0);
63 if (error) {
64 return false;
67 for (res = res0; res; res = res->ai_next) {
68 if (getnameinfo(res->ai_addr, res->ai_addrlen, h_name, NI_MAXHOST,
69 NULL, 0, 0) < 0) {
70 continue;
72 freeaddrinfo(res0);
73 return String(h_name, CopyString);
75 freeaddrinfo(res0);
76 return ip_address;
79 const StaticString s_empty("");
81 String HHVM_FUNCTION(gethostbyname, const String& hostname) {
82 IOStatusHelper io("gethostbyname", hostname.data());
84 HostEnt result;
85 if (!safe_gethostbyname(hostname.data(), result)) {
86 return hostname;
89 struct in_addr in;
90 memcpy(&in.s_addr, *(result.hostbuf.h_addr_list), sizeof(in.s_addr));
91 try {
92 return String(folly::IPAddressV4(in).str());
93 } catch (folly::IPAddressFormatException &e) {
94 return hostname;
98 Variant HHVM_FUNCTION(gethostbynamel, const String& hostname) {
99 IOStatusHelper io("gethostbynamel", hostname.data());
100 HostEnt result;
101 if (!safe_gethostbyname(hostname.data(), result)) {
102 return false;
105 Array ret;
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];
108 try {
109 ret.append(String(folly::IPAddressV4(in).str()));
110 } catch (folly::IPAddressFormatException &e) {
111 // ok to skip
114 return ret;
117 Variant HHVM_FUNCTION(getprotobyname, const String& name) {
118 Lock lock(NetworkMutex);
120 struct protoent *ent = getprotobyname(name.data());
121 if (ent == NULL) {
122 return false;
124 return ent->p_proto;
127 Variant HHVM_FUNCTION(getprotobynumber, int64_t number) {
128 Lock lock(NetworkMutex);
130 struct protoent *ent = getprotobynumber(number);
131 if (ent == NULL) {
132 return false;
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());
142 if (serv == NULL) {
143 return false;
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());
152 if (serv == NULL) {
153 return false;
155 return String(serv->s_name, CopyString);
158 Variant HHVM_FUNCTION(inet_ntop, const String& in_addr) {
159 int af = AF_INET;
160 if (in_addr.size() == 16) {
161 af = AF_INET6;
162 } else if (in_addr.size() != 4) {
163 raise_warning("Invalid in_addr value");
164 return false;
167 char buffer[40];
168 if (!inet_ntop(af, in_addr.data(), buffer, sizeof(buffer))) {
169 raise_warning("An unknown error occurred");
170 return false;
172 return String(buffer, CopyString);
175 Variant HHVM_FUNCTION(inet_pton, const String& address) {
176 int af = AF_INET;
177 const char *saddress = address.data();
178 if (strchr(saddress, ':')) {
179 af = AF_INET6;
180 } else if (!strchr(saddress, '.')) {
181 raise_warning("Unrecognized address %s", saddress);
182 return false;
185 char buffer[17];
186 memset(buffer, 0, sizeof(buffer));
187 int ret = inet_pton(af, saddress, buffer);
188 if (ret <= 0) {
189 raise_warning("Unrecognized address %s", saddress);
190 return false;
193 return String(buffer, af == AF_INET ? 4 : 16, CopyString);
196 Variant HHVM_FUNCTION(ip2long, const String& ip_address) {
197 struct in_addr ip;
198 if (ip_address.empty() ||
199 inet_pton(AF_INET, ip_address.data(), &ip) != 1) {
200 return false;
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);
208 try {
209 return folly::IPAddress::fromLongHBO(ul).str();
210 } catch (folly::IPAddressFormatException &e) {
211 return s_empty;
215 ///////////////////////////////////////////////////////////////////////////////
216 // http
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");
230 return;
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)) {
240 int code = 200;
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) != ' ') {
247 reason = ptr + 1;
248 break;
251 break;
254 if (code) {
255 transport->setResponse(code, reason);
257 return;
260 const char *colon_offset = strchr(header_line, ':');
261 String newHeader;
262 if (colon_offset) {
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++;
267 mimetype = ptr;
268 if (strncmp(mimetype, "text/", 5) == 0 &&
269 strstr(mimetype, "charset=") == NULL) {
270 newHeader = header + ";charset=utf-8";
274 if (replace) {
275 transport->replaceHeader(newHeader.empty() ? header : newHeader);
276 } else {
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();
289 if (transport) {
290 *s_response_code = transport->getResponseCode();
291 if (response_code) {
292 transport->setResponse(response_code);
296 int old_code = *s_response_code;
297 if (response_code) {
298 *s_response_code = response_code;
301 if (old_code) {
302 return old_code;
305 return response_code ? true : false;
308 Array HHVM_FUNCTION(headers_list) {
309 Transport *transport = g_context->getTransport();
310 Array ret = Array::Create();
311 if (transport) {
312 HeaderMap headers;
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]));
322 return ret;
325 bool HHVM_FUNCTION(headers_sent, VRefParam file /* = null */,
326 VRefParam line /* = null */) {
327 Transport *transport = g_context->getTransport();
328 if (transport) {
329 file.assignIfRef(String(transport->getFirstHeaderFile()));
330 line.assignIfRef(transport->getFirstHeaderLine());
331 return transport->headersSent();
332 } else {
333 return g_context->getStdoutBytesWritten() > 0;
335 return false;
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");
341 return init_null();
344 auto transport = g_context->getTransport();
345 if (!transport) {
346 // fail if there is no transport
347 return false;
349 if (transport->headersSent()) {
350 // fail if headers have already been sent
351 return false;
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();
361 if (transport) {
362 if (name.isNull()) {
363 transport->removeAllHeaders();
364 } else {
365 transport->removeHeader(name.toString().data());
370 int64_t HHVM_FUNCTION(get_http_request_size) {
371 Transport *transport = g_context->getTransport();
372 if (transport) {
373 return transport->getRequestSize();
374 } else {
375 return 0;
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();
387 if (transport) {
388 return transport->setCookie(name, value, expire, path, domain, secure,
389 httponly, true);
391 return false;
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();
402 if (transport) {
403 return transport->setCookie(name, value, expire, path, domain, secure,
404 httponly, false);
406 return false;
409 ///////////////////////////////////////////////////////////////////////////////
411 bool HHVM_FUNCTION(openlog, const String& ident, int option, int facility) {
412 openlog(ident.data(), option, facility);
413 return true;
416 bool HHVM_FUNCTION(closelog) {
417 closelog();
418 return true;
421 bool HHVM_FUNCTION(syslog, int priority, const String& message) {
422 syslog(priority, "%s", message.data());
423 return true;
426 bool validate_dns_arguments(const String& host, const String& type,
427 int& ntype) {
428 IOStatusHelper io("dns_check_record", host.data());
429 const char *stype;
430 if (type.empty()) {
431 stype = "MX";
432 } else {
433 stype = type.data();
435 if (host.empty()) {
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;
451 else {
452 throw_invalid_argument("type: %s", stype);
453 return false;
456 return true;
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);
468 HHVM_FE(inet_ntop);
469 HHVM_FE(inet_pton);
470 HHVM_FE(ip2long);
471 HHVM_FE(long2ip);
472 HHVM_FE(checkdnsrr);
473 HHVM_FE(dns_get_record);
474 HHVM_FE(getmxrr);
475 HHVM_FE(header);
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);
482 HHVM_FE(setcookie);
483 HHVM_FE(setrawcookie);
484 HHVM_FE(openlog);
485 HHVM_FE(closelog);
486 HHVM_FE(syslog);
488 // These are defined in ext_socket, but Zend has them in network
489 HHVM_FE(fsockopen);
490 HHVM_FE(pfsockopen);
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);
516 #ifdef LOG_KERN
517 HHVM_RC_INT_SAME(LOG_KERN);
518 #endif
519 #ifdef LOG_USER
520 HHVM_RC_INT_SAME(LOG_USER);
521 #endif
522 #ifdef LOG_MAIL
523 HHVM_RC_INT_SAME(LOG_MAIL);
524 #endif
525 #ifdef LOG_DAEMON
526 HHVM_RC_INT_SAME(LOG_DAEMON);
527 #endif
528 #ifdef LOG_AUTH
529 HHVM_RC_INT_SAME(LOG_AUTH);
530 #endif
531 #ifdef LOG_SYSLOG
532 HHVM_RC_INT_SAME(LOG_SYSLOG);
533 #endif
534 #ifdef LOG_LPR
535 HHVM_RC_INT_SAME(LOG_LPR);
536 #endif
537 #ifdef LOG_PID
538 HHVM_RC_INT_SAME(LOG_PID);
539 #endif
540 #ifdef LOG_CONS
541 HHVM_RC_INT_SAME(LOG_CONS);
542 #endif
543 #ifdef LOG_ODELAY
544 HHVM_RC_INT_SAME(LOG_ODELAY);
545 #endif
546 #ifdef LOG_NDELAY
547 HHVM_RC_INT_SAME(LOG_NDELAY);
548 #endif
549 #ifdef LOG_NEWS
550 HHVM_RC_INT_SAME(LOG_NEWS);
551 #endif
552 #ifdef LOG_UUCP
553 HHVM_RC_INT_SAME(LOG_UUCP);
554 #endif
555 #ifdef LOG_CRON
556 HHVM_RC_INT_SAME(LOG_CRON);
557 #endif
558 #ifdef LOG_AUTHPRIV
559 HHVM_RC_INT_SAME(LOG_AUTHPRIV);
560 #endif
561 #ifdef LOG_NOWAIT
562 HHVM_RC_INT_SAME(LOG_NOWAIT);
563 #endif
564 #ifdef LOG_PERROR
565 HHVM_RC_INT_SAME(LOG_PERROR);
566 #endif
568 #ifndef _WIN32
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);
577 #endif
579 loadSystemlib("std_network");
582 ///////////////////////////////////////////////////////////////////////////////