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

Reply via email to