summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2018-10-09 10:30:24 +0000
committerHåvard Pettersen <havardpe@oath.com>2018-10-09 10:32:05 +0000
commit58850f92f00b6289ff5feccf3634a34943e760d2 (patch)
treedb6b2ba5b94fd2776608f4a8f2da18891330e270 /vespalib
parent71f6af23c4bccee32cc33e9a3a391b7b9cf96629 (diff)
added simple test for various crypto sockets
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/CMakeLists.txt1
-rw-r--r--vespalib/src/tests/net/crypto_socket/CMakeLists.txt8
-rw-r--r--vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp190
3 files changed, 199 insertions, 0 deletions
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt
index 58f2cbc8891..264f274db15 100644
--- a/vespalib/CMakeLists.txt
+++ b/vespalib/CMakeLists.txt
@@ -54,6 +54,7 @@ vespa_define_module(
src/tests/make_fixture_macros
src/tests/memory
src/tests/net/async_resolver
+ src/tests/net/crypto_socket
src/tests/net/selector
src/tests/net/send_fd
src/tests/net/socket
diff --git a/vespalib/src/tests/net/crypto_socket/CMakeLists.txt b/vespalib/src/tests/net/crypto_socket/CMakeLists.txt
new file mode 100644
index 00000000000..52e64abc128
--- /dev/null
+++ b/vespalib/src/tests/net/crypto_socket/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_crypto_socket_test_app TEST
+ SOURCES
+ crypto_socket_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_crypto_socket_test_app COMMAND vespalib_crypto_socket_test_app)
diff --git a/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp b/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp
new file mode 100644
index 00000000000..91babc51476
--- /dev/null
+++ b/vespalib/src/tests/net/crypto_socket/crypto_socket_test.cpp
@@ -0,0 +1,190 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/testkit/test_kit.h>
+#include <vespa/vespalib/net/crypto_engine.h>
+#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
+#include <vespa/vespalib/net/tls/maybe_tls_crypto_engine.h>
+#include <vespa/vespalib/net/crypto_socket.h>
+#include <vespa/vespalib/net/selector.h>
+#include <vespa/vespalib/net/server_socket.h>
+#include <vespa/vespalib/net/socket_handle.h>
+#include <vespa/vespalib/net/socket_spec.h>
+#include <vespa/vespalib/data/smart_buffer.h>
+#include <vespa/vespalib/test/make_tls_options_for_testing.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+using namespace vespalib;
+
+struct SocketPair {
+ SocketHandle client;
+ SocketHandle server;
+ SocketPair() : client(), server() {
+ int sockets[2];
+ ASSERT_EQUAL(0, socketpair(AF_UNIX, SOCK_STREAM | O_NONBLOCK, 0, sockets));
+ client.reset(sockets[0]);
+ server.reset(sockets[1]);
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+bool is_blocked(int res) {
+ return ((res == -1) && ((errno == EWOULDBLOCK) || (errno == EAGAIN)));
+}
+
+void read(CryptoSocket &socket, SmartBuffer &buffer) {
+ size_t chunk_size = std::max(size_t(4096), socket.min_read_buffer_size());
+ auto chunk = buffer.reserve(chunk_size);
+ int res = socket.read(chunk.data, chunk.size);
+ if (res > 0) {
+ buffer.commit(res);
+ } else {
+ ASSERT_TRUE(is_blocked(res));
+ }
+}
+
+void drain(CryptoSocket &socket, SmartBuffer &buffer) {
+ int res;
+ size_t chunk_size = std::max(size_t(4096), socket.min_read_buffer_size());
+ do {
+ auto chunk = buffer.reserve(chunk_size);
+ res = socket.drain(chunk.data, chunk.size);
+ if (res > 0) {
+ buffer.commit(res);
+ }
+ } while (res > 0);
+ ASSERT_EQUAL(res, 0);
+}
+
+void write(CryptoSocket &socket, SmartBuffer &buffer) {
+ auto chunk = buffer.obtain();
+ auto res = socket.write(chunk.data, chunk.size);
+ if (res > 0) {
+ buffer.evict(res);
+ } else {
+ ASSERT_TRUE(is_blocked(res));
+ }
+}
+
+void flush(CryptoSocket &socket) {
+ int res = 1;
+ while (res > 0) {
+ res = socket.flush();
+ }
+ ASSERT_TRUE((res == 0) || is_blocked(res));
+}
+
+//-----------------------------------------------------------------------------
+
+vespalib::string read_bytes(CryptoSocket &socket, SmartBuffer &read_buffer, size_t wanted_bytes) {
+ SingleFdSelector selector(socket.get_fd());
+ while (read_buffer.obtain().size < wanted_bytes) {
+ ASSERT_TRUE(selector.wait_readable());
+ read(socket, read_buffer);
+ drain(socket, read_buffer);
+ }
+ auto data = read_buffer.obtain();
+ return vespalib::string(data.data, wanted_bytes);
+}
+
+//-----------------------------------------------------------------------------
+
+void write_bytes(CryptoSocket &socket, const vespalib::string &message) {
+ SmartBuffer write_buffer(message.size());
+ SingleFdSelector selector(socket.get_fd());
+ auto data = write_buffer.reserve(message.size());
+ memcpy(data.data, message.data(), message.size());
+ write_buffer.commit(message.size());
+ while (write_buffer.obtain().size > 0) {
+ ASSERT_TRUE(selector.wait_writable());
+ write(socket, write_buffer);
+ flush(socket);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void verify_socket_io(CryptoSocket &socket, SmartBuffer &read_buffer, bool is_server) {
+ vespalib::string client_message = "please pick up, I need to talk to you";
+ vespalib::string server_message = "hello, this is the server speaking";
+ if(is_server) {
+ vespalib::string read = read_bytes(socket, read_buffer, client_message.size());
+ write_bytes(socket, server_message);
+ EXPECT_EQUAL(client_message, read);
+ } else {
+ write_bytes(socket, client_message);
+ vespalib::string read = read_bytes(socket, read_buffer, server_message.size());
+ EXPECT_EQUAL(server_message, read);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void verify_handshake(CryptoSocket &socket) {
+ bool done = false;
+ SingleFdSelector selector(socket.get_fd());
+ while (!done) {
+ auto res = socket.handshake();
+ ASSERT_TRUE(res != CryptoSocket::HandshakeResult::FAIL);
+ switch (res) {
+ case CryptoSocket::HandshakeResult::FAIL:
+ case CryptoSocket::HandshakeResult::DONE:
+ done = true;
+ break;
+ case CryptoSocket::HandshakeResult::NEED_READ:
+ ASSERT_TRUE(selector.wait_readable());
+ break;
+ case CryptoSocket::HandshakeResult::NEED_WRITE:
+ ASSERT_TRUE(selector.wait_writable());
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void verify_crypto_socket(SocketPair &sockets, CryptoEngine &engine, bool is_server) {
+ SocketHandle &my_handle = is_server ? sockets.server : sockets.client;
+ my_handle.set_blocking(false);
+ SmartBuffer read_buffer(4096);
+ CryptoSocket::UP my_socket = engine.create_crypto_socket(std::move(my_handle), is_server);
+ TEST_DO(verify_handshake(*my_socket));
+ drain(*my_socket, read_buffer);
+ TEST_DO(verify_socket_io(*my_socket, read_buffer, is_server));
+}
+
+//-----------------------------------------------------------------------------
+
+TEST_MT_FFF("require that encrypted async socket io works with NullCryptoEngine",
+ 2, SocketPair(), NullCryptoEngine(), TimeBomb(60))
+{
+ TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0)));
+}
+
+TEST_MT_FFF("require that encrypted async socket io works with XorCryptoEngine",
+ 2, SocketPair(), XorCryptoEngine(), TimeBomb(60))
+{
+ TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0)));
+}
+
+TEST_MT_FFF("require that encrypted async socket io works with TlsCryptoEngine",
+ 2, SocketPair(), TlsCryptoEngine(vespalib::test::make_tls_options_for_testing()), TimeBomb(60))
+{
+ TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0)));
+}
+
+TEST_MT_FFF("require that encrypted async socket io works with MaybeTlsCryptoEngine(true)",
+ 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()), true), TimeBomb(60))
+{
+ TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0)));
+}
+
+TEST_MT_FFF("require that encrypted async socket io works with MaybeTlsCryptoEngine(false)",
+ 2, SocketPair(), MaybeTlsCryptoEngine(std::make_shared<TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing()), false), TimeBomb(60))
+{
+ TEST_DO(verify_crypto_socket(f1, f2, (thread_id == 0)));
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }