This source file includes following definitions.
- php_gai_strerror
- php_network_freeaddresses
- php_network_getaddresses
- php_network_connect_socket
- sub_times
- php_network_bind_socket_to_local_addr
- php_network_parse_network_address_with_port
- php_network_populate_name_from_sockaddr
- php_network_get_peer_name
- php_network_get_sock_name
- php_network_accept_incoming
- php_network_connect_socket_to_host
- php_any_addr
- php_sockaddr_size
- php_socket_strerror
- php_socket_error_str
- _php_stream_sock_open_from_socket
- _php_stream_sock_open_host
- php_set_sock_blocking
- _php_emit_fd_setsize_warning
- php_poll2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #include "php.h"
25
26 #include <stddef.h>
27 #include <errno.h>
28
29
30 #ifdef PHP_WIN32
31 # include <Ws2tcpip.h>
32 # include "win32/inet.h"
33 # define O_RDONLY _O_RDONLY
34 # include "win32/param.h"
35 #elif defined(NETWARE)
36 #include <sys/timeval.h>
37 #include <sys/param.h>
38 #else
39 #include <sys/param.h>
40 #endif
41
42 #include <sys/types.h>
43 #if HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46
47 #ifndef _FCNTL_H
48 #include <fcntl.h>
49 #endif
50
51 #ifdef HAVE_SYS_SELECT_H
52 #include <sys/select.h>
53 #endif
54 #if HAVE_SYS_POLL_H
55 #include <sys/poll.h>
56 #endif
57
58 #if defined(NETWARE)
59 #ifdef USE_WINSOCK
60 #include <novsock2.h>
61 #else
62 #include <arpa/inet.h>
63 #include <netinet/in.h>
64 #include <netdb.h>
65 #include <sys/select.h>
66 #include <sys/socket.h>
67 #endif
68 #elif !defined(PHP_WIN32)
69 #include <netinet/in.h>
70 #include <netdb.h>
71 #if HAVE_ARPA_INET_H
72 #include <arpa/inet.h>
73 #endif
74 #endif
75
76 #ifndef HAVE_INET_ATON
77 int inet_aton(const char *, struct in_addr *);
78 #endif
79
80 #include "php_network.h"
81
82 #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
83 #undef AF_UNIX
84 #endif
85
86 #if defined(AF_UNIX)
87 #include <sys/un.h>
88 #endif
89
90 #include "ext/standard/file.h"
91
92 #ifdef PHP_WIN32
93 # include "win32/time.h"
94 # define SOCK_ERR INVALID_SOCKET
95 # define SOCK_CONN_ERR SOCKET_ERROR
96 # define PHP_TIMEOUT_ERROR_VALUE WSAETIMEDOUT
97
98 #if HAVE_IPV6
99 const struct in6_addr in6addr_any = {0};
100 #endif
101
102 #else
103 # define SOCK_ERR -1
104 # define SOCK_CONN_ERR -1
105 # define PHP_TIMEOUT_ERROR_VALUE ETIMEDOUT
106 #endif
107
108 #if HAVE_GETADDRINFO
109 #ifdef HAVE_GAI_STRERROR
110 # define PHP_GAI_STRERROR(x) (gai_strerror(x))
111 #else
112 # define PHP_GAI_STRERROR(x) (php_gai_strerror(x))
113
114
115 static const char *php_gai_strerror(int code)
116 {
117 static struct {
118 int code;
119 const char *msg;
120 } values[] = {
121 # ifdef EAI_ADDRFAMILY
122 {EAI_ADDRFAMILY, "Address family for hostname not supported"},
123 # endif
124 {EAI_AGAIN, "Temporary failure in name resolution"},
125 {EAI_BADFLAGS, "Bad value for ai_flags"},
126 {EAI_FAIL, "Non-recoverable failure in name resolution"},
127 {EAI_FAMILY, "ai_family not supported"},
128 {EAI_MEMORY, "Memory allocation failure"},
129 # ifdef EAI_NODATA
130 {EAI_NODATA, "No address associated with hostname"},
131 # endif
132 {EAI_NONAME, "Name or service not known"},
133 {EAI_SERVICE, "Servname not supported for ai_socktype"},
134 {EAI_SOCKTYPE, "ai_socktype not supported"},
135 {EAI_SYSTEM, "System error"},
136 {0, NULL}
137 };
138 int i;
139
140 for (i = 0; values[i].msg != NULL; i++) {
141 if (values[i].code == code) {
142 return (char *)values[i].msg;
143 }
144 }
145
146 return "Unknown error";
147 }
148
149 #endif
150 #endif
151
152
153
154 PHPAPI void php_network_freeaddresses(struct sockaddr **sal)
155 {
156 struct sockaddr **sap;
157
158 if (sal == NULL)
159 return;
160 for (sap = sal; *sap != NULL; sap++)
161 efree(*sap);
162 efree(sal);
163 }
164
165
166
167
168
169 PHPAPI int php_network_getaddresses(const char *host, int socktype, struct sockaddr ***sal, zend_string **error_string)
170 {
171 struct sockaddr **sap;
172 int n;
173 #if HAVE_GETADDRINFO
174 # if HAVE_IPV6
175 static int ipv6_borked = -1;
176 # endif
177 struct addrinfo hints, *res, *sai;
178 #else
179 struct hostent *host_info;
180 struct in_addr in;
181 #endif
182
183 if (host == NULL) {
184 return 0;
185 }
186 #if HAVE_GETADDRINFO
187 memset(&hints, '\0', sizeof(hints));
188
189 hints.ai_family = AF_INET;
190 hints.ai_socktype = socktype;
191
192 # if HAVE_IPV6
193
194
195
196
197
198
199 if (ipv6_borked == -1) {
200 int s;
201
202 s = socket(PF_INET6, SOCK_DGRAM, 0);
203 if (s == SOCK_ERR) {
204 ipv6_borked = 1;
205 } else {
206 ipv6_borked = 0;
207 closesocket(s);
208 }
209 }
210 hints.ai_family = ipv6_borked ? AF_INET : AF_UNSPEC;
211 # endif
212
213 if ((n = getaddrinfo(host, NULL, &hints, &res))) {
214 if (error_string) {
215 *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
216 php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
217 } else {
218 php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
219 }
220 return 0;
221 } else if (res == NULL) {
222 if (error_string) {
223 *error_string = strpprintf(0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
224 php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
225 } else {
226 php_error_docref(NULL, E_WARNING, "php_network_getaddresses: getaddrinfo failed (null result pointer)");
227 }
228 return 0;
229 }
230
231 sai = res;
232 for (n = 1; (sai = sai->ai_next) != NULL; n++)
233 ;
234
235 *sal = safe_emalloc((n + 1), sizeof(*sal), 0);
236 sai = res;
237 sap = *sal;
238
239 do {
240 *sap = emalloc(sai->ai_addrlen);
241 memcpy(*sap, sai->ai_addr, sai->ai_addrlen);
242 sap++;
243 } while ((sai = sai->ai_next) != NULL);
244
245 freeaddrinfo(res);
246 #else
247 if (!inet_aton(host, &in)) {
248
249 if(strlen(host) > MAXFQDNLEN) {
250 host_info = NULL;
251 errno = E2BIG;
252 } else {
253 host_info = gethostbyname(host);
254 }
255 if (host_info == NULL) {
256 if (error_string) {
257 error_string = strpprintf(0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
258 php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(*error_string));
259 } else {
260 php_error_docref(NULL, E_WARNING, "php_network_getaddresses: gethostbyname failed");
261 }
262 return 0;
263 }
264 in = *((struct in_addr *) host_info->h_addr);
265 }
266
267 *sal = safe_emalloc(2, sizeof(*sal), 0);
268 sap = *sal;
269 *sap = emalloc(sizeof(struct sockaddr_in));
270 (*sap)->sa_family = AF_INET;
271 ((struct sockaddr_in *)*sap)->sin_addr = in;
272 sap++;
273 n = 1;
274 #endif
275
276 *sap = NULL;
277 return n;
278 }
279
280
281 #ifndef O_NONBLOCK
282 #define O_NONBLOCK O_NDELAY
283 #endif
284
285 #if !defined(__BEOS__)
286 # define HAVE_NON_BLOCKING_CONNECT 1
287 # ifdef PHP_WIN32
288 typedef u_long php_non_blocking_flags_t;
289 # define SET_SOCKET_BLOCKING_MODE(sock, save) \
290 save = TRUE; ioctlsocket(sock, FIONBIO, &save)
291 # define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
292 ioctlsocket(sock, FIONBIO, &save)
293 # else
294 typedef int php_non_blocking_flags_t;
295 # define SET_SOCKET_BLOCKING_MODE(sock, save) \
296 save = fcntl(sock, F_GETFL, 0); \
297 fcntl(sock, F_SETFL, save | O_NONBLOCK)
298 # define RESTORE_SOCKET_BLOCKING_MODE(sock, save) \
299 fcntl(sock, F_SETFL, save)
300 # endif
301 #endif
302
303
304
305
306
307
308 PHPAPI int php_network_connect_socket(php_socket_t sockfd,
309 const struct sockaddr *addr,
310 socklen_t addrlen,
311 int asynchronous,
312 struct timeval *timeout,
313 zend_string **error_string,
314 int *error_code)
315 {
316 #if HAVE_NON_BLOCKING_CONNECT
317 php_non_blocking_flags_t orig_flags;
318 int n;
319 int error = 0;
320 socklen_t len;
321 int ret = 0;
322
323 SET_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
324
325 if ((n = connect(sockfd, addr, addrlen)) != 0) {
326 error = php_socket_errno();
327
328 if (error_code) {
329 *error_code = error;
330 }
331
332 if (error != EINPROGRESS) {
333 if (error_string) {
334 *error_string = php_socket_error_str(error);
335 }
336
337 return -1;
338 }
339 if (asynchronous && error == EINPROGRESS) {
340
341 return 0;
342 }
343 }
344
345 if (n == 0) {
346 goto ok;
347 }
348 # ifdef PHP_WIN32
349
350
351
352
353
354
355
356 if ((n = php_pollfd_for(sockfd, POLLOUT|POLLPRI, timeout)) == 0) {
357 #else
358 if ((n = php_pollfd_for(sockfd, PHP_POLLREADABLE|POLLOUT, timeout)) == 0) {
359 #endif
360 error = PHP_TIMEOUT_ERROR_VALUE;
361 }
362
363 if (n > 0) {
364 len = sizeof(error);
365
366
367
368
369 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*)&error, &len) != 0) {
370 ret = -1;
371 }
372 } else {
373
374 ret = -1;
375 }
376
377 ok:
378 if (!asynchronous) {
379
380 RESTORE_SOCKET_BLOCKING_MODE(sockfd, orig_flags);
381 }
382
383 if (error_code) {
384 *error_code = error;
385 }
386
387 if (error) {
388 ret = -1;
389 if (error_string) {
390 *error_string = php_socket_error_str(error);
391 }
392 }
393 return ret;
394 #else
395 if (asynchronous) {
396 php_error_docref(NULL, E_WARNING, "Asynchronous connect() not supported on this platform");
397 }
398 return (connect(sockfd, addr, addrlen) == 0) ? 0 : -1;
399 #endif
400 }
401
402
403
404 static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
405 {
406 result->tv_usec = a.tv_usec - b.tv_usec;
407 if (result->tv_usec < 0L) {
408 a.tv_sec--;
409 result->tv_usec += 1000000L;
410 }
411 result->tv_sec = a.tv_sec - b.tv_sec;
412 if (result->tv_sec < 0L) {
413 result->tv_sec++;
414 result->tv_usec -= 1000000L;
415 }
416 }
417
418
419
420
421
422
423 php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port,
424 int socktype, long sockopts, zend_string **error_string, int *error_code
425 )
426 {
427 int num_addrs, n, err = 0;
428 php_socket_t sock;
429 struct sockaddr **sal, **psal, *sa;
430 socklen_t socklen;
431 int sockoptval = 1;
432
433 num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
434
435 if (num_addrs == 0) {
436
437 return -1;
438 }
439
440 for (sal = psal; *sal != NULL; sal++) {
441 sa = *sal;
442
443
444 sock = socket(sa->sa_family, socktype, 0);
445
446 if (sock == SOCK_ERR) {
447 continue;
448 }
449
450 switch (sa->sa_family) {
451 #if HAVE_GETADDRINFO && HAVE_IPV6
452 case AF_INET6:
453 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
454 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
455 socklen = sizeof(struct sockaddr_in6);
456 break;
457 #endif
458 case AF_INET:
459 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
460 ((struct sockaddr_in *)sa)->sin_port = htons(port);
461 socklen = sizeof(struct sockaddr_in);
462 break;
463 default:
464
465 socklen = 0;
466 sa = NULL;
467 }
468
469 if (sa) {
470
471
472 #ifdef SO_REUSEADDR
473 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval));
474 #endif
475 #ifdef IPV6_V6ONLY
476 if (sockopts & STREAM_SOCKOP_IPV6_V6ONLY) {
477 int ipv6_val = !!(sockopts & STREAM_SOCKOP_IPV6_V6ONLY_ENABLED);
478 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ipv6_val, sizeof(sockoptval));
479 }
480 #endif
481 #ifdef SO_REUSEPORT
482 if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) {
483 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval));
484 }
485 #endif
486 #ifdef SO_BROADCAST
487 if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
488 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval));
489 }
490 #endif
491
492 n = bind(sock, sa, socklen);
493
494 if (n != SOCK_CONN_ERR) {
495 goto bound;
496 }
497
498 err = php_socket_errno();
499 }
500
501 closesocket(sock);
502 }
503 sock = -1;
504
505 if (error_code) {
506 *error_code = err;
507 }
508 if (error_string) {
509 *error_string = php_socket_error_str(err);
510 }
511
512 bound:
513
514 php_network_freeaddresses(psal);
515
516 return sock;
517
518 }
519
520
521 PHPAPI int php_network_parse_network_address_with_port(const char *addr, zend_long addrlen, struct sockaddr *sa, socklen_t *sl)
522 {
523 char *colon;
524 char *tmp;
525 int ret = FAILURE;
526 short port;
527 struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
528 struct sockaddr **psal;
529 int n;
530 zend_string *errstr = NULL;
531 #if HAVE_IPV6
532 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
533 #endif
534
535 if (*addr == '[') {
536 colon = memchr(addr + 1, ']', addrlen-1);
537 if (!colon || colon[1] != ':') {
538 return FAILURE;
539 }
540 port = atoi(colon + 2);
541 addr++;
542 } else {
543 colon = memchr(addr, ':', addrlen);
544 if (!colon) {
545 return FAILURE;
546 }
547 port = atoi(colon + 1);
548 }
549
550 tmp = estrndup(addr, colon - addr);
551
552
553
554 #if HAVE_IPV6 && HAVE_INET_PTON
555 if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
556 in6->sin6_port = htons(port);
557 in6->sin6_family = AF_INET6;
558 *sl = sizeof(struct sockaddr_in6);
559 ret = SUCCESS;
560 goto out;
561 }
562 #endif
563 if (inet_aton(tmp, &in4->sin_addr) > 0) {
564 in4->sin_port = htons(port);
565 in4->sin_family = AF_INET;
566 *sl = sizeof(struct sockaddr_in);
567 ret = SUCCESS;
568 goto out;
569 }
570
571
572 n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr);
573
574 if (n == 0) {
575 if (errstr) {
576 php_error_docref(NULL, E_WARNING, "Failed to resolve `%s': %s", tmp, ZSTR_VAL(errstr));
577 zend_string_release(errstr);
578 }
579 goto out;
580 }
581
582
583 switch ((*psal)->sa_family) {
584 #if HAVE_GETADDRINFO && HAVE_IPV6
585 case AF_INET6:
586 *in6 = **(struct sockaddr_in6**)psal;
587 in6->sin6_port = htons(port);
588 *sl = sizeof(struct sockaddr_in6);
589 ret = SUCCESS;
590 break;
591 #endif
592 case AF_INET:
593 *in4 = **(struct sockaddr_in**)psal;
594 in4->sin_port = htons(port);
595 *sl = sizeof(struct sockaddr_in);
596 ret = SUCCESS;
597 break;
598 }
599
600 php_network_freeaddresses(psal);
601
602 out:
603 efree(tmp);
604 return ret;
605 }
606
607
608 PHPAPI void php_network_populate_name_from_sockaddr(
609
610 struct sockaddr *sa, socklen_t sl,
611
612 zend_string **textaddr,
613
614 struct sockaddr **addr,
615 socklen_t *addrlen
616 )
617 {
618 if (addr) {
619 *addr = emalloc(sl);
620 memcpy(*addr, sa, sl);
621 *addrlen = sl;
622 }
623
624 if (textaddr) {
625 #if HAVE_IPV6 && HAVE_INET_NTOP
626 char abuf[256];
627 #endif
628 char *buf = NULL;
629
630 switch (sa->sa_family) {
631 case AF_INET:
632
633 buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
634 if (buf) {
635 *textaddr = strpprintf(0, "%s:%d",
636 buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
637 }
638
639 break;
640
641 #if HAVE_IPV6 && HAVE_INET_NTOP
642 case AF_INET6:
643 buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
644 if (buf) {
645 *textaddr = strpprintf(0, "%s:%d",
646 buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
647 }
648
649 break;
650 #endif
651 #ifdef AF_UNIX
652 case AF_UNIX:
653 {
654 struct sockaddr_un *ua = (struct sockaddr_un*)sa;
655
656 if (ua->sun_path[0] == '\0') {
657
658 int len = strlen(ua->sun_path + 1) + 1;
659 *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
660 } else {
661 int len = strlen(ua->sun_path);
662 *textaddr = zend_string_init((char*)ua->sun_path, len, 0);
663 }
664 }
665 break;
666 #endif
667
668 }
669
670 }
671 }
672
673 PHPAPI int php_network_get_peer_name(php_socket_t sock,
674 zend_string **textaddr,
675 struct sockaddr **addr,
676 socklen_t *addrlen
677 )
678 {
679 php_sockaddr_storage sa;
680 socklen_t sl = sizeof(sa);
681 memset(&sa, 0, sizeof(sa));
682
683 if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
684 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
685 textaddr,
686 addr, addrlen
687 );
688 return 0;
689 }
690 return -1;
691 }
692
693 PHPAPI int php_network_get_sock_name(php_socket_t sock,
694 zend_string **textaddr,
695 struct sockaddr **addr,
696 socklen_t *addrlen
697 )
698 {
699 php_sockaddr_storage sa;
700 socklen_t sl = sizeof(sa);
701 memset(&sa, 0, sizeof(sa));
702
703 if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
704 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
705 textaddr,
706 addr, addrlen
707 );
708 return 0;
709 }
710 return -1;
711
712 }
713
714
715
716
717
718
719
720
721
722
723
724 PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
725 zend_string **textaddr,
726 struct sockaddr **addr,
727 socklen_t *addrlen,
728 struct timeval *timeout,
729 zend_string **error_string,
730 int *error_code
731 )
732 {
733 php_socket_t clisock = -1;
734 int error = 0, n;
735 php_sockaddr_storage sa;
736 socklen_t sl;
737
738 n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
739
740 if (n == 0) {
741 error = PHP_TIMEOUT_ERROR_VALUE;
742 } else if (n == -1) {
743 error = php_socket_errno();
744 } else {
745 sl = sizeof(sa);
746
747 clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
748
749 if (clisock != SOCK_ERR) {
750 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
751 textaddr,
752 addr, addrlen
753 );
754 } else {
755 error = php_socket_errno();
756 }
757 }
758
759 if (error_code) {
760 *error_code = error;
761 }
762 if (error_string) {
763 *error_string = php_socket_error_str(error);
764 }
765
766 return clisock;
767 }
768
769
770
771
772
773
774
775
776
777
778
779 php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
780 int socktype, int asynchronous, struct timeval *timeout, zend_string **error_string,
781 int *error_code, char *bindto, unsigned short bindport, long sockopts
782 )
783 {
784 int num_addrs, n, fatal = 0;
785 php_socket_t sock;
786 struct sockaddr **sal, **psal, *sa;
787 struct timeval working_timeout;
788 socklen_t socklen;
789 #if HAVE_GETTIMEOFDAY
790 struct timeval limit_time, time_now;
791 #endif
792
793 num_addrs = php_network_getaddresses(host, socktype, &psal, error_string);
794
795 if (num_addrs == 0) {
796
797 return -1;
798 }
799
800 if (timeout) {
801 memcpy(&working_timeout, timeout, sizeof(working_timeout));
802 #if HAVE_GETTIMEOFDAY
803 gettimeofday(&limit_time, NULL);
804 limit_time.tv_sec += working_timeout.tv_sec;
805 limit_time.tv_usec += working_timeout.tv_usec;
806 if (limit_time.tv_usec >= 1000000) {
807 limit_time.tv_usec -= 1000000;
808 limit_time.tv_sec++;
809 }
810 #endif
811 }
812
813 for (sal = psal; !fatal && *sal != NULL; sal++) {
814 sa = *sal;
815
816
817 sock = socket(sa->sa_family, socktype, 0);
818
819 if (sock == SOCK_ERR) {
820 continue;
821 }
822
823 switch (sa->sa_family) {
824 #if HAVE_GETADDRINFO && HAVE_IPV6
825 case AF_INET6:
826 if (!bindto || strchr(bindto, ':')) {
827 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
828 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
829 socklen = sizeof(struct sockaddr_in6);
830 } else {
831 socklen = 0;
832 sa = NULL;
833 }
834 break;
835 #endif
836 case AF_INET:
837 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
838 ((struct sockaddr_in *)sa)->sin_port = htons(port);
839 socklen = sizeof(struct sockaddr_in);
840 break;
841 default:
842
843 socklen = 0;
844 sa = NULL;
845 }
846
847 if (sa) {
848
849
850 if (bindto) {
851 struct sockaddr *local_address = NULL;
852 int local_address_len = 0;
853
854 if (sa->sa_family == AF_INET) {
855 struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
856
857 local_address = (struct sockaddr*)in4;
858 local_address_len = sizeof(struct sockaddr_in);
859
860 in4->sin_family = sa->sa_family;
861 in4->sin_port = htons(bindport);
862 if (!inet_aton(bindto, &in4->sin_addr)) {
863 php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
864 goto skip_bind;
865 }
866 memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
867 }
868 #if HAVE_IPV6 && HAVE_INET_PTON
869 else {
870 struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
871
872 local_address = (struct sockaddr*)in6;
873 local_address_len = sizeof(struct sockaddr_in6);
874
875 in6->sin6_family = sa->sa_family;
876 in6->sin6_port = htons(bindport);
877 if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
878 php_error_docref(NULL, E_WARNING, "Invalid IP Address: %s", bindto);
879 goto skip_bind;
880 }
881 }
882 #endif
883
884 if (!local_address || bind(sock, local_address, local_address_len)) {
885 php_error_docref(NULL, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
886 }
887 skip_bind:
888 if (local_address) {
889 efree(local_address);
890 }
891 }
892
893 if (error_string && *error_string) {
894 zend_string_release(*error_string);
895 *error_string = NULL;
896 }
897
898 #ifdef SO_BROADCAST
899 {
900 int val = 1;
901 if (sockopts & STREAM_SOCKOP_SO_BROADCAST) {
902 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val));
903 }
904 }
905 #endif
906 n = php_network_connect_socket(sock, sa, socklen, asynchronous,
907 timeout ? &working_timeout : NULL,
908 error_string, error_code);
909
910 if (n != -1) {
911 goto connected;
912 }
913
914
915 #if HAVE_GETTIMEOFDAY
916 if (timeout) {
917 gettimeofday(&time_now, NULL);
918
919 if (timercmp(&time_now, &limit_time, >=)) {
920
921 fatal = 1;
922 } else {
923
924 sub_times(limit_time, time_now, &working_timeout);
925 }
926 }
927 #else
928 if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
929
930
931
932 fatal = 1;
933 } else {
934
935
936 if (timeout) {
937 memcpy(&working_timeout, timeout, sizeof(working_timeout));
938 }
939 }
940 #endif
941 }
942
943 closesocket(sock);
944 }
945 sock = -1;
946
947 connected:
948
949 php_network_freeaddresses(psal);
950
951 return sock;
952 }
953
954
955
956
957
958 PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
959 {
960 memset(addr, 0, sizeof(php_sockaddr_storage));
961 switch (family) {
962 #if HAVE_IPV6
963 case AF_INET6: {
964 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
965 sin6->sin6_family = AF_INET6;
966 sin6->sin6_port = htons(port);
967 sin6->sin6_addr = in6addr_any;
968 break;
969 }
970 #endif
971 case AF_INET: {
972 struct sockaddr_in *sin = (struct sockaddr_in *) addr;
973 sin->sin_family = AF_INET;
974 sin->sin_port = htons(port);
975 sin->sin_addr.s_addr = htonl(INADDR_ANY);
976 break;
977 }
978 }
979 }
980
981
982
983
984
985 PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
986 {
987 switch (((struct sockaddr *)addr)->sa_family) {
988 case AF_INET:
989 return sizeof(struct sockaddr_in);
990 #if HAVE_IPV6
991 case AF_INET6:
992 return sizeof(struct sockaddr_in6);
993 #endif
994 #ifdef AF_UNIX
995 case AF_UNIX:
996 return sizeof(struct sockaddr_un);
997 #endif
998 default:
999 return 0;
1000 }
1001 }
1002
1003
1004
1005
1006
1007
1008
1009
1010 PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
1011 {
1012 #ifndef PHP_WIN32
1013 char *errstr;
1014
1015 errstr = strerror(err);
1016 if (buf == NULL) {
1017 buf = estrdup(errstr);
1018 } else {
1019 strncpy(buf, errstr, bufsize);
1020 buf[bufsize?(bufsize-1):0] = 0;
1021 }
1022 return buf;
1023 #else
1024 char *sysbuf;
1025 int free_it = 1;
1026
1027 if (!FormatMessage(
1028 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1029 FORMAT_MESSAGE_FROM_SYSTEM |
1030 FORMAT_MESSAGE_IGNORE_INSERTS,
1031 NULL,
1032 err,
1033 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1034 (LPTSTR)&sysbuf,
1035 0,
1036 NULL)) {
1037 free_it = 0;
1038 sysbuf = "Unknown Error";
1039 }
1040
1041 if (buf == NULL) {
1042 buf = estrdup(sysbuf);
1043 } else {
1044 strncpy(buf, sysbuf, bufsize);
1045 buf[bufsize?(bufsize-1):0] = 0;
1046 }
1047
1048 if (free_it) {
1049 LocalFree(sysbuf);
1050 }
1051
1052 return buf;
1053 #endif
1054 }
1055
1056
1057
1058 PHPAPI zend_string *php_socket_error_str(long err)
1059 {
1060 #ifndef PHP_WIN32
1061 char *errstr;
1062
1063 errstr = strerror(err);
1064 return zend_string_init(errstr, strlen(errstr), 0);
1065 #else
1066 zend_string *ret;
1067 char *sysbuf;
1068 int free_it = 1;
1069
1070 if (!FormatMessage(
1071 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1072 FORMAT_MESSAGE_FROM_SYSTEM |
1073 FORMAT_MESSAGE_IGNORE_INSERTS,
1074 NULL,
1075 err,
1076 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1077 (LPTSTR)&sysbuf,
1078 0,
1079 NULL)) {
1080 free_it = 0;
1081 sysbuf = "Unknown Error";
1082 }
1083
1084 ret = zend_string_init(sysbuf, strlen(sysbuf), 0);
1085
1086 if (free_it) {
1087 LocalFree(sysbuf);
1088 }
1089
1090 return ret;
1091 #endif
1092 }
1093
1094
1095
1096 PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC)
1097 {
1098 php_stream *stream;
1099 php_netstream_data_t *sock;
1100
1101 sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
1102 memset(sock, 0, sizeof(php_netstream_data_t));
1103
1104 sock->is_blocked = 1;
1105 sock->timeout.tv_sec = FG(default_socket_timeout);
1106 sock->timeout.tv_usec = 0;
1107 sock->socket = socket;
1108
1109 stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
1110
1111 if (stream == NULL) {
1112 pefree(sock, persistent_id ? 1 : 0);
1113 } else {
1114 stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
1115 }
1116
1117 return stream;
1118 }
1119
1120 PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
1121 int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC)
1122 {
1123 char *res;
1124 zend_long reslen;
1125 php_stream *stream;
1126
1127 reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
1128
1129 stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
1130 STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
1131
1132 efree(res);
1133
1134 return stream;
1135 }
1136
1137 PHPAPI int php_set_sock_blocking(php_socket_t socketd, int block)
1138 {
1139 int ret = SUCCESS;
1140
1141 #ifdef PHP_WIN32
1142 u_long flags;
1143
1144
1145 flags = !block;
1146 if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
1147 ret = FAILURE;
1148 }
1149 #else
1150 int myflag = 0;
1151 int flags = fcntl(socketd, F_GETFL);
1152
1153 #ifdef O_NONBLOCK
1154 myflag = O_NONBLOCK;
1155 #elif defined(O_NDELAY)
1156 myflag = O_NDELAY;
1157 #endif
1158 if (!block) {
1159 flags |= myflag;
1160 } else {
1161 flags &= ~myflag;
1162 }
1163 if (fcntl(socketd, F_SETFL, flags) == -1) {
1164 ret = FAILURE;
1165 }
1166 #endif
1167 return ret;
1168 }
1169
1170 PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
1171 {
1172
1173 #ifdef PHP_WIN32
1174 php_error_docref(NULL, E_WARNING,
1175 "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
1176 "If this binary is from an official www.php.net package, file a bug report\n"
1177 "at http://bugs.php.net, including the following information:\n"
1178 "FD_SETSIZE=%d, but you are using %d.\n"
1179 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1180 "to match to maximum number of sockets each script will work with at\n"
1181 "one time, in order to avoid seeing this error again at a later date.",
1182 FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
1183 #else
1184 php_error_docref(NULL, E_WARNING,
1185 "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
1186 "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
1187 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1188 "to equal the maximum number of open files supported by your system,\n"
1189 "in order to avoid seeing this error again at a later date.",
1190 FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
1191 #endif
1192 }
1193
1194 #if defined(PHP_USE_POLL_2_EMULATION)
1195
1196
1197
1198 PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
1199 {
1200 fd_set rset, wset, eset;
1201 php_socket_t max_fd = SOCK_ERR;
1202 unsigned int i;
1203 int n;
1204 struct timeval tv;
1205
1206
1207 for (i = 0; i < nfds; i++) {
1208 if (ufds[i].fd > max_fd)
1209 max_fd = ufds[i].fd;
1210 }
1211
1212 PHP_SAFE_MAX_FD(max_fd, nfds + 1);
1213
1214 FD_ZERO(&rset);
1215 FD_ZERO(&wset);
1216 FD_ZERO(&eset);
1217
1218 for (i = 0; i < nfds; i++) {
1219 if (ufds[i].events & PHP_POLLREADABLE) {
1220 PHP_SAFE_FD_SET(ufds[i].fd, &rset);
1221 }
1222 if (ufds[i].events & POLLOUT) {
1223 PHP_SAFE_FD_SET(ufds[i].fd, &wset);
1224 }
1225 if (ufds[i].events & POLLPRI) {
1226 PHP_SAFE_FD_SET(ufds[i].fd, &eset);
1227 }
1228 }
1229
1230 if (timeout >= 0) {
1231 tv.tv_sec = timeout / 1000;
1232 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
1233 }
1234
1235 #ifdef PHP_WIN32
1236 WSASetLastError(0);
1237 #else
1238 errno = 0;
1239 #endif
1240 n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
1241
1242 if (n >= 0) {
1243 for (i = 0; i < nfds; i++) {
1244 ufds[i].revents = 0;
1245
1246 if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
1247
1248 ufds[i].revents |= POLLIN;
1249 }
1250 if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
1251 ufds[i].revents |= POLLOUT;
1252 }
1253 if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
1254 ufds[i].revents |= POLLPRI;
1255 }
1256 }
1257 }
1258 return n;
1259 }
1260
1261 #endif
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271