mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
New user-space functions:
. stream_socket_client() - similar to fsockopen(), but more powerful. . stream_socket_server() - Creates a server socket. . stream_socket_accept() - Accept a client connection. . stream_socket_get_name() - Get local or remote name of socket. Tidy up some leaks and debug printfs. Move more streams functions into streamsfuncs.c and streamsfuncs.h.
This commit is contained in:
parent
14bf872003
commit
1b53a2d12e
10
NEWS
10
NEWS
@ -21,8 +21,16 @@ PHP 4 NEWS
|
|||||||
of the specified parameters to be passed as extra parameters to the sendmail
|
of the specified parameters to be passed as extra parameters to the sendmail
|
||||||
binary. These parameters will always replace the value of the 5th parameter
|
binary. These parameters will always replace the value of the 5th parameter
|
||||||
to mail(), even in safe mode. (Derick)
|
to mail(), even in safe mode. (Derick)
|
||||||
|
- Added new "transport" layer for sockets and associated functions. (Wez)
|
||||||
|
. stream_socket_client() - similar to fsockopen(), but more powerful.
|
||||||
|
. stream_socket_server() - Creates a server socket.
|
||||||
|
. stream_socket_accept() - Accept a client connection.
|
||||||
|
. stream_socket_get_name() - Get local or remote name of socket.
|
||||||
|
. generic crypto interface for streams (supports dynamic loading of OpenSSL)
|
||||||
|
- Added memory mapping support under win32 to improve performance of
|
||||||
|
readfile(), fpassthru() and some internal streams operations. (Wez)
|
||||||
- Added DBA handler 'inifile' to support ini files. (Marcus)
|
- Added DBA handler 'inifile' to support ini files. (Marcus)
|
||||||
- Added filter support. See README.input_filter. (Rasmus)
|
- Added input filter support. See README.input_filter. (Rasmus)
|
||||||
- Added "session.hash_function" and "session.hash_bits_per_character". (Sascha)
|
- Added "session.hash_function" and "session.hash_bits_per_character". (Sascha)
|
||||||
- Added lightweight streaming input abstraction to the Zend Engine scanners
|
- Added lightweight streaming input abstraction to the Zend Engine scanners
|
||||||
that provides uniform support for include()'ing data from PHP streams across
|
that provides uniform support for include()'ing data from PHP streams across
|
||||||
|
@ -461,6 +461,8 @@ getservbyport \
|
|||||||
getrusage \
|
getrusage \
|
||||||
gettimeofday \
|
gettimeofday \
|
||||||
gmtime_r \
|
gmtime_r \
|
||||||
|
inet_ntoa \
|
||||||
|
inet_ntop \
|
||||||
isascii \
|
isascii \
|
||||||
link \
|
link \
|
||||||
localtime_r \
|
localtime_r \
|
||||||
|
@ -135,7 +135,9 @@ ftp_open(const char *host, short port, long timeout_sec TSRMLS_DC)
|
|||||||
tv.tv_sec = timeout_sec;
|
tv.tv_sec = timeout_sec;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
ftp->fd = php_hostconnect(host, (unsigned short) (port ? port : 21), SOCK_STREAM, &tv TSRMLS_CC);
|
ftp->fd = php_network_connect_socket_to_host(host,
|
||||||
|
(unsigned short) (port ? port : 21), SOCK_STREAM,
|
||||||
|
0, &tv, NULL, NULL TSRMLS_CC);
|
||||||
if (ftp->fd == -1) {
|
if (ftp->fd == -1) {
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
@ -288,7 +288,6 @@ static inline int php_openssl_setup_crypto(php_stream *stream,
|
|||||||
method = TLSv1_server_method();
|
method = TLSv1_server_method();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("unknown method\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -307,19 +306,16 @@ static inline int php_openssl_setup_crypto(php_stream *stream,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) {
|
if (!SSL_set_fd(sslsock->ssl_handle, sslsock->s.socket)) {
|
||||||
printf("failed to set fd %d\n", sslsock->s.socket);
|
|
||||||
handle_ssl_error(stream, 0 TSRMLS_CC);
|
handle_ssl_error(stream, 0 TSRMLS_CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cparam->inputs.session) {
|
if (cparam->inputs.session) {
|
||||||
printf("sess=%p\n", cparam->inputs.session);
|
|
||||||
if (cparam->inputs.session->ops != &php_openssl_socket_ops) {
|
if (cparam->inputs.session->ops != &php_openssl_socket_ops) {
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied session stream must be an SSL enabled stream");
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied session stream must be an SSL enabled stream");
|
||||||
} else {
|
} else {
|
||||||
SSL_copy_session_id(sslsock->ssl_handle, ((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle);
|
SSL_copy_session_id(sslsock->ssl_handle, ((php_openssl_netstream_data_t*)cparam->inputs.session->abstract)->ssl_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("crypto prepared for fd=%d\n", sslsock->s.socket);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,13 +333,11 @@ static inline int php_openssl_enable_crypto(php_stream *stream,
|
|||||||
|
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
retry = handle_ssl_error(stream, n TSRMLS_CC);
|
retry = handle_ssl_error(stream, n TSRMLS_CC);
|
||||||
printf("error; retry = %d\n", retry);
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (retry);
|
} while (retry);
|
||||||
|
|
||||||
printf("enabled_crypto: n=%d\n", n);
|
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
sslsock->ssl_active = 1;
|
sslsock->ssl_active = 1;
|
||||||
}
|
}
|
||||||
@ -359,6 +353,47 @@ static inline int php_openssl_enable_crypto(php_stream *stream,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int php_openssl_tcp_sockop_accept(php_stream *stream, php_openssl_netstream_data_t *sock,
|
||||||
|
php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
|
||||||
|
{
|
||||||
|
int clisock;
|
||||||
|
|
||||||
|
xparam->outputs.client = NULL;
|
||||||
|
|
||||||
|
clisock = php_network_accept_incoming(sock->s.socket,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addr : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addrlen : NULL,
|
||||||
|
xparam->inputs.timeout,
|
||||||
|
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
|
||||||
|
&xparam->outputs.error_code
|
||||||
|
TSRMLS_CC);
|
||||||
|
|
||||||
|
if (clisock >= 0) {
|
||||||
|
php_openssl_netstream_data_t *clisockdata;
|
||||||
|
|
||||||
|
clisockdata = pemalloc(sizeof(*clisockdata), stream->is_persistent);
|
||||||
|
|
||||||
|
if (clisockdata == NULL) {
|
||||||
|
close(clisock);
|
||||||
|
/* technically a fatal error */
|
||||||
|
} else {
|
||||||
|
/* copy underlying tcp fields */
|
||||||
|
memset(clisockdata, 0, sizeof(*clisockdata));
|
||||||
|
memcpy(clisockdata, sock, sizeof(clisockdata->s));
|
||||||
|
|
||||||
|
clisockdata->s.socket = clisock;
|
||||||
|
|
||||||
|
xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
|
||||||
|
if (xparam->outputs.client) {
|
||||||
|
xparam->outputs.client->context = stream->context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xparam->outputs.client == NULL ? -1 : 0;
|
||||||
|
}
|
||||||
static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
|
static int php_openssl_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
|
||||||
{
|
{
|
||||||
php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
|
php_openssl_netstream_data_t *sslsock = (php_openssl_netstream_data_t*)stream->abstract;
|
||||||
@ -403,6 +438,14 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val
|
|||||||
}
|
}
|
||||||
return PHP_STREAM_OPTION_RETURN_OK;
|
return PHP_STREAM_OPTION_RETURN_OK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case STREAM_XPORT_OP_ACCEPT:
|
||||||
|
/* we need to copy the additional fields that the underlying tcp transport
|
||||||
|
* doesn't know about */
|
||||||
|
xparam->outputs.returncode = php_openssl_tcp_sockop_accept(stream, sslsock, xparam STREAMS_CC TSRMLS_CC);
|
||||||
|
return PHP_STREAM_OPTION_RETURN_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* fall through */
|
/* fall through */
|
||||||
break;
|
break;
|
||||||
@ -464,7 +507,7 @@ PHPAPI php_stream *php_openssl_ssl_socket_factory(const char *proto, long protol
|
|||||||
php_openssl_netstream_data_t *sslsock = NULL;
|
php_openssl_netstream_data_t *sslsock = NULL;
|
||||||
|
|
||||||
sslsock = pemalloc(sizeof(php_openssl_netstream_data_t), persistent_id ? 1 : 0);
|
sslsock = pemalloc(sizeof(php_openssl_netstream_data_t), persistent_id ? 1 : 0);
|
||||||
memset(sslsock, 0, sizeof(php_openssl_netstream_data_t));
|
memset(sslsock, 0, sizeof(*sslsock));
|
||||||
|
|
||||||
sslsock->s.is_blocked = 1;
|
sslsock->s.is_blocked = 1;
|
||||||
sslsock->s.timeout.tv_sec = FG(default_socket_timeout);
|
sslsock->s.timeout.tv_sec = FG(default_socket_timeout);
|
||||||
@ -488,6 +531,8 @@ PHPAPI php_stream *php_openssl_ssl_socket_factory(const char *proto, long protol
|
|||||||
sslsock->enable_on_connect = 1;
|
sslsock->enable_on_connect = 1;
|
||||||
sslsock->method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
sslsock->method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("enable_on_connect = %d --> proto %s\n", sslsock->enable_on_connect, proto);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,8 @@ int basic_globals_id;
|
|||||||
php_basic_globals basic_globals;
|
php_basic_globals basic_globals;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include "php_fopen_wrappers.h"
|
#include "php_fopen_wrappers.h"
|
||||||
|
#include "streamsfuncs.h"
|
||||||
|
|
||||||
static unsigned char first_and_second__args_force_ref[] = { 2, BYREF_FORCE, BYREF_FORCE };
|
static unsigned char first_and_second__args_force_ref[] = { 2, BYREF_FORCE, BYREF_FORCE };
|
||||||
static unsigned char second_and_third_args_force_ref[] = { 3, BYREF_NONE, BYREF_FORCE, BYREF_FORCE };
|
static unsigned char second_and_third_args_force_ref[] = { 3, BYREF_NONE, BYREF_FORCE, BYREF_FORCE };
|
||||||
@ -679,6 +679,10 @@ function_entry basic_functions[] = {
|
|||||||
PHP_FE(stream_context_get_options, NULL)
|
PHP_FE(stream_context_get_options, NULL)
|
||||||
PHP_FE(stream_filter_prepend, NULL)
|
PHP_FE(stream_filter_prepend, NULL)
|
||||||
PHP_FE(stream_filter_append, NULL)
|
PHP_FE(stream_filter_append, NULL)
|
||||||
|
PHP_FE(stream_socket_client, second_and_third_args_force_ref)
|
||||||
|
PHP_FE(stream_socket_server, second_and_third_args_force_ref)
|
||||||
|
PHP_FE(stream_socket_accept, third_arg_force_ref)
|
||||||
|
PHP_FE(stream_socket_get_name, NULL)
|
||||||
PHP_FE(fgetcsv, NULL)
|
PHP_FE(fgetcsv, NULL)
|
||||||
PHP_FE(flock, NULL)
|
PHP_FE(flock, NULL)
|
||||||
PHP_FE(get_meta_tags, NULL)
|
PHP_FE(get_meta_tags, NULL)
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "fsock.h"
|
#include "fsock.h"
|
||||||
#include "fopen_wrappers.h"
|
#include "fopen_wrappers.h"
|
||||||
#include "php_streams.h"
|
#include "streamsfuncs.h"
|
||||||
#include "php_globals.h"
|
#include "php_globals.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_FILE_H
|
#ifdef HAVE_SYS_FILE_H
|
||||||
@ -187,6 +187,12 @@ PHP_MINIT_FUNCTION(file)
|
|||||||
REGISTER_LONG_CONSTANT("STREAM_FILTER_WRITE", PHP_STREAM_FILTER_WRITE, CONST_CS | CONST_PERSISTENT);
|
REGISTER_LONG_CONSTANT("STREAM_FILTER_WRITE", PHP_STREAM_FILTER_WRITE, CONST_CS | CONST_PERSISTENT);
|
||||||
REGISTER_LONG_CONSTANT("STREAM_FILTER_ALL", PHP_STREAM_FILTER_ALL, CONST_CS | CONST_PERSISTENT);
|
REGISTER_LONG_CONSTANT("STREAM_FILTER_ALL", PHP_STREAM_FILTER_ALL, CONST_CS | CONST_PERSISTENT);
|
||||||
|
|
||||||
|
REGISTER_LONG_CONSTANT("STREAM_CLIENT_PERSISTENT", PHP_STREAM_CLIENT_PERSISTENT, CONST_CS | CONST_PERSISTENT);
|
||||||
|
REGISTER_LONG_CONSTANT("STREAM_CLIENT_ASYNC_CONNECT", PHP_STREAM_CLIENT_ASYNC_CONNECT, CONST_CS | CONST_PERSISTENT);
|
||||||
|
|
||||||
|
REGISTER_LONG_CONSTANT("STREAM_SERVER_BIND", STREAM_XPORT_BIND, CONST_CS | CONST_PERSISTENT);
|
||||||
|
REGISTER_LONG_CONSTANT("STREAM_SERVER_LISTEN", STREAM_XPORT_LISTEN, CONST_CS | CONST_PERSISTENT);
|
||||||
|
|
||||||
REGISTER_LONG_CONSTANT("FILE_USE_INCLUDE_PATH", PHP_FILE_USE_INCLUDE_PATH, CONST_CS | CONST_PERSISTENT);
|
REGISTER_LONG_CONSTANT("FILE_USE_INCLUDE_PATH", PHP_FILE_USE_INCLUDE_PATH, CONST_CS | CONST_PERSISTENT);
|
||||||
REGISTER_LONG_CONSTANT("FILE_IGNORE_NEW_LINES", PHP_FILE_IGNORE_NEW_LINES, CONST_CS | CONST_PERSISTENT);
|
REGISTER_LONG_CONSTANT("FILE_IGNORE_NEW_LINES", PHP_FILE_IGNORE_NEW_LINES, CONST_CS | CONST_PERSISTENT);
|
||||||
REGISTER_LONG_CONSTANT("FILE_SKIP_EMPTY_LINES", PHP_FILE_SKIP_EMPTY_LINES, CONST_CS | CONST_PERSISTENT);
|
REGISTER_LONG_CONSTANT("FILE_SKIP_EMPTY_LINES", PHP_FILE_SKIP_EMPTY_LINES, CONST_CS | CONST_PERSISTENT);
|
||||||
|
@ -54,13 +54,6 @@ PHP_FUNCTION(unlink);
|
|||||||
PHP_FUNCTION(copy);
|
PHP_FUNCTION(copy);
|
||||||
PHP_FUNCTION(file);
|
PHP_FUNCTION(file);
|
||||||
PHP_FUNCTION(file_get_contents);
|
PHP_FUNCTION(file_get_contents);
|
||||||
PHP_FUNCTION(set_socket_blocking); /* deprecated */
|
|
||||||
PHP_FUNCTION(stream_set_blocking);
|
|
||||||
PHP_FUNCTION(stream_select);
|
|
||||||
PHP_FUNCTION(stream_set_timeout);
|
|
||||||
PHP_FUNCTION(stream_set_write_buffer);
|
|
||||||
PHP_FUNCTION(stream_get_wrappers);
|
|
||||||
PHP_FUNCTION(stream_get_line);
|
|
||||||
PHP_FUNCTION(get_meta_tags);
|
PHP_FUNCTION(get_meta_tags);
|
||||||
PHP_FUNCTION(flock);
|
PHP_FUNCTION(flock);
|
||||||
PHP_FUNCTION(fd_set);
|
PHP_FUNCTION(fd_set);
|
||||||
@ -72,14 +65,6 @@ PHP_FUNCTION(fnmatch);
|
|||||||
PHP_NAMED_FUNCTION(php_if_ftruncate);
|
PHP_NAMED_FUNCTION(php_if_ftruncate);
|
||||||
PHP_NAMED_FUNCTION(php_if_fstat);
|
PHP_NAMED_FUNCTION(php_if_fstat);
|
||||||
|
|
||||||
PHP_FUNCTION(stream_get_meta_data);
|
|
||||||
PHP_FUNCTION(stream_register_wrapper);
|
|
||||||
PHP_FUNCTION(stream_context_create);
|
|
||||||
PHP_FUNCTION(stream_context_set_params);
|
|
||||||
PHP_FUNCTION(stream_context_set_option);
|
|
||||||
PHP_FUNCTION(stream_context_get_options);
|
|
||||||
PHP_FUNCTION(stream_filter_prepend);
|
|
||||||
PHP_FUNCTION(stream_filter_append);
|
|
||||||
PHP_MINIT_FUNCTION(user_streams);
|
PHP_MINIT_FUNCTION(user_streams);
|
||||||
|
|
||||||
PHPAPI int php_le_stream_context(void);
|
PHPAPI int php_le_stream_context(void);
|
||||||
|
@ -83,7 +83,7 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
|||||||
efree(hostname);
|
efree(hostname);
|
||||||
}
|
}
|
||||||
if (stream == NULL) {
|
if (stream == NULL) {
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s:%d", host, port);
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s:%d (%s)", host, port, errstr == NULL ? "Unknown error" : errstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashkey) {
|
if (hashkey) {
|
||||||
@ -102,6 +102,10 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
|||||||
}
|
}
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errstr) {
|
||||||
|
efree(errstr);
|
||||||
|
}
|
||||||
|
|
||||||
php_stream_to_zval(stream, return_value);
|
php_stream_to_zval(stream, return_value);
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,239 @@
|
|||||||
#include "php_open_temporary_file.h"
|
#include "php_open_temporary_file.h"
|
||||||
#include "ext/standard/basic_functions.h"
|
#include "ext/standard/basic_functions.h"
|
||||||
#include "php_ini.h"
|
#include "php_ini.h"
|
||||||
|
#include "streamsfuncs.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef PHP_WIN32
|
#ifndef PHP_WIN32
|
||||||
#define php_select(m, r, w, e, t) select(m, r, w, e, t)
|
#define php_select(m, r, w, e, t) select(m, r, w, e, t)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static php_stream_context *decode_context_param(zval *contextresource TSRMLS_DC);
|
||||||
|
|
||||||
|
/* Streams based network functions */
|
||||||
|
|
||||||
|
/* {{{ proto resource stream_socket_client(string remoteaddress [, long &errcode, string &errstring, double timeout, long flags, resource context])
|
||||||
|
Open a client connection to a remote address */
|
||||||
|
PHP_FUNCTION(stream_socket_client)
|
||||||
|
{
|
||||||
|
char *host;
|
||||||
|
long host_len;
|
||||||
|
zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
|
||||||
|
double timeout = FG(default_socket_timeout);
|
||||||
|
unsigned long conv;
|
||||||
|
struct timeval tv;
|
||||||
|
char *hashkey = NULL;
|
||||||
|
php_stream *stream = NULL;
|
||||||
|
int err;
|
||||||
|
long flags = 0;
|
||||||
|
char *errstr = NULL;
|
||||||
|
php_stream_context *context = NULL;
|
||||||
|
|
||||||
|
RETVAL_FALSE;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzd!lr", &host, &host_len, &zerrno, &zerrstr, &timeout, &flags, &zcontext) == FAILURE) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zcontext) {
|
||||||
|
context = decode_context_param(zcontext TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & PHP_STREAM_CLIENT_PERSISTENT) {
|
||||||
|
spprintf(&hashkey, 0, "stream_socket_client__%s", host);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare the timeout value for use */
|
||||||
|
conv = (unsigned long) (timeout * 1000000.0);
|
||||||
|
tv.tv_sec = conv / 1000000;
|
||||||
|
tv.tv_usec = conv % 1000000;
|
||||||
|
|
||||||
|
if (zerrno) {
|
||||||
|
zval_dtor(zerrno);
|
||||||
|
ZVAL_LONG(zerrno, 0);
|
||||||
|
}
|
||||||
|
if (zerrstr) {
|
||||||
|
zval_dtor(zerrstr);
|
||||||
|
ZVAL_STRING(zerrstr, "", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE | REPORT_ERRORS,
|
||||||
|
STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT |
|
||||||
|
(flags & PHP_STREAM_CLIENT_ASYNC_CONNECT ? STREAM_XPORT_CONNECT_ASYNC : 0),
|
||||||
|
hashkey, &tv, context, &errstr, &err);
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
/* host might contain binary characters */
|
||||||
|
char *quoted_host = php_addslashes(host, host_len, NULL, 0 TSRMLS_CC);
|
||||||
|
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", quoted_host, errstr == NULL ? "Unknown error" : errstr);
|
||||||
|
efree(quoted_host);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashkey) {
|
||||||
|
efree(hashkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
if (zerrno) {
|
||||||
|
zval_dtor(zerrno);
|
||||||
|
ZVAL_LONG(zerrno, err);
|
||||||
|
}
|
||||||
|
if (zerrstr && errstr) {
|
||||||
|
/* no need to dup; we need to efree buf anyway */
|
||||||
|
zval_dtor(zerrstr);
|
||||||
|
ZVAL_STRING(zerrstr, errstr, 0);
|
||||||
|
} else if (errstr) {
|
||||||
|
efree(errstr);
|
||||||
|
}
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errstr) {
|
||||||
|
efree(errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
php_stream_to_zval(stream, return_value);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto resource stream_socket_server(string localaddress [, long &errcode, string &errstring, long flags, resource context])
|
||||||
|
Create a server socket bound to localaddress */
|
||||||
|
PHP_FUNCTION(stream_socket_server)
|
||||||
|
{
|
||||||
|
char *host;
|
||||||
|
long host_len;
|
||||||
|
zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
|
||||||
|
php_stream *stream = NULL;
|
||||||
|
int err;
|
||||||
|
long flags = STREAM_XPORT_BIND | STREAM_XPORT_LISTEN;
|
||||||
|
char *errstr = NULL;
|
||||||
|
php_stream_context *context = NULL;
|
||||||
|
|
||||||
|
RETVAL_FALSE;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|zzlr", &host, &host_len, &zerrno, &zerrstr, &flags, &zcontext) == FAILURE) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zcontext) {
|
||||||
|
context = decode_context_param(zcontext TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zerrno) {
|
||||||
|
zval_dtor(zerrno);
|
||||||
|
ZVAL_LONG(zerrno, 0);
|
||||||
|
}
|
||||||
|
if (zerrstr) {
|
||||||
|
zval_dtor(zerrstr);
|
||||||
|
ZVAL_STRING(zerrstr, "", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = php_stream_xport_create(host, host_len, ENFORCE_SAFE_MODE | REPORT_ERRORS,
|
||||||
|
STREAM_XPORT_SERVER | flags,
|
||||||
|
NULL, NULL, context, &errstr, &err);
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s (%s)", host, errstr == NULL ? "Unknown error" : errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
if (zerrno) {
|
||||||
|
zval_dtor(zerrno);
|
||||||
|
ZVAL_LONG(zerrno, err);
|
||||||
|
}
|
||||||
|
if (zerrstr && errstr) {
|
||||||
|
/* no need to dup; we need to efree buf anyway */
|
||||||
|
zval_dtor(zerrstr);
|
||||||
|
ZVAL_STRING(zerrstr, errstr, 0);
|
||||||
|
}
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errstr) {
|
||||||
|
efree(errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
php_stream_to_zval(stream, return_value);
|
||||||
|
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto resource stream_socket_accept(resource serverstream, [ double timeout, string &peername ])
|
||||||
|
Accept a client connection from a server socket */
|
||||||
|
PHP_FUNCTION(stream_socket_accept)
|
||||||
|
{
|
||||||
|
double timeout = FG(default_socket_timeout);
|
||||||
|
zval *peername = NULL;
|
||||||
|
unsigned long conv;
|
||||||
|
struct timeval tv;
|
||||||
|
php_stream *stream = NULL, *clistream = NULL;
|
||||||
|
zval *zstream;
|
||||||
|
|
||||||
|
char *errstr = NULL;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|dz!", &zstream, &timeout, &peername) == FAILURE) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
php_stream_from_zval(stream, &zstream);
|
||||||
|
|
||||||
|
/* prepare the timeout value for use */
|
||||||
|
conv = (unsigned long) (timeout * 1000000.0);
|
||||||
|
tv.tv_sec = conv / 1000000;
|
||||||
|
tv.tv_usec = conv % 1000000;
|
||||||
|
|
||||||
|
if (peername) {
|
||||||
|
zval_dtor(peername);
|
||||||
|
ZVAL_STRING(peername, "", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == php_stream_xport_accept(stream, &clistream,
|
||||||
|
peername ? &Z_STRVAL_P(peername) : NULL,
|
||||||
|
peername ? &Z_STRLEN_P(peername) : NULL,
|
||||||
|
NULL, NULL,
|
||||||
|
&tv, &errstr
|
||||||
|
TSRMLS_CC) && clistream) {
|
||||||
|
|
||||||
|
php_stream_to_zval(clistream, return_value);
|
||||||
|
} else {
|
||||||
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "accept failed: %s", errstr ? errstr : "Unknown error");
|
||||||
|
|
||||||
|
RETVAL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errstr) {
|
||||||
|
efree(errstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto string stream_socket_get_name(resource stream, bool want_peer)
|
||||||
|
Returns either the locally bound or remote name for a socket stream */
|
||||||
|
PHP_FUNCTION(stream_socket_get_name)
|
||||||
|
{
|
||||||
|
php_stream *stream;
|
||||||
|
zval *zstream;
|
||||||
|
zend_bool want_peer;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rb", &zstream, &want_peer) == FAILURE) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
php_stream_from_zval(stream, &zstream);
|
||||||
|
|
||||||
|
Z_TYPE_P(return_value) = IS_STRING;
|
||||||
|
|
||||||
|
if (0 != php_stream_xport_get_name(stream, want_peer,
|
||||||
|
&Z_STRVAL_P(return_value),
|
||||||
|
&Z_STRLEN_P(return_value),
|
||||||
|
NULL, NULL
|
||||||
|
TSRMLS_CC)) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ proto resource stream_get_meta_data(resource fp)
|
/* {{{ proto resource stream_get_meta_data(resource fp)
|
||||||
Retrieves header/meta data from streams/file pointers */
|
Retrieves header/meta data from streams/file pointers */
|
||||||
PHP_FUNCTION(stream_get_meta_data)
|
PHP_FUNCTION(stream_get_meta_data)
|
||||||
|
504
main/network.c
504
main/network.c
@ -275,9 +275,6 @@ typedef int php_non_blocking_flags_t;
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Connect to a socket using an interruptible connect with optional timeout.
|
/* Connect to a socket using an interruptible connect with optional timeout.
|
||||||
* Optionally, the connect can be made asynchronously, which will implicitly
|
* Optionally, the connect can be made asynchronously, which will implicitly
|
||||||
* enable non-blocking mode on the socket.
|
* enable non-blocking mode on the socket.
|
||||||
@ -376,148 +373,6 @@ ok:
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ php_connect_nonb */
|
|
||||||
PHPAPI int php_connect_nonb(int sockfd,
|
|
||||||
const struct sockaddr *addr,
|
|
||||||
socklen_t addrlen,
|
|
||||||
struct timeval *timeout)
|
|
||||||
{
|
|
||||||
#if (!defined(__BEOS__) && !defined(PHP_WIN32)) && (defined(O_NONBLOCK) || defined(O_NDELAY))
|
|
||||||
|
|
||||||
|
|
||||||
int flags;
|
|
||||||
int n;
|
|
||||||
int error = 0;
|
|
||||||
socklen_t len;
|
|
||||||
int ret = 0;
|
|
||||||
fd_set rset;
|
|
||||||
fd_set wset;
|
|
||||||
fd_set eset;
|
|
||||||
|
|
||||||
if (timeout == NULL) {
|
|
||||||
/* blocking mode */
|
|
||||||
return connect(sockfd, addr, addrlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
flags = fcntl(sockfd, F_GETFL, 0);
|
|
||||||
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
if ((n = connect(sockfd, addr, addrlen)) < 0) {
|
|
||||||
if (errno != EINPROGRESS) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n == 0) {
|
|
||||||
goto ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&rset);
|
|
||||||
FD_ZERO(&eset);
|
|
||||||
FD_SET(sockfd, &rset);
|
|
||||||
FD_SET(sockfd, &eset);
|
|
||||||
|
|
||||||
wset = rset;
|
|
||||||
|
|
||||||
if ((n = select(sockfd + 1, &rset, &wset, &eset, timeout)) == 0) {
|
|
||||||
error = ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
|
|
||||||
len = sizeof(error);
|
|
||||||
/*
|
|
||||||
BSD-derived systems set errno correctly
|
|
||||||
Solaris returns -1 from getsockopt in case of error
|
|
||||||
*/
|
|
||||||
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* whoops: sockfd has disappeared */
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok:
|
|
||||||
fcntl(sockfd, F_SETFL, flags);
|
|
||||||
|
|
||||||
if(error) {
|
|
||||||
errno = error;
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
#else /* !defined(PHP_WIN32) && ... */
|
|
||||||
#ifdef PHP_WIN32
|
|
||||||
return php_connect_nonb_win32((SOCKET) sockfd, addr, addrlen, timeout);
|
|
||||||
#endif
|
|
||||||
return connect(sockfd, addr, addrlen);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
#ifdef PHP_WIN32
|
|
||||||
/* {{{ php_connect_nonb_win32 */
|
|
||||||
PHPAPI int php_connect_nonb_win32(SOCKET sockfd,
|
|
||||||
const struct sockaddr *addr,
|
|
||||||
socklen_t addrlen,
|
|
||||||
struct timeval *timeout)
|
|
||||||
{
|
|
||||||
int error = 0, error_len, ret;
|
|
||||||
u_long non_block = TRUE, block = FALSE;
|
|
||||||
|
|
||||||
fd_set rset, wset;
|
|
||||||
|
|
||||||
if (timeout == NULL) {
|
|
||||||
/* blocking mode */
|
|
||||||
return connect(sockfd, addr, addrlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the socket to be non-blocking */
|
|
||||||
ioctlsocket(sockfd, FIONBIO, &non_block);
|
|
||||||
|
|
||||||
if (connect(sockfd, addr, addrlen) == SOCKET_ERROR) {
|
|
||||||
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&rset);
|
|
||||||
FD_SET(sockfd, &rset);
|
|
||||||
|
|
||||||
FD_ZERO(&wset);
|
|
||||||
FD_SET(sockfd, &wset);
|
|
||||||
|
|
||||||
if ((ret = select(sockfd + 1, &rset, &wset, NULL, timeout)) == 0) {
|
|
||||||
WSASetLastError(WSAETIMEDOUT);
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == SOCKET_ERROR) {
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
|
|
||||||
error_len = sizeof(error);
|
|
||||||
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) == SOCKET_ERROR) {
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* whoops: sockfd has disappeared */
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the socket back to blocking */
|
|
||||||
ioctlsocket(sockfd, FIONBIO, &block);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
WSASetLastError(error);
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* {{{ sub_times */
|
/* {{{ sub_times */
|
||||||
static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
|
static inline void sub_times(struct timeval a, struct timeval b, struct timeval *result)
|
||||||
{
|
{
|
||||||
@ -534,6 +389,261 @@ static inline void sub_times(struct timeval a, struct timeval b, struct timeval
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
/* Bind to a local IP address.
|
||||||
|
* Returns the bound socket, or -1 on failure.
|
||||||
|
* */
|
||||||
|
/* {{{ php_network_bind_socket_to_local_addr */
|
||||||
|
int php_network_bind_socket_to_local_addr(const char *host, unsigned port,
|
||||||
|
int socktype, char **error_string, int *error_code
|
||||||
|
TSRMLS_DC)
|
||||||
|
{
|
||||||
|
int num_addrs, sock, n, err = 0;
|
||||||
|
struct sockaddr **sal, **psal, *sa;
|
||||||
|
socklen_t socklen;
|
||||||
|
|
||||||
|
num_addrs = php_network_getaddresses(host, &psal, error_string TSRMLS_CC);
|
||||||
|
|
||||||
|
if (num_addrs == 0) {
|
||||||
|
/* could not resolve address(es) */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sal = psal; *sal != NULL; sal++) {
|
||||||
|
sa = *sal;
|
||||||
|
|
||||||
|
/* create a socket for this address */
|
||||||
|
sock = socket(sa->sa_family, socktype, 0);
|
||||||
|
|
||||||
|
if (sock == SOCK_ERR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sa->sa_family) {
|
||||||
|
#if HAVE_GETADDRINFO && HAVE_IPV6
|
||||||
|
case AF_INET6:
|
||||||
|
((struct sockaddr_in6 *)sa)->sin6_family = sa->sa_family;
|
||||||
|
((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
|
||||||
|
socklen = sizeof(struct sockaddr_in6);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case AF_INET:
|
||||||
|
((struct sockaddr_in *)sa)->sin_family = sa->sa_family;
|
||||||
|
((struct sockaddr_in *)sa)->sin_port = htons(port);
|
||||||
|
socklen = sizeof(struct sockaddr_in);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Unknown family */
|
||||||
|
sa = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sa) {
|
||||||
|
/* attempt to bind */
|
||||||
|
|
||||||
|
#ifdef SO_REUSEADDR
|
||||||
|
{
|
||||||
|
int val = 1;
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
n = bind(sock, sa, socklen);
|
||||||
|
|
||||||
|
if (n != SOCK_CONN_ERR) {
|
||||||
|
goto bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = php_socket_errno();
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
}
|
||||||
|
sock = -1;
|
||||||
|
|
||||||
|
if (error_code) {
|
||||||
|
*error_code = err;
|
||||||
|
}
|
||||||
|
if (error_string) {
|
||||||
|
*error_string = php_socket_strerror(err, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bound:
|
||||||
|
|
||||||
|
php_network_freeaddresses(psal);
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static void populate_name(
|
||||||
|
/* input address */
|
||||||
|
struct sockaddr *sa, socklen_t sl,
|
||||||
|
/* output readable address */
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
/* output address */
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen
|
||||||
|
TSRMLS_DC)
|
||||||
|
{
|
||||||
|
if (addr) {
|
||||||
|
*addr = emalloc(sl);
|
||||||
|
memcpy(*addr, sa, sl);
|
||||||
|
*addrlen = sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textaddr) {
|
||||||
|
#if HAVE_IPV6 && HAVE_INET_NTOP
|
||||||
|
char abuf[256];
|
||||||
|
#endif
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
switch (sa->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
/* generally not thread safe, but it *is* thread safe under win32 */
|
||||||
|
buf = inet_ntoa(((struct sockaddr_in*)sa)->sin_addr);
|
||||||
|
if (buf) {
|
||||||
|
*textaddrlen = strlen(buf);
|
||||||
|
*textaddr = estrndup(buf, *textaddrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if HAVE_IPV6
|
||||||
|
case AF_INET6:
|
||||||
|
buf = (char*)inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, (char *)&abuf, sizeof(abuf));
|
||||||
|
if (buf) {
|
||||||
|
*textaddrlen = strlen(buf);
|
||||||
|
*textaddr = estrndup(buf, *textaddrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef AF_UNIX
|
||||||
|
case AF_UNIX:
|
||||||
|
{
|
||||||
|
struct sockaddr_un *ua = (struct sockaddr_un*)sa;
|
||||||
|
|
||||||
|
if (ua->sun_path[0] == '\0') {
|
||||||
|
/* abstract name */
|
||||||
|
int len = strlen(ua->sun_path + 1) + 1;
|
||||||
|
*textaddrlen = len;
|
||||||
|
*textaddr = emalloc(len + 1);
|
||||||
|
memcpy(*textaddr, ua->sun_path, len);
|
||||||
|
(*textaddr)[len] = '\0';
|
||||||
|
} else {
|
||||||
|
*textaddrlen = strlen(ua->sun_path);
|
||||||
|
*textaddr = estrndup(ua->sun_path, *textaddrlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PHPAPI int php_network_get_peer_name(int sock,
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen
|
||||||
|
TSRMLS_DC)
|
||||||
|
{
|
||||||
|
php_sockaddr_storage sa;
|
||||||
|
socklen_t sl = sizeof(sa);
|
||||||
|
|
||||||
|
if (getpeername(sock, (struct sockaddr*)&sa, &sl) == 0) {
|
||||||
|
populate_name((struct sockaddr*)&sa, sl,
|
||||||
|
textaddr, textaddrlen,
|
||||||
|
addr, addrlen
|
||||||
|
TSRMLS_CC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHPAPI int php_network_get_sock_name(int sock,
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen
|
||||||
|
TSRMLS_DC)
|
||||||
|
{
|
||||||
|
php_sockaddr_storage sa;
|
||||||
|
socklen_t sl = sizeof(sa);
|
||||||
|
|
||||||
|
if (getsockname(sock, (struct sockaddr*)&sa, &sl) == 0) {
|
||||||
|
populate_name((struct sockaddr*)&sa, sl,
|
||||||
|
textaddr, textaddrlen,
|
||||||
|
addr, addrlen
|
||||||
|
TSRMLS_CC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Accept a client connection from a server socket,
|
||||||
|
* using an optional timeout.
|
||||||
|
* Returns the peer address in addr/addrlen (it will emalloc
|
||||||
|
* these, so be sure to efree the result).
|
||||||
|
* If you specify textaddr/textaddrlen, a text-printable
|
||||||
|
* version of the address will be emalloc'd and returned.
|
||||||
|
* */
|
||||||
|
|
||||||
|
/* {{{ php_network_accept_incoming */
|
||||||
|
PHPAPI int php_network_accept_incoming(int srvsock,
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen,
|
||||||
|
struct timeval *timeout,
|
||||||
|
char **error_string,
|
||||||
|
int *error_code
|
||||||
|
TSRMLS_DC)
|
||||||
|
{
|
||||||
|
int clisock = -1;
|
||||||
|
fd_set rset;
|
||||||
|
int error, n;
|
||||||
|
php_sockaddr_storage sa;
|
||||||
|
socklen_t sl;
|
||||||
|
|
||||||
|
FD_ZERO(&rset);
|
||||||
|
FD_SET(srvsock, &rset);
|
||||||
|
|
||||||
|
n = select(srvsock + 1, &rset, NULL, NULL, timeout);
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
error = PHP_TIMEOUT_ERROR_VALUE;
|
||||||
|
} else if (n == -1) {
|
||||||
|
error = php_socket_errno();
|
||||||
|
} else if (FD_ISSET(srvsock, &rset)) {
|
||||||
|
sl = sizeof(sa);
|
||||||
|
|
||||||
|
clisock = accept(srvsock, (struct sockaddr*)&sa, &sl);
|
||||||
|
|
||||||
|
if (clisock >= 0) {
|
||||||
|
populate_name((struct sockaddr*)&sa, sl,
|
||||||
|
textaddr, textaddrlen,
|
||||||
|
addr, addrlen
|
||||||
|
TSRMLS_CC);
|
||||||
|
} else {
|
||||||
|
error = php_socket_errno();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error_code) {
|
||||||
|
*error_code = error;
|
||||||
|
}
|
||||||
|
if (error_string) {
|
||||||
|
*error_string = php_socket_strerror(error, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clisock;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Connect to a remote host using an interruptible connect with optional timeout.
|
/* Connect to a remote host using an interruptible connect with optional timeout.
|
||||||
* Optionally, the connect can be made asynchronously, which will implicitly
|
* Optionally, the connect can be made asynchronously, which will implicitly
|
||||||
* enable non-blocking mode on the socket.
|
* enable non-blocking mode on the socket.
|
||||||
@ -654,110 +764,6 @@ connected:
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* {{{ php_hostconnect
|
|
||||||
* Creates a socket of type socktype and connects to the given host and
|
|
||||||
* port, returns the created socket on success, else returns -1.
|
|
||||||
* timeout gives timeout in seconds, 0 means blocking mode.
|
|
||||||
*/
|
|
||||||
int php_hostconnect(const char *host, unsigned short port, int socktype, struct timeval *timeout TSRMLS_DC)
|
|
||||||
{
|
|
||||||
int n, repeatto, s;
|
|
||||||
struct sockaddr **sal, **psal;
|
|
||||||
struct timeval individual_timeout;
|
|
||||||
int set_timeout = 0;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
n = php_network_getaddresses(host, &sal, NULL TSRMLS_CC);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (timeout != NULL) {
|
|
||||||
/* is this a good idea? 5s? */
|
|
||||||
repeatto = timeout->tv_sec / n > 5;
|
|
||||||
if (repeatto) {
|
|
||||||
individual_timeout.tv_sec = timeout->tv_sec / n;
|
|
||||||
} else {
|
|
||||||
individual_timeout.tv_sec = timeout->tv_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
individual_timeout.tv_usec = timeout->tv_usec;
|
|
||||||
} else {
|
|
||||||
individual_timeout.tv_sec = 0;
|
|
||||||
individual_timeout.tv_usec = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Boolean indicating whether to pass a timeout */
|
|
||||||
set_timeout = individual_timeout.tv_sec + individual_timeout.tv_usec;
|
|
||||||
|
|
||||||
psal = sal;
|
|
||||||
while (*sal != NULL) {
|
|
||||||
s = socket((*sal)->sa_family, socktype, 0);
|
|
||||||
if (s != SOCK_ERR) {
|
|
||||||
switch ((*sal)->sa_family) {
|
|
||||||
#if defined( HAVE_GETADDRINFO ) && defined( HAVE_IPV6 )
|
|
||||||
case AF_INET6:
|
|
||||||
{
|
|
||||||
struct sockaddr_in6 *sa =
|
|
||||||
(struct sockaddr_in6 *)*sal;
|
|
||||||
|
|
||||||
sa->sin6_family = (*sal)->sa_family;
|
|
||||||
sa->sin6_port = htons(port);
|
|
||||||
if (php_connect_nonb(s, (struct sockaddr *) sa,
|
|
||||||
sizeof(*sa), (set_timeout) ? &individual_timeout : NULL) != SOCK_CONN_ERR)
|
|
||||||
goto ok;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case AF_INET:
|
|
||||||
{
|
|
||||||
struct sockaddr_in *sa =
|
|
||||||
(struct sockaddr_in *)*sal;
|
|
||||||
|
|
||||||
sa->sin_family = (*sal)->sa_family;
|
|
||||||
sa->sin_port = htons(port);
|
|
||||||
if (php_connect_nonb(s, (struct sockaddr *) sa,
|
|
||||||
sizeof(*sa), (set_timeout) ? &individual_timeout : NULL) != SOCK_CONN_ERR)
|
|
||||||
goto ok;
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef PHP_WIN32
|
|
||||||
/* Preserve the last error */
|
|
||||||
err = WSAGetLastError();
|
|
||||||
#else
|
|
||||||
err = errno;
|
|
||||||
#endif
|
|
||||||
close (s);
|
|
||||||
}
|
|
||||||
sal++;
|
|
||||||
|
|
||||||
if (err == PHP_TIMEOUT_ERROR_VALUE) {
|
|
||||||
/* if the first attempt timed out, it's highly likely
|
|
||||||
* that any subsequent attempts will do so also */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
php_network_freeaddresses(psal);
|
|
||||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_hostconnect: connect failed");
|
|
||||||
|
|
||||||
#ifdef PHP_WIN32
|
|
||||||
/* Restore the last error */
|
|
||||||
WSASetLastError(err);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ok:
|
|
||||||
php_network_freeaddresses(psal);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
/* {{{ php_any_addr
|
/* {{{ php_any_addr
|
||||||
* Fills the any (wildcard) address into php_sockaddr_storage
|
* Fills the any (wildcard) address into php_sockaddr_storage
|
||||||
*/
|
*/
|
||||||
|
@ -119,12 +119,33 @@ PHPAPI int php_network_connect_socket(int sockfd,
|
|||||||
char **error_string,
|
char **error_string,
|
||||||
int *error_code);
|
int *error_code);
|
||||||
|
|
||||||
int php_hostconnect(const char *host, unsigned short port, int socktype, struct timeval *timeout TSRMLS_DC);
|
#define php_connect_nonb(sock, addr, addrlen, timeout) \
|
||||||
PHPAPI int php_connect_nonb(int sockfd, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout);
|
php_network_connect_socket((sock), (addr), (addrlen), 0, (timeout), NULL, NULL)
|
||||||
|
|
||||||
#ifdef PHP_WIN32
|
PHPAPI int php_network_bind_socket_to_local_addr(const char *host, unsigned port,
|
||||||
PHPAPI int php_connect_nonb_win32(SOCKET sockfd, const struct sockaddr *addr, socklen_t addrlen, struct timeval *timeout);
|
int socktype, char **error_string, int *error_code
|
||||||
#endif
|
TSRMLS_DC);
|
||||||
|
|
||||||
|
PHPAPI int php_network_accept_incoming(int srvsock,
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen,
|
||||||
|
struct timeval *timeout,
|
||||||
|
char **error_string,
|
||||||
|
int *error_code
|
||||||
|
TSRMLS_DC);
|
||||||
|
|
||||||
|
PHPAPI int php_network_get_sock_name(int sock,
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen
|
||||||
|
TSRMLS_DC);
|
||||||
|
|
||||||
|
PHPAPI int php_network_get_peer_name(int sock,
|
||||||
|
char **textaddr, long *textaddrlen,
|
||||||
|
struct sockaddr **addr,
|
||||||
|
socklen_t *addrlen
|
||||||
|
TSRMLS_DC);
|
||||||
|
|
||||||
void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port);
|
void php_any_addr(int family, php_sockaddr_storage *addr, unsigned short port);
|
||||||
int php_sockaddr_size(php_sockaddr_storage *addr);
|
int php_sockaddr_size(php_sockaddr_storage *addr);
|
||||||
@ -134,6 +155,7 @@ struct _php_netstream_data_t {
|
|||||||
char is_blocked;
|
char is_blocked;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
char timeout_event;
|
char timeout_event;
|
||||||
|
size_t ownsize;
|
||||||
};
|
};
|
||||||
typedef struct _php_netstream_data_t php_netstream_data_t;
|
typedef struct _php_netstream_data_t php_netstream_data_t;
|
||||||
extern php_stream_ops php_stream_socket_ops;
|
extern php_stream_ops php_stream_socket_ops;
|
||||||
|
@ -72,19 +72,27 @@ PHPAPI int php_stream_xport_listen(php_stream *stream,
|
|||||||
/* Get the next client and their address as a string, or the underlying address
|
/* Get the next client and their address as a string, or the underlying address
|
||||||
* structure. You must efree either of these if you request them */
|
* structure. You must efree either of these if you request them */
|
||||||
PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
|
PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
|
||||||
char **textaddr, long *textaddrlen,
|
char **textaddr, int *textaddrlen,
|
||||||
void **addr, size_t *addrlen,
|
void **addr, size_t *addrlen,
|
||||||
struct timeval *timeout,
|
struct timeval *timeout,
|
||||||
char **error_text
|
char **error_text
|
||||||
TSRMLS_DC);
|
TSRMLS_DC);
|
||||||
|
|
||||||
|
/* Get the name of either the socket or it's peer */
|
||||||
|
PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
|
||||||
|
char **textaddr, int *textaddrlen,
|
||||||
|
void **addr, size_t *addrlen
|
||||||
|
TSRMLS_DC);
|
||||||
|
|
||||||
/* Structure definition for the set_option interface that the above functions wrap */
|
/* Structure definition for the set_option interface that the above functions wrap */
|
||||||
|
|
||||||
typedef struct _php_stream_xport_param {
|
typedef struct _php_stream_xport_param {
|
||||||
enum {
|
enum {
|
||||||
STREAM_XPORT_OP_BIND, STREAM_XPORT_OP_CONNECT,
|
STREAM_XPORT_OP_BIND, STREAM_XPORT_OP_CONNECT,
|
||||||
STREAM_XPORT_OP_LISTEN, STREAM_XPORT_OP_ACCEPT,
|
STREAM_XPORT_OP_LISTEN, STREAM_XPORT_OP_ACCEPT,
|
||||||
STREAM_XPORT_OP_CONNECT_ASYNC
|
STREAM_XPORT_OP_CONNECT_ASYNC,
|
||||||
|
STREAM_XPORT_OP_GET_NAME,
|
||||||
|
STREAM_XPORT_OP_GET_PEER_NAME
|
||||||
} op;
|
} op;
|
||||||
int want_addr:1;
|
int want_addr:1;
|
||||||
int want_textaddr:1;
|
int want_textaddr:1;
|
||||||
@ -99,7 +107,7 @@ typedef struct _php_stream_xport_param {
|
|||||||
struct {
|
struct {
|
||||||
php_stream *client;
|
php_stream *client;
|
||||||
int returncode;
|
int returncode;
|
||||||
void *addr;
|
struct sockaddr *addr;
|
||||||
size_t addrlen;
|
size_t addrlen;
|
||||||
char *textaddr;
|
char *textaddr;
|
||||||
long textaddrlen;
|
long textaddrlen;
|
||||||
|
@ -252,7 +252,7 @@ PHPAPI int php_stream_xport_listen(php_stream *stream, int backlog, char **error
|
|||||||
|
|
||||||
/* Get the next client and their address (as a string) */
|
/* Get the next client and their address (as a string) */
|
||||||
PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
|
PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
|
||||||
char **textaddr, long *textaddrlen,
|
char **textaddr, int *textaddrlen,
|
||||||
void **addr, size_t *addrlen,
|
void **addr, size_t *addrlen,
|
||||||
struct timeval *timeout,
|
struct timeval *timeout,
|
||||||
char **error_text
|
char **error_text
|
||||||
@ -263,7 +263,7 @@ PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
|
|||||||
|
|
||||||
memset(¶m, 0, sizeof(param));
|
memset(¶m, 0, sizeof(param));
|
||||||
|
|
||||||
param.op = STREAM_XPORT_OP_BIND;
|
param.op = STREAM_XPORT_OP_ACCEPT;
|
||||||
param.inputs.timeout = timeout;
|
param.inputs.timeout = timeout;
|
||||||
param.want_addr = addr ? 1 : 0;
|
param.want_addr = addr ? 1 : 0;
|
||||||
param.want_textaddr = textaddr ? 1 : 0;
|
param.want_textaddr = textaddr ? 1 : 0;
|
||||||
@ -290,6 +290,37 @@ PHPAPI int php_stream_xport_accept(php_stream *stream, php_stream **client,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PHPAPI int php_stream_xport_get_name(php_stream *stream, int want_peer,
|
||||||
|
char **textaddr, int *textaddrlen,
|
||||||
|
void **addr, size_t *addrlen
|
||||||
|
TSRMLS_DC)
|
||||||
|
{
|
||||||
|
php_stream_xport_param param;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(¶m, 0, sizeof(param));
|
||||||
|
|
||||||
|
param.op = want_peer ? STREAM_XPORT_OP_GET_PEER_NAME : STREAM_XPORT_OP_GET_NAME;
|
||||||
|
param.want_addr = addr ? 1 : 0;
|
||||||
|
param.want_textaddr = textaddr ? 1 : 0;
|
||||||
|
|
||||||
|
ret = php_stream_set_option(stream, PHP_STREAM_OPTION_XPORT_API, 0, ¶m);
|
||||||
|
|
||||||
|
if (ret == PHP_STREAM_OPTION_RETURN_OK) {
|
||||||
|
if (addr) {
|
||||||
|
*addr = param.outputs.addr;
|
||||||
|
*addrlen = param.outputs.addrlen;
|
||||||
|
}
|
||||||
|
if (textaddr) {
|
||||||
|
*textaddr = param.outputs.textaddr;
|
||||||
|
*textaddrlen = param.outputs.textaddrlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return param.outputs.returncode;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC)
|
PHPAPI int php_stream_xport_crypto_setup(php_stream *stream, php_stream_xport_crypt_method_t crypto_method, php_stream *session_stream TSRMLS_DC)
|
||||||
{
|
{
|
||||||
php_stream_xport_crypto_param param;
|
php_stream_xport_crypto_param param;
|
||||||
|
@ -217,6 +217,25 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void
|
|||||||
xparam->outputs.returncode = listen(sock->socket, 5);
|
xparam->outputs.returncode = listen(sock->socket, 5);
|
||||||
return PHP_STREAM_OPTION_RETURN_OK;
|
return PHP_STREAM_OPTION_RETURN_OK;
|
||||||
|
|
||||||
|
case STREAM_XPORT_OP_GET_NAME:
|
||||||
|
xparam->outputs.returncode = php_network_get_sock_name(sock->socket,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addr : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addrlen : NULL
|
||||||
|
TSRMLS_CC);
|
||||||
|
return PHP_STREAM_OPTION_RETURN_OK;
|
||||||
|
|
||||||
|
case STREAM_XPORT_OP_GET_PEER_NAME:
|
||||||
|
xparam->outputs.returncode = php_network_get_peer_name(sock->socket,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addr : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addrlen : NULL
|
||||||
|
TSRMLS_CC);
|
||||||
|
return PHP_STREAM_OPTION_RETURN_OK;
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return PHP_STREAM_OPTION_RETURN_NOTIMPL;
|
return PHP_STREAM_OPTION_RETURN_NOTIMPL;
|
||||||
}
|
}
|
||||||
@ -311,17 +330,97 @@ php_stream_ops php_stream_unixdg_socket_ops = {
|
|||||||
|
|
||||||
/* network socket operations */
|
/* network socket operations */
|
||||||
|
|
||||||
|
#ifdef AF_UNIX
|
||||||
|
static inline int parse_unix_address(php_stream_xport_param *xparam, struct sockaddr_un *unix_addr TSRMLS_DC)
|
||||||
|
{
|
||||||
|
memset(unix_addr, 0, sizeof(*unix_addr));
|
||||||
|
unix_addr->sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
/* we need to be binary safe on systems that support an abstract
|
||||||
|
* namespace */
|
||||||
|
if (xparam->inputs.namelen >= sizeof(unix_addr->sun_path)) {
|
||||||
|
/* On linux, when the path begins with a NUL byte we are
|
||||||
|
* referring to an abstract namespace. In theory we should
|
||||||
|
* allow an extra byte below, since we don't need the NULL.
|
||||||
|
* BUT, to get into this branch of code, the name is too long,
|
||||||
|
* so we don't care. */
|
||||||
|
xparam->inputs.namelen = sizeof(unix_addr->sun_path) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(unix_addr->sun_path, xparam->inputs.name, xparam->inputs.namelen);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno TSRMLS_DC)
|
||||||
|
{
|
||||||
|
char *colon;
|
||||||
|
char *host = NULL;
|
||||||
|
|
||||||
|
colon = memchr(xparam->inputs.name, ':', xparam->inputs.namelen);
|
||||||
|
if (colon) {
|
||||||
|
*portno = atoi(colon + 1);
|
||||||
|
host = estrndup(xparam->inputs.name, colon - xparam->inputs.name);
|
||||||
|
} else {
|
||||||
|
if (xparam->want_errortext) {
|
||||||
|
spprintf(&xparam->outputs.error_text, 0, "Failed to parse address \"%s\"", xparam->inputs.name);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
|
static inline int php_tcp_sockop_bind(php_stream *stream, php_netstream_data_t *sock,
|
||||||
php_stream_xport_param *xparam TSRMLS_DC)
|
php_stream_xport_param *xparam TSRMLS_DC)
|
||||||
{
|
{
|
||||||
|
char *host = NULL;
|
||||||
|
int portno, err;
|
||||||
|
|
||||||
return -1;
|
#ifdef AF_UNIX
|
||||||
|
if (stream->ops == &php_stream_unix_socket_ops || stream->ops == &php_stream_unixdg_socket_ops) {
|
||||||
|
struct sockaddr_un unix_addr;
|
||||||
|
|
||||||
|
sock->socket = socket(PF_UNIX, stream->ops == &php_stream_unix_socket_ops ? SOCK_STREAM : SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
if (sock->socket == SOCK_ERR) {
|
||||||
|
if (xparam->want_errortext) {
|
||||||
|
spprintf(&xparam->outputs.error_text, 0, "Failed to create unix%s socket %s",
|
||||||
|
stream->ops == &php_stream_unix_socket_ops ? "" : "datagram",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_unix_address(xparam, &unix_addr TSRMLS_CC);
|
||||||
|
|
||||||
|
return bind(sock->socket, &unix_addr, sizeof(unix_addr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
host = parse_ip_address(xparam, &portno TSRMLS_CC);
|
||||||
|
|
||||||
|
if (host == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock->socket = php_network_bind_socket_to_local_addr(host, portno,
|
||||||
|
stream->ops == &php_stream_udp_socket_ops ? SOCK_DGRAM : SOCK_STREAM,
|
||||||
|
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
|
||||||
|
&err
|
||||||
|
TSRMLS_CC);
|
||||||
|
|
||||||
|
if (host) {
|
||||||
|
efree(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock->socket == -1 ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
|
static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_t *sock,
|
||||||
php_stream_xport_param *xparam TSRMLS_DC)
|
php_stream_xport_param *xparam TSRMLS_DC)
|
||||||
{
|
{
|
||||||
char *colon;
|
|
||||||
char *host = NULL;
|
char *host = NULL;
|
||||||
int portno, err;
|
int portno, err;
|
||||||
int ret;
|
int ret;
|
||||||
@ -339,21 +438,7 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(&unix_addr, 0, sizeof(unix_addr));
|
parse_unix_address(xparam, &unix_addr TSRMLS_CC);
|
||||||
unix_addr.sun_family = AF_UNIX;
|
|
||||||
|
|
||||||
/* we need to be binary safe on systems that support an abstract
|
|
||||||
* namespace */
|
|
||||||
if (xparam->inputs.namelen >= sizeof(unix_addr.sun_path)) {
|
|
||||||
/* On linux, when the path begins with a NUL byte we are
|
|
||||||
* referring to an abstract namespace. In theory we should
|
|
||||||
* allow an extra byte below, since we don't need the NULL.
|
|
||||||
* BUT, to get into this branch of code, the name is too long,
|
|
||||||
* so we don't care. */
|
|
||||||
xparam->inputs.namelen = sizeof(unix_addr.sun_path) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(unix_addr.sun_path, xparam->inputs.name, xparam->inputs.namelen);
|
|
||||||
|
|
||||||
ret = php_network_connect_socket(sock->socket,
|
ret = php_network_connect_socket(sock->socket,
|
||||||
(const struct sockaddr *)&unix_addr, sizeof(unix_addr),
|
(const struct sockaddr *)&unix_addr, sizeof(unix_addr),
|
||||||
@ -366,15 +451,10 @@ static inline int php_tcp_sockop_connect(php_stream *stream, php_netstream_data_
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
colon = memchr(xparam->inputs.name, ':', xparam->inputs.namelen);
|
host = parse_ip_address(xparam, &portno TSRMLS_CC);
|
||||||
if (colon) {
|
|
||||||
portno = atoi(colon + 1);
|
if (host == NULL) {
|
||||||
host = estrndup(xparam->inputs.name, colon - xparam->inputs.name);
|
|
||||||
} else {
|
|
||||||
if (xparam->want_errortext) {
|
|
||||||
spprintf(&xparam->outputs.error_text, 0, "Failed to parse address \"%s\"", xparam->inputs.name);
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,9 +489,42 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
|
static inline int php_tcp_sockop_accept(php_stream *stream, php_netstream_data_t *sock,
|
||||||
php_stream_xport_param *xparam TSRMLS_DC)
|
php_stream_xport_param *xparam STREAMS_DC TSRMLS_DC)
|
||||||
{
|
{
|
||||||
return -1;
|
int clisock;
|
||||||
|
|
||||||
|
xparam->outputs.client = NULL;
|
||||||
|
|
||||||
|
clisock = php_network_accept_incoming(sock->socket,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
|
||||||
|
xparam->want_textaddr ? &xparam->outputs.textaddrlen : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addr : NULL,
|
||||||
|
xparam->want_addr ? &xparam->outputs.addrlen : NULL,
|
||||||
|
xparam->inputs.timeout,
|
||||||
|
xparam->want_errortext ? &xparam->outputs.error_text : NULL,
|
||||||
|
&xparam->outputs.error_code
|
||||||
|
TSRMLS_CC);
|
||||||
|
|
||||||
|
if (clisock >= 0) {
|
||||||
|
php_netstream_data_t *clisockdata;
|
||||||
|
|
||||||
|
clisockdata = pemalloc(sizeof(*clisockdata), stream->is_persistent);
|
||||||
|
|
||||||
|
if (clisockdata == NULL) {
|
||||||
|
close(clisock);
|
||||||
|
/* technically a fatal error */
|
||||||
|
} else {
|
||||||
|
memcpy(clisockdata, sock, sizeof(*clisockdata));
|
||||||
|
clisockdata->socket = clisock;
|
||||||
|
|
||||||
|
xparam->outputs.client = php_stream_alloc_rel(stream->ops, clisockdata, NULL, "r+");
|
||||||
|
if (xparam->outputs.client) {
|
||||||
|
xparam->outputs.client->context = stream->context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return xparam->outputs.client == NULL ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
|
static int php_tcp_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC)
|
||||||
@ -435,7 +548,7 @@ static int php_tcp_sockop_set_option(php_stream *stream, int option, int value,
|
|||||||
|
|
||||||
|
|
||||||
case STREAM_XPORT_OP_ACCEPT:
|
case STREAM_XPORT_OP_ACCEPT:
|
||||||
xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam TSRMLS_CC);
|
xparam->outputs.returncode = php_tcp_sockop_accept(stream, sock, xparam STREAMS_CC TSRMLS_CC);
|
||||||
return PHP_STREAM_OPTION_RETURN_OK;
|
return PHP_STREAM_OPTION_RETURN_OK;
|
||||||
default:
|
default:
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
Loading…
Reference in New Issue
Block a user