2 +----------------------------------------------------------------------+
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>
26 #include <netinet/in.h>
27 #include <netinet/tcp.h>
29 #include <arpa/inet.h>
36 #include <util/network.h>
39 #define PHP_NORMAL_READ 0x0001
40 #define PHP_BINARY_READ 0x0002
43 IMPLEMENT_DEFAULT_EXTENSION(sockets
);
44 ///////////////////////////////////////////////////////////////////////////////
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
);
55 raise_warning("invalid socket type [%d] specified for argument 2, "
56 "assuming SOCK_STREAM", type
);
61 static bool get_sockaddr(sockaddr
*sa
, Variant
&address
, Variant
&port
) {
62 switch (sa
->sa_family
) {
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
);
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
);
81 struct sockaddr_un
*s_un
= (struct sockaddr_un
*)sa
;
82 address
= String(s_un
->sun_path
, CopyString
);
90 raise_warning("Unsupported address family %d", sa
->sa_family
);
94 static bool php_set_inet6_addr(struct sockaddr_in6
*sin6
, const char *address
,
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
));
104 memset(&hints
, 0, sizeof(struct addrinfo
));
105 hints
.ai_family
= PF_INET6
;
106 getaddrinfo(address
, NULL
, &hints
, &addrinfo
);
108 SOCKET_ERROR(sock
, "Host lookup failed", (-10000 - h_errno
));
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
);
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
);
128 static bool php_set_inet_addr(struct sockaddr_in
*sin
, const char *address
,
132 if (inet_aton(address
, &tmp
)) {
133 sin
->sin_addr
.s_addr
= tmp
.s_addr
;
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
));
141 if (result
.hostbuf
.h_addrtype
!= AF_INET
) {
142 raise_warning("Host lookup failed: Non AF_INET domain "
143 "returned on AF_INET socket");
146 memcpy(&(sin
->sin_addr
.s_addr
), result
.hostbuf
.h_addr_list
[0],
147 result
.hostbuf
.h_length
);
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()) {
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
);
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
)) {
177 sa_ptr
= (struct sockaddr
*)sa
;
178 sa_size
= sizeof(struct sockaddr_in
);
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
)) {
190 sa_ptr
= (struct sockaddr
*)sa
;
191 sa_size
= sizeof(struct sockaddr_in6
);
195 raise_warning("unsupported socket type '%d', must be "
196 "AF_UNIX, AF_INET, or AF_INET6", sock
->getType());
202 static void sock_array_to_fd_set(CArrRef sockets
, pollfd
*fds
, int &nfds
,
205 for (ArrayIter
iter(sockets
); iter
; ++iter
) {
206 File
*sock
= iter
.second().toObject().getTyped
<File
>();
207 pollfd
&fd
= fds
[nfds
++];
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();
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());
230 static int php_read(Socket
*sock
, void *buf
, int maxlen
, int flags
) {
231 int m
= fcntl(sock
->fd(), F_GETFL
);
235 int nonblock
= (m
& O_NONBLOCK
);
238 char *t
= (char *)buf
;
242 while (*t
!= '\n' && *t
!= '\r' && n
< maxlen
) {
248 if (nonblock
&& no_read
>= 2) {
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.. */
262 m
= recv(sock
->fd(), (void *)t
, 1, flags
);
265 if (errno
!= 0 && errno
!= ESPIPE
&& errno
!= EAGAIN
) {
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..) */
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) {
290 } else if (strncmp(name
, "tcp://", 6) == 0) {
292 } else if (strncmp(name
, "unix://", 7) == 0) {
297 sock
= new Socket(socket(domain
, type
, 0), domain
, name
, port
);
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()));
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
);
318 Socket
*sock
= new Socket(socketId
, domain
);
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
)) {
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
,
338 if (!sock
->valid()) {
339 SOCKET_ERROR(sock
, "unable to create listening socket", errno
);
343 if (::bind(sock
->fd(), (struct sockaddr
*)&la
, sizeof(la
)) < 0) {
344 SOCKET_ERROR(sock
, "unable to bind to given adress", errno
);
348 if (listen(sock
->fd(), backlog
) < 0) {
349 SOCKET_ERROR(sock
, "unable to listen on socket", errno
);
356 bool f_socket_create_pair(int domain
, int type
, int protocol
, VRefParam fd
) {
357 check_socket_parameters(domain
, type
);
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
);
367 ret
.set(0, Object(new Socket(fds_array
[0], domain
)));
368 ret
.set(1, Object(new Socket(fds_array
[1], domain
)));
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
>();
386 struct linger linger_val
;
387 optlen
= sizeof(linger_val
);
388 if (getsockopt(sock
->fd(), level
, optname
, (char*)&linger_val
,
390 SOCKET_ERROR(sock
, "unable to retrieve socket option", errno
);
394 ret
.set(s_l_onoff
, linger_val
.l_onoff
);
395 ret
.set(s_l_linger
, linger_val
.l_linger
);
404 if (getsockopt(sock
->fd(), level
, optname
, (char*)&tv
, &optlen
) != 0) {
405 SOCKET_ERROR(sock
, "unable to retrieve socket option", errno
);
408 ret
.set(s_sec
, (int)tv
.tv_sec
);
409 ret
.set(s_usec
, (int)tv
.tv_usec
);
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
);
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
);
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
);
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
,
467 Socket
*sock
= socket
.getTyped
<Socket
>();
478 Array value
= optval
.toArray();
479 if (!value
.exists(s_l_onoff
)) {
480 raise_warning("no key \"l_onoff\" passed in optval");
483 if (!value
.exists(s_l_linger
)) {
484 raise_warning("no key \"l_linger\" passed in optval");
488 lv
.l_onoff
= (unsigned short)value
[s_l_onoff
].toInt32();
489 lv
.l_linger
= (unsigned short)value
[s_l_linger
].toInt32();
498 Array value
= optval
.toArray();
499 if (!value
.exists(s_sec
)) {
500 raise_warning("no key \"sec\" passed in optval");
503 if (!value
.exists(s_usec
)) {
504 raise_warning("no key \"usec\" passed in optval");
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;
516 sock
->setTimeout(tv
);
521 ov
= optval
.toInt32();
527 if (setsockopt(sock
->fd(), level
, optname
, opt_ptr
, optlen
) != 0) {
528 SOCKET_ERROR(sock
, "unable to set socket option", errno
);
534 bool f_socket_connect(CObjRef socket
, CStrRef address
, int port
/* = 0 */) {
535 Socket
*sock
= socket
.getTyped
<Socket
>();
537 switch (sock
->getType()) {
541 raise_warning("Socket of type AF_INET/6 requires 3 arguments");
549 const char *addr
= address
.data();
550 sockaddr_storage sa_storage
;
551 struct sockaddr
*sa_ptr
;
553 if (!set_sockaddr(sa_storage
, sock
, addr
, port
, sa_ptr
, sa_size
)) {
557 IOStatusHelper
io("socket::connect", address
.data(), port
);
558 int retval
= connect(sock
->fd(), sa_ptr
, sa_size
);
560 std::string msg
= "unable to connect to ";
563 msg
+= boost::lexical_cast
<std::string
>(port
);
564 SOCKET_ERROR(sock
, msg
.c_str(), errno
);
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
;
578 if (!set_sockaddr(sa_storage
, sock
, addr
, port
, sa_ptr
, sa_size
)) {
582 long retval
= ::bind(sock
->fd(), sa_ptr
, sa_size
);
584 std::string msg
= "unable to bind address";
587 msg
+= boost::lexical_cast
<std::string
>(port
);
588 SOCKET_ERROR(sock
, msg
.c_str(), errno
);
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
);
604 Variant
f_socket_select(VRefParam read
, VRefParam write
, VRefParam except
,
605 CVarRef vtv_sec
, int tv_usec
/* = 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();
620 struct pollfd
*fds
= (struct pollfd
*)calloc(count
, sizeof(struct pollfd
));
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");
634 if (!vtv_sec
.isNull()) {
635 timeout_ms
= vtv_sec
.toInt32() * 1000 + tv_usec
/ 1000;
637 int retval
= poll(fds
, count
, timeout_ms
);
639 raise_warning("unable to select [%d]: %s", errno
,
640 Util::safe_strerror(errno
).c_str());
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
);
661 Variant
f_socket_server(CStrRef hostname
, int port
/* = -1 */,
662 VRefParam errnum
/* = null */,
663 VRefParam errstr
/* = null */) {
666 const char *name
= hostname
.data();
667 if (!create_new_socket(name
, port
, errnum
, errstr
, ret
, sock
)) {
670 assert(ret
.get() && sock
);
672 sockaddr_storage sa_storage
;
673 struct sockaddr
*sa_ptr
;
675 if (!set_sockaddr(sa_storage
, sock
, name
, port
, sa_ptr
, sa_size
)) {
678 if (::bind(sock
->fd(), sa_ptr
, sa_size
) < 0) {
679 SOCKET_ERROR(sock
, "unable to bind to given adress", errno
);
682 if (listen(sock
->fd(), 128) < 0) {
683 SOCKET_ERROR(sock
, "unable to listen on socket", errno
);
690 Variant
f_socket_accept(CObjRef socket
) {
691 Socket
*sock
= socket
.getTyped
<Socket
>();
693 socklen_t salen
= sizeof(sa
);
694 Socket
*new_sock
= new Socket(accept(sock
->fd(), &sa
, &salen
),
696 if (!new_sock
->valid()) {
697 SOCKET_ERROR(new_sock
, "unable to accept incoming connection", errno
);
701 return Object(new_sock
);
704 Variant
f_socket_read(CObjRef socket
, int length
, int type
/* = 0 */) {
708 Socket
*sock
= socket
.getTyped
<Socket
>();
710 char *tmpbuf
= (char *)malloc(length
+ 1);
712 if (type
== PHP_NORMAL_READ
) {
713 retval
= php_read(sock
, tmpbuf
, length
, 0);
715 retval
= recv(sock
->fd(), tmpbuf
, length
, 0);
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
);
724 SOCKET_ERROR(sock
, "unable to read from socket", errno
);
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
);
742 SOCKET_ERROR(sock
, "unable to write to socket", errno
);
748 Variant
f_socket_send(CObjRef socket
, CStrRef buf
, int len
, int flags
) {
749 Socket
*sock
= socket
.getTyped
<Socket
>();
750 if (len
> buf
.size()) {
753 int retval
= send(sock
->fd(), buf
.data(), len
, flags
);
755 SOCKET_ERROR(sock
, "unable to write to socket", errno
);
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()) {
768 switch (sock
->getType()) {
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
));
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
)) {
790 retval
= sendto(sock
->fd(), buf
.data(), len
, flags
,
791 (struct sockaddr
*)&sin
, sizeof(sin
));
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
)) {
805 retval
= sendto(sock
->fd(), buf
.data(), len
, flags
,
806 (struct sockaddr
*)&sin6
, sizeof(sin6
));
810 raise_warning("Unsupported socket type %d", sock
->getType());
815 SOCKET_ERROR(sock
, "unable to write to socket", errno
);
822 Variant
f_socket_recv(CObjRef socket
, VRefParam buf
, int len
, int flags
) {
826 Socket
*sock
= socket
.getTyped
<Socket
>();
828 char *recv_buf
= (char *)malloc(len
+ 1);
830 if ((retval
= recv(sock
->fd(), recv_buf
, len
, flags
)) < 1) {
834 recv_buf
[retval
] = '\0';
835 buf
= String(recv_buf
, retval
, AttachString
);
839 SOCKET_ERROR(sock
, "unable to read from socket", errno
);
845 Variant
f_socket_recvfrom(CObjRef socket
, VRefParam buf
, int len
, int flags
,
846 VRefParam name
, VRefParam port
/* = 0 */) {
851 Socket
*sock
= socket
.getTyped
<Socket
>();
853 char *recv_buf
= (char *)malloc(len
+ 2);
857 switch (sock
->getType()) {
860 struct sockaddr_un 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
);
868 SOCKET_ERROR(sock
, "unable to recvfrom", errno
);
872 recv_buf
[retval
] = 0;
873 buf
= String(recv_buf
, retval
, AttachString
);
874 name
= String(s_un
.sun_path
, CopyString
);
879 struct sockaddr_in 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
);
888 SOCKET_ERROR(sock
, "unable to recvfrom", errno
);
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()) {
898 port
= ntohs(sin
.sin_port
);
903 struct sockaddr_in6 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
);
912 SOCKET_ERROR(sock
, "unable to recvfrom", errno
);
916 char addr6
[INET6_ADDRSTRLEN
];
918 inet_ntop(AF_INET6
, &sin6
.sin6_addr
, addr6
, INET6_ADDRSTRLEN
);
920 recv_buf
[retval
] = 0;
921 buf
= String(recv_buf
, retval
, AttachString
);
923 name
= String(addr6
, CopyString
);
927 port
= ntohs(sin6
.sin6_port
);
931 raise_warning("Unsupported socket type %d", sock
->getType());
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
);
947 void f_socket_close(CObjRef socket
) {
948 Socket
*sock
= socket
.getTyped
<Socket
>();
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
>();
971 ///////////////////////////////////////////////////////////////////////////////
972 // fsock: treating sockets as "file"
974 static Variant
sockopen_impl(CStrRef hostname
, int port
, Variant
&errnum
,
975 Variant
&errstr
, double timeout
,
979 key
= hostname
.data();
981 key
+= boost::lexical_cast
<string
>(port
);
983 dynamic_cast<Socket
*>(g_persistentObjects
->get("socket", key
.c_str()));
985 if (sock
->getError() == 0 && sock
->checkLiveness()) {
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());
996 const char *name
= hostname
.data();
999 // test if protocol is SSL
1000 SSLSocket
*sslsock
= SSLSocket::Create(name
, port
, timeout
);
1004 } else if (!create_new_socket(name
, port
, errnum
, errstr
, ret
, sock
)) {
1007 assert(ret
.get() && sock
);
1009 sockaddr_storage sa_storage
;
1010 struct sockaddr
*sa_ptr
;
1012 if (!set_sockaddr(sa_storage
, sock
, name
, port
, sa_ptr
, sa_size
)) {
1017 int fd
= sock
->fd();
1018 IOStatusHelper
io("socket::connect", name
, port
);
1020 retval
= connect(fd
, sa_ptr
, sa_size
);
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
);
1028 if (errno
== EINPROGRESS
) {
1029 struct pollfd fds
[1];
1031 fds
[0].events
= POLLOUT
;
1032 if (poll(fds
, 1, (int)(timeout
* 1000))) {
1033 socklen_t lon
= sizeof(int);
1035 getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, (void*)(&valopt
), &lon
);
1037 std::string msg
= "failed to connect to ";
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()));
1046 retval
= 0; // success
1049 std::string msg
= "timed out after ";
1050 msg
+= boost::lexical_cast
<std::string
>(timeout
);
1051 msg
+= " seconds when connecting to ";
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()));
1063 // set to blocking mode
1064 arg
= fcntl(fd
, F_GETFL
, NULL
);
1065 fcntl(fd
, F_SETFL
, arg
& ~O_NONBLOCK
);
1069 errnum
= sock
->getError();
1070 errstr
= String(Util::safe_strerror(sock
->getError()));
1074 if (sslsock
&& !sslsock
->onConnect()) {
1075 raise_warning("Failed to enable crypto");
1080 assert(!key
.empty());
1081 g_persistentObjects
->set("socket", key
.c_str(), sock
);
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
);
1107 raise_warning("%s", gai_strerror(error
));
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
;
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
);
1145 raise_warning("%s", gai_strerror(error
));
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
) {
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
));
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
);
1190 data
.set(s_sockaddr
, (sockinfo
.empty() ? nullptr : sockinfo
));
1202 ///////////////////////////////////////////////////////////////////////////////