diff options
author | Daniel Lowrey <rdlowrey@php.net> | 2014-08-04 12:41:51 -0400 |
---|---|---|
committer | Daniel Lowrey <rdlowrey@php.net> | 2014-08-05 23:13:04 -0400 |
commit | a51bf0cadf7862d10b2cc19cae2c991d24d670b1 (patch) | |
tree | 249332785260201b944727d852f0bb84315acc9d | |
parent | 29eb0ea68605e81822e34d5a95443f2c176b2c73 (diff) | |
download | php-git-a51bf0cadf7862d10b2cc19cae2c991d24d670b1.tar.gz |
Add SO_REUSEPORT + SO_BROADCAST support via socket stream context option
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | UPGRADING | 7 | ||||
-rw-r--r-- | ext/ftp/ftp.c | 2 | ||||
-rw-r--r-- | main/network.c | 27 | ||||
-rw-r--r-- | main/php_network.h | 9 | ||||
-rw-r--r-- | main/streams/xp_socket.c | 36 |
6 files changed, 76 insertions, 9 deletions
@@ -21,6 +21,10 @@ PHP NEWS - SPL: . Revert fix for bug #67064 (BC issues). (Bob) +- Streams: + . Expose so_reuseport and so_broadcast capability via socket context option + assignment. (Daniel Lowrey) + - Zlib: . Fixed bug #67724 (chained zlib filters silently fail with large amounts of data). (Mike) @@ -151,6 +151,13 @@ PHP 5.6 UPGRADE NOTES - Non-blocking read/write query behavior now optionally available in database operations using the ext/pgsql extension. +- Stream socket servers may now use SO_REUSEPORT in systems that support the + option to bind on the same address/port in separate processes via a new + "so_reuseport" socket context option. + +- UDP stream servers and clients may now enable SO_BROADCAST via a new + "so_broadcast" socket context option. + ======================================== 3. Changes in SAPI modules ======================================== diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 558463b845..d05f0eec71 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, NULL, 0 TSRMLS_CC); + 0, &tv, NULL, NULL, NULL, 0, STREAM_SOCKOP_NONE TSRMLS_CC); if (ftp->fd == -1) { goto bail; } diff --git a/main/network.c b/main/network.c index fc2a94badd..39f5a22f48 100644 --- a/main/network.c +++ b/main/network.c @@ -416,13 +416,14 @@ static inline void sub_times(struct timeval a, struct timeval b, struct timeval * */ /* {{{ php_network_bind_socket_to_local_addr */ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, - int socktype, char **error_string, int *error_code + int socktype, long sockopts, char **error_string, int *error_code TSRMLS_DC) { int num_addrs, n, err = 0; php_socket_t sock; struct sockaddr **sal, **psal, *sa; socklen_t socklen; + int sockoptval = 1; num_addrs = php_network_getaddresses(host, socktype, &psal, error_string TSRMLS_CC); @@ -464,9 +465,16 @@ php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned po /* attempt to bind */ #ifdef SO_REUSEADDR - { - int val = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&val, sizeof(val)); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&sockoptval, sizeof(sockoptval)); +#endif +#ifdef SO_REUSEPORT + if (sockopts & STREAM_SOCKOP_SO_REUSEPORT) { + setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char*)&sockoptval, sizeof(sockoptval)); + } +#endif +#ifdef SO_BROADCAST + if (sockopts & STREAM_SOCKOP_SO_BROADCAST) { + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&sockoptval, sizeof(sockoptval)); } #endif @@ -762,7 +770,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, char *bindto, unsigned short bindport + int *error_code, char *bindto, unsigned short bindport, long sockopts TSRMLS_DC) { int num_addrs, n, fatal = 0; @@ -864,6 +872,7 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short } } #endif + if (!local_address || bind(sock, local_address, local_address_len)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to bind to '%s:%d', system said: %s", bindto, bindport, strerror(errno)); } @@ -878,6 +887,14 @@ skip_bind: *error_string = NULL; } +#ifdef SO_BROADCAST + { + int val = 1; + if (sockopts & STREAM_SOCKOP_SO_BROADCAST) { + setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&val, sizeof(val)); + } + } +#endif 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 d69bba308a..95299e63da 100644 --- a/main/php_network.h +++ b/main/php_network.h @@ -105,6 +105,11 @@ typedef int php_socket_t; # define SOCK_RECV_ERR -1 #endif +#define STREAM_SOCKOP_NONE 1 << 0 +#define STREAM_SOCKOP_SO_REUSEPORT 1 << 1 +#define STREAM_SOCKOP_SO_BROADCAST 1 << 2 + + /* uncomment this to debug poll(2) emulation on systems that have poll(2) */ /* #define PHP_USE_POLL_2_EMULATION 1 */ @@ -229,7 +234,7 @@ PHPAPI void php_network_freeaddresses(struct sockaddr **sal); 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, char *bindto, unsigned short bindport + int *error_code, char *bindto, unsigned short bindport, long sockopts TSRMLS_DC); PHPAPI int php_network_connect_socket(php_socket_t sockfd, @@ -244,7 +249,7 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd, php_network_connect_socket((sock), (addr), (addrlen), 0, (timeout), NULL, NULL) PHPAPI php_socket_t php_network_bind_socket_to_local_addr(const char *host, unsigned port, - int socktype, char **error_string, int *error_code + int socktype, long sockopts, char **error_string, int *error_code TSRMLS_DC); PHPAPI php_socket_t php_network_accept_incoming(php_socket_t srvsock, diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index a6dc115962..c7b5a7098d 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -570,6 +570,8 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * { char *host = NULL; int portno, err; + long sockopts = STREAM_SOCKOP_NONE; + zval **tmpzval = NULL; #ifdef AF_UNIX if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) { @@ -599,8 +601,28 @@ static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t * return -1; } +#ifdef SO_REUSEPORT + if (stream->context + && php_stream_context_get_option(stream->context, "socket", "so_reuseport", &tmpzval) == SUCCESS + && zend_is_true(*tmpzval) + ) { + sockopts |= STREAM_SOCKOP_SO_REUSEPORT; + } +#endif + +#ifdef SO_BROADCAST + if (&php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */ + && stream->context + && php_stream_context_get_option(stream->context, "socket", "so_broadcast", &tmpzval) == SUCCESS + && zend_is_true(*tmpzval) + ) { + sockopts |= STREAM_SOCKOP_SO_BROADCAST; + } +#endif + sock->socket = php_network_bind_socket_to_local_addr(host, portno, stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM, + sockopts, xparam->want_errortext ? &xparam->outputs.error_text : NULL, &err TSRMLS_CC); @@ -620,6 +642,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ int err = 0; int ret; zval **tmpzval = NULL; + long sockopts = STREAM_SOCKOP_NONE; #ifdef AF_UNIX if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) { @@ -665,6 +688,16 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ bindto = parse_ip_address_ex(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), &bindport, xparam->want_errortext, &xparam->outputs.error_text TSRMLS_CC); } +#ifdef SO_BROADCAST + if (&php_stream_udp_socket_ops /* SO_BROADCAST is only applicable for UDP */ + && stream->context + && php_stream_context_get_option(stream->context, "socket", "so_broadcast", &tmpzval) == SUCCESS + && zend_is_true(*tmpzval) + ) { + sockopts |= STREAM_SOCKOP_SO_BROADCAST; + } +#endif + /* 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. */ @@ -676,7 +709,8 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_ xparam->want_errortext ? &xparam->outputs.error_text : NULL, &err, bindto, - bindport + bindport, + sockopts TSRMLS_CC); ret = sock->socket == -1 ? -1 : 0; |