]> granicus.if.org Git - php/commitdiff
Added bindto socket context option.
authorIlia Alshanetsky <iliaa@php.net>
Tue, 14 Jun 2005 02:39:42 +0000 (02:39 +0000)
committerIlia Alshanetsky <iliaa@php.net>
Tue, 14 Jun 2005 02:39:42 +0000 (02:39 +0000)
NEWS
ext/ftp/ftp.c
main/network.c
main/php_network.h
main/streams/xp_socket.c

diff --git a/NEWS b/NEWS
index 24c25a004f420c591474815c5a6127cb0d493ab7..ad05bb1003d6107b0780dee202ad5213e9ae9d3b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? Jun 2005, PHP 5.1 Beta 2
+- Added bindto socket context option. (Ilia)
 - Fixed PDO shutdown problem (possible inifite loop running rollback on
   shutdown). (Wez)
 - Fixed PECL bug #3714 (beginTransaction doesn't work if you're in
index 208b6e79e740fda4139d401dae5d64e85febdff8..120ea20d42cbb5c24fd8becdb9b7b3f6d1d02c8f 100644 (file)
@@ -136,7 +136,7 @@ ftp_open(const char *host, short port, long timeout_sec TSRMLS_DC)
 
        ftp->fd = php_network_connect_socket_to_host(host,
                        (unsigned short) (port ? port : 21), SOCK_STREAM,
-                       0, &tv, NULL, NULL TSRMLS_CC);
+                       0, &tv, NULL, NULL, NULL, 0 TSRMLS_CC);
        if (ftp->fd == -1) {
                goto bail;
        }
index a89f87c1978a12a222416b7bed7fe44225f8a3b3..bf0ef35d8e1d64db2de2ee2a4745a98f5580e459 100644 (file)
@@ -722,7 +722,7 @@ PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock,
 /* {{{ php_network_connect_socket_to_host */
 php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
                int socktype, int asynchronous, struct timeval *timeout, char **error_string,
-               int *error_code
+               int *error_code, char *bindto, unsigned short bindport 
                TSRMLS_DC)
 {
        int num_addrs, n, fatal = 0;
@@ -785,7 +785,39 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short
 
                if (sa) {
                        /* make a connection attempt */
+
+                       if (bindto) {
+                               struct sockaddr local_address;
                        
+                               if (sa->sa_family == AF_INET) {
+                                       struct sockaddr_in *in4 = (struct sockaddr_in*)&local_address;
+                               
+                                       in4->sin_family = sa->sa_family;
+                                       in4->sin_port = htons(bindport);
+                                       if (!inet_aton(bindto, &in4->sin_addr)) {
+                                               goto bad_ip;
+                                       }
+                                       bzero(&(in4->sin_zero), 8);
+                               }
+#if HAVE_IPV6 && HAVE_INET_PTON
+                                else { /* IPV6 */
+                                       struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&local_address;
+                               
+                                       in6->sin6_family = sa->sa_family;
+                                       in6->sin6_port = htons(bindport);
+                                       if (inet_pton(AF_INET6, bindto, &in6->sin6_addr) < 1) {
+                                               goto bad_ip;
+                                       }
+                               }
+#endif
+                               if (bind(sock, &local_address, sizeof(struct sockaddr))) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno));
+                               }
+                               goto bind_done;
+bad_ip:
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid IP Address: %s", bindto);
+                       }
+bind_done:                     
                        n = php_network_connect_socket(sock, sa, socklen, asynchronous,
                                        timeout ? &working_timeout : NULL,
                                        error_string, error_code);
index d88fbc890dfeea424d9842adc11d92210b05c0a4..8b8eee65ef219116a3bbd3a87a76460250e75bf7 100644 (file)
@@ -223,7 +223,7 @@ typedef struct {
 BEGIN_EXTERN_C()
 PHPAPI php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short port,
                int socktype, int asynchronous, struct timeval *timeout, char **error_string,
-               int *error_code
+               int *error_code, char *bindto, unsigned short bindport 
                TSRMLS_DC);
 
 PHPAPI int php_network_connect_socket(php_socket_t sockfd,
index f67161698c788798969d20092408e06784c9e98d..c406599bfc74c0065e7c515d0c005a84d0b0ea38 100644 (file)
@@ -487,7 +487,7 @@ static inline int parse_unix_address(php_stream_xport_param *xparam, struct sock
 }
 #endif
 
-static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno TSRMLS_DC)
+static inline char *parse_ip_address_ex(const char *str, int str_len, int *portno, int get_err, char **err TSRMLS_DC)
 {
        char *colon;
        char *host = NULL;
@@ -495,27 +495,27 @@ static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno
 #ifdef HAVE_IPV6
        char *p;
 
-       if (*(xparam->inputs.name) == '[') {
+       if (*(str) == '[') {
                /* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
-               p = memchr(xparam->inputs.name + 1, ']', xparam->inputs.namelen - 2);
+               p = memchr(str + 1, ']', str_len - 2);
                if (!p || *(p + 1) != ':') {
-                       if (xparam->want_errortext) {
-                               spprintf(&xparam->outputs.error_text, 0, "Failed to parse IPv6 address \"%s\"", xparam->inputs.name);
+                       if (get_err) {
+                               spprintf(err, 0, "Failed to parse IPv6 address \"%s\"", str);
                        }
                        return NULL;
                }
                *portno = atoi(p + 2);
-               return estrndup(xparam->inputs.name + 1, p - xparam->inputs.name - 1);
+               return estrndup(str + 1, p - str - 1);
        }
 #endif
 
-       colon = memchr(xparam->inputs.name, ':', xparam->inputs.namelen - 1);
+       colon = memchr(str, ':', str_len - 1);
        if (colon) {
                *portno = atoi(colon + 1);
-               host = estrndup(xparam->inputs.name, colon - xparam->inputs.name);
+               host = estrndup(str, colon - str);
        } else {
-               if (xparam->want_errortext) {
-                       spprintf(&xparam->outputs.error_text, 0, "Failed to parse address \"%s\"", xparam->inputs.name);
+               if (get_err) {
+                       spprintf(err, 0, "Failed to parse address \"%s\"", str);
                }
                return NULL;
        }
@@ -523,6 +523,11 @@ static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno
        return host;
 }
 
+static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno TSRMLS_DC)
+{
+       return parse_ip_address_ex(xparam->inputs.name, xparam->inputs.namelen, portno, xparam->want_errortext, &xparam->outputs.error_text);
+}
+
 static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
                php_stream_xport_param *xparam TSRMLS_DC)
 {
@@ -572,10 +577,11 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *
 static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
                php_stream_xport_param *xparam TSRMLS_DC)
 {
-       char *host = NULL;
-       int portno;
+       char *host = NULL, *bindto = NULL;
+       int portno, bindport;
        int err;
        int ret;
+       zval **tmpzval = NULL;
 
 #ifdef AF_UNIX
        if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
@@ -610,6 +616,16 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
                return -1;
        }
 
+       if (stream->context && php_stream_context_get_option(stream->context, "socket", "bindto", &tmpzval) == SUCCESS) {
+               if (Z_TYPE_PP(tmpzval) != IS_STRING) {
+                       if (xparam->want_errortext) {
+                               spprintf(&xparam->outputs.error_text, 0, "local_addr context option is not a string.");
+                       }
+                       return -1;
+               }
+               bindto = parse_ip_address_ex(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC);
+       }
+
        /* Note: the test here for php_stream_udp_socket_ops is important, because we
         * want the default to be TCP sockets so that the openssl extension can
         * re-use this code. */
@@ -619,7 +635,9 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
                        xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC,
                        xparam->inputs.timeout,
                        xparam->want_errortext ? &xparam->outputs.error_text : NULL,
-                       &err
+                       &err,
+                       bindto,
+                       bindport
                        TSRMLS_CC);
        
        ret = sock->socket == -1 ? -1 : 0;
@@ -628,6 +646,9 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
        if (host) {
                efree(host);
        }
+       if (bindto) {
+               efree(bindto);
+       }
 
 #ifdef AF_UNIX
 out: