/hphp/runtime/ext/ext_socket.cpp
C++ | 1267 lines | 1070 code | 152 blank | 45 comment | 203 complexity | 6001964cd246e6c05a1cf89e59d5ea30 MD5 | raw file
1/* 2 +----------------------------------------------------------------------+ 3 | HipHop for PHP | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 2010-2013 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 +----------------------------------------------------------------------+ 16*/ 17 18#include "hphp/runtime/ext/ext_socket.h" 19#include "hphp/runtime/base/socket.h" 20#include "hphp/runtime/base/ssl-socket.h" 21#include "hphp/runtime/server/server-stats.h" 22#include "hphp/util/logger.h" 23#include "folly/String.h" 24 25#include <sys/types.h> 26#include <sys/socket.h> 27#include <netdb.h> 28#include <netinet/in.h> 29#include <netinet/tcp.h> 30#include <sys/un.h> 31#include <arpa/inet.h> 32#include <sys/time.h> 33#include <unistd.h> 34#include <errno.h> 35#include <fcntl.h> 36#include <signal.h> 37#include <sys/uio.h> 38#include "hphp/util/network.h" 39#include <poll.h> 40 41#define PHP_NORMAL_READ 0x0001 42#define PHP_BINARY_READ 0x0002 43 44namespace HPHP { 45IMPLEMENT_DEFAULT_EXTENSION(sockets); 46/////////////////////////////////////////////////////////////////////////////// 47// helpers 48 49static void check_socket_parameters(int &domain, int &type) { 50 if (domain != AF_UNIX && domain != AF_INET6 && domain != AF_INET) { 51 raise_warning("invalid socket domain [%d] specified for argument 1, " 52 "assuming AF_INET", domain); 53 domain = AF_INET; 54 } 55 56 if (type > 10) { 57 raise_warning("invalid socket type [%d] specified for argument 2, " 58 "assuming SOCK_STREAM", type); 59 type = SOCK_STREAM; 60 } 61} 62 63static bool get_sockaddr(sockaddr *sa, socklen_t salen, 64 Variant &address, Variant &port) { 65 switch (sa->sa_family) { 66 case AF_INET6: 67 { 68 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 69 char addr6[INET6_ADDRSTRLEN+1]; 70 inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN); 71 address = String(addr6, CopyString); 72 port = htons(sin6->sin6_port); 73 } 74 return true; 75 case AF_INET: 76 { 77 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 78 address = String(Util::safe_inet_ntoa(sin->sin_addr)); 79 port = htons(sin->sin_port); 80 } 81 return true; 82 case AF_UNIX: 83 { 84 // NB: an unnamed socket has no path, and sun_path should not be 85 // inspected. In that case the length is just the size of the 86 // struct without sun_path. 87 struct sockaddr_un *s_un = (struct sockaddr_un *)sa; 88 if (salen > offsetof(sockaddr_un, sun_path)) { 89 address = String(s_un->sun_path, CopyString); 90 } 91 } 92 return true; 93 94 default: 95 break; 96 } 97 98 raise_warning("Unsupported address family %d", sa->sa_family); 99 return false; 100} 101 102static bool php_set_inet6_addr(struct sockaddr_in6 *sin6, const char *address, 103 Socket *sock) { 104 struct in6_addr tmp; 105 struct addrinfo hints; 106 struct addrinfo *addrinfo = NULL; 107 108 if (inet_pton(AF_INET6, address, &tmp)) { 109 memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), 110 sizeof(struct in6_addr)); 111 } else { 112 memset(&hints, 0, sizeof(struct addrinfo)); 113 hints.ai_family = PF_INET6; 114 getaddrinfo(address, NULL, &hints, &addrinfo); 115 if (!addrinfo) { 116 SOCKET_ERROR(sock, "Host lookup failed", (-10000 - h_errno)); 117 return false; 118 } 119 if (addrinfo->ai_family != PF_INET6 || 120 addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) { 121 raise_warning("Host lookup failed: Non AF_INET6 domain " 122 "returned on AF_INET6 socket"); 123 freeaddrinfo(addrinfo); 124 return false; 125 } 126 127 memcpy(&(sin6->sin6_addr.s6_addr), 128 ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, 129 sizeof(struct in6_addr)); 130 freeaddrinfo(addrinfo); 131 } 132 133 return true; 134} 135 136static bool php_set_inet_addr(struct sockaddr_in *sin, const char *address, 137 Socket *sock) { 138 struct in_addr tmp; 139 140 if (inet_aton(address, &tmp)) { 141 sin->sin_addr.s_addr = tmp.s_addr; 142 } else { 143 Util::HostEnt result; 144 if (!Util::safe_gethostbyname(address, result)) { 145 /* Note: < -10000 indicates a host lookup error */ 146 SOCKET_ERROR(sock, "Host lookup failed", (-10000 - result.herr)); 147 return false; 148 } 149 if (result.hostbuf.h_addrtype != AF_INET) { 150 raise_warning("Host lookup failed: Non AF_INET domain " 151 "returned on AF_INET socket"); 152 return false; 153 } 154 memcpy(&(sin->sin_addr.s_addr), result.hostbuf.h_addr_list[0], 155 result.hostbuf.h_length); 156 } 157 158 return true; 159} 160 161static bool set_sockaddr(sockaddr_storage &sa_storage, Socket *sock, 162 const char *addr, int port, 163 struct sockaddr *&sa_ptr, size_t &sa_size) { 164 struct sockaddr *sock_type = (struct sockaddr*) &sa_storage; 165 switch (sock->getType()) { 166 case AF_UNIX: 167 { 168 struct sockaddr_un *sa = (struct sockaddr_un *)sock_type; 169 memset(sa, 0, sizeof(sa_storage)); 170 sa->sun_family = AF_UNIX; 171 snprintf(sa->sun_path, 108, "%s", addr); 172 sa_ptr = (struct sockaddr *)sa; 173 sa_size = SUN_LEN(sa); 174 } 175 break; 176 case AF_INET: 177 { 178 struct sockaddr_in *sa = (struct sockaddr_in *)sock_type; 179 memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */ 180 sa->sin_family = AF_INET; 181 sa->sin_port = htons((unsigned short) port); 182 if (!php_set_inet_addr(sa, addr, sock)) { 183 return false; 184 } 185 sa_ptr = (struct sockaddr *)sa; 186 sa_size = sizeof(struct sockaddr_in); 187 } 188 break; 189 case AF_INET6: 190 { 191 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)sock_type; 192 memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */ 193 sa->sin6_family = AF_INET6; 194 sa->sin6_port = htons((unsigned short) port); 195 if (!php_set_inet6_addr(sa, addr, sock)) { 196 return false; 197 } 198 sa_ptr = (struct sockaddr *)sa; 199 sa_size = sizeof(struct sockaddr_in6); 200 } 201 break; 202 default: 203 raise_warning("unsupported socket type '%d', must be " 204 "AF_UNIX, AF_INET, or AF_INET6", sock->getType()); 205 return false; 206 } 207 return true; 208} 209 210static void sock_array_to_fd_set(CArrRef sockets, pollfd *fds, int &nfds, 211 short flag) { 212 assert(fds); 213 for (ArrayIter iter(sockets); iter; ++iter) { 214 File *sock = iter.second().toResource().getTyped<File>(); 215 pollfd &fd = fds[nfds++]; 216 fd.fd = sock->fd(); 217 fd.events = flag; 218 fd.revents = 0; 219 } 220} 221 222static void sock_array_from_fd_set(Variant &sockets, pollfd *fds, int &nfds, 223 int &count, short flag) { 224 assert(sockets.is(KindOfArray)); 225 Array sock_array = sockets.toArray(); 226 Array ret; 227 for (ArrayIter iter(sock_array); iter; ++iter) { 228 pollfd &fd = fds[nfds++]; 229 assert(fd.fd == iter.second().toResource().getTyped<File>()->fd()); 230 if (fd.revents & flag) { 231 ret.append(iter.second()); 232 count++; 233 } 234 } 235 sockets = ret; 236} 237 238static int php_read(Socket *sock, void *buf, int maxlen, int flags) { 239 int m = fcntl(sock->fd(), F_GETFL); 240 if (m < 0) { 241 return m; 242 } 243 int nonblock = (m & O_NONBLOCK); 244 m = 0; 245 246 char *t = (char *)buf; 247 *t = '\0'; 248 int n = 0; 249 int no_read = 0; 250 while (*t != '\n' && *t != '\r' && n < maxlen) { 251 if (m > 0) { 252 t++; 253 n++; 254 } else if (m == 0) { 255 no_read++; 256 if (nonblock && no_read >= 2) { 257 return n; 258 /* The first pass, m always is 0, so no_read becomes 1 259 * in the first pass. no_read becomes 2 in the second pass, 260 * and if this is nonblocking, we should return.. */ 261 } 262 263 if (no_read > 200) { 264 errno = ECONNRESET; 265 return -1; 266 } 267 } 268 269 if (n < maxlen) { 270 m = recv(sock->fd(), (void *)t, 1, flags); 271 } 272 273 if (errno != 0 && errno != ESPIPE && errno != EAGAIN) { 274 return -1; 275 } 276 errno = 0; 277 } 278 279 if (n < maxlen) { 280 n++; 281 /* The only reasons it makes it to here is 282 * if '\n' or '\r' are encountered. So, increase 283 * the return by 1 to make up for the lack of the 284 * '\n' or '\r' in the count (since read() takes 285 * place at the end of the loop..) */ 286 } 287 288 return n; 289} 290 291static bool create_new_socket(const Util::HostURL &hosturl, 292 Variant &errnum, Variant &errstr, Resource &ret, 293 Socket *&sock, double timeout) { 294 int domain = hosturl.isIPv6() ? AF_INET6 : AF_INET; 295 int type = SOCK_STREAM; 296 const std::string scheme = hosturl.getScheme(); 297 298 if (scheme == "udp" || scheme == "udg") { 299 type = SOCK_DGRAM; 300 } else if (scheme == "unix") { 301 domain = AF_UNIX; 302 } 303 304 sock = new Socket(socket(domain, type, 0), domain, 305 hosturl.getHost().c_str(), hosturl.getPort(), timeout); 306 ret = Resource(sock); 307 if (!sock->valid()) { 308 SOCKET_ERROR(sock, "unable to create socket", errno); 309 errnum = sock->getError(); 310 errstr = String(folly::errnoStr(sock->getError()).toStdString()); 311 return false; 312 } 313 return true; 314} 315 316/////////////////////////////////////////////////////////////////////////////// 317 318Variant f_socket_create(int domain, int type, int protocol) { 319 check_socket_parameters(domain, type); 320 int socketId = socket(domain, type, protocol); 321 if (socketId == -1) { 322 Socket dummySock; // for setting last socket error 323 SOCKET_ERROR((&dummySock), "Unable to create socket", errno); 324 return false; 325 } 326 Socket *sock = new Socket(socketId, domain); 327 Resource ret(sock); 328 return ret; 329} 330 331Variant f_socket_create_listen(int port, int backlog /* = 128 */) { 332 Util::HostEnt result; 333 if (!Util::safe_gethostbyname("0.0.0.0", result)) { 334 return false; 335 } 336 337 struct sockaddr_in la; 338 memcpy((char *) &la.sin_addr, result.hostbuf.h_addr, 339 result.hostbuf.h_length); 340 la.sin_family = result.hostbuf.h_addrtype; 341 la.sin_port = htons((unsigned short)port); 342 343 Socket *sock = new Socket(socket(PF_INET, SOCK_STREAM, 0), PF_INET, 344 "0.0.0.0", port); 345 Resource ret(sock); 346 if (!sock->valid()) { 347 SOCKET_ERROR(sock, "unable to create listening socket", errno); 348 return false; 349 } 350 351 if (::bind(sock->fd(), (struct sockaddr *)&la, sizeof(la)) < 0) { 352 SOCKET_ERROR(sock, "unable to bind to given address", errno); 353 return false; 354 } 355 356 if (listen(sock->fd(), backlog) < 0) { 357 SOCKET_ERROR(sock, "unable to listen on socket", errno); 358 return false; 359 } 360 361 return ret; 362} 363 364bool f_socket_create_pair(int domain, int type, int protocol, VRefParam fd) { 365 check_socket_parameters(domain, type); 366 367 int fds_array[2]; 368 if (socketpair(domain, type, protocol, fds_array) != 0) { 369 Socket dummySock; // for setting last socket error 370 SOCKET_ERROR((&dummySock), "unable to create socket pair", errno); 371 return false; 372 } 373 374 Array ret; 375 ret.set(0, Resource(new Socket(fds_array[0], domain))); 376 ret.set(1, Resource(new Socket(fds_array[1], domain))); 377 fd = ret; 378 return true; 379} 380 381const StaticString 382 s_l_onoff("l_onoff"), 383 s_l_linger("l_linger"), 384 s_sec("sec"), 385 s_usec("usec"); 386 387Variant f_socket_get_option(CResRef socket, int level, int optname) { 388 Socket *sock = socket.getTyped<Socket>(); 389 Array ret; 390 socklen_t optlen; 391 392 switch (optname) { 393 case SO_LINGER: 394 { 395 struct linger linger_val; 396 optlen = sizeof(linger_val); 397 if (getsockopt(sock->fd(), level, optname, (char*)&linger_val, 398 &optlen) != 0) { 399 SOCKET_ERROR(sock, "unable to retrieve socket option", errno); 400 return false; 401 } 402 403 ret.set(s_l_onoff, linger_val.l_onoff); 404 ret.set(s_l_linger, linger_val.l_linger); 405 } 406 break; 407 408 case SO_RCVTIMEO: 409 case SO_SNDTIMEO: 410 { 411 struct timeval tv; 412 optlen = sizeof(tv); 413 if (getsockopt(sock->fd(), level, optname, (char*)&tv, &optlen) != 0) { 414 SOCKET_ERROR(sock, "unable to retrieve socket option", errno); 415 return false; 416 } 417 ret.set(s_sec, (int)tv.tv_sec); 418 ret.set(s_usec, (int)tv.tv_usec); 419 } 420 break; 421 422 default: 423 { 424 int other_val; 425 optlen = sizeof(other_val); 426 if (getsockopt(sock->fd(), level, optname, (char*)&other_val, &optlen)) { 427 SOCKET_ERROR(sock, "unable to retrieve socket option", errno); 428 return false; 429 } 430 return other_val; 431 } 432 } 433 return ret; 434} 435 436bool f_socket_getpeername(CResRef socket, VRefParam address, 437 VRefParam port /* = null */) { 438 Socket *sock = socket.getTyped<Socket>(); 439 440 sockaddr_storage sa_storage; 441 socklen_t salen = sizeof(sockaddr_storage); 442 struct sockaddr *sa = (struct sockaddr *)&sa_storage; 443 if (getpeername(sock->fd(), sa, &salen) < 0) { 444 SOCKET_ERROR(sock, "unable to retrieve peer name", errno); 445 return false; 446 } 447 return get_sockaddr(sa, salen, address, port); 448} 449 450bool f_socket_getsockname(CResRef socket, VRefParam address, 451 VRefParam port /* = null */) { 452 Socket *sock = socket.getTyped<Socket>(); 453 454 sockaddr_storage sa_storage; 455 socklen_t salen = sizeof(sockaddr_storage); 456 struct sockaddr *sa = (struct sockaddr *)&sa_storage; 457 if (getsockname(sock->fd(), sa, &salen) < 0) { 458 SOCKET_ERROR(sock, "unable to retrieve peer name", errno); 459 return false; 460 } 461 return get_sockaddr(sa, salen, address, port); 462} 463 464bool f_socket_set_block(CResRef socket) { 465 Socket *sock = socket.getTyped<Socket>(); 466 return sock->setBlocking(true); 467} 468 469bool f_socket_set_nonblock(CResRef socket) { 470 Socket *sock = socket.getTyped<Socket>(); 471 return sock->setBlocking(false); 472} 473 474bool f_socket_set_option(CResRef socket, int level, int optname, 475 CVarRef optval) { 476 Socket *sock = socket.getTyped<Socket>(); 477 478 struct linger lv; 479 struct timeval tv; 480 int ov; 481 int optlen; 482 void *opt_ptr; 483 484 switch (optname) { 485 case SO_LINGER: 486 { 487 Array value = optval.toArray(); 488 if (!value.exists(s_l_onoff)) { 489 raise_warning("no key \"l_onoff\" passed in optval"); 490 return false; 491 } 492 if (!value.exists(s_l_linger)) { 493 raise_warning("no key \"l_linger\" passed in optval"); 494 return false; 495 } 496 497 lv.l_onoff = (unsigned short)value[s_l_onoff].toInt32(); 498 lv.l_linger = (unsigned short)value[s_l_linger].toInt32(); 499 optlen = sizeof(lv); 500 opt_ptr = &lv; 501 } 502 break; 503 504 case SO_RCVTIMEO: 505 case SO_SNDTIMEO: 506 { 507 Array value = optval.toArray(); 508 if (!value.exists(s_sec)) { 509 raise_warning("no key \"sec\" passed in optval"); 510 return false; 511 } 512 if (!value.exists(s_usec)) { 513 raise_warning("no key \"usec\" passed in optval"); 514 return false; 515 } 516 517 tv.tv_sec = value[s_sec].toInt32(); 518 tv.tv_usec = value[s_usec].toInt32(); 519 if (tv.tv_usec >= 1000000) { 520 tv.tv_sec += tv.tv_usec / 1000000; 521 tv.tv_usec %= 1000000; 522 } 523 optlen = sizeof(tv); 524 opt_ptr = &tv; 525 sock->setTimeout(tv); 526 } 527 break; 528 529 default: 530 ov = optval.toInt32(); 531 optlen = sizeof(ov); 532 opt_ptr = &ov; 533 break; 534 } 535 536 if (setsockopt(sock->fd(), level, optname, opt_ptr, optlen) != 0) { 537 SOCKET_ERROR(sock, "unable to set socket option", errno); 538 return false; 539 } 540 return true; 541} 542 543bool f_socket_connect(CResRef socket, const String& address, int port /* = 0 */) { 544 Socket *sock = socket.getTyped<Socket>(); 545 546 switch (sock->getType()) { 547 case AF_INET6: 548 case AF_INET: 549 if (port == 0) { 550 raise_warning("Socket of type AF_INET/6 requires 3 arguments"); 551 return false; 552 } 553 break; 554 default: 555 break; 556 } 557 558 const char *addr = address.data(); 559 sockaddr_storage sa_storage; 560 struct sockaddr *sa_ptr; 561 size_t sa_size; 562 if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) { 563 return false; 564 } 565 566 IOStatusHelper io("socket::connect", address.data(), port); 567 int retval = connect(sock->fd(), sa_ptr, sa_size); 568 if (retval != 0) { 569 std::string msg = "unable to connect to "; 570 msg += addr; 571 msg += ":"; 572 msg += boost::lexical_cast<std::string>(port); 573 SOCKET_ERROR(sock, msg.c_str(), errno); 574 return false; 575 } 576 577 return true; 578} 579 580bool f_socket_bind(CResRef socket, const String& address, int port /* = 0 */) { 581 Socket *sock = socket.getTyped<Socket>(); 582 583 const char *addr = address.data(); 584 sockaddr_storage sa_storage; 585 struct sockaddr *sa_ptr; 586 size_t sa_size; 587 if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) { 588 return false; 589 } 590 591 long retval = ::bind(sock->fd(), sa_ptr, sa_size); 592 if (retval != 0) { 593 std::string msg = "unable to bind address"; 594 msg += addr; 595 msg += ":"; 596 msg += boost::lexical_cast<std::string>(port); 597 SOCKET_ERROR(sock, msg.c_str(), errno); 598 return false; 599 } 600 601 return true; 602} 603 604bool f_socket_listen(CResRef socket, int backlog /* = 0 */) { 605 Socket *sock = socket.getTyped<Socket>(); 606 if (listen(sock->fd(), backlog) != 0) { 607 SOCKET_ERROR(sock, "unable to listen on socket", errno); 608 return false; 609 } 610 return true; 611} 612 613Variant f_socket_select(VRefParam read, VRefParam write, VRefParam except, 614 CVarRef vtv_sec, int tv_usec /* = 0 */) { 615 int count = 0; 616 if (!read.isNull()) { 617 count += read.toArray().size(); 618 } 619 if (!write.isNull()) { 620 count += write.toArray().size(); 621 } 622 if (!except.isNull()) { 623 count += except.toArray().size(); 624 } 625 if (!count) { 626 return false; 627 } 628 629 struct pollfd *fds = (struct pollfd *)calloc(count, sizeof(struct pollfd)); 630 count = 0; 631 if (!read.isNull()) { 632 sock_array_to_fd_set(read.toArray(), fds, count, POLLIN); 633 } 634 if (!write.isNull()) { 635 sock_array_to_fd_set(write.toArray(), fds, count, POLLOUT); 636 } 637 if (!except.isNull()) { 638 sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI); 639 } 640 641 IOStatusHelper io("socket_select"); 642 int timeout_ms = -1; 643 if (!vtv_sec.isNull()) { 644 timeout_ms = vtv_sec.toInt32() * 1000 + tv_usec / 1000; 645 } 646 647 /* slight hack to support buffered data; if there is data sitting in the 648 * read buffer of any of the streams in the read array, let's pretend 649 * that we selected, but return only the readable sockets */ 650 if (!read.isNull()) { 651 auto hasData = Array::Create(); 652 for (ArrayIter iter(read.toArray()); iter; ++iter) { 653 File *file = iter.second().toResource().getTyped<File>(); 654 if (file->bufferedLen() > 0) { 655 hasData.append(iter.second()); 656 } 657 } 658 if (hasData.size() > 0) { 659 if (!write.isNull()) { 660 write = Array::Create(); 661 } 662 if (!except.isNull()) { 663 except = Array::Create(); 664 } 665 read = hasData; 666 return hasData.size(); 667 } 668 } 669 670 int retval = poll(fds, count, timeout_ms); 671 if (retval == -1) { 672 raise_warning("unable to select [%d]: %s", errno, 673 folly::errnoStr(errno).c_str()); 674 free(fds); 675 return false; 676 } 677 678 count = 0; 679 int nfds = 0; 680 if (!read.isNull()) { 681 sock_array_from_fd_set(read, fds, nfds, count, POLLIN|POLLERR|POLLHUP); 682 } 683 if (!write.isNull()) { 684 sock_array_from_fd_set(write, fds, nfds, count, POLLOUT|POLLERR); 685 } 686 if (!except.isNull()) { 687 sock_array_from_fd_set(except, fds, nfds, count, POLLPRI|POLLERR); 688 } 689 690 free(fds); 691 return count; 692} 693 694Variant f_socket_server(const String& hostname, int port /* = -1 */, 695 VRefParam errnum /* = null */, 696 VRefParam errstr /* = null */) { 697 Util::HostURL hosturl(static_cast<const std::string>(hostname), port); 698 return socket_server_impl(hosturl, 699 k_STREAM_SERVER_BIND|k_STREAM_SERVER_LISTEN, 700 errnum, errstr); 701} 702 703Variant socket_server_impl(const Util::HostURL &hosturl, 704 int flags, /* = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN */ 705 VRefParam errnum /* = null */, 706 VRefParam errstr /* = null */) { 707 Resource ret; 708 Socket *sock = NULL; 709 if (!create_new_socket(hosturl, errnum, errstr, ret, sock, 0.0)) { 710 return false; 711 } 712 assert(ret.get() && sock); 713 714 sockaddr_storage sa_storage; 715 struct sockaddr *sa_ptr; 716 size_t sa_size; 717 if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(), 718 hosturl.getPort(), sa_ptr, sa_size)) { 719 return false; 720 } 721 int yes = 1; 722 setsockopt(sock->fd(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); 723 if ((flags & k_STREAM_SERVER_BIND) != 0 && 724 ::bind(sock->fd(), sa_ptr, sa_size) < 0) { 725 SOCKET_ERROR(sock, "unable to bind to given address", errno); 726 return false; 727 } 728 if ((flags & k_STREAM_SERVER_LISTEN) != 0 && listen(sock->fd(), 128) < 0) { 729 SOCKET_ERROR(sock, "unable to listen on socket", errno); 730 return false; 731 } 732 733 return ret; 734} 735 736Variant f_socket_accept(CResRef socket) { 737 Socket *sock = socket.getTyped<Socket>(); 738 struct sockaddr sa; 739 socklen_t salen = sizeof(sa); 740 Socket *new_sock = new Socket(accept(sock->fd(), &sa, &salen), 741 sock->getType()); 742 if (!new_sock->valid()) { 743 SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno); 744 delete new_sock; 745 return false; 746 } 747 return Resource(new_sock); 748} 749 750Variant f_socket_read(CResRef socket, int length, int type /* = 0 */) { 751 if (length <= 0) { 752 return false; 753 } 754 Socket *sock = socket.getTyped<Socket>(); 755 756 char *tmpbuf = (char *)malloc(length + 1); 757 int retval; 758 if (type == PHP_NORMAL_READ) { 759 retval = php_read(sock, tmpbuf, length, 0); 760 } else { 761 retval = recv(sock->fd(), tmpbuf, length, 0); 762 } 763 764 if (retval == -1) { 765 /* if the socket is in non-blocking mode and there's no data to read, 766 don't output any error, as this is a normal situation, and not an error */ 767 if (errno == EAGAIN || errno == EWOULDBLOCK) { 768 sock->setError(errno); 769 } else { 770 SOCKET_ERROR(sock, "unable to read from socket", errno); 771 } 772 773 free(tmpbuf); 774 return false; 775 } 776 777 tmpbuf[retval] = '\0' ; 778 return String(tmpbuf, retval, AttachString); 779} 780 781Variant f_socket_write(CResRef socket, const String& buffer, int length /* = 0 */) { 782 Socket *sock = socket.getTyped<Socket>(); 783 if (length == 0 || length > buffer.size()) { 784 length = buffer.size(); 785 } 786 int retval = write(sock->fd(), buffer.data(), length); 787 if (retval < 0) { 788 SOCKET_ERROR(sock, "unable to write to socket", errno); 789 return false; 790 } 791 return retval; 792} 793 794Variant f_socket_send(CResRef socket, const String& buf, int len, int flags) { 795 Socket *sock = socket.getTyped<Socket>(); 796 if (len > buf.size()) { 797 len = buf.size(); 798 } 799 int retval = send(sock->fd(), buf.data(), len, flags); 800 if (retval == -1) { 801 SOCKET_ERROR(sock, "unable to write to socket", errno); 802 return false; 803 } 804 return retval; 805} 806 807Variant f_socket_sendto(CResRef socket, const String& buf, int len, int flags, 808 const String& addr, int port /* = -1 */) { 809 Socket *sock = socket.getTyped<Socket>(); 810 if (len > buf.size()) { 811 len = buf.size(); 812 } 813 int retval; 814 switch (sock->getType()) { 815 case AF_UNIX: 816 { 817 struct sockaddr_un s_un; 818 memset(&s_un, 0, sizeof(s_un)); 819 s_un.sun_family = AF_UNIX; 820 snprintf(s_un.sun_path, 108, "%s", addr.data()); 821 822 retval = sendto(sock->fd(), buf.data(), len, flags, 823 (struct sockaddr *)&s_un, SUN_LEN(&s_un)); 824 } 825 break; 826 case AF_INET: 827 { 828 if (port == -1) { 829 throw_missing_arguments_nr("socket_sendto", 6, 5); 830 return false; 831 } 832 833 struct sockaddr_in sin; 834 memset(&sin, 0, sizeof(sin)); 835 sin.sin_family = AF_INET; 836 sin.sin_port = htons((unsigned short) port); 837 if (!php_set_inet_addr(&sin, addr.c_str(), sock)) { 838 return false; 839 } 840 841 retval = sendto(sock->fd(), buf.data(), len, flags, 842 (struct sockaddr *)&sin, sizeof(sin)); 843 } 844 break; 845 case AF_INET6: 846 { 847 if (port == -1) { 848 throw_missing_arguments_nr("socket_sendto", 6, 5); 849 return false; 850 } 851 852 struct sockaddr_in6 sin6; 853 memset(&sin6, 0, sizeof(sin6)); 854 sin6.sin6_family = AF_INET6; 855 sin6.sin6_port = htons((unsigned short) port); 856 857 if (!php_set_inet6_addr(&sin6, addr.c_str(), sock)) { 858 return false; 859 } 860 861 retval = sendto(sock->fd(), buf.data(), len, flags, 862 (struct sockaddr *)&sin6, sizeof(sin6)); 863 } 864 break; 865 default: 866 raise_warning("Unsupported socket type %d", sock->getType()); 867 return false; 868 } 869 870 if (retval == -1) { 871 SOCKET_ERROR(sock, "unable to write to socket", errno); 872 return false; 873 } 874 875 return retval; 876} 877 878Variant f_socket_recv(CResRef socket, VRefParam buf, int len, int flags) { 879 if (len <= 0) { 880 return false; 881 } 882 Socket *sock = socket.getTyped<Socket>(); 883 884 char *recv_buf = (char *)malloc(len + 1); 885 int retval; 886 if ((retval = recv(sock->fd(), recv_buf, len, flags)) < 1) { 887 free(recv_buf); 888 buf = uninit_null(); 889 } else { 890 recv_buf[retval] = '\0'; 891 buf = String(recv_buf, retval, AttachString); 892 } 893 894 if (retval == -1) { 895 SOCKET_ERROR(sock, "unable to read from socket", errno); 896 return false; 897 } 898 return retval; 899} 900 901const StaticString 902 s_2colons("::"), 903 s_0_0_0_0("0.0.0.0"); 904 905Variant f_socket_recvfrom(CResRef socket, VRefParam buf, int len, int flags, 906 VRefParam name, VRefParam port /* = -1*/) { 907 if (len <= 0) { 908 return false; 909 } 910 911 Socket *sock = socket.getTyped<Socket>(); 912 913 char *recv_buf = (char *)malloc(len + 2); 914 socklen_t slen; 915 int retval; 916 917 switch (sock->getType()) { 918 case AF_UNIX: 919 { 920 struct sockaddr_un s_un; 921 slen = sizeof(s_un); 922 memset(&s_un, 0, slen); 923 s_un.sun_family = AF_UNIX; 924 retval = recvfrom(sock->fd(), recv_buf, len, flags, 925 (struct sockaddr *)&s_un, (socklen_t *)&slen); 926 if (retval < 0) { 927 free(recv_buf); 928 SOCKET_ERROR(sock, "unable to recvfrom", errno); 929 return false; 930 } 931 932 recv_buf[retval] = 0; 933 buf = String(recv_buf, retval, AttachString); 934 name = String(s_un.sun_path, CopyString); 935 } 936 break; 937 case AF_INET: 938 { 939 if (int(port) == -1) { 940 throw_missing_arguments_nr("socket_recvfrom", 5, 4); 941 return false; 942 } 943 944 struct sockaddr_in sin; 945 slen = sizeof(sin); 946 memset(&sin, 0, slen); 947 948 retval = recvfrom(sock->fd(), recv_buf, len, flags, 949 (struct sockaddr *)&sin, (socklen_t *)&slen); 950 if (retval < 0) { 951 free(recv_buf); 952 SOCKET_ERROR(sock, "unable to recvfrom", errno); 953 return false; 954 } 955 recv_buf[retval] = 0; 956 buf = String(recv_buf, retval, AttachString); 957 958 name = String(Util::safe_inet_ntoa(sin.sin_addr)); 959 if (name.toString().empty()) { 960 name = s_0_0_0_0; 961 } 962 port = ntohs(sin.sin_port); 963 } 964 break; 965 case AF_INET6: 966 { 967 if (int(port) == -1) { 968 throw_missing_arguments_nr("socket_recvfrom", 5, 4); 969 return false; 970 } 971 972 struct sockaddr_in6 sin6; 973 slen = sizeof(sin6); 974 memset(&sin6, 0, slen); 975 976 retval = recvfrom(sock->fd(), recv_buf, len, flags, 977 (struct sockaddr *)&sin6, (socklen_t *)&slen); 978 if (retval < 0) { 979 free(recv_buf); 980 SOCKET_ERROR(sock, "unable to recvfrom", errno); 981 return false; 982 } 983 984 char addr6[INET6_ADDRSTRLEN]; 985 const char* succ = 986 inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN); 987 988 recv_buf[retval] = 0; 989 buf = String(recv_buf, retval, AttachString); 990 if (succ) { 991 name = String(addr6, CopyString); 992 } else { 993 name = s_2colons; 994 } 995 port = ntohs(sin6.sin6_port); 996 } 997 break; 998 default: 999 raise_warning("Unsupported socket type %d", sock->getType()); 1000 return false; 1001 } 1002 1003 return retval; 1004} 1005 1006bool f_socket_shutdown(CResRef socket, int how /* = 0 */) { 1007 Socket *sock = socket.getTyped<Socket>(); 1008 if (shutdown(sock->fd(), how) != 0) { 1009 SOCKET_ERROR(sock, "unable to shutdown socket", errno); 1010 return false; 1011 } 1012 return true; 1013} 1014 1015void f_socket_close(CResRef socket) { 1016 Socket *sock = socket.getTyped<Socket>(); 1017 sock->close(); 1018} 1019 1020String f_socket_strerror(int errnum) { 1021 return String(folly::errnoStr(errnum).toStdString()); 1022} 1023 1024int64_t f_socket_last_error(CResRef socket /* = null_object */) { 1025 if (!socket.isNull()) { 1026 Socket *sock = socket.getTyped<Socket>(); 1027 return sock->getError(); 1028 } 1029 return Socket::getLastError(); 1030} 1031 1032void f_socket_clear_error(CResRef socket /* = null_object */) { 1033 if (!socket.isNull()) { 1034 Socket *sock = socket.getTyped<Socket>(); 1035 sock->setError(0); 1036 } 1037} 1038/////////////////////////////////////////////////////////////////////////////// 1039// fsock: treating sockets as "file" 1040 1041Variant sockopen_impl(const Util::HostURL &hosturl, VRefParam errnum, 1042 VRefParam errstr, double timeout, bool persistent) { 1043 1044 string key; 1045 if (persistent) { 1046 key = hosturl.getHostURL(); 1047 Socket *sock = 1048 dynamic_cast<Socket*>(g_persistentObjects->get("socket", key.c_str())); 1049 if (sock) { 1050 if (sock->getError() == 0 && sock->checkLiveness()) { 1051 return Resource(sock); 1052 } 1053 1054 // socket had an error earlier, we need to remove it from persistent 1055 // storage, and create a new one 1056 g_persistentObjects->remove("socket", key.c_str()); 1057 } 1058 } 1059 1060 Resource ret; 1061 Socket *sock = NULL; 1062 1063 if (timeout < 0) timeout = RuntimeOption::SocketDefaultTimeout; 1064 // test if protocol is SSL 1065 SSLSocket *sslsock = SSLSocket::Create(hosturl, timeout); 1066 if (sslsock) { 1067 sock = sslsock; 1068 ret = sock; 1069 } else if (!create_new_socket(hosturl, errnum, errstr, ret, sock, timeout)) { 1070 return false; 1071 } 1072 assert(ret.get() && sock); 1073 1074 sockaddr_storage sa_storage; 1075 struct sockaddr *sa_ptr; 1076 size_t sa_size; 1077 if (!set_sockaddr(sa_storage, sock, hosturl.getHost().c_str(), 1078 hosturl.getPort(), sa_ptr, sa_size)) { 1079 return false; 1080 } 1081 1082 int retval; 1083 int fd = sock->fd(); 1084 IOStatusHelper io("socket::connect", 1085 hosturl.getHostURL().c_str(), hosturl.getPort()); 1086 if (timeout <= 0) { 1087 retval = connect(fd, sa_ptr, sa_size); 1088 } else { 1089 // set non-blocking so we can do timeouts 1090 long arg = fcntl(fd, F_GETFL, NULL); 1091 fcntl(fd, F_SETFL, arg | O_NONBLOCK); 1092 1093 retval = connect(fd, sa_ptr, sa_size); 1094 if (retval < 0) { 1095 if (errno == EINPROGRESS) { 1096 struct pollfd fds[1]; 1097 fds[0].fd = fd; 1098 fds[0].events = POLLOUT; 1099 if (poll(fds, 1, (int)(timeout * 1000))) { 1100 socklen_t lon = sizeof(int); 1101 int valopt; 1102 getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon); 1103 if (valopt) { 1104 std::string msg = "failed to connect to " + hosturl.getHostURL(); 1105 SOCKET_ERROR(sock, msg.c_str(), valopt); 1106 errnum = sock->getError(); 1107 errstr = String(folly::errnoStr(sock->getError()).toStdString()); 1108 return false; 1109 } else { 1110 retval = 0; // success 1111 } 1112 } else { 1113 std::string msg = "timed out after "; 1114 msg += boost::lexical_cast<std::string>(timeout); 1115 msg += " seconds when connecting to " + hosturl.getHostURL(); 1116 SOCKET_ERROR(sock, msg.c_str(), ETIMEDOUT); 1117 errnum = sock->getError(); 1118 errstr = String(folly::errnoStr(sock->getError()).toStdString()); 1119 return false; 1120 } 1121 } 1122 } 1123 1124 // set to blocking mode 1125 arg = fcntl(fd, F_GETFL, NULL); 1126 fcntl(fd, F_SETFL, arg & ~O_NONBLOCK); 1127 } 1128 1129 if (retval != 0) { 1130 errnum = sock->getError(); 1131 errstr = String(folly::errnoStr(sock->getError()).toStdString()); 1132 return false; 1133 } 1134 1135 if (sslsock && !sslsock->onConnect()) { 1136 raise_warning("Failed to enable crypto"); 1137 return false; 1138 } 1139 1140 if (persistent) { 1141 assert(!key.empty()); 1142 g_persistentObjects->set("socket", key.c_str(), sock); 1143 } 1144 1145 return ret; 1146} 1147 1148Variant f_fsockopen(const String& hostname, int port /* = -1 */, 1149 VRefParam errnum /* = null */, 1150 VRefParam errstr /* = null */, 1151 double timeout /* = -1.0 */) { 1152 Util::HostURL hosturl(static_cast<const std::string>(hostname), port); 1153 return sockopen_impl(hosturl, errnum, errstr, timeout, false); 1154} 1155 1156Variant f_pfsockopen(const String& hostname, int port /* = -1 */, 1157 VRefParam errnum /* = null */, 1158 VRefParam errstr /* = null */, 1159 double timeout /* = -1.0 */) { 1160 // TODO: persistent socket handling 1161 Util::HostURL hosturl(static_cast<const std::string>(hostname), port); 1162 return sockopen_impl(hosturl, errnum, errstr, timeout, true); 1163} 1164 1165String ipaddr_convert(struct sockaddr *addr, int addrlen) { 1166 char buffer[NI_MAXHOST]; 1167 int error = getnameinfo(addr, addrlen, buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST); 1168 1169 if (error) { 1170 raise_warning("%s", gai_strerror(error)); 1171 return ""; 1172 } 1173 return String(buffer, CopyString); 1174} 1175 1176const StaticString 1177 s_family("family"), 1178 s_socktype("socktype"), 1179 s_protocol("protocol"), 1180 s_address("address"), 1181 s_port("port"), 1182 s_flow_info("flow_info"), 1183 s_scope_id("scope_id"), 1184 s_sockaddr("sockaddr"); 1185 1186Variant f_getaddrinfo(const String& host, const String& port, int family /* = 0 */, 1187 int socktype /* = 0 */, int protocol /* = 0 */, 1188 int flags /* = 0 */) { 1189 const char *hptr = NULL, *pptr = NULL; 1190 if (!host.empty()) { 1191 hptr = host.c_str(); 1192 } 1193 if (!port.empty()) { 1194 pptr = port.c_str(); 1195 } 1196 1197 struct addrinfo hints, *res; 1198 struct addrinfo *res0 = NULL; 1199 int error; 1200 1201 memset(&hints, 0, sizeof(hints)); 1202 hints.ai_family = family; 1203 hints.ai_socktype = socktype; 1204 hints.ai_protocol = protocol; 1205 hints.ai_flags = flags; 1206 error = getaddrinfo(hptr, pptr, &hints, &res0); 1207 1208 if (error) { 1209 raise_warning("%s", gai_strerror(error)); 1210 1211 if (res0) { 1212 freeaddrinfo(res0); 1213 } 1214 return false; 1215 } 1216 1217 Array ret = Array::Create(); 1218 1219 for (res = res0; res; res = res->ai_next) { 1220 Array data = Array::Create(); 1221 Array sockinfo = Array::Create(); 1222 1223 data.set(s_family, res->ai_family); 1224 data.set(s_socktype, res->ai_socktype); 1225 data.set(s_protocol, res->ai_protocol); 1226 1227 switch (res->ai_addr->sa_family) { 1228 case AF_INET: 1229 { 1230 struct sockaddr_in *a; 1231 String buffer = ipaddr_convert(res->ai_addr, sizeof(*a)); 1232 if (!buffer.empty()) { 1233 a = (struct sockaddr_in *)res->ai_addr; 1234 sockinfo.set(s_address, buffer); 1235 sockinfo.set(s_port, ntohs(a->sin_port)); 1236 } 1237 break; 1238 } 1239 case AF_INET6: 1240 { 1241 struct sockaddr_in6 *a; 1242 String buffer = ipaddr_convert(res->ai_addr, sizeof(*a)); 1243 if (!buffer.empty()) { 1244 a = (struct sockaddr_in6 *)res->ai_addr; 1245 sockinfo.set(s_address, buffer); 1246 sockinfo.set(s_port, ntohs(a->sin6_port)); 1247 sockinfo.set(s_flow_info, (int32_t)a->sin6_flowinfo); 1248 sockinfo.set(s_scope_id, (int32_t)a->sin6_scope_id); 1249 } 1250 break; 1251 } 1252 } 1253 1254 data.set(s_sockaddr, (sockinfo.empty() ? nullptr : sockinfo)); 1255 1256 ret.append(data); 1257 } 1258 1259 if (res0) { 1260 freeaddrinfo(res0); 1261 } 1262 1263 return ret; 1264} 1265 1266/////////////////////////////////////////////////////////////////////////////// 1267}