From: Ilia Alshanetsky Date: Tue, 14 Jun 2005 02:39:42 +0000 (+0000) Subject: Added bindto socket context option. X-Git-Tag: php-5.1.0b2~208 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b36d4ae02c918118c9e93ac44f6d792e79a26129;p=php Added bindto socket context option. --- diff --git a/NEWS b/NEWS index 24c25a004f..ad05bb1003 100644 --- 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 diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 208b6e79e7..120ea20d42 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -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; } diff --git a/main/network.c b/main/network.c index a89f87c197..bf0ef35d8e 100644 --- a/main/network.c +++ b/main/network.c @@ -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); diff --git a/main/php_network.h b/main/php_network.h index d88fbc890d..8b8eee65ef 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -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, diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index f67161698c..c406599bfc 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -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: