Commit: 710150ccb7d62c87eb198e5cbb13d0f1867c176f Author: Gustavo Lopes <glo...@nebm.ist.utl.pt> Mon, 15 Jul 2013 01:51:15 +0200 Parents: e2744f1aa33da3afade2c454b008c0de65a72da9 Branches: PHP-5.5 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=710150ccb7d62c87eb198e5cbb13d0f1867c176f Log: socket: support unix paths in the abstract namespace Those starting with '\0'. Changed paths: M ext/sockets/conversions.c M ext/sockets/sockets.c A ext/sockets/tests/socket_abstract_path.phpt A ext/sockets/tests/socket_abstract_path_sendmsg.phpt Diff: diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index 3b58b39..ed55ed5 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -98,8 +98,8 @@ typedef struct { } field_descriptor; #define KEY_FILL_SOCKADDR "fill_sockaddr" -#define KEY_RECVMSG_RET "recvmsg_ret" -#define KEY_CMSG_LEN "cmsg_len" +#define KEY_RECVMSG_RET "recvmsg_ret" +#define KEY_CMSG_LEN "cmsg_len" const struct key_value empty_key_value_list[] = {{0}}; @@ -667,6 +667,13 @@ static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_ path = &lzval; } + /* code in this file relies on the path being nul terminated, even though + * this is not required, at least on linux for abstract paths. It also + * assumes that the path is not empty */ + if (Z_STRLEN_P(path) == 0) { + do_from_zval_err(ctx, "%s", "the path is cannot be empty"); + return; + } if (Z_STRLEN_P(path) >= sizeof(saddr->sun_path)) { do_from_zval_err(ctx, "the path is too long, the maximum permitted " "length is %ld", sizeof(saddr->sun_path) - 1); @@ -768,10 +775,22 @@ static void from_zval_write_sockaddr_aux(const zval *container, return; } *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx); - *sockaddr_len = sizeof(struct sockaddr_un); if (fill_sockaddr) { + struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr; + from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx); (*sockaddr_ptr)->sa_family = AF_UNIX; + + /* calculating length is more complicated here. Giving the size of + * struct sockaddr_un here and relying on the nul termination of + * sun_path does not work for paths in the abstract namespace. Note + * that we always assume the path is not empty and nul terminated */ + *sockaddr_len = offsetof(struct sockaddr_un, sun_path) + + (sock_un->sun_path[0] == '\0' + ? (1 + strlen(&sock_un->sun_path[1])) + : strlen(sock_un->sun_path)); + } else { + *sockaddr_len = sizeof(struct sockaddr_un); } break; diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 801af0a..b226d94 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1479,7 +1479,7 @@ PHP_FUNCTION(socket_strerror) PHP_FUNCTION(socket_bind) { zval *arg1; - php_sockaddr_storage sa_storage; + php_sockaddr_storage sa_storage = {0}; struct sockaddr *sock_type = (struct sockaddr*) &sa_storage; php_socket *php_sock; char *addr; @@ -1497,10 +1497,19 @@ PHP_FUNCTION(socket_bind) case AF_UNIX: { struct sockaddr_un *sa = (struct sockaddr_un *) sock_type; - memset(sa, 0, sizeof(sa_storage)); + sa->sun_family = AF_UNIX; - snprintf(sa->sun_path, 108, "%s", addr); - retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa, SUN_LEN(sa)); + + if (addr_len >= sizeof(sa->sun_path)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, + "Invalid path: too long (maximum size is %d)", + (int)sizeof(sa->sun_path) - 1); + RETURN_FALSE; + } + memcpy(&sa->sun_path, addr, addr_len); + + retval = bind(php_sock->bsd_socket, (struct sockaddr *) sa, + offsetof(struct sockaddr_un, sun_path) + addr_len); break; } @@ -1508,8 +1517,6 @@ PHP_FUNCTION(socket_bind) { struct sockaddr_in *sa = (struct sockaddr_in *) sock_type; - memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */ - sa->sin_family = AF_INET; sa->sin_port = htons((unsigned short) port); @@ -1525,8 +1532,6 @@ PHP_FUNCTION(socket_bind) { struct sockaddr_in6 *sa = (struct sockaddr_in6 *) sock_type; - memset(sa, 0, sizeof(sa_storage)); /* Apparently, Mac OSX needs this */ - sa->sin6_family = AF_INET6; sa->sin6_port = htons((unsigned short) port); diff --git a/ext/sockets/tests/socket_abstract_path.phpt b/ext/sockets/tests/socket_abstract_path.phpt new file mode 100644 index 0000000..816e5c1 --- /dev/null +++ b/ext/sockets/tests/socket_abstract_path.phpt @@ -0,0 +1,44 @@ +--TEST-- +Support for paths in the abstract namespace (bind, connect) +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) + die('skip sockets extension not available.'); + +if (PHP_OS != 'Linux') { + die('skip For Linux only'); +} +?> +--FILE-- +<?php +include __DIR__."/mcast_helpers.php.inc"; + +$path = "\x00/foo_bar"; + +echo "creating server socket\n"; +$servers = socket_create(AF_UNIX, SOCK_STREAM, 0) or die("err"); +socket_bind($servers, $path) or die("Could not bind"); +socket_listen($servers) or die("Could not listen"); +socket_set_nonblock($servers) or die("Could not put in non-blocking mode"); + +echo "creating client socket\n"; +$clients = socket_create(AF_UNIX, SOCK_STREAM, 0) or die("err"); +socket_connect($clients, $path) or die("Error connecting"); + +$conns = socket_accept($servers) or die("Could not accept connection"); + +$r = socket_sendmsg($clients, [ + //"name" => [ "addr" => $path, ], + "iov" => ["test ", "thing", "\n"], +], 0); +var_dump($r); +checktimeout($conns, 500); + +if (!socket_recv($conns, $buf, 20, 0)) die("recv"); +print_r($buf); +?> +--EXPECTF-- +creating server socket +creating client socket +int(11) +test thing diff --git a/ext/sockets/tests/socket_abstract_path_sendmsg.phpt b/ext/sockets/tests/socket_abstract_path_sendmsg.phpt new file mode 100644 index 0000000..5a9275a --- /dev/null +++ b/ext/sockets/tests/socket_abstract_path_sendmsg.phpt @@ -0,0 +1,40 @@ +--TEST-- +Support for paths in the abstract namespace (bind, sendmsg, recvmsg) +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) + die('skip sockets extension not available.'); + +if (PHP_OS != 'Linux') { + die('skip For Linux only'); +} +?> +--FILE-- +<?php +include __DIR__."/mcast_helpers.php.inc"; + +$path = "\x00/bar_foo"; + +echo "creating send socket\n"; +$sends1 = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err"); +socket_set_nonblock($sends1) or die("Could not put in non-blocking mode"); + +echo "creating receive socket\n"; +$s = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err"); +socket_bind($s, $path) or die("err"); + +$r = socket_sendmsg($sends1, [ + "name" => [ "path" => $path], + "iov" => ["test ", "thing", "\n"], +], 0); +var_dump($r); +checktimeout($s, 500); + +if (!socket_recv($s, $buf, 20, 0)) die("recv"); +print_r($buf); +?> +--EXPECTF-- +creating send socket +creating receive socket +int(11) +test thing -- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php