Remove String::operator const char*().
[hiphop-php.git] / hphp / runtime / ext / ext_socket.cpp
blob4630192d987e0c1b48465c5d083ecaf2fcd0ec76
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- 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 +----------------------------------------------------------------------+
18 #include <runtime/ext/ext_socket.h>
19 #include <runtime/base/file/socket.h>
20 #include <runtime/base/file/ssl_socket.h>
21 #include <runtime/base/server/server_stats.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
28 #include <sys/un.h>
29 #include <arpa/inet.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <signal.h>
35 #include <sys/uio.h>
36 #include <util/network.h>
37 #include <poll.h>
39 #define PHP_NORMAL_READ 0x0001
40 #define PHP_BINARY_READ 0x0002
42 namespace HPHP {
43 IMPLEMENT_DEFAULT_EXTENSION(sockets);
44 ///////////////////////////////////////////////////////////////////////////////
45 // helpers
47 static void check_socket_parameters(int &domain, int &type) {
48 if (domain != AF_UNIX && domain != AF_INET6 && domain != AF_INET) {
49 raise_warning("invalid socket domain [%d] specified for argument 1, "
50 "assuming AF_INET", domain);
51 domain = AF_INET;
54 if (type > 10) {
55 raise_warning("invalid socket type [%d] specified for argument 2, "
56 "assuming SOCK_STREAM", type);
57 type = SOCK_STREAM;
61 static bool get_sockaddr(sockaddr *sa, Variant &address, Variant &port) {
62 switch (sa->sa_family) {
63 case AF_INET6:
65 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
66 char addr6[INET6_ADDRSTRLEN+1];
67 inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN);
68 address = String(addr6, CopyString);
69 port = htons(sin6->sin6_port);
71 return true;
72 case AF_INET:
74 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
75 address = String(Util::safe_inet_ntoa(sin->sin_addr));
76 port = htons(sin->sin_port);
78 return true;
79 case AF_UNIX:
81 struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
82 address = String(s_un->sun_path, CopyString);
84 return true;
86 default:
87 break;
90 raise_warning("Unsupported address family %d", sa->sa_family);
91 return false;
94 static bool php_set_inet6_addr(struct sockaddr_in6 *sin6, const char *address,
95 Socket *sock) {
96 struct in6_addr tmp;
97 struct addrinfo hints;
98 struct addrinfo *addrinfo = NULL;
100 if (inet_pton(AF_INET6, address, &tmp)) {
101 memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr),
102 sizeof(struct in6_addr));
103 } else {
104 memset(&hints, 0, sizeof(struct addrinfo));
105 hints.ai_family = PF_INET6;
106 getaddrinfo(address, NULL, &hints, &addrinfo);
107 if (!addrinfo) {
108 SOCKET_ERROR(sock, "Host lookup failed", (-10000 - h_errno));
109 return false;
111 if (addrinfo->ai_family != PF_INET6 ||
112 addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
113 raise_warning("Host lookup failed: Non AF_INET6 domain "
114 "returned on AF_INET6 socket");
115 freeaddrinfo(addrinfo);
116 return false;
119 memcpy(&(sin6->sin6_addr.s6_addr),
120 ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr,
121 sizeof(struct in6_addr));
122 freeaddrinfo(addrinfo);
125 return true;
128 static bool php_set_inet_addr(struct sockaddr_in *sin, const char *address,
129 Socket *sock) {
130 struct in_addr tmp;
132 if (inet_aton(address, &tmp)) {
133 sin->sin_addr.s_addr = tmp.s_addr;
134 } else {
135 Util::HostEnt result;
136 if (!Util::safe_gethostbyname(address, result)) {
137 /* Note: < -10000 indicates a host lookup error */
138 SOCKET_ERROR(sock, "Host lookup failed", (-10000 - result.herr));
139 return false;
141 if (result.hostbuf.h_addrtype != AF_INET) {
142 raise_warning("Host lookup failed: Non AF_INET domain "
143 "returned on AF_INET socket");
144 return false;
146 memcpy(&(sin->sin_addr.s_addr), result.hostbuf.h_addr_list[0],
147 result.hostbuf.h_length);
150 return true;
153 static bool set_sockaddr(sockaddr_storage &sa_storage, Socket *sock,
154 const char *addr, int port,
155 struct sockaddr *&sa_ptr, size_t &sa_size) {
156 struct sockaddr *sock_type = (struct sockaddr*) &sa_storage;
157 switch (sock->getType()) {
158 case AF_UNIX:
160 struct sockaddr_un *sa = (struct sockaddr_un *)sock_type;
161 memset(sa, 0, sizeof(sa_storage));
162 sa->sun_family = AF_UNIX;
163 snprintf(sa->sun_path, 108, "%s", addr);
164 sa_ptr = (struct sockaddr *)sa;
165 sa_size = SUN_LEN(sa);
167 break;
168 case AF_INET:
170 struct sockaddr_in *sa = (struct sockaddr_in *)sock_type;
171 memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
172 sa->sin_family = AF_INET;
173 sa->sin_port = htons((unsigned short) port);
174 if (!php_set_inet_addr(sa, addr, sock)) {
175 return false;
177 sa_ptr = (struct sockaddr *)sa;
178 sa_size = sizeof(struct sockaddr_in);
180 break;
181 case AF_INET6:
183 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)sock_type;
184 memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */
185 sa->sin6_family = AF_INET6;
186 sa->sin6_port = htons((unsigned short) port);
187 if (!php_set_inet6_addr(sa, addr, sock)) {
188 return false;
190 sa_ptr = (struct sockaddr *)sa;
191 sa_size = sizeof(struct sockaddr_in6);
193 break;
194 default:
195 raise_warning("unsupported socket type '%d', must be "
196 "AF_UNIX, AF_INET, or AF_INET6", sock->getType());
197 return false;
199 return true;
202 static void sock_array_to_fd_set(CArrRef sockets, pollfd *fds, int &nfds,
203 short flag) {
204 assert(fds);
205 for (ArrayIter iter(sockets); iter; ++iter) {
206 File *sock = iter.second().toObject().getTyped<File>();
207 pollfd &fd = fds[nfds++];
208 fd.fd = sock->fd();
209 fd.events = flag;
210 fd.revents = 0;
214 static void sock_array_from_fd_set(Variant &sockets, pollfd *fds, int &nfds,
215 int &count, short flag) {
216 assert(sockets.is(KindOfArray));
217 Array sock_array = sockets.toArray();
218 Array ret;
219 for (ArrayIter iter(sock_array); iter; ++iter) {
220 pollfd &fd = fds[nfds++];
221 assert(fd.fd == iter.second().toObject().getTyped<File>()->fd());
222 if (fd.revents & flag) {
223 ret.append(iter.second());
224 count++;
227 sockets = ret;
230 static int php_read(Socket *sock, void *buf, int maxlen, int flags) {
231 int m = fcntl(sock->fd(), F_GETFL);
232 if (m < 0) {
233 return m;
235 int nonblock = (m & O_NONBLOCK);
236 m = 0;
238 char *t = (char *)buf;
239 *t = '\0';
240 int n = 0;
241 int no_read = 0;
242 while (*t != '\n' && *t != '\r' && n < maxlen) {
243 if (m > 0) {
244 t++;
245 n++;
246 } else if (m == 0) {
247 no_read++;
248 if (nonblock && no_read >= 2) {
249 return n;
250 /* The first pass, m always is 0, so no_read becomes 1
251 * in the first pass. no_read becomes 2 in the second pass,
252 * and if this is nonblocking, we should return.. */
255 if (no_read > 200) {
256 errno = ECONNRESET;
257 return -1;
261 if (n < maxlen) {
262 m = recv(sock->fd(), (void *)t, 1, flags);
265 if (errno != 0 && errno != ESPIPE && errno != EAGAIN) {
266 return -1;
268 errno = 0;
271 if (n < maxlen) {
272 n++;
273 /* The only reasons it makes it to here is
274 * if '\n' or '\r' are encountered. So, increase
275 * the return by 1 to make up for the lack of the
276 * '\n' or '\r' in the count (since read() takes
277 * place at the end of the loop..) */
280 return n;
283 static bool create_new_socket(const char *&name, int port, Variant &errnum,
284 Variant &errstr, Object &ret, Socket *&sock) {
285 int domain = AF_INET;
286 int type = SOCK_STREAM;
287 if (strncmp(name, "udp://", 6) == 0 || strncmp(name, "udg://", 6) == 0) {
288 type = SOCK_DGRAM;
289 name += 6;
290 } else if (strncmp(name, "tcp://", 6) == 0) {
291 name += 6;
292 } else if (strncmp(name, "unix://", 7) == 0) {
293 domain = AF_UNIX;
294 name += 7;
297 sock = new Socket(socket(domain, type, 0), domain, name, port);
298 ret = Object(sock);
299 if (!sock->valid()) {
300 SOCKET_ERROR(sock, "unable to create socket", errno);
301 errnum = sock->getError();
302 errstr = String(Util::safe_strerror(sock->getError()));
303 return false;
305 return true;
308 ///////////////////////////////////////////////////////////////////////////////
310 Variant f_socket_create(int domain, int type, int protocol) {
311 check_socket_parameters(domain, type);
312 int socketId = socket(domain, type, protocol);
313 if (socketId == -1) {
314 Socket dummySock; // for setting last socket error
315 SOCKET_ERROR((&dummySock), "Unable to create socket", errno);
316 return false;
318 Socket *sock = new Socket(socketId, domain);
319 Object ret(sock);
320 return ret;
323 Variant f_socket_create_listen(int port, int backlog /* = 128 */) {
324 Util::HostEnt result;
325 if (!Util::safe_gethostbyname("0.0.0.0", result)) {
326 return false;
329 struct sockaddr_in la;
330 memcpy((char *) &la.sin_addr, result.hostbuf.h_addr,
331 result.hostbuf.h_length);
332 la.sin_family = result.hostbuf.h_addrtype;
333 la.sin_port = htons((unsigned short)port);
335 Socket *sock = new Socket(socket(PF_INET, SOCK_STREAM, 0), PF_INET,
336 "0.0.0.0", port);
337 Object ret(sock);
338 if (!sock->valid()) {
339 SOCKET_ERROR(sock, "unable to create listening socket", errno);
340 return false;
343 if (::bind(sock->fd(), (struct sockaddr *)&la, sizeof(la)) < 0) {
344 SOCKET_ERROR(sock, "unable to bind to given adress", errno);
345 return false;
348 if (listen(sock->fd(), backlog) < 0) {
349 SOCKET_ERROR(sock, "unable to listen on socket", errno);
350 return false;
353 return ret;
356 bool f_socket_create_pair(int domain, int type, int protocol, VRefParam fd) {
357 check_socket_parameters(domain, type);
359 int fds_array[2];
360 if (socketpair(domain, type, protocol, fds_array) != 0) {
361 Socket dummySock; // for setting last socket error
362 SOCKET_ERROR((&dummySock), "unable to create socket pair", errno);
363 return false;
366 Array ret;
367 ret.set(0, Object(new Socket(fds_array[0], domain)));
368 ret.set(1, Object(new Socket(fds_array[1], domain)));
369 fd = ret;
370 return true;
373 static const StaticString s_l_onoff("l_onoff");
374 static const StaticString s_l_linger("l_linger");
375 static const StaticString s_sec("sec");
376 static const StaticString s_usec("usec");
378 Variant f_socket_get_option(CObjRef socket, int level, int optname) {
379 Socket *sock = socket.getTyped<Socket>();
380 Array ret;
381 socklen_t optlen;
383 switch (optname) {
384 case SO_LINGER:
386 struct linger linger_val;
387 optlen = sizeof(linger_val);
388 if (getsockopt(sock->fd(), level, optname, (char*)&linger_val,
389 &optlen) != 0) {
390 SOCKET_ERROR(sock, "unable to retrieve socket option", errno);
391 return false;
394 ret.set(s_l_onoff, linger_val.l_onoff);
395 ret.set(s_l_linger, linger_val.l_linger);
397 break;
399 case SO_RCVTIMEO:
400 case SO_SNDTIMEO:
402 struct timeval tv;
403 optlen = sizeof(tv);
404 if (getsockopt(sock->fd(), level, optname, (char*)&tv, &optlen) != 0) {
405 SOCKET_ERROR(sock, "unable to retrieve socket option", errno);
406 return false;
408 ret.set(s_sec, (int)tv.tv_sec);
409 ret.set(s_usec, (int)tv.tv_usec);
411 break;
413 default:
415 int other_val;
416 optlen = sizeof(other_val);
417 if (getsockopt(sock->fd(), level, optname, (char*)&other_val, &optlen)) {
418 SOCKET_ERROR(sock, "unable to retrieve socket option", errno);
419 return false;
421 return other_val;
424 return ret;
427 bool f_socket_getpeername(CObjRef socket, VRefParam address,
428 VRefParam port /* = null */) {
429 Socket *sock = socket.getTyped<Socket>();
431 sockaddr_storage sa_storage;
432 socklen_t salen = sizeof(sockaddr_storage);
433 struct sockaddr *sa = (struct sockaddr *)&sa_storage;
434 if (getpeername(sock->fd(), sa, &salen) < 0) {
435 SOCKET_ERROR(sock, "unable to retrieve peer name", errno);
436 return false;
438 return get_sockaddr(sa, address, port);
441 bool f_socket_getsockname(CObjRef socket, VRefParam address,
442 VRefParam port /* = null */) {
443 Socket *sock = socket.getTyped<Socket>();
445 sockaddr_storage sa_storage;
446 socklen_t salen = sizeof(sockaddr_storage);
447 struct sockaddr *sa = (struct sockaddr *)&sa_storage;
448 if (getsockname(sock->fd(), sa, &salen) < 0) {
449 SOCKET_ERROR(sock, "unable to retrieve peer name", errno);
450 return false;
452 return get_sockaddr(sa, address, port);
455 bool f_socket_set_block(CObjRef socket) {
456 Socket *sock = socket.getTyped<Socket>();
457 return sock->setBlocking(true);
460 bool f_socket_set_nonblock(CObjRef socket) {
461 Socket *sock = socket.getTyped<Socket>();
462 return sock->setBlocking(false);
465 bool f_socket_set_option(CObjRef socket, int level, int optname,
466 CVarRef optval) {
467 Socket *sock = socket.getTyped<Socket>();
469 struct linger lv;
470 struct timeval tv;
471 int ov;
472 int optlen;
473 void *opt_ptr;
475 switch (optname) {
476 case SO_LINGER:
478 Array value = optval.toArray();
479 if (!value.exists(s_l_onoff)) {
480 raise_warning("no key \"l_onoff\" passed in optval");
481 return false;
483 if (!value.exists(s_l_linger)) {
484 raise_warning("no key \"l_linger\" passed in optval");
485 return false;
488 lv.l_onoff = (unsigned short)value[s_l_onoff].toInt32();
489 lv.l_linger = (unsigned short)value[s_l_linger].toInt32();
490 optlen = sizeof(lv);
491 opt_ptr = &lv;
493 break;
495 case SO_RCVTIMEO:
496 case SO_SNDTIMEO:
498 Array value = optval.toArray();
499 if (!value.exists(s_sec)) {
500 raise_warning("no key \"sec\" passed in optval");
501 return false;
503 if (!value.exists(s_usec)) {
504 raise_warning("no key \"usec\" passed in optval");
505 return false;
508 tv.tv_sec = value[s_sec].toInt32();
509 tv.tv_usec = value[s_usec].toInt32();
510 if (tv.tv_usec >= 1000000) {
511 tv.tv_sec += tv.tv_usec / 1000000;
512 tv.tv_usec %= 1000000;
514 optlen = sizeof(tv);
515 opt_ptr = &tv;
516 sock->setTimeout(tv);
518 break;
520 default:
521 ov = optval.toInt32();
522 optlen = sizeof(ov);
523 opt_ptr = &ov;
524 break;
527 if (setsockopt(sock->fd(), level, optname, opt_ptr, optlen) != 0) {
528 SOCKET_ERROR(sock, "unable to set socket option", errno);
529 return false;
531 return true;
534 bool f_socket_connect(CObjRef socket, CStrRef address, int port /* = 0 */) {
535 Socket *sock = socket.getTyped<Socket>();
537 switch (sock->getType()) {
538 case AF_INET6:
539 case AF_INET:
540 if (port == 0) {
541 raise_warning("Socket of type AF_INET/6 requires 3 arguments");
542 return false;
544 break;
545 default:
546 break;
549 const char *addr = address.data();
550 sockaddr_storage sa_storage;
551 struct sockaddr *sa_ptr;
552 size_t sa_size;
553 if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) {
554 return false;
557 IOStatusHelper io("socket::connect", address.data(), port);
558 int retval = connect(sock->fd(), sa_ptr, sa_size);
559 if (retval != 0) {
560 std::string msg = "unable to connect to ";
561 msg += addr;
562 msg += ":";
563 msg += boost::lexical_cast<std::string>(port);
564 SOCKET_ERROR(sock, msg.c_str(), errno);
565 return false;
568 return true;
571 bool f_socket_bind(CObjRef socket, CStrRef address, int port /* = 0 */) {
572 Socket *sock = socket.getTyped<Socket>();
574 const char *addr = address.data();
575 sockaddr_storage sa_storage;
576 struct sockaddr *sa_ptr;
577 size_t sa_size;
578 if (!set_sockaddr(sa_storage, sock, addr, port, sa_ptr, sa_size)) {
579 return false;
582 long retval = ::bind(sock->fd(), sa_ptr, sa_size);
583 if (retval != 0) {
584 std::string msg = "unable to bind address";
585 msg += addr;
586 msg += ":";
587 msg += boost::lexical_cast<std::string>(port);
588 SOCKET_ERROR(sock, msg.c_str(), errno);
589 return false;
592 return true;
595 bool f_socket_listen(CObjRef socket, int backlog /* = 0 */) {
596 Socket *sock = socket.getTyped<Socket>();
597 if (listen(sock->fd(), backlog) != 0) {
598 SOCKET_ERROR(sock, "unable to listen on socket", errno);
599 return false;
601 return true;
604 Variant f_socket_select(VRefParam read, VRefParam write, VRefParam except,
605 CVarRef vtv_sec, int tv_usec /* = 0 */) {
606 int count = 0;
607 if (!read.isNull()) {
608 count += read.toArray().size();
610 if (!write.isNull()) {
611 count += write.toArray().size();
613 if (!except.isNull()) {
614 count += except.toArray().size();
616 if (!count) {
617 return false;
620 struct pollfd *fds = (struct pollfd *)calloc(count, sizeof(struct pollfd));
621 count = 0;
622 if (!read.isNull()) {
623 sock_array_to_fd_set(read.toArray(), fds, count, POLLIN);
625 if (!write.isNull()) {
626 sock_array_to_fd_set(write.toArray(), fds, count, POLLOUT);
628 if (!except.isNull()) {
629 sock_array_to_fd_set(except.toArray(), fds, count, POLLPRI);
632 IOStatusHelper io("socket_select");
633 int timeout_ms = -1;
634 if (!vtv_sec.isNull()) {
635 timeout_ms = vtv_sec.toInt32() * 1000 + tv_usec / 1000;
637 int retval = poll(fds, count, timeout_ms);
638 if (retval == -1) {
639 raise_warning("unable to select [%d]: %s", errno,
640 Util::safe_strerror(errno).c_str());
641 free(fds);
642 return false;
645 count = 0;
646 int nfds = 0;
647 if (!read.isNull()) {
648 sock_array_from_fd_set(read, fds, nfds, count, POLLIN|POLLERR);
650 if (!write.isNull()) {
651 sock_array_from_fd_set(write, fds, nfds, count, POLLOUT|POLLERR);
653 if (!except.isNull()) {
654 sock_array_from_fd_set(except, fds, nfds, count, POLLPRI|POLLERR);
657 free(fds);
658 return count;
661 Variant f_socket_server(CStrRef hostname, int port /* = -1 */,
662 VRefParam errnum /* = null */,
663 VRefParam errstr /* = null */) {
664 Object ret;
665 Socket *sock = NULL;
666 const char *name = hostname.data();
667 if (!create_new_socket(name, port, errnum, errstr, ret, sock)) {
668 return false;
670 assert(ret.get() && sock);
672 sockaddr_storage sa_storage;
673 struct sockaddr *sa_ptr;
674 size_t sa_size;
675 if (!set_sockaddr(sa_storage, sock, name, port, sa_ptr, sa_size)) {
676 return false;
678 if (::bind(sock->fd(), sa_ptr, sa_size) < 0) {
679 SOCKET_ERROR(sock, "unable to bind to given adress", errno);
680 return false;
682 if (listen(sock->fd(), 128) < 0) {
683 SOCKET_ERROR(sock, "unable to listen on socket", errno);
684 return false;
687 return ret;
690 Variant f_socket_accept(CObjRef socket) {
691 Socket *sock = socket.getTyped<Socket>();
692 struct sockaddr sa;
693 socklen_t salen = sizeof(sa);
694 Socket *new_sock = new Socket(accept(sock->fd(), &sa, &salen),
695 sock->getType());
696 if (!new_sock->valid()) {
697 SOCKET_ERROR(new_sock, "unable to accept incoming connection", errno);
698 delete new_sock;
699 return false;
701 return Object(new_sock);
704 Variant f_socket_read(CObjRef socket, int length, int type /* = 0 */) {
705 if (length <= 0) {
706 return false;
708 Socket *sock = socket.getTyped<Socket>();
710 char *tmpbuf = (char *)malloc(length + 1);
711 int retval;
712 if (type == PHP_NORMAL_READ) {
713 retval = php_read(sock, tmpbuf, length, 0);
714 } else {
715 retval = recv(sock->fd(), tmpbuf, length, 0);
718 if (retval == -1) {
719 /* if the socket is in non-blocking mode and there's no data to read,
720 don't output any error, as this is a normal situation, and not an error */
721 if (errno == EAGAIN || errno == EWOULDBLOCK) {
722 sock->setError(errno);
723 } else {
724 SOCKET_ERROR(sock, "unable to read from socket", errno);
727 free(tmpbuf);
728 return false;
731 tmpbuf[retval] = '\0' ;
732 return String(tmpbuf, retval, AttachString);
735 Variant f_socket_write(CObjRef socket, CStrRef buffer, int length /* = 0 */) {
736 Socket *sock = socket.getTyped<Socket>();
737 if (length == 0 || length > buffer.size()) {
738 length = buffer.size();
740 int retval = write(sock->fd(), buffer.data(), length);
741 if (retval < 0) {
742 SOCKET_ERROR(sock, "unable to write to socket", errno);
743 return false;
745 return retval;
748 Variant f_socket_send(CObjRef socket, CStrRef buf, int len, int flags) {
749 Socket *sock = socket.getTyped<Socket>();
750 if (len > buf.size()) {
751 len = buf.size();
753 int retval = send(sock->fd(), buf.data(), len, flags);
754 if (retval == -1) {
755 SOCKET_ERROR(sock, "unable to write to socket", errno);
756 return false;
758 return retval;
761 Variant f_socket_sendto(CObjRef socket, CStrRef buf, int len, int flags,
762 CStrRef addr, int port /* = 0 */) {
763 Socket *sock = socket.getTyped<Socket>();
764 if (len > buf.size()) {
765 len = buf.size();
767 int retval;
768 switch (sock->getType()) {
769 case AF_UNIX:
771 struct sockaddr_un s_un;
772 memset(&s_un, 0, sizeof(s_un));
773 s_un.sun_family = AF_UNIX;
774 snprintf(s_un.sun_path, 108, "%s", addr.data());
776 retval = sendto(sock->fd(), buf.data(), len, flags,
777 (struct sockaddr *)&s_un, SUN_LEN(&s_un));
779 break;
780 case AF_INET:
782 struct sockaddr_in sin;
783 memset(&sin, 0, sizeof(sin));
784 sin.sin_family = AF_INET;
785 sin.sin_port = htons((unsigned short) port);
786 if (!php_set_inet_addr(&sin, addr.c_str(), sock)) {
787 return false;
790 retval = sendto(sock->fd(), buf.data(), len, flags,
791 (struct sockaddr *)&sin, sizeof(sin));
793 break;
794 case AF_INET6:
796 struct sockaddr_in6 sin6;
797 memset(&sin6, 0, sizeof(sin6));
798 sin6.sin6_family = AF_INET6;
799 sin6.sin6_port = htons((unsigned short) port);
801 if (!php_set_inet6_addr(&sin6, addr.c_str(), sock)) {
802 return false;
805 retval = sendto(sock->fd(), buf.data(), len, flags,
806 (struct sockaddr *)&sin6, sizeof(sin6));
808 break;
809 default:
810 raise_warning("Unsupported socket type %d", sock->getType());
811 return false;
814 if (retval == -1) {
815 SOCKET_ERROR(sock, "unable to write to socket", errno);
816 return false;
819 return retval;
822 Variant f_socket_recv(CObjRef socket, VRefParam buf, int len, int flags) {
823 if (len <= 0) {
824 return false;
826 Socket *sock = socket.getTyped<Socket>();
828 char *recv_buf = (char *)malloc(len + 1);
829 int retval;
830 if ((retval = recv(sock->fd(), recv_buf, len, flags)) < 1) {
831 free(recv_buf);
832 buf = uninit_null();
833 } else {
834 recv_buf[retval] = '\0';
835 buf = String(recv_buf, retval, AttachString);
838 if (retval == -1) {
839 SOCKET_ERROR(sock, "unable to read from socket", errno);
840 return false;
842 return retval;
845 Variant f_socket_recvfrom(CObjRef socket, VRefParam buf, int len, int flags,
846 VRefParam name, VRefParam port /* = 0 */) {
847 if (len <= 0) {
848 return false;
851 Socket *sock = socket.getTyped<Socket>();
853 char *recv_buf = (char *)malloc(len + 2);
854 socklen_t slen;
855 int retval;
857 switch (sock->getType()) {
858 case AF_UNIX:
860 struct sockaddr_un s_un;
861 slen = sizeof(s_un);
862 memset(&s_un, 0, slen);
863 s_un.sun_family = AF_UNIX;
864 retval = recvfrom(sock->fd(), recv_buf, len, flags,
865 (struct sockaddr *)&s_un, (socklen_t *)&slen);
866 if (retval < 0) {
867 free(recv_buf);
868 SOCKET_ERROR(sock, "unable to recvfrom", errno);
869 return false;
872 recv_buf[retval] = 0;
873 buf = String(recv_buf, retval, AttachString);
874 name = String(s_un.sun_path, CopyString);
876 break;
877 case AF_INET:
879 struct sockaddr_in sin;
880 slen = sizeof(sin);
881 memset(&sin, 0, slen);
882 sin.sin_family = AF_INET;
884 retval = recvfrom(sock->fd(), recv_buf, len, flags,
885 (struct sockaddr *)&sin, (socklen_t *)&slen);
886 if (retval < 0) {
887 free(recv_buf);
888 SOCKET_ERROR(sock, "unable to recvfrom", errno);
889 return false;
891 recv_buf[retval] = 0;
892 buf = String(recv_buf, retval, AttachString);
894 name = String(Util::safe_inet_ntoa(sin.sin_addr));
895 if (name.toString().empty()) {
896 name = "0.0.0.0";
898 port = ntohs(sin.sin_port);
900 break;
901 case AF_INET6:
903 struct sockaddr_in6 sin6;
904 slen = sizeof(sin6);
905 memset(&sin6, 0, slen);
906 sin6.sin6_family = AF_INET6;
908 retval = recvfrom(sock->fd(), recv_buf, len, flags,
909 (struct sockaddr *)&sin6, (socklen_t *)&slen);
910 if (retval < 0) {
911 free(recv_buf);
912 SOCKET_ERROR(sock, "unable to recvfrom", errno);
913 return false;
916 char addr6[INET6_ADDRSTRLEN];
917 const char* succ =
918 inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN);
920 recv_buf[retval] = 0;
921 buf = String(recv_buf, retval, AttachString);
922 if (succ) {
923 name = String(addr6, CopyString);
924 } else {
925 name = "::";
927 port = ntohs(sin6.sin6_port);
929 break;
930 default:
931 raise_warning("Unsupported socket type %d", sock->getType());
932 return false;
935 return retval;
938 bool f_socket_shutdown(CObjRef socket, int how /* = 0 */) {
939 Socket *sock = socket.getTyped<Socket>();
940 if (shutdown(sock->fd(), how) != 0) {
941 SOCKET_ERROR(sock, "unable to shutdown socket", errno);
942 return false;
944 return true;
947 void f_socket_close(CObjRef socket) {
948 Socket *sock = socket.getTyped<Socket>();
949 sock->close();
952 String f_socket_strerror(int errnum) {
953 return String(Util::safe_strerror(errnum));
956 int64_t f_socket_last_error(CObjRef socket /* = null_object */) {
957 if (!socket.isNull()) {
958 Socket *sock = socket.getTyped<Socket>();
959 return sock->getError();
961 return Socket::getLastError();
964 void f_socket_clear_error(CObjRef socket /* = null_object */) {
965 if (!socket.isNull()) {
966 Socket *sock = socket.getTyped<Socket>();
967 sock->setError(0);
971 ///////////////////////////////////////////////////////////////////////////////
972 // fsock: treating sockets as "file"
974 static Variant sockopen_impl(CStrRef hostname, int port, Variant &errnum,
975 Variant &errstr, double timeout,
976 bool persistent) {
977 string key;
978 if (persistent) {
979 key = hostname.data();
980 key += ":";
981 key += boost::lexical_cast<string>(port);
982 Socket *sock =
983 dynamic_cast<Socket*>(g_persistentObjects->get("socket", key.c_str()));
984 if (sock) {
985 if (sock->getError() == 0 && sock->checkLiveness()) {
986 return Object(sock);
989 // socket had an error earlier, we need to remove it from persistent
990 // storage, and create a new one
991 g_persistentObjects->remove("socket", key.c_str());
995 Object ret;
996 const char *name = hostname.data();
997 Socket *sock = NULL;
999 // test if protocol is SSL
1000 SSLSocket *sslsock = SSLSocket::Create(name, port, timeout);
1001 if (sslsock) {
1002 sock = sslsock;
1003 ret = sock;
1004 } else if (!create_new_socket(name, port, errnum, errstr, ret, sock)) {
1005 return false;
1007 assert(ret.get() && sock);
1009 sockaddr_storage sa_storage;
1010 struct sockaddr *sa_ptr;
1011 size_t sa_size;
1012 if (!set_sockaddr(sa_storage, sock, name, port, sa_ptr, sa_size)) {
1013 return false;
1016 int retval;
1017 int fd = sock->fd();
1018 IOStatusHelper io("socket::connect", name, port);
1019 if (timeout <= 0) {
1020 retval = connect(fd, sa_ptr, sa_size);
1021 } else {
1022 // set non-blocking so we can do timeouts
1023 long arg = fcntl(fd, F_GETFL, NULL);
1024 fcntl(fd, F_SETFL, arg | O_NONBLOCK);
1026 retval = connect(fd, sa_ptr, sa_size);
1027 if (retval < 0) {
1028 if (errno == EINPROGRESS) {
1029 struct pollfd fds[1];
1030 fds[0].fd = fd;
1031 fds[0].events = POLLOUT;
1032 if (poll(fds, 1, (int)(timeout * 1000))) {
1033 socklen_t lon = sizeof(int);
1034 int valopt;
1035 getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
1036 if (valopt) {
1037 std::string msg = "failed to connect to ";
1038 msg += name;
1039 msg += ":";
1040 msg += boost::lexical_cast<std::string>(port);
1041 SOCKET_ERROR(sock, msg.c_str(), valopt);
1042 errnum = sock->getError();
1043 errstr = String(Util::safe_strerror(sock->getError()));
1044 return false;
1045 } else {
1046 retval = 0; // success
1048 } else {
1049 std::string msg = "timed out after ";
1050 msg += boost::lexical_cast<std::string>(timeout);
1051 msg += " seconds when connecting to ";
1052 msg += name;
1053 msg += ":";
1054 msg += boost::lexical_cast<std::string>(port);
1055 SOCKET_ERROR(sock, msg.c_str(), ETIMEDOUT);
1056 errnum = sock->getError();
1057 errstr = String(Util::safe_strerror(sock->getError()));
1058 return false;
1063 // set to blocking mode
1064 arg = fcntl(fd, F_GETFL, NULL);
1065 fcntl(fd, F_SETFL, arg & ~O_NONBLOCK);
1068 if (retval != 0) {
1069 errnum = sock->getError();
1070 errstr = String(Util::safe_strerror(sock->getError()));
1071 return false;
1074 if (sslsock && !sslsock->onConnect()) {
1075 raise_warning("Failed to enable crypto");
1076 return false;
1079 if (persistent) {
1080 assert(!key.empty());
1081 g_persistentObjects->set("socket", key.c_str(), sock);
1084 return ret;
1087 Variant f_fsockopen(CStrRef hostname, int port /* = -1 */,
1088 VRefParam errnum /* = null */,
1089 VRefParam errstr /* = null */,
1090 double timeout /* = 0.0 */) {
1091 return sockopen_impl(hostname, port, errnum, errstr, timeout, false);
1094 Variant f_pfsockopen(CStrRef hostname, int port /* = -1 */,
1095 VRefParam errnum /* = null */,
1096 VRefParam errstr /* = null */,
1097 double timeout /* = 0.0 */) {
1098 // TODO: persistent socket handling
1099 return sockopen_impl(hostname, port, errnum, errstr, timeout, true);
1102 String ipaddr_convert(struct sockaddr *addr, int addrlen) {
1103 char buffer[NI_MAXHOST];
1104 int error = getnameinfo(addr, addrlen, buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST);
1106 if (error) {
1107 raise_warning("%s", gai_strerror(error));
1108 return "";
1110 return String(buffer, CopyString);
1113 static const StaticString s_family("family");
1114 static const StaticString s_socktype("socktype");
1115 static const StaticString s_protocol("protocol");
1116 static const StaticString s_address("address");
1117 static const StaticString s_port("port");
1118 static const StaticString s_flow_info("flow_info");
1119 static const StaticString s_scope_id("scope_id");
1120 static const StaticString s_sockaddr("sockaddr");
1122 Variant f_getaddrinfo(CStrRef host, CStrRef port, int family /* = 0 */,
1123 int socktype /* = 0 */, int protocol /* = 0 */,
1124 int flags /* = 0 */) {
1125 const char *hptr = NULL, *pptr = NULL;
1126 if (!host.empty()) {
1127 hptr = host.c_str();
1129 if (!port.empty()) {
1130 pptr = port.c_str();
1133 struct addrinfo hints, *res;
1134 struct addrinfo *res0 = NULL;
1135 int error;
1137 memset(&hints, 0, sizeof(hints));
1138 hints.ai_family = family;
1139 hints.ai_socktype = socktype;
1140 hints.ai_protocol = protocol;
1141 hints.ai_flags = flags;
1142 error = getaddrinfo(hptr, pptr, &hints, &res0);
1144 if (error) {
1145 raise_warning("%s", gai_strerror(error));
1147 if (res0) {
1148 freeaddrinfo(res0);
1150 return false;
1153 Array ret = Array::Create();
1155 for (res = res0; res; res = res->ai_next) {
1156 Array data = Array::Create();
1157 Array sockinfo = Array::Create();
1159 data.set(s_family, res->ai_family);
1160 data.set(s_socktype, res->ai_socktype);
1161 data.set(s_protocol, res->ai_protocol);
1163 switch (res->ai_addr->sa_family) {
1164 case AF_INET:
1166 struct sockaddr_in *a;
1167 String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
1168 if (!buffer.empty()) {
1169 a = (struct sockaddr_in *)res->ai_addr;
1170 sockinfo.set(s_address, buffer);
1171 sockinfo.set(s_port, ntohs(a->sin_port));
1173 break;
1175 case AF_INET6:
1177 struct sockaddr_in6 *a;
1178 String buffer = ipaddr_convert(res->ai_addr, sizeof(*a));
1179 if (!buffer.empty()) {
1180 a = (struct sockaddr_in6 *)res->ai_addr;
1181 sockinfo.set(s_address, buffer);
1182 sockinfo.set(s_port, ntohs(a->sin6_port));
1183 sockinfo.set(s_flow_info, (int32_t)a->sin6_flowinfo);
1184 sockinfo.set(s_scope_id, (int32_t)a->sin6_scope_id);
1186 break;
1190 data.set(s_sockaddr, (sockinfo.empty() ? nullptr : sockinfo));
1192 ret.append(data);
1195 if (res0) {
1196 freeaddrinfo(res0);
1199 return ret;
1202 ///////////////////////////////////////////////////////////////////////////////