blob: 8c6b3ae3516eae6a8a9ff86efbf89059f5a70e36 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fbl/array.h>
#include <unittest/unittest.h>
#include <zircon/syscalls.h>
namespace {
zx_signals_t get_satisfied_signals(zx_handle_t handle) {
zx_signals_t pending = 0;
zx_object_wait_one(handle, 0u, 0u, &pending);
return pending;
}
bool socket_basic() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_handle_t h[2];
uint32_t read_data[] = {0, 0};
status = zx_socket_create(0, h, h + 1);
ASSERT_EQ(status, ZX_OK, "");
// Check that koids line up.
zx_info_handle_basic_t info[2] = {};
status = zx_object_get_info(h[0], ZX_INFO_HANDLE_BASIC, &info[0], sizeof(info[0]), NULL, NULL);
ASSERT_EQ(status, ZX_OK, "");
status = zx_object_get_info(h[1], ZX_INFO_HANDLE_BASIC, &info[1], sizeof(info[1]), NULL, NULL);
ASSERT_EQ(status, ZX_OK, "");
ASSERT_NE(info[0].koid, 0u, "zero koid!");
ASSERT_NE(info[0].related_koid, 0u, "zero peer koid!");
ASSERT_NE(info[1].koid, 0u, "zero koid!");
ASSERT_NE(info[1].related_koid, 0u, "zero peer koid!");
ASSERT_EQ(info[0].koid, info[1].related_koid, "mismatched koids!");
ASSERT_EQ(info[1].koid, info[0].related_koid, "mismatched koids!");
status = zx_socket_read(h[0], 0u, read_data, sizeof(read_data), &count);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
constexpr uint32_t write_data[] = {0xdeadbeef, 0xc0ffee};
status = zx_socket_write(h[0], 0u, &write_data[0], sizeof(write_data[0]), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(write_data[0]), "");
status = zx_socket_write(h[0], 0u, &write_data[1], sizeof(write_data[1]), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(write_data[1]), "");
status = zx_socket_read(h[1], 0u, read_data, sizeof(read_data), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(read_data), "");
EXPECT_EQ(read_data[0], write_data[0], "");
EXPECT_EQ(read_data[1], write_data[1], "");
status = zx_socket_write(h[0], 0u, write_data, sizeof(write_data), NULL);
EXPECT_EQ(status, ZX_OK, "");
memset(read_data, 0, sizeof(read_data));
status = zx_socket_read(h[1], 0u, read_data, sizeof(read_data), NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(read_data[0], write_data[0], "");
EXPECT_EQ(read_data[1], write_data[1], "");
zx_handle_close(h[1]);
status = zx_socket_write(h[0], 0u, &write_data[1], sizeof(write_data[1]), &count);
EXPECT_EQ(status, ZX_ERR_PEER_CLOSED, "");
zx_handle_close(h[0]);
END_TEST;
}
bool socket_peek() {
BEGIN_TEST;
size_t count;
zx_handle_t h[2];
uint32_t read_data[] = {0, 0};
constexpr uint32_t write_data[] = {0xdeadbeef, 0xc0ffee};
ASSERT_EQ(zx_socket_create(0, h, h + 1), ZX_OK, "");
EXPECT_EQ(zx_socket_write(h[0], 0u, &write_data[0], sizeof(write_data[0]), &count), ZX_OK, "");
EXPECT_EQ(count, sizeof(write_data[0]), "");
EXPECT_EQ(zx_socket_write(h[0], 0u, &write_data[1], sizeof(write_data[1]), &count), ZX_OK, "");
EXPECT_EQ(count, sizeof(write_data[1]), "");
EXPECT_EQ(zx_socket_read(h[1], ZX_SOCKET_PEEK, read_data, sizeof(read_data), &count),
ZX_OK, "");
EXPECT_EQ(count, sizeof(read_data), "");
EXPECT_EQ(read_data[0], write_data[0], "");
EXPECT_EQ(read_data[1], write_data[1], "");
// The message should still be pending for h1 to read.
EXPECT_EQ(get_satisfied_signals(h[0]), ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(get_satisfied_signals(h[1]), ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE, "");
memset(read_data, 0, sizeof(read_data));
EXPECT_EQ(zx_socket_read(h[1], 0u, read_data, sizeof(read_data), &count), ZX_OK, "");
EXPECT_EQ(count, sizeof(read_data), "");
EXPECT_EQ(read_data[0], write_data[0], "");
EXPECT_EQ(read_data[1], write_data[1], "");
zx_handle_close(h[0]);
zx_handle_close(h[1]);
END_TEST;
}
bool socket_peek_empty() {
BEGIN_TEST;
zx_handle_t h[2];
ASSERT_EQ(zx_socket_create(0, h, h + 1), ZX_OK, "");
size_t count;
char data;
EXPECT_EQ(zx_socket_read(h[0], ZX_SOCKET_PEEK, &data, sizeof(data), &count),
ZX_ERR_SHOULD_WAIT, "");
zx_handle_close(h[0]);
zx_handle_close(h[1]);
END_TEST;
}
bool socket_signals() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
zx_signals_t signals0 = get_satisfied_signals(h0);
zx_signals_t signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
const size_t kAllSize = 128 * 1024;
fbl::Array<char> big_buf(new char[kAllSize], kAllSize);
ASSERT_NONNULL(big_buf.get(), "");
memset(big_buf.get(), 0x66, kAllSize);
status = zx_socket_write(h0, 0u, big_buf.get(), kAllSize / 16, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, kAllSize / 16, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_READABLE | ZX_SOCKET_WRITABLE, "");
status = zx_socket_read(h1, 0u, big_buf.get(), kAllSize, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, kAllSize / 16, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
status = zx_object_signal_peer(h0, ZX_SOCKET_WRITABLE, 0u);
EXPECT_EQ(status, ZX_ERR_INVALID_ARGS, "");
status = zx_object_signal_peer(h0, 0u, ZX_USER_SIGNAL_1);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_USER_SIGNAL_1, "");
zx_handle_close(h1);
signals0 = get_satisfied_signals(h0);
EXPECT_EQ(signals0, ZX_SOCKET_PEER_CLOSED, "");
zx_handle_close(h0);
END_TEST;
}
bool socket_signals2() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "socket_create");
/* Set some invalid threshold values and verify */
count = 0;
status = zx_object_set_property(h0, ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_set_property");
count = 0xefffffff;
status = zx_object_set_property(h0, ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_ERR_INVALID_ARGS, "object_set_property");
count = 0;
status = zx_object_set_property(h1, ZX_PROP_SOCKET_TX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_set_property");
count = 0xefffffff;
status = zx_object_set_property(h1, ZX_PROP_SOCKET_TX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_ERR_INVALID_ARGS, "object_set_property");
/*
* In the code below, we are going to trigger the READ threshold
* signal as soon as 101 bytes are available to read, and triger
* the write threshold as long as we have 103 bytes we can write/
*/
/* Set valid Read/Write thresholds and verify */
constexpr size_t SOCKET2_SIGNALTEST_RX_THRESHOLD = 101;
count = SOCKET2_SIGNALTEST_RX_THRESHOLD;
status = zx_object_set_property(h0, ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_set_property");
status = zx_object_get_property(h0, ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_get_property");
ASSERT_EQ(count, (size_t)SOCKET2_SIGNALTEST_RX_THRESHOLD, "");
zx_info_socket_t info;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h1, ZX_INFO_SOCKET, &info, sizeof(info), NULL, NULL);
ASSERT_EQ(status, ZX_OK, "zx_object_get_info");
size_t write_threshold = info.tx_buf_max - (SOCKET2_SIGNALTEST_RX_THRESHOLD + 2);
status = zx_object_set_property(h1, ZX_PROP_SOCKET_TX_THRESHOLD,
&write_threshold, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_set_property");
status = zx_object_get_property(h1, ZX_PROP_SOCKET_TX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_get_property");
ASSERT_EQ(count, write_threshold, "");
/* Make sure duplicates get the same thresholds ! */
zx_handle_t h0_clone, h1_clone;
status = zx_handle_duplicate(h0, ZX_RIGHT_SAME_RIGHTS, &h0_clone);
ASSERT_EQ(status, ZX_OK, "handle_duplicate");
status = zx_handle_duplicate(h1, ZX_RIGHT_SAME_RIGHTS, &h1_clone);
ASSERT_EQ(status, ZX_OK, "handle_duplicate");
status = zx_object_get_property(h0_clone,
ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_get_property");
ASSERT_EQ(count, (size_t)SOCKET2_SIGNALTEST_RX_THRESHOLD, "");
status = zx_object_get_property(h1_clone,
ZX_PROP_SOCKET_TX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_get_property");
ASSERT_EQ(count, write_threshold, "");
/* Test starting signal state after setting thresholds */
zx_signals_t signals0 = get_satisfied_signals(h0);
zx_signals_t signals1 = get_satisfied_signals(h1);
zx_signals_t signals0_clone = get_satisfied_signals(h0_clone);
zx_signals_t signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals0_clone, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
EXPECT_EQ(signals1_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
/* Write data and test signals */
size_t bufsize = SOCKET2_SIGNALTEST_RX_THRESHOLD - 1;
char buf[SOCKET2_SIGNALTEST_RX_THRESHOLD - 1];
status = zx_socket_write(h1, 0u, buf, bufsize, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, bufsize, "");
/*
* We wrote less than the read and write thresholds. So we expect
* the READ_THRESHOLD signal to be de-asserted and the WRITE_THRESHOLD
* signal to be asserted.
*/
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
signals0_clone = get_satisfied_signals(h0_clone);
signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE, "");
EXPECT_EQ(signals0_clone, ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE, "");
EXPECT_EQ(signals1_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
/*
* Now write exactly enough data to hit the read threshold
*/
bufsize = 1;
status = zx_socket_write(h1, 0u, buf, bufsize, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, bufsize, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
signals0_clone = get_satisfied_signals(h0_clone);
signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_READ_THRESHOLD,
"");
EXPECT_EQ(signals0_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_READ_THRESHOLD,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
EXPECT_EQ(signals1_clone, ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
/*
* Bump up the read threshold and make sure the READ THRESHOLD signal gets
* deasserted (and then restore the read threshold back).
*/
count = SOCKET2_SIGNALTEST_RX_THRESHOLD + 50;
status = zx_object_set_property(h0, ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_set_property");
signals0 = get_satisfied_signals(h0);
signals0_clone = get_satisfied_signals(h0_clone);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE,
"");
EXPECT_EQ(signals0_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE,
"");
count = SOCKET2_SIGNALTEST_RX_THRESHOLD;
status = zx_object_set_property(h0, ZX_PROP_SOCKET_RX_THRESHOLD,
&count, sizeof(size_t));
signals0 = get_satisfied_signals(h0);
signals0_clone = get_satisfied_signals(h0_clone);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_READ_THRESHOLD,
"");
EXPECT_EQ(signals0_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_READ_THRESHOLD,
"");
/*
* Bump the write threshold way up and make sure the WRITE THRESHOLD signal gets
* deasserted (and then restore the write threshold back).
*/
count = info.tx_buf_max - 10;
status = zx_object_set_property(h1, ZX_PROP_SOCKET_TX_THRESHOLD,
&count, sizeof(size_t));
ASSERT_EQ(status, ZX_OK, "object_set_property");
signals1 = get_satisfied_signals(h1);
signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals1,
ZX_SOCKET_WRITABLE,
"");
EXPECT_EQ(signals1_clone,
ZX_SOCKET_WRITABLE,
"");
count = write_threshold;
status = zx_object_set_property(h1, ZX_PROP_SOCKET_TX_THRESHOLD,
&count, sizeof(size_t));
signals1 = get_satisfied_signals(h1);
signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals1,
ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD,
"");
EXPECT_EQ(signals1_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD,
"");
/*
* Next write enough data to de-assert WRITE Threshold
*/
bufsize = write_threshold - (SOCKET2_SIGNALTEST_RX_THRESHOLD + 1);
fbl::Array<char> buf2(new char[bufsize], bufsize);
status = zx_socket_write(h1, 0u, buf2.get(), bufsize, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, bufsize, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
signals0_clone = get_satisfied_signals(h0_clone);
signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_READ_THRESHOLD,
"");
EXPECT_EQ(signals0_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_READ_THRESHOLD,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1_clone, ZX_SOCKET_WRITABLE, "");
/*
* Finally read enough data to de-assert the read threshold and
* re-assert the write threshold signals.
*/
bufsize += 10;
buf2.reset(new char[bufsize], bufsize);
status = zx_socket_read(h0, 0u, buf2.get(), bufsize, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, bufsize, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
signals0_clone = get_satisfied_signals(h0_clone);
signals1_clone = get_satisfied_signals(h1_clone);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE,
"");
EXPECT_EQ(signals0_clone,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
EXPECT_EQ(signals1_clone, ZX_SOCKET_WRITABLE | ZX_SOCKET_WRITE_THRESHOLD, "");
zx_handle_close(h0);
zx_handle_close(h1);
zx_handle_close(h0_clone);
zx_handle_close(h1_clone);
END_TEST;
}
bool socket_peer_closed_signal() {
BEGIN_TEST;
zx_handle_t socket[2];
ASSERT_EQ(zx_socket_create(0, &socket[0], &socket[1]), ZX_OK, "");
ASSERT_EQ(zx_handle_close(socket[1]), ZX_OK, "");
ASSERT_EQ(zx_object_signal_peer(socket[0], 0u, ZX_USER_SIGNAL_0), ZX_ERR_PEER_CLOSED, "");
ASSERT_EQ(zx_handle_close(socket[0]), ZX_OK, "");
END_TEST;
}
bool socket_peer_closed_set_property() {
BEGIN_TEST;
zx_handle_t socket[2];
ASSERT_EQ(zx_socket_create(0, &socket[0], &socket[1]), ZX_OK, "");
size_t t = 1;
ASSERT_EQ(zx_object_set_property(socket[0], ZX_PROP_SOCKET_TX_THRESHOLD, &t, sizeof(t)),
ZX_OK, "");
ASSERT_EQ(zx_handle_close(socket[1]), ZX_OK, "");
ASSERT_EQ(zx_object_set_property(socket[0], ZX_PROP_SOCKET_TX_THRESHOLD, &t, sizeof(t)),
ZX_ERR_PEER_CLOSED, "");
ASSERT_EQ(zx_handle_close(socket[0]), ZX_OK, "");
END_TEST;
}
bool socket_shutdown_write() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_signals_t signals0, signals1;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
status = zx_socket_write(h1, 0u, "12345", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
status = zx_socket_shutdown(h1, ZX_SOCKET_SHUTDOWN_WRITE);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_PEER_WRITE_DISABLED,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h0, 0u, "abcde", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals1, ZX_SOCKET_READABLE | ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h1, 0u, "fghij", 5u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
char rbuf[10] = {0};
status = zx_socket_read(h0, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "12345", 5), 0, "");
status = zx_socket_read(h0, 0u, rbuf, 1u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
signals0 = get_satisfied_signals(h0);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_PEER_WRITE_DISABLED, "");
status = zx_socket_read(h1, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "abcde", 5), 0, "");
zx_handle_close(h0);
// Calling shutdown after the peer is closed is completely valid.
status = zx_socket_shutdown(h1, ZX_SOCKET_SHUTDOWN_READ);
EXPECT_EQ(status, ZX_OK, "");
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals1,
ZX_SOCKET_PEER_WRITE_DISABLED | ZX_SOCKET_WRITE_DISABLED | ZX_SOCKET_PEER_CLOSED,
"");
zx_handle_close(h1);
END_TEST;
}
bool socket_shutdown_read() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_signals_t signals0, signals1;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
status = zx_socket_write(h1, 0u, "12345", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
status = zx_socket_shutdown(h0, ZX_SOCKET_SHUTDOWN_READ);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_PEER_WRITE_DISABLED,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h0, 0u, "abcde", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals1, ZX_SOCKET_READABLE | ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h1, 0u, "fghij", 5u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
char rbuf[10] = {0};
status = zx_socket_read(h0, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "12345", 5), 0, "");
status = zx_socket_read(h0, 0u, rbuf, 1u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
signals0 = get_satisfied_signals(h0);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_PEER_WRITE_DISABLED, "");
status = zx_socket_read(h1, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "abcde", 5), 0, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_bytes_outstanding() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_handle_t h[2];
uint32_t read_data[] = {0, 0};
status = zx_socket_create(0, h, h + 1);
ASSERT_EQ(status, ZX_OK, "");
status = zx_socket_read(h[0], 0u, read_data, sizeof(read_data), &count);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
constexpr uint32_t write_data[] = {0xdeadbeef, 0xc0ffee};
status = zx_socket_write(h[0], 0u, &write_data[0], sizeof(write_data[0]), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(write_data[0]), "");
status = zx_socket_write(h[0], 0u, &write_data[1], sizeof(write_data[1]), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(write_data[1]), "");
// Check the number of bytes outstanding.
zx_info_socket_t info;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h[1], ZX_INFO_SOCKET, &info, sizeof(info),
NULL, NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(info.rx_buf_available, sizeof(write_data), "");
// Check that the prior zx_socket_read call didn't disturb the pending data.
status = zx_socket_read(h[1], 0u, read_data, sizeof(read_data), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(read_data), "");
EXPECT_EQ(read_data[0], write_data[0], "");
EXPECT_EQ(read_data[1], write_data[1], "");
zx_handle_close(h[1]);
status = zx_socket_write(h[0], 0u, &write_data[1], sizeof(write_data[1]), &count);
EXPECT_EQ(status, ZX_ERR_PEER_CLOSED, "");
zx_handle_close(h[0]);
END_TEST;
}
bool socket_bytes_outstanding_shutdown_write() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_signals_t signals0, signals1;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
status = zx_socket_write(h1, 0u, "12345", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
status = zx_socket_shutdown(h1, ZX_SOCKET_SHUTDOWN_WRITE);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_PEER_WRITE_DISABLED,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h0, 0u, "abcde", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals1, ZX_SOCKET_READABLE | ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h1, 0u, "fghij", 5u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
char rbuf[10] = {0};
zx_info_socket_t info;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h0, ZX_INFO_SOCKET, &info, sizeof(info),
NULL, NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(info.rx_buf_available, 5u, "");
count = 0;
status = zx_socket_read(h0, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "12345", 5), 0, "");
status = zx_socket_read(h0, 0u, rbuf, 1u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
signals0 = get_satisfied_signals(h0);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_PEER_WRITE_DISABLED, "");
status = zx_socket_read(h1, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "abcde", 5), 0, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_bytes_outstanding_shutdown_read() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_signals_t signals0, signals1;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE, "");
status = zx_socket_write(h1, 0u, "12345", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
status = zx_socket_shutdown(h0, ZX_SOCKET_SHUTDOWN_READ);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_READABLE | ZX_SOCKET_PEER_WRITE_DISABLED,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h0, 0u, "abcde", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals1, ZX_SOCKET_READABLE | ZX_SOCKET_WRITE_DISABLED, "");
status = zx_socket_write(h1, 0u, "fghij", 5u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
char rbuf[10] = {0};
zx_info_socket_t info;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h0, ZX_INFO_SOCKET, &info, sizeof(info),
NULL, NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(info.rx_buf_available, 5u, "");
count = 0;
status = zx_socket_read(h0, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "12345", 5), 0, "");
status = zx_socket_read(h0, 0u, rbuf, 1u, &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
signals0 = get_satisfied_signals(h0);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_PEER_WRITE_DISABLED, "");
status = zx_socket_read(h1, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "abcde", 5), 0, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_short_write() {
BEGIN_TEST;
zx_status_t status;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
// TODO(qsr): Request socket buffer and use (socket_buffer + 1).
const size_t buffer_size = 256 * 1024 + 1;
fbl::Array<char> buffer(new char[buffer_size], buffer_size);
size_t written = ~(size_t)0; // This should get overwritten by the syscall.
status = zx_socket_write(h0, 0u, buffer.get(), buffer_size, &written);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_LT(written, buffer_size, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_datagram() {
BEGIN_TEST;
size_t count;
zx_status_t status;
zx_handle_t h0, h1;
unsigned char rbuf[4096] = {0}; // bigger than an mbuf
status = zx_socket_create(ZX_SOCKET_DATAGRAM, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
status = zx_socket_write(h0, 0u, "packet1", 8u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 8u, "");
status = zx_socket_write(h0, 0u, "pkt2", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
rbuf[0] = 'a';
rbuf[1000] = 'b';
rbuf[2000] = 'c';
rbuf[3000] = 'd';
rbuf[4000] = 'e';
rbuf[4095] = 'f';
status = zx_socket_write(h0, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(rbuf), "");
zx_info_socket_t info;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h1, ZX_INFO_SOCKET, &info, sizeof(info),
NULL, NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(info.rx_buf_available, 8u, "");
count = 0;
bzero(rbuf, sizeof(rbuf));
status = zx_socket_read(h1, 0u, rbuf, 3, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 3u, "");
EXPECT_EQ(memcmp(rbuf, "pac", 4), 0, ""); // short read "packet1"
count = 0;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h1, ZX_INFO_SOCKET, &info, sizeof(info),
NULL, NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(info.rx_buf_available, 5u, "");
count = 0;
status = zx_socket_read(h1, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(rbuf, "pkt2", 5), 0, "");
status = zx_socket_read(h1, 0u, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, sizeof(rbuf), "");
EXPECT_EQ(rbuf[0], 'a', "");
EXPECT_EQ(rbuf[1000], 'b', "");
EXPECT_EQ(rbuf[2000], 'c', "");
EXPECT_EQ(rbuf[3000], 'd', "");
EXPECT_EQ(rbuf[4000], 'e', "");
EXPECT_EQ(rbuf[4095], 'f', "");
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h1, ZX_INFO_SOCKET, &info, sizeof(info),
NULL, NULL);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(info.rx_buf_available, 0u, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_datagram_peek() {
BEGIN_TEST;
size_t count;
zx_handle_t h0, h1;
ASSERT_EQ(zx_socket_create(ZX_SOCKET_DATAGRAM, &h0, &h1), ZX_OK, "");
EXPECT_EQ(zx_socket_write(h0, 0u, "pkt1", 5u, &count), ZX_OK, "");
EXPECT_EQ(zx_socket_write(h0, 0u, "pkt2", 5u, &count), ZX_OK, "");
char buffer[16];
// Short peek.
EXPECT_EQ(zx_socket_read(h1, ZX_SOCKET_PEEK, buffer, 3, &count), ZX_OK, "");
EXPECT_EQ(count, 3u, "");
EXPECT_EQ(memcmp(buffer, "pkt", 3), 0, "");
// Full peek should still see the 1st packet.
EXPECT_EQ(zx_socket_read(h1, ZX_SOCKET_PEEK, buffer, 5, &count), ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(buffer, "pkt1", 5), 0, "");
// Read and consume the 1st packet.
EXPECT_EQ(zx_socket_read(h1, 0u, buffer, 5, &count), ZX_OK, "");
// Now peek should see the 2nd packet.
EXPECT_EQ(zx_socket_read(h1, ZX_SOCKET_PEEK, buffer, 5, &count), ZX_OK, "");
EXPECT_EQ(count, 5u, "");
EXPECT_EQ(memcmp(buffer, "pkt2", 5), 0, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_datagram_peek_empty() {
BEGIN_TEST;
zx_handle_t h[2];
ASSERT_EQ(zx_socket_create(ZX_SOCKET_DATAGRAM, h, h + 1), ZX_OK, "");
size_t count;
char data;
EXPECT_EQ(zx_socket_read(h[0], ZX_SOCKET_PEEK, &data, sizeof(data), &count),
ZX_ERR_SHOULD_WAIT, "");
zx_handle_close(h[0]);
zx_handle_close(h[1]);
END_TEST;
}
bool socket_datagram_no_short_write() {
BEGIN_TEST;
zx_status_t status;
zx_handle_t h0, h1;
status = zx_socket_create(ZX_SOCKET_DATAGRAM, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
zx_info_socket_t info;
memset(&info, 0, sizeof(info));
status = zx_object_get_info(h1, ZX_INFO_SOCKET, &info, sizeof(info), NULL, NULL);
ASSERT_EQ(status, ZX_OK, "zx_object_get_info");
EXPECT_GT(info.tx_buf_max, 0u, "");
// Pick a size for a huge datagram, and make sure not to overflow.
size_t buffer_size = info.tx_buf_max * 2;
EXPECT_GT(buffer_size, 0u, "");
fbl::Array<char> buffer(new char[buffer_size]{}, buffer_size);
EXPECT_NONNULL(buffer.get(), "");
size_t written = ~0u;
status = zx_socket_write(h0, 0u, buffer.get(), buffer_size, &written);
EXPECT_EQ(status, ZX_ERR_OUT_OF_RANGE, "");
// Since the syscall failed, it should not have overwritten this output
// parameter.
EXPECT_EQ(written, ~0u, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_control_plane_absent() {
BEGIN_TEST;
zx_status_t status;
zx_handle_t h0, h1;
status = zx_socket_create(0, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
status = zx_socket_write(h0, ZX_SOCKET_CONTROL, "hi", 2u, NULL);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
status = zx_socket_write(h1, ZX_SOCKET_CONTROL, "hi", 2u, NULL);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
size_t count;
char rbuf[10] = {0};
status = zx_socket_read(h0, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
status = zx_socket_read(h1, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
END_TEST;
}
bool socket_control_plane() {
BEGIN_TEST;
zx_status_t status;
zx_handle_t h0, h1;
status = zx_socket_create(ZX_SOCKET_HAS_CONTROL, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
zx_signals_t signals0 = get_satisfied_signals(h0);
zx_signals_t signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
// Write to the control plane.
size_t count;
status = zx_socket_write(h0, ZX_SOCKET_CONTROL, "hello1", 6u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 6u, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1,
ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_READABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
status = zx_socket_write(h0, ZX_SOCKET_CONTROL, "hi", 2u, NULL);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_write(h1, ZX_SOCKET_CONTROL, "hello0", 6u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 6u, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_READABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_READABLE, "");
status = zx_socket_write(h1, ZX_SOCKET_CONTROL, "hi", 2u, NULL);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
char rbuf[10] = {0};
// The control plane is independent of normal reads and writes.
status = zx_socket_read(h0, 0, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_read(h1, 0, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_write(h0, 0, "normal", 7u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 7u, "");
status = zx_socket_read(h1, 0, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 7u, "");
EXPECT_EQ(memcmp(rbuf, "normal", 7), 0, "");
// Read from the control plane.
status = zx_socket_read(h0, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 6u, "");
EXPECT_EQ(memcmp(rbuf, "hello0", 6), 0, "");
status = zx_socket_read(h0, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_read(h1, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 6u, "");
EXPECT_EQ(memcmp(rbuf, "hello1", 6), 0, "");
status = zx_socket_read(h1, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
END_TEST;
}
bool socket_control_plane_peek() {
BEGIN_TEST;
zx_handle_t h0, h1;
ASSERT_EQ(zx_socket_create(ZX_SOCKET_HAS_CONTROL, &h0, &h1), ZX_OK, "");
size_t count;
EXPECT_EQ(zx_socket_write(h0, ZX_SOCKET_CONTROL, "hello0", 6u, &count), ZX_OK, "");
EXPECT_EQ(count, 6u, "");
char rbuf[10] = {0};
EXPECT_EQ(zx_socket_read(h1, ZX_SOCKET_CONTROL | ZX_SOCKET_PEEK, rbuf, sizeof(rbuf), &count),
ZX_OK, "");
EXPECT_EQ(count, 6u, "");
EXPECT_EQ(memcmp(rbuf, "hello0", 6), 0, "");
// The message should still be pending for h1 to read.
EXPECT_EQ(get_satisfied_signals(h0), ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(get_satisfied_signals(h1),
ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE | ZX_SOCKET_CONTROL_READABLE, "");
rbuf[0] = '\0';
EXPECT_EQ(zx_socket_read(h1, ZX_SOCKET_CONTROL, rbuf, sizeof(rbuf), &count), ZX_OK, "");
EXPECT_EQ(count, 6u, "");
EXPECT_EQ(memcmp(rbuf, "hello0", 6), 0, "");
EXPECT_EQ(get_satisfied_signals(h0), ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
EXPECT_EQ(get_satisfied_signals(h1), ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
zx_handle_close(h0);
zx_handle_close(h1);
END_TEST;
}
bool socket_control_plane_peek_empty() {
BEGIN_TEST;
zx_handle_t h[2];
ASSERT_EQ(zx_socket_create(ZX_SOCKET_HAS_CONTROL, h, h + 1), ZX_OK, "");
size_t count;
char data;
EXPECT_EQ(zx_socket_read(h[0], ZX_SOCKET_CONTROL | ZX_SOCKET_PEEK, &data, sizeof(data), &count),
ZX_ERR_SHOULD_WAIT, "");
zx_handle_close(h[0]);
zx_handle_close(h[1]);
END_TEST;
}
bool socket_control_plane_shutdown() {
BEGIN_TEST;
zx_status_t status;
size_t count;
zx_handle_t h0, h1;
status = zx_socket_create(ZX_SOCKET_HAS_CONTROL, &h0, &h1);
ASSERT_EQ(status, ZX_OK, "");
zx_signals_t signals0 = get_satisfied_signals(h0);
zx_signals_t signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE, "");
status = zx_socket_write(h1, 0u, "12345", 5u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 5u, "");
status = zx_socket_shutdown(h1, ZX_SOCKET_SHUTDOWN_WRITE);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_WRITABLE | ZX_SOCKET_READABLE |
ZX_SOCKET_PEER_WRITE_DISABLED,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITE_DISABLED | ZX_SOCKET_CONTROL_WRITABLE, "");
status = zx_socket_write(h0, ZX_SOCKET_CONTROL, "hello1", 6u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 6u, "");
status = zx_socket_write(h1, ZX_SOCKET_CONTROL, "hello0", 6u, &count);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(count, 6u, "");
signals0 = get_satisfied_signals(h0);
signals1 = get_satisfied_signals(h1);
EXPECT_EQ(signals0,
ZX_SOCKET_WRITABLE | ZX_SOCKET_CONTROL_READABLE | ZX_SOCKET_READABLE |
ZX_SOCKET_PEER_WRITE_DISABLED,
"");
EXPECT_EQ(signals1, ZX_SOCKET_WRITE_DISABLED | ZX_SOCKET_CONTROL_READABLE, "");
END_TEST;
}
bool socket_accept() {
BEGIN_TEST;
zx_status_t status;
zx_handle_t a0, a1;
status = zx_socket_create(ZX_SOCKET_HAS_ACCEPT, &a0, &a1);
ASSERT_EQ(status, ZX_OK, "");
zx_handle_t b0, b1;
status = zx_socket_create(0, &b0, &b1);
ASSERT_EQ(status, ZX_OK, "");
zx_handle_t c0, c1;
status = zx_socket_create(0, &c0, &c1);
ASSERT_EQ(status, ZX_OK, "");
zx_signals_t signals0 = get_satisfied_signals(a0);
zx_signals_t signals1 = get_satisfied_signals(a1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_SHARE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_SHARE, "");
// cannot share a HAS_ACCEPT socket
status = zx_socket_share(b0, a0);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
zx_handle_close(a1);
status = zx_socket_create(ZX_SOCKET_HAS_ACCEPT, &a0, &a1);
ASSERT_EQ(status, ZX_OK, "");
// cannot share via a non-HAS_ACCEPT socket
status = zx_socket_share(b0, c0);
EXPECT_EQ(status, ZX_ERR_NOT_SUPPORTED, "");
// cannot share a socket via itself (either direction)
status = zx_socket_share(a0, a0);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
zx_handle_close(a1);
status = zx_socket_create(ZX_SOCKET_HAS_ACCEPT, &a0, &a1);
ASSERT_EQ(status, ZX_OK, "");
status = zx_socket_share(a0, a1);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
zx_handle_close(a0);
status = zx_socket_create(ZX_SOCKET_HAS_ACCEPT, &a0, &a1);
ASSERT_EQ(status, ZX_OK, "");
status = zx_socket_share(a1, a0);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
zx_handle_close(a1);
status = zx_socket_create(ZX_SOCKET_HAS_ACCEPT, &a0, &a1);
ASSERT_EQ(status, ZX_OK, "");
status = zx_socket_share(a1, a1);
EXPECT_EQ(status, ZX_ERR_BAD_STATE, "");
zx_handle_close(a0);
status = zx_socket_create(ZX_SOCKET_HAS_ACCEPT, &a0, &a1);
ASSERT_EQ(status, ZX_OK, "");
// cannot accept from a non-HAS_ACCEPT socket
zx_handle_t h;
status = zx_socket_accept(b0, &h);
EXPECT_EQ(status, ZX_ERR_NOT_SUPPORTED, "");
status = zx_socket_share(a0, b0);
EXPECT_EQ(status, ZX_OK, "");
signals0 = get_satisfied_signals(a0);
signals1 = get_satisfied_signals(a1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_SHARE | ZX_SOCKET_ACCEPT, "");
// queue is only one deep
status = zx_socket_share(a0, b1);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_accept(a1, &h);
EXPECT_EQ(status, ZX_OK, "");
b0 = h;
// queue is only one deep
status = zx_socket_accept(a0, &h);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
signals0 = get_satisfied_signals(a0);
signals1 = get_satisfied_signals(a1);
EXPECT_EQ(signals0, ZX_SOCKET_WRITABLE | ZX_SOCKET_SHARE, "");
EXPECT_EQ(signals1, ZX_SOCKET_WRITABLE | ZX_SOCKET_SHARE, "");
zx_handle_close(a0);
zx_handle_close(a1);
zx_handle_close(b0);
zx_handle_close(b1);
zx_handle_close(c0);
zx_handle_close(c1);
END_TEST;
}
bool socket_share_invalid_handle() {
BEGIN_TEST;
zx_handle_t socket[2];
zx_status_t status = zx_socket_create(0, &socket[0], &socket[1]);
EXPECT_EQ(status, ZX_OK, "");
status = zx_socket_share(socket[0], ZX_HANDLE_INVALID);
EXPECT_EQ(status, ZX_ERR_BAD_HANDLE, "");
zx_handle_close(socket[0]);
zx_handle_close(socket[1]);
END_TEST;
}
bool socket_zero_size() {
BEGIN_TEST;
zx_handle_t socket[2];
zx_status_t status = zx_socket_create(0, &socket[0], &socket[1]);
EXPECT_EQ(status, ZX_OK, "");
char buffer;
status = zx_socket_read(socket[0], 0, &buffer, 0, NULL);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_write(socket[0], 0, "a", 1, NULL);
EXPECT_EQ(status, ZX_OK, "");
status = zx_socket_read(socket[0], 0, &buffer, 0, NULL);
EXPECT_EQ(status, ZX_OK, "");
zx_handle_close(socket[0]);
zx_handle_close(socket[1]);
status = zx_socket_create(ZX_SOCKET_DATAGRAM, &socket[0], &socket[1]);
EXPECT_EQ(status, ZX_OK, "");
status = zx_socket_read(socket[0], 0, &buffer, 0, NULL);
EXPECT_EQ(status, ZX_ERR_SHOULD_WAIT, "");
status = zx_socket_write(socket[0], 0, "a", 1, NULL);
EXPECT_EQ(status, ZX_OK, "");
status = zx_socket_read(socket[0], 0, &buffer, 0, NULL);
EXPECT_EQ(status, ZX_OK, "");
zx_handle_close(socket[0]);
zx_handle_close(socket[1]);
END_TEST;
}
bool socket_share_consumes_on_failure() {
BEGIN_TEST;
zx_handle_t socket[2];
zx_status_t status = zx_socket_create(0, &socket[0], &socket[1]);
EXPECT_EQ(status, ZX_OK, "");
zx_handle_t eventpair[2];
status = zx_eventpair_create(0, &eventpair[0], &eventpair[1]);
EXPECT_EQ(status, ZX_OK, "");
status = zx_socket_share(socket[0], eventpair[0]);
EXPECT_EQ(status, ZX_ERR_WRONG_TYPE, "");
// eventpair[0] should have been closed, which we can detect by
// waiting on its peer.
zx_signals_t signals;
status = zx_object_wait_one(eventpair[1], ZX_EVENTPAIR_PEER_CLOSED, 0u, &signals);
EXPECT_EQ(status, ZX_OK, "");
EXPECT_EQ(signals & ZX_EVENTPAIR_PEER_CLOSED, ZX_EVENTPAIR_PEER_CLOSED, "");
zx_handle_close(socket[0]);
zx_handle_close(socket[1]);
zx_handle_close(eventpair[1]);
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(socket_tests)
RUN_TEST(socket_basic)
RUN_TEST(socket_peek)
RUN_TEST(socket_peek_empty)
RUN_TEST(socket_signals)
RUN_TEST(socket_peer_closed_signal)
RUN_TEST(socket_peer_closed_set_property)
RUN_TEST(socket_shutdown_write)
RUN_TEST(socket_shutdown_read)
RUN_TEST(socket_bytes_outstanding)
RUN_TEST(socket_bytes_outstanding_shutdown_write)
RUN_TEST(socket_bytes_outstanding_shutdown_read)
RUN_TEST(socket_short_write)
RUN_TEST(socket_datagram)
RUN_TEST(socket_datagram_peek)
RUN_TEST(socket_datagram_peek_empty)
RUN_TEST(socket_datagram_no_short_write)
RUN_TEST(socket_control_plane_absent)
RUN_TEST(socket_control_plane)
RUN_TEST(socket_control_plane_peek)
RUN_TEST(socket_control_plane_peek_empty)
RUN_TEST(socket_control_plane_shutdown)
RUN_TEST(socket_accept)
RUN_TEST(socket_share_invalid_handle)
RUN_TEST(socket_share_consumes_on_failure)
RUN_TEST(socket_signals2)
END_TEST_CASE(socket_tests)