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_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, char **error_string TSRMLS_DC)
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 spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed: %s", PHP_GAI_STRERROR(n));
216 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
217 } else {
218 php_error_docref(NULL TSRMLS_CC, 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 spprintf(error_string, 0, "php_network_getaddresses: getaddrinfo failed (null result pointer) errno=%d", errno);
224 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
225 } else {
226 php_error_docref(NULL TSRMLS_CC, 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 spprintf(error_string, 0, "php_network_getaddresses: gethostbyname failed. errno=%d", errno);
258 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", *error_string);
259 } else {
260 php_error_docref(NULL TSRMLS_CC, 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 char **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_strerror(error, NULL, 0);
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_strerror(error, NULL, 0);
391 }
392 }
393 return ret;
394 #else
395 if (asynchronous) {
396 php_error_docref(NULL TSRMLS_CC, 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, char **error_string, int *error_code
425 TSRMLS_DC)
426 {
427 int num_addrs, n, err = 0;
428 php_socket_t sock;
429 struct sockaddr **sal, **psal, *sa;
430 socklen_t socklen;
431
432 num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC);
433
434 if (num_addrs == 0) {
435
436 return -1;
437 }
438
439 for (sal = psal; *sal != NULL; sal++) {
440 sa = *sal;
441
442
443 sock = socket(sa->sa_family, socktype, 0);
444
445 if (sock == SOCK_ERR) {
446 continue;
447 }
448
449 switch (sa->sa_family) {
450 #if HAVE_GETADDRINFO && HAVE_IPV6
451 case AF_INET6:
452 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
453 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
454 socklen = sizeof(struct sockaddr_in6);
455 break;
456 #endif
457 case AF_INET:
458 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
459 ((struct sockaddr_in *)sa)->sin_port = htons(port);
460 socklen = sizeof(struct sockaddr_in);
461 break;
462 default:
463
464 socklen = 0;
465 sa = NULL;
466 }
467
468 if (sa) {
469
470
471 #ifdef SO_REUSEADDR
472 {
473 int val = 1;
474 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val));
475 }
476 #endif
477
478 n = bind(sock, sa, socklen);
479
480 if (n != SOCK_CONN_ERR) {
481 goto bound;
482 }
483
484 err = php_socket_errno();
485 }
486
487 closesocket(sock);
488 }
489 sock = -1;
490
491 if (error_code) {
492 *error_code = err;
493 }
494 if (error_string) {
495 *error_string = php_socket_strerror(err, NULL, 0);
496 }
497
498 bound:
499
500 php_network_freeaddresses(psal);
501
502 return sock;
503
504 }
505
506
507 PHPAPI int php_network_parse_network_address_with_port(const char *addr, long addrlen, struct sockaddr *sa, socklen_t *sl TSRMLS_DC)
508 {
509 char *colon;
510 char *tmp;
511 int ret = FAILURE;
512 short port;
513 struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
514 struct sockaddr **psal;
515 int n;
516 char *errstr = NULL;
517 #if HAVE_IPV6
518 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
519 #endif
520
521 if (*addr == '[') {
522 colon = memchr(addr + 1, ']', addrlen-1);
523 if (!colon || colon[1] != ':') {
524 return FAILURE;
525 }
526 port = atoi(colon + 2);
527 addr++;
528 } else {
529 colon = memchr(addr, ':', addrlen);
530 if (!colon) {
531 return FAILURE;
532 }
533 port = atoi(colon + 1);
534 }
535
536 tmp = estrndup(addr, colon - addr);
537
538
539
540 #if HAVE_IPV6 && HAVE_INET_PTON
541 if (inet_pton(AF_INET6, tmp, &in6->sin6_addr) > 0) {
542 in6->sin6_port = htons(port);
543 in6->sin6_family = AF_INET6;
544 *sl = sizeof(struct sockaddr_in6);
545 ret = SUCCESS;
546 goto out;
547 }
548 #endif
549 if (inet_aton(tmp, &in4->sin_addr) > 0) {
550 in4->sin_port = htons(port);
551 in4->sin_family = AF_INET;
552 *sl = sizeof(struct sockaddr_in);
553 ret = SUCCESS;
554 goto out;
555 }
556
557
558 n = php_network_getaddresses(tmp, SOCK_DGRAM, &psal, &errstr TSRMLS_CC);
559
560 if (n == 0) {
561 if (errstr) {
562 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to resolve `%s': %s", tmp, errstr);
563 STR_FREE(errstr);
564 }
565 goto out;
566 }
567
568
569 switch ((*psal)->sa_family) {
570 #if HAVE_GETADDRINFO && HAVE_IPV6
571 case AF_INET6:
572 *in6 = **(struct sockaddr_in6**)psal;
573 in6->sin6_port = htons(port);
574 *sl = sizeof(struct sockaddr_in6);
575 ret = SUCCESS;
576 break;
577 #endif
578 case AF_INET:
579 *in4 = **(struct sockaddr_in**)psal;
580 in4->sin_port = htons(port);
581 *sl = sizeof(struct sockaddr_in);
582 ret = SUCCESS;
583 break;
584 }
585
586 php_network_freeaddresses(psal);
587
588 out:
589 STR_FREE(tmp);
590 return ret;
591 }
592
593
594 PHPAPI void php_network_populate_name_from_sockaddr(
595
596 struct sockaddr *sa, socklen_t sl,
597
598 char **textaddr, long *textaddrlen,
599
600 struct sockaddr **addr,
601 socklen_t *addrlen
602 TSRMLS_DC)
603 {
604 if (addr) {
605 *addr = emalloc(sl);
606 memcpy(*addr, sa, sl);
607 *addrlen = sl;
608 }
609
610 if (textaddr) {
611 #if HAVE_IPV6 && HAVE_INET_NTOP
612 char abuf[256];
613 #endif
614 char *buf = NULL;
615
616 switch (sa->sa_family) {
617 case AF_INET:
618
619 buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
620 if (buf) {
621 *textaddrlen = spprintf(textaddr, 0, "%s:%d",
622 buf, ntohs(((struct sockaddr_in*)sa)->sin_port));
623 }
624
625 break;
626
627 #if HAVE_IPV6 && HAVE_INET_NTOP
628 case AF_INET6:
629 buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
630 if (buf) {
631 *textaddrlen = spprintf(textaddr, 0, "%s:%d",
632 buf, ntohs(((struct sockaddr_in6*)sa)->sin6_port));
633 }
634
635 break;
636 #endif
637 #ifdef AF_UNIX
638 case AF_UNIX:
639 {
640 struct sockaddr_un *ua = (struct sockaddr_un*)sa;
641
642 if (ua->sun_path[0] == '\0') {
643
644 int len = strlen(ua->sun_path + 1) + 1;
645 *textaddrlen = len;
646 *textaddr = emalloc(len + 1);
647 memcpy(*textaddr, ua->sun_path, len);
648 (*textaddr)[len] = '\0';
649 } else {
650 *textaddrlen = strlen(ua->sun_path);
651 *textaddr = estrndup(ua->sun_path, *textaddrlen);
652 }
653 }
654 break;
655 #endif
656
657 }
658
659 }
660 }
661
662 PHPAPI int php_network_get_peer_name(php_socket_t sock,
663 char **textaddr, long *textaddrlen,
664 struct sockaddr **addr,
665 socklen_t *addrlen
666 TSRMLS_DC)
667 {
668 php_sockaddr_storage sa;
669 socklen_t sl = sizeof(sa);
670 memset(&sa, 0, sizeof(sa));
671
672 if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
673 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
674 textaddr, textaddrlen,
675 addr, addrlen
676 TSRMLS_CC);
677 return 0;
678 }
679 return -1;
680 }
681
682 PHPAPI int php_network_get_sock_name(php_socket_t sock,
683 char **textaddr, long *textaddrlen,
684 struct sockaddr **addr,
685 socklen_t *addrlen
686 TSRMLS_DC)
687 {
688 php_sockaddr_storage sa;
689 socklen_t sl = sizeof(sa);
690 memset(&sa, 0, sizeof(sa));
691
692 if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
693 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
694 textaddr, textaddrlen,
695 addr, addrlen
696 TSRMLS_CC);
697 return 0;
698 }
699 return -1;
700
701 }
702
703
704
705
706
707
708
709
710
711
712
713 PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
714 char **textaddr, long *textaddrlen,
715 struct sockaddr **addr,
716 socklen_t *addrlen,
717 struct timeval *timeout,
718 char **error_string,
719 int *error_code
720 TSRMLS_DC)
721 {
722 php_socket_t clisock = -1;
723 int error = 0, n;
724 php_sockaddr_storage sa;
725 socklen_t sl;
726
727 n = php_pollfd_for(srvsock, PHP_POLLREADABLE, timeout);
728
729 if (n == 0) {
730 error = PHP_TIMEOUT_ERROR_VALUE;
731 } else if (n == -1) {
732 error = php_socket_errno();
733 } else {
734 sl = sizeof(sa);
735
736 clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
737
738 if (clisock != SOCK_ERR) {
739 php_network_populate_name_from_sockaddr((struct sockaddr*)&sa, sl,
740 textaddr, textaddrlen,
741 addr, addrlen
742 TSRMLS_CC);
743 } else {
744 error = php_socket_errno();
745 }
746 }
747
748 if (error_code) {
749 *error_code = error;
750 }
751 if (error_string) {
752 *error_string = php_socket_strerror(error, NULL, 0);
753 }
754
755 return clisock;
756 }
757
758
759
760
761
762
763
764
765
766
767
768 php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
769 int socktype, int asynchronous, struct timeval *timeout, char **error_string,
770 int *error_code, char *bindto, unsigned short bindport
771 TSRMLS_DC)
772 {
773 int num_addrs, n, fatal = 0;
774 php_socket_t sock;
775 struct sockaddr **sal, **psal, *sa;
776 struct timeval working_timeout;
777 socklen_t socklen;
778 #if HAVE_GETTIMEOFDAY
779 struct timeval limit_time, time_now;
780 #endif
781
782 num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC);
783
784 if (num_addrs == 0) {
785
786 return -1;
787 }
788
789 if (timeout) {
790 memcpy(&working_timeout, timeout, sizeof(working_timeout));
791 #if HAVE_GETTIMEOFDAY
792 gettimeofday(&limit_time, NULL);
793 limit_time.tv_sec += working_timeout.tv_sec;
794 limit_time.tv_usec += working_timeout.tv_usec;
795 if (limit_time.tv_usec >= 1000000) {
796 limit_time.tv_usec -= 1000000;
797 limit_time.tv_sec++;
798 }
799 #endif
800 }
801
802 for (sal = psal; !fatal && *sal != NULL; sal++) {
803 sa = *sal;
804
805
806 sock = socket(sa->sa_family, socktype, 0);
807
808 if (sock == SOCK_ERR) {
809 continue;
810 }
811
812 switch (sa->sa_family) {
813 #if HAVE_GETADDRINFO && HAVE_IPV6
814 case AF_INET6:
815 if (!bindto || strchr(bindto, ':')) {
816 ((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
817 ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
818 socklen = sizeof(struct sockaddr_in6);
819 } else {
820 socklen = 0;
821 sa = NULL;
822 }
823 break;
824 #endif
825 case AF_INET:
826 ((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
827 ((struct sockaddr_in *)sa)->sin_port = htons(port);
828 socklen = sizeof(struct sockaddr_in);
829 break;
830 default:
831
832 socklen = 0;
833 sa = NULL;
834 }
835
836 if (sa) {
837
838
839 if (bindto) {
840 struct sockaddr *local_address = NULL;
841 int local_address_len = 0;
842
843 if (sa->sa_family == AF_INET) {
844 struct sockaddr_in *in4 = emalloc(sizeof(struct sockaddr_in));
845
846 local_address = (struct sockaddr*)in4;
847 local_address_len = sizeof(struct sockaddr_in);
848
849 in4->sin_family = sa->sa_family;
850 in4->sin_port = htons(bindport);
851 if (!inet_aton(bindto, &in4->sin_addr)) {
852 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
853 goto skip_bind;
854 }
855 memset(&(in4->sin_zero), 0, sizeof(in4->sin_zero));
856 }
857 #if HAVE_IPV6 && HAVE_INET_PTON
858 else {
859 struct sockaddr_in6 *in6 = emalloc(sizeof(struct sockaddr_in6));
860
861 local_address = (struct sockaddr*)in6;
862 local_address_len = sizeof(struct sockaddr_in6);
863
864 in6->sin6_family = sa->sa_family;
865 in6->sin6_port = htons(bindport);
866 if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
867 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
868 goto skip_bind;
869 }
870 }
871 #endif
872 if (!local_address || bind(sock, local_address, local_address_len)) {
873 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
874 }
875 skip_bind:
876 if (local_address) {
877 efree(local_address);
878 }
879 }
880
881 if (error_string && *error_string) {
882 efree(*error_string);
883 *error_string = NULL;
884 }
885
886 n = php_network_connect_socket(sock, sa, socklen, asynchronous,
887 timeout ? &working_timeout : NULL,
888 error_string, error_code);
889
890 if (n != -1) {
891 goto connected;
892 }
893
894
895 #if HAVE_GETTIMEOFDAY
896 if (timeout) {
897 gettimeofday(&time_now, NULL);
898
899 if (timercmp(&time_now, &limit_time, >=)) {
900
901 fatal = 1;
902 } else {
903
904 sub_times(limit_time, time_now, &working_timeout);
905 }
906 }
907 #else
908 if (error_code && *error_code == PHP_TIMEOUT_ERROR_VALUE) {
909
910
911
912 fatal = 1;
913 } else {
914
915
916 if (timeout) {
917 memcpy(&working_timeout, timeout, sizeof(working_timeout));
918 }
919 }
920 #endif
921 }
922
923 closesocket(sock);
924 }
925 sock = -1;
926
927 connected:
928
929 php_network_freeaddresses(psal);
930
931 return sock;
932 }
933
934
935
936
937
938 PHPAPI void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port)
939 {
940 memset(addr, 0, sizeof(php_sockaddr_storage));
941 switch (family) {
942 #if HAVE_IPV6
943 case AF_INET6: {
944 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
945 sin6->sin6_family = AF_INET6;
946 sin6->sin6_port = htons(port);
947 sin6->sin6_addr = in6addr_any;
948 break;
949 }
950 #endif
951 case AF_INET: {
952 struct sockaddr_in *sin = (struct sockaddr_in *) addr;
953 sin->sin_family = AF_INET;
954 sin->sin_port = htons(port);
955 sin->sin_addr.s_addr = htonl(INADDR_ANY);
956 break;
957 }
958 }
959 }
960
961
962
963
964
965 PHPAPI int php_sockaddr_size(php_sockaddr_storage *addr)
966 {
967 switch (((struct sockaddr *)addr)->sa_family) {
968 case AF_INET:
969 return sizeof(struct sockaddr_in);
970 #if HAVE_IPV6
971 case AF_INET6:
972 return sizeof(struct sockaddr_in6);
973 #endif
974 #ifdef AF_UNIX
975 case AF_UNIX:
976 return sizeof(struct sockaddr_un);
977 #endif
978 default:
979 return 0;
980 }
981 }
982
983
984
985
986
987
988
989
990 PHPAPI char *php_socket_strerror(long err, char *buf, size_t bufsize)
991 {
992 #ifndef PHP_WIN32
993 char *errstr;
994
995 errstr = strerror(err);
996 if (buf == NULL) {
997 buf = estrdup(errstr);
998 } else {
999 strncpy(buf, errstr, bufsize);
1000 buf[bufsize?(bufsize-1):0] = 0;
1001 }
1002 return buf;
1003 #else
1004 char *sysbuf;
1005 int free_it = 1;
1006
1007 if (!FormatMessage(
1008 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1009 FORMAT_MESSAGE_FROM_SYSTEM |
1010 FORMAT_MESSAGE_IGNORE_INSERTS,
1011 NULL,
1012 err,
1013 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1014 (LPTSTR)&sysbuf,
1015 0,
1016 NULL)) {
1017 free_it = 0;
1018 sysbuf = "Unknown Error";
1019 }
1020
1021 if (buf == NULL) {
1022 buf = estrdup(sysbuf);
1023 } else {
1024 strncpy(buf, sysbuf, bufsize);
1025 buf[bufsize?(bufsize-1):0] = 0;
1026 }
1027
1028 if (free_it) {
1029 LocalFree(sysbuf);
1030 }
1031
1032 return buf;
1033 #endif
1034 }
1035
1036
1037
1038 PHPAPI php_stream *_php_stream_sock_open_from_socket(php_socket_t socket, const char *persistent_id STREAMS_DC TSRMLS_DC)
1039 {
1040 php_stream *stream;
1041 php_netstream_data_t *sock;
1042
1043 sock = pemalloc(sizeof(php_netstream_data_t), persistent_id ? 1 : 0);
1044 memset(sock, 0, sizeof(php_netstream_data_t));
1045
1046 sock->is_blocked = 1;
1047 sock->timeout.tv_sec = FG(default_socket_timeout);
1048 sock->timeout.tv_usec = 0;
1049 sock->socket = socket;
1050
1051 stream = php_stream_alloc_rel(&php_stream_generic_socket_ops, sock, persistent_id, "r+");
1052
1053 if (stream == NULL) {
1054 pefree(sock, persistent_id ? 1 : 0);
1055 } else {
1056 stream->flags |= PHP_STREAM_FLAG_AVOID_BLOCKING;
1057 }
1058
1059 return stream;
1060 }
1061
1062 PHPAPI php_stream *_php_stream_sock_open_host(const char *host, unsigned short port,
1063 int socktype, struct timeval *timeout, const char *persistent_id STREAMS_DC TSRMLS_DC)
1064 {
1065 char *res;
1066 long reslen;
1067 php_stream *stream;
1068
1069 reslen = spprintf(&res, 0, "tcp://%s:%d", host, port);
1070
1071 stream = php_stream_xport_create(res, reslen, REPORT_ERRORS,
1072 STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, persistent_id, timeout, NULL, NULL, NULL);
1073
1074 efree(res);
1075
1076 return stream;
1077 }
1078
1079 PHPAPI int php_set_sock_blocking(int socketd, int block TSRMLS_DC)
1080 {
1081 int ret = SUCCESS;
1082 int flags;
1083 int myflag = 0;
1084
1085 #ifdef PHP_WIN32
1086
1087 flags = !block;
1088 if (ioctlsocket(socketd, FIONBIO, &flags) == SOCKET_ERROR) {
1089 ret = FAILURE;
1090 }
1091 #else
1092 flags = fcntl(socketd, F_GETFL);
1093 #ifdef O_NONBLOCK
1094 myflag = O_NONBLOCK;
1095 #elif defined(O_NDELAY)
1096 myflag = O_NDELAY;
1097 #endif
1098 if (!block) {
1099 flags |= myflag;
1100 } else {
1101 flags &= ~myflag;
1102 }
1103 if (fcntl(socketd, F_SETFL, flags) == -1) {
1104 ret = FAILURE;
1105 }
1106 #endif
1107 return ret;
1108 }
1109
1110 PHPAPI void _php_emit_fd_setsize_warning(int max_fd)
1111 {
1112 TSRMLS_FETCH();
1113
1114 #ifdef PHP_WIN32
1115 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1116 "PHP needs to be recompiled with a larger value of FD_SETSIZE.\n"
1117 "If this binary is from an official www.php.net package, file a bug report\n"
1118 "at http://bugs.php.net, including the following information:\n"
1119 "FD_SETSIZE=%d, but you are using %d.\n"
1120 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1121 "to match to maximum number of sockets each script will work with at\n"
1122 "one time, in order to avoid seeing this error again at a later date.",
1123 FD_SETSIZE, max_fd, (max_fd + 128) & ~127);
1124 #else
1125 php_error_docref(NULL TSRMLS_CC, E_WARNING,
1126 "You MUST recompile PHP with a larger value of FD_SETSIZE.\n"
1127 "It is set to %d, but you have descriptors numbered at least as high as %d.\n"
1128 " --enable-fd-setsize=%d is recommended, but you may want to set it\n"
1129 "to equal the maximum number of open files supported by your system,\n"
1130 "in order to avoid seeing this error again at a later date.",
1131 FD_SETSIZE, max_fd, (max_fd + 1024) & ~1023);
1132 #endif
1133 }
1134
1135 #if defined(PHP_USE_POLL_2_EMULATION)
1136
1137
1138
1139 PHPAPI int php_poll2(php_pollfd *ufds, unsigned int nfds, int timeout)
1140 {
1141 fd_set rset, wset, eset;
1142 php_socket_t max_fd = SOCK_ERR;
1143 unsigned int i;
1144 int n;
1145 struct timeval tv;
1146
1147
1148 for (i = 0; i < nfds; i++) {
1149 if (ufds[i].fd > max_fd)
1150 max_fd = ufds[i].fd;
1151 }
1152
1153 PHP_SAFE_MAX_FD(max_fd, nfds + 1);
1154
1155 FD_ZERO(&rset);
1156 FD_ZERO(&wset);
1157 FD_ZERO(&eset);
1158
1159 for (i = 0; i < nfds; i++) {
1160 if (ufds[i].events & PHP_POLLREADABLE) {
1161 PHP_SAFE_FD_SET(ufds[i].fd, &rset);
1162 }
1163 if (ufds[i].events & POLLOUT) {
1164 PHP_SAFE_FD_SET(ufds[i].fd, &wset);
1165 }
1166 if (ufds[i].events & POLLPRI) {
1167 PHP_SAFE_FD_SET(ufds[i].fd, &eset);
1168 }
1169 }
1170
1171 if (timeout >= 0) {
1172 tv.tv_sec = timeout / 1000;
1173 tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000;
1174 }
1175
1176 #ifdef PHP_WIN32
1177 WSASetLastError(0);
1178 #else
1179 errno = 0;
1180 #endif
1181 n = select(max_fd + 1, &rset, &wset, &eset, timeout >= 0 ? &tv : NULL);
1182
1183 if (n >= 0) {
1184 for (i = 0; i < nfds; i++) {
1185 ufds[i].revents = 0;
1186
1187 if (PHP_SAFE_FD_ISSET(ufds[i].fd, &rset)) {
1188
1189 ufds[i].revents |= POLLIN;
1190 }
1191 if (PHP_SAFE_FD_ISSET(ufds[i].fd, &wset)) {
1192 ufds[i].revents |= POLLOUT;
1193 }
1194 if (PHP_SAFE_FD_ISSET(ufds[i].fd, &eset)) {
1195 ufds[i].revents |= POLLPRI;
1196 }
1197 }
1198 }
1199 return n;
1200 }
1201
1202 #endif
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212