]> granicus.if.org Git - php/commitdiff
Add test for CMSG_CREDENTIALS message
authorGustavo Lopes <glopes@nebm.ist.utl.pt>
Mon, 5 Nov 2012 10:40:24 +0000 (11:40 +0100)
committerGustavo Lopes <glopes@nebm.ist.utl.pt>
Sat, 2 Feb 2013 15:38:06 +0000 (16:38 +0100)
ext/sockets/sendrecvmsg.c
ext/sockets/tests/socket_cmsg_credentials.phpt [new file with mode: 0644]

index f6a71dbefc7efe18bd9f260e2a8d5322c2f20c5d..385c2322336af5b064cb8fb31682c9ab40269f00 100644 (file)
@@ -719,7 +719,8 @@ static void to_zval_read_sun_path(const char *data, zval *zv, res_context *ctx)
 }
 static const field_descriptor descriptors_sockaddr_un[] = {
                {"family", sizeof("family"), 0, offsetof(struct sockaddr_un, sun_family), from_zval_write_sa_family, to_zval_read_sa_family},
-               {"path", sizeof("path"), 0, offsetof(struct sockaddr_un, sun_path), from_zval_write_sun_path, to_zval_read_sun_path},
+               {"path", sizeof("path"), 0, 0, from_zval_write_sun_path, to_zval_read_sun_path},
+               {0}
 };
 static void from_zval_write_sockaddr_un(const zval *container, char *sockaddr, ser_context *ctx)
 {
@@ -857,7 +858,8 @@ static void from_zval_write_control(const zval                      *arr,
        struct cmsghdr          *cmsghdr;
        int                                     level,
                                                type;
-       size_t                          req_space,
+       size_t                          data_len,
+                                               req_space,
                                                space_left;
        ancillary_reg_entry     *entry;
 
@@ -891,13 +893,14 @@ static void from_zval_write_control(const zval                    *arr,
        }
 
        if (entry->calc_space) {
-               entry->calc_space(arr, ctx);
+               data_len = entry->calc_space(arr, ctx);
                if (ctx->err.has_error) {
                        return;
                }
        } else {
-               req_space = CMSG_SPACE(entry->size);
+               data_len = entry->size;
        }
+       req_space = CMSG_SPACE(data_len);
        space_left = *control_len - *offset;
        assert(*control_len >= *offset);
 
@@ -910,7 +913,7 @@ static void from_zval_write_control(const zval                      *arr,
        cmsghdr = (struct cmsghdr*)(((char*)*control_buf) + *offset);
        cmsghdr->cmsg_level     = level;
        cmsghdr->cmsg_type      = type;
-       cmsghdr->cmsg_len       = CMSG_LEN(entry->size);
+       cmsghdr->cmsg_len       = CMSG_LEN(data_len);
 
        descriptor_data[0].from_zval = entry->from_array;
        from_zval_write_aggregation(arr, (char*)CMSG_DATA(cmsghdr), descriptor_data, ctx);
@@ -1302,27 +1305,23 @@ static size_t calculate_scm_rights_space(const zval *arr, ser_context *ctx)
 
        return zend_hash_num_elements(Z_ARRVAL_P(arr)) * sizeof(int);
 }
-static void from_zval_write_int_array_aux(zval **elem, unsigned i, void **args, ser_context *ctx)
+static void from_zval_write_fd_array_aux(zval **elem, unsigned i, void **args, ser_context *ctx)
 {
        int *iarr = args[0];
 
-       if (Z_TYPE_PP(elem) == IS_LONG) {
-
-               from_zval_write_int(*elem, (char*)&iarr[i], ctx);
-
-       } else if (Z_TYPE_PP(elem) == IS_RESOURCE) {
+       if (Z_TYPE_PP(elem) == IS_RESOURCE) {
                php_stream *stream;
                php_socket *sock;
 
                ZEND_FETCH_RESOURCE_NO_RETURN(sock, php_socket *, elem, -1,
-                               php_sockets_le_socket_name, php_sockets_le_socket());
+                               NULL, php_sockets_le_socket());
                if (sock) {
                        iarr[i] = sock->bsd_socket;
                        return;
                }
 
                ZEND_FETCH_RESOURCE2_NO_RETURN(stream, php_stream *, elem, -1,
-                               "stream", php_file_le_stream(), php_file_le_pstream());
+                               NULL, php_file_le_stream(), php_file_le_pstream());
                if (stream == NULL) {
                        do_from_zval_err(ctx, "resource is not a stream or a socket");
                        return;
@@ -1334,25 +1333,26 @@ static void from_zval_write_int_array_aux(zval **elem, unsigned i, void **args,
                        return;
                }
        } else {
-               do_from_zval_err(ctx, "expected an integer or resource variable");
+               do_from_zval_err(ctx, "expected a resource variable");
        }
 }
-static void from_zval_write_int_array(const zval *arr, char *int_arr, ser_context *ctx)
+static void from_zval_write_fd_array(const zval *arr, char *int_arr, ser_context *ctx)
 {
        if (Z_TYPE_P(arr) != IS_ARRAY) {
                do_from_zval_err(ctx, "%s", "expected an array here");
                return;
        }
 
-   from_array_iterate(arr, &from_zval_write_int_array_aux, (void**)&int_arr, ctx);
+   from_array_iterate(arr, &from_zval_write_fd_array_aux, (void**)&int_arr, ctx);
 }
-static void to_zval_read_int_array(const char *data, zval *zv, res_context *ctx)
+static void to_zval_read_fd_array(const char *data, zval *zv, res_context *ctx)
 {
        size_t                  **cmsg_len;
        int                             num_elems,
                                        i;
        struct cmsghdr  *dummy_cmsg = 0;
        size_t                  data_offset;
+       TSRMLS_FETCH();
 
        data_offset = (unsigned char *)CMSG_DATA(dummy_cmsg)
                        - (unsigned char *)dummy_cmsg;
@@ -1373,7 +1373,25 @@ static void to_zval_read_int_array(const char *data, zval *zv, res_context *ctx)
        array_init_size(zv, num_elems);
 
        for (i = 0; i < num_elems; i++) {
-               add_next_index_long(zv, (long)*((int *)data + i));
+               zval            *elem;
+               int                     fd;
+               struct stat     statbuf;
+
+               MAKE_STD_ZVAL(elem);
+
+               fd = *((int *)data + i);
+
+               /* determine whether we have a socket */
+               fstat(fd, &statbuf);
+               if (S_ISSOCK(statbuf.st_mode)) {
+                       php_socket *sock = socket_import_file_descriptor(fd);
+                       zend_register_resource(elem, sock, php_sockets_le_socket());
+               } else {
+                       php_stream *stream = php_stream_fopen_from_fd(fd, "rw", NULL);
+                       php_stream_to_zval(stream, elem);
+               }
+
+               add_next_index_zval(zv, elem);
        }
 }
 
@@ -1500,8 +1518,8 @@ static void init_ancillary_registry(void)
        PUT_ENTRY(sizeof(struct ucred), 0, 0, from_zval_write_ucred,
                        to_zval_read_ucred, SOL_SOCKET, SCM_CREDENTIALS);
 
-       PUT_ENTRY(0, sizeof(int), calculate_scm_rights_space, from_zval_write_int_array,
-                       to_zval_read_int_array, SOL_SOCKET, SCM_RIGHTS);
+       PUT_ENTRY(0, sizeof(int), calculate_scm_rights_space, from_zval_write_fd_array,
+                       to_zval_read_fd_array, SOL_SOCKET, SCM_RIGHTS);
 
 }
 static ancillary_reg_entry *get_ancillary_reg_entry(int cmsg_level, int msg_type)
@@ -1676,7 +1694,7 @@ PHP_FUNCTION(socket_cmsg_space)
                return;
        }
 
-       RETURN_LONG((long)CMSG_SPACE(entry->size + n * entry->size));
+       RETURN_LONG((long)CMSG_SPACE(entry->size + n * entry->var_el_size));
 }
 
 void _socket_sendrecvmsg_init(INIT_FUNC_ARGS)
diff --git a/ext/sockets/tests/socket_cmsg_credentials.phpt b/ext/sockets/tests/socket_cmsg_credentials.phpt
new file mode 100644 (file)
index 0000000..6a1c23f
--- /dev/null
@@ -0,0 +1,89 @@
+--TEST--
+recvmsg(): receive SCM_CREDENTIALS messages
+--SKIPIF--
+<?php
+if (!extension_loaded('sockets')) {
+die('skip sockets extension not available.');
+}
+if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
+die('skip not for Microsoft Windows');
+}
+--CLEAN--
+<?php
+$path = __DIR__ . "/unix_sock";
+@unlink($path);
+
+--FILE--
+<?php
+include __DIR__."/mcast_helpers.php.inc";
+$path = __DIR__ . "/unix_sock";
+
+@unlink($path);
+
+echo "creating send socket\n";
+$sends1 = socket_create(AF_UNIX, SOCK_DGRAM, 0) or die("err");
+var_dump($sends1);
+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");
+var_dump($s);
+$br = socket_bind($s, $path) or die("err");
+var_dump($br);
+socket_set_nonblock($sends1) or die("Could not put in non-blocking mode");
+socket_set_option($s, SOL_SOCKET, SO_PASSCRED, 1) or die("could not set SO_PASSCRED");
+
+
+//$r = socket_sendmsg($sends1, [
+//  "iov" => ["test ", "thing", "\n"],
+//], 0);
+$r = socket_sendto($sends1, $msg = "dread", strlen($msg), 0, $path);
+var_dump($r);
+checktimeout($s, 500);
+
+$data = [
+    "name" => [],
+    "buffer_size" => 2000,
+    "controllen" => socket_cmsg_space(SOL_SOCKET, SCM_CREDENTIALS)
+];
+if (!socket_recvmsg($s, $data, 0)) die("recvmsg");
+print_r($data);
+
+$pid = getmypid();
+var_dump($data['control'][0]['data']['pid'] === $pid);
+
+--EXPECTF--
+creating send socket
+resource(%d) of type (Socket)
+creating receive socket
+resource(%d) of type (Socket)
+bool(true)
+int(5)
+Array
+(
+    [name] => 
+    [control] => Array
+        (
+            [0] => Array
+                (
+                    [level] => %d
+                    [type] => %d
+                    [data] => Array
+                        (
+                            [pid] => %d
+                            [uid] => %d
+                            [gid] => %d
+                        )
+
+                )
+
+        )
+
+    [iov] => Array
+        (
+            [0] => dread
+        )
+
+    [flags] => 0
+)
+bool(true)