aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHaavard <havardpe@yahoo-inc.com>2017-04-21 14:33:12 +0000
committerHaavard <havardpe@yahoo-inc.com>2017-04-21 21:04:33 +0000
commitbbf11af22fff91b6f8f757a252ee4255bd018166 (patch)
tree7f8306230bfc0d37a7baa91589705c0cdd571a0c /vespalib
parent33390132c1249768e445d8272bbfe421c6d2a5fc (diff)
let socket handle handle more socket stuff
very simple Socket/SimpleSocket stop using fastos sockets in websocket experimental code stop using fastos sockets in vbench
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/net/socket/socket_client.cpp15
-rw-r--r--vespalib/src/tests/net/socket/socket_server.cpp23
-rw-r--r--vespalib/src/tests/net/socket/socket_test.cpp134
-rw-r--r--vespalib/src/tests/websocket/websocket_test.cpp39
-rw-r--r--vespalib/src/vespa/vespalib/net/server_socket.cpp70
-rw-r--r--vespalib/src/vespa/vespalib/net/server_socket.h19
-rw-r--r--vespalib/src/vespa/vespalib/net/socket.cpp51
-rw-r--r--vespalib/src/vespa/vespalib/net/socket.h37
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_address.cpp10
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_handle.cpp41
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_handle.h15
-rw-r--r--vespalib/src/vespa/vespalib/websocket/CMakeLists.txt2
-rw-r--r--vespalib/src/vespa/vespalib/websocket/acceptor.cpp15
-rw-r--r--vespalib/src/vespa/vespalib/websocket/acceptor.h7
-rw-r--r--vespalib/src/vespa/vespalib/websocket/connection.h2
-rw-r--r--vespalib/src/vespa/vespalib/websocket/server_socket.cpp44
-rw-r--r--vespalib/src/vespa/vespalib/websocket/server_socket.h31
-rw-r--r--vespalib/src/vespa/vespalib/websocket/socket.cpp44
-rw-r--r--vespalib/src/vespa/vespalib/websocket/socket.h29
19 files changed, 238 insertions, 390 deletions
diff --git a/vespalib/src/tests/net/socket/socket_client.cpp b/vespalib/src/tests/net/socket/socket_client.cpp
index e12fe5330d0..fd4abd2813d 100644
--- a/vespalib/src/tests/net/socket/socket_client.cpp
+++ b/vespalib/src/tests/net/socket/socket_client.cpp
@@ -11,7 +11,7 @@
using namespace vespalib;
-vespalib::string read_msg(Socket &socket) {
+vespalib::string read_msg(SocketHandle &socket) {
vespalib::string msg;
for (;;) {
char c;
@@ -27,7 +27,7 @@ vespalib::string read_msg(Socket &socket) {
}
}
-void write_msg(Socket &socket, const vespalib::string &msg) {
+void write_msg(SocketHandle &socket, const vespalib::string &msg) {
for (size_t i = 0; i < msg.size(); ++i) {
ssize_t ret = socket.write(&msg[i], 1);
if (ret != 1) {
@@ -53,14 +53,15 @@ int main(int argc, char **argv) {
fprintf(stderr, " %s\n", addr.spec().c_str());
}
}
- Socket::UP socket = Socket::connect(SocketSpec::from_host_port(host, port));
- if (!socket->valid()) {
+ SocketHandle socket = SocketSpec::from_host_port(host, port).client_address().connect();
+ if (!socket.valid()) {
fprintf(stderr, "connect failed\n");
return 1;
}
fprintf(stderr, "connected to: %s (local address: %s)\n",
- socket->peer_address().spec().c_str(), socket->address().spec().c_str());
- write_msg(*socket, "hello from client\n");
- fprintf(stderr, "message from server: '%s'\n", read_msg(*socket).c_str());
+ SocketAddress::peer_address(socket.get()).spec().c_str(),
+ SocketAddress::address_of(socket.get()).spec().c_str());
+ write_msg(socket, "hello from client\n");
+ fprintf(stderr, "message from server: '%s'\n", read_msg(socket).c_str());
return 0;
}
diff --git a/vespalib/src/tests/net/socket/socket_server.cpp b/vespalib/src/tests/net/socket/socket_server.cpp
index ff8d77f317d..c14c69caa70 100644
--- a/vespalib/src/tests/net/socket/socket_server.cpp
+++ b/vespalib/src/tests/net/socket/socket_server.cpp
@@ -12,7 +12,7 @@
using namespace vespalib;
-vespalib::string read_msg(Socket &socket) {
+vespalib::string read_msg(SocketHandle &socket) {
vespalib::string msg;
for (;;) {
char c;
@@ -28,7 +28,7 @@ vespalib::string read_msg(Socket &socket) {
}
}
-void write_msg(Socket &socket, const vespalib::string &msg) {
+void write_msg(SocketHandle &socket, const vespalib::string &msg) {
for (size_t i = 0; i < msg.size(); ++i) {
ssize_t ret = socket.write(&msg[i], 1);
if (ret != 1) {
@@ -39,8 +39,8 @@ void write_msg(Socket &socket, const vespalib::string &msg) {
}
int main(int, char **) {
- ServerSocket::UP server = ServerSocket::listen(SocketSpec::from_port(0));
- if (!server->valid()) {
+ ServerSocket server(0);
+ if (!server.valid()) {
fprintf(stderr, "listen failed, exiting\n");
return 1;
}
@@ -52,18 +52,19 @@ int main(int, char **) {
fprintf(stderr, " %s\n", addr.spec().c_str());
}
}
- fprintf(stderr, "listening to %s\n", server->address().spec().c_str());
+ fprintf(stderr, "listening to %s\n", server.address().spec().c_str());
fprintf(stderr, "client command: ./vespalib_socket_client_app %s %d\n",
- HostName::get().c_str(), server->address().port());
+ HostName::get().c_str(), server.address().port());
fprintf(stderr, "use ^C (SIGINT) to exit\n");
SignalHandler::INT.hook();
while (!SignalHandler::INT.check()) {
- Socket::UP socket = server->accept();
- if (socket->valid()) {
+ SocketHandle socket = server.accept();
+ if (socket.valid()) {
fprintf(stderr, "got connection from: %s (local address: %s)\n",
- socket->peer_address().spec().c_str(), socket->address().spec().c_str());
- fprintf(stderr, "message from client: '%s'\n", read_msg(*socket).c_str());
- write_msg(*socket, "hello from server\n");
+ SocketAddress::peer_address(socket.get()).spec().c_str(),
+ SocketAddress::address_of(socket.get()).spec().c_str());
+ fprintf(stderr, "message from client: '%s'\n", read_msg(socket).c_str());
+ write_msg(socket, "hello from server\n");
} else {
fprintf(stderr, "(got invalid socket from accept)\n");
}
diff --git a/vespalib/src/tests/net/socket/socket_test.cpp b/vespalib/src/tests/net/socket/socket_test.cpp
index bf0a5a2f273..c4b1e5286b2 100644
--- a/vespalib/src/tests/net/socket/socket_test.cpp
+++ b/vespalib/src/tests/net/socket/socket_test.cpp
@@ -74,7 +74,7 @@ vespalib::string get_meta(const SocketAddress &addr) {
return meta;
}
-vespalib::string read_bytes(Socket &socket, size_t wanted_bytes) {
+vespalib::string read_bytes(SocketHandle &socket, size_t wanted_bytes) {
char tmp[64];
vespalib::string result;
while (result.size() < wanted_bytes) {
@@ -88,7 +88,7 @@ vespalib::string read_bytes(Socket &socket, size_t wanted_bytes) {
return result;
}
-void verify_socket_io(bool is_server, Socket &socket) {
+void verify_socket_io(bool is_server, SocketHandle &socket) {
vespalib::string server_message = "hello, this is the server speaking";
vespalib::string client_message = "please pick up, I need to talk to you";
if(is_server) {
@@ -104,7 +104,7 @@ void verify_socket_io(bool is_server, Socket &socket) {
}
}
-Socket::UP connect_sockets(bool is_server, ServerSocket &server_socket) {
+SocketHandle connect_sockets(bool is_server, ServerSocket &server_socket) {
if (is_server) {
return server_socket.accept();
} else {
@@ -113,7 +113,7 @@ Socket::UP connect_sockets(bool is_server, ServerSocket &server_socket) {
auto client = SocketSpec(spec).client_address();
fprintf(stderr, "connecting to '%s' (server: %s) (client: %s)\n",
spec.c_str(), get_meta(server).c_str(), get_meta(client).c_str());
- return Socket::connect(SocketSpec(spec));
+ return client.connect();
}
}
@@ -187,84 +187,79 @@ TEST("local client/server addresses") {
fprintf(stderr, "server(tcp/123): %s (%s)\n", server.spec().c_str(), get_meta(server).c_str());
}
-struct ServerWrapper {
- ServerSocket::UP server;
- ServerWrapper(const vespalib::string &spec) : server(ServerSocket::listen(SocketSpec(spec))) {}
-};
-
-TEST_MT_FF("require that basic socket io works", 2, ServerWrapper("tcp/0"), TimeBomb(60)) {
+TEST_MT_FF("require that basic socket io works", 2, ServerSocket("tcp/0"), TimeBomb(60)) {
bool is_server = (thread_id == 0);
- Socket::UP socket = connect_sockets(is_server, *f1.server);
- TEST_DO(verify_socket_io(is_server, *socket));
+ SocketHandle socket = connect_sockets(is_server, f1);
+ TEST_DO(verify_socket_io(is_server, socket));
}
TEST_MT_FF("require that basic unix domain socket io works (path)", 2,
- ServerWrapper("ipc/file:my_socket"), TimeBomb(60))
+ ServerSocket("ipc/file:my_socket"), TimeBomb(60))
{
bool is_server = (thread_id == 0);
- Socket::UP socket = connect_sockets(is_server, *f1.server);
- TEST_DO(verify_socket_io(is_server, *socket));
+ SocketHandle socket = connect_sockets(is_server, f1);
+ TEST_DO(verify_socket_io(is_server, socket));
}
TEST_MT_FF("require that basic unix domain socket io works (name)", 2,
- ServerWrapper(make_string("ipc/name:my_socket-%d", int(getpid()))), TimeBomb(60))
+ ServerSocket(make_string("ipc/name:my_socket-%d", int(getpid()))), TimeBomb(60))
{
bool is_server = (thread_id == 0);
- Socket::UP socket = connect_sockets(is_server, *f1.server);
- TEST_DO(verify_socket_io(is_server, *socket));
+ SocketHandle socket = connect_sockets(is_server, f1);
+ TEST_DO(verify_socket_io(is_server, socket));
}
-TEST_MT_FF("require that server accept can be interrupted", 2, ServerWrapper("tcp/0"), TimeBomb(60)) {
+TEST_MT_FF("require that server accept can be interrupted", 2, ServerSocket("tcp/0"), TimeBomb(60)) {
bool is_server = (thread_id == 0);
if (is_server) {
fprintf(stderr, "--> calling accept\n");
- Socket::UP socket = f1.server->accept();
+ SocketHandle socket = f1.accept();
fprintf(stderr, "<-- accept returned\n");
- EXPECT_TRUE(!socket->valid());
+ EXPECT_TRUE(!socket.valid());
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
fprintf(stderr, "--- closing server socket\n");
- f1.server->shutdown();
+ f1.shutdown();
}
}
TEST("require that socket file is removed by server socket when destructed") {
remove_file("my_socket");
- ServerSocket::UP server = ServerSocket::listen(SocketSpec("ipc/file:my_socket"));
- EXPECT_TRUE(server->valid());
+ ServerSocket server("ipc/file:my_socket");
+ EXPECT_TRUE(server.valid());
EXPECT_TRUE(is_socket("my_socket"));
- server.reset();
+ server = ServerSocket("invalid");
EXPECT_TRUE(!is_socket("my_socket"));
}
TEST("require that socket file is only removed on destruction if it is a socket") {
remove_file("my_socket");
- ServerSocket::UP server = ServerSocket::listen(SocketSpec("ipc/file:my_socket"));
- EXPECT_TRUE(server->valid());
+ ServerSocket server("ipc/file:my_socket");
+ EXPECT_TRUE(server.valid());
EXPECT_TRUE(is_socket("my_socket"));
replace_file("my_socket", "hello\n");
- server.reset();
+ server = ServerSocket("invalid");
EXPECT_TRUE(is_file("my_socket"));
remove_file("my_socket");
}
TEST("require that a server socket will fail to listen to a path that is already a regular file") {
replace_file("my_socket", "hello\n");
- ServerSocket::UP server = ServerSocket::listen(SocketSpec("ipc/file:my_socket"));
- EXPECT_TRUE(!server->valid());
- server.reset();
+ ServerSocket server("ipc/file:my_socket");
+ EXPECT_TRUE(!server.valid());
+ server = ServerSocket("invalid");
EXPECT_TRUE(is_file("my_socket"));
remove_file("my_socket");
}
TEST("require that a server socket will fail to listen to a path that is already taken by another server") {
remove_file("my_socket");
- ServerSocket::UP server1 = ServerSocket::listen(SocketSpec("ipc/file:my_socket"));
- ServerSocket::UP server2 = ServerSocket::listen(SocketSpec("ipc/file:my_socket"));
- EXPECT_TRUE(server1->valid());
- EXPECT_TRUE(!server2->valid());
+ ServerSocket server1("ipc/file:my_socket");
+ ServerSocket server2("ipc/file:my_socket");
+ EXPECT_TRUE(server1.valid());
+ EXPECT_TRUE(!server2.valid());
EXPECT_TRUE(is_socket("my_socket"));
- server1.reset();
+ server1 = ServerSocket("invalid");
EXPECT_TRUE(!is_socket("my_socket"));
}
@@ -275,55 +270,54 @@ TEST("require that a server socket will remove an old socket file if it cannot b
EXPECT_TRUE(is_socket("my_socket"));
}
EXPECT_TRUE(is_socket("my_socket"));
- ServerSocket::UP server = ServerSocket::listen(SocketSpec("ipc/file:my_socket"));
- EXPECT_TRUE(server->valid());
- server.reset();
+ ServerSocket server("ipc/file:my_socket");
+ EXPECT_TRUE(server.valid());
+ server = ServerSocket("invalid");
EXPECT_TRUE(!is_socket("my_socket"));
}
TEST("require that two server sockets cannot have the same abstract unix domain socket name") {
vespalib::string spec = make_string("ipc/name:my_socket-%d", int(getpid()));
- ServerSocket::UP server1 = ServerSocket::listen(SocketSpec(spec));
- ServerSocket::UP server2 = ServerSocket::listen(SocketSpec(spec));
- EXPECT_TRUE(server1->valid());
- EXPECT_TRUE(!server2->valid());
+ ServerSocket server1(spec);
+ ServerSocket server2(spec);
+ EXPECT_TRUE(server1.valid());
+ EXPECT_TRUE(!server2.valid());
}
TEST("require that abstract socket names are freed when the server socket is destructed") {
vespalib::string spec = make_string("ipc/name:my_socket-%d", int(getpid()));
- ServerSocket::UP server1 = ServerSocket::listen(SocketSpec(spec));
- EXPECT_TRUE(server1->valid());
- server1.reset();
- ServerSocket::UP server2 = ServerSocket::listen(SocketSpec(spec));
- EXPECT_TRUE(server2->valid());
+ ServerSocket server1(spec);
+ EXPECT_TRUE(server1.valid());
+ server1 = ServerSocket("invalid");
+ ServerSocket server2(spec);
+ EXPECT_TRUE(server2.valid());
}
TEST("require that abstract sockets do not have socket files") {
vespalib::string name = make_string("my_socket-%d", int(getpid()));
- vespalib::string spec = make_string("ipc/name:%s", name.c_str());
- ServerSocket::UP server = ServerSocket::listen(SocketSpec(spec));
- EXPECT_TRUE(server->valid());
+ ServerSocket server(SocketSpec::from_name(name));
+ EXPECT_TRUE(server.valid());
EXPECT_TRUE(!is_socket(name));
EXPECT_TRUE(!is_file(name));
}
TEST_MT_FFF("require that abstract and file-based unix domain sockets are not in conflict", 4,
- ServerWrapper(make_string("ipc/file:my_socket-%d", int(getpid()))),
- ServerWrapper(make_string("ipc/name:my_socket-%d", int(getpid()))), TimeBomb(60))
+ ServerSocket(make_string("ipc/file:my_socket-%d", int(getpid()))),
+ ServerSocket(make_string("ipc/name:my_socket-%d", int(getpid()))), TimeBomb(60))
{
bool is_server = ((thread_id % 2) == 0);
- ServerSocket &server_socket = ((thread_id / 2) == 0) ? *f1.server : *f2.server;
- Socket::UP socket = connect_sockets(is_server, server_socket);
- TEST_DO(verify_socket_io(is_server, *socket));
+ ServerSocket &server_socket = ((thread_id / 2) == 0) ? f1 : f2;
+ SocketHandle socket = connect_sockets(is_server, server_socket);
+ TEST_DO(verify_socket_io(is_server, socket));
}
TEST("require that sockets can be set blocking and non-blocking") {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_blocking(-1, true));
- EXPECT_TRUE(SocketOptions::set_blocking(handle.get(), true));
+ EXPECT_TRUE(handle.set_blocking(true));
TEST_DO(verifier.verify_blocking(true));
- EXPECT_TRUE(SocketOptions::set_blocking(handle.get(), false));
+ EXPECT_TRUE(handle.set_blocking(false));
TEST_DO(verifier.verify_blocking(false));
}
@@ -331,9 +325,9 @@ TEST("require that tcp nodelay can be enabled and disabled") {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_nodelay(-1, true));
- EXPECT_TRUE(SocketOptions::set_nodelay(handle.get(), true));
+ EXPECT_TRUE(handle.set_nodelay(true));
TEST_DO(verifier.verify_nodelay(true));
- EXPECT_TRUE(SocketOptions::set_nodelay(handle.get(), false));
+ EXPECT_TRUE(handle.set_nodelay(false));
TEST_DO(verifier.verify_nodelay(false));
}
@@ -341,9 +335,9 @@ TEST("require that reuse addr can be set and cleared") {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_reuse_addr(-1, true));
- EXPECT_TRUE(SocketOptions::set_reuse_addr(handle.get(), true));
+ EXPECT_TRUE(handle.set_reuse_addr(true));
TEST_DO(verifier.verify_reuse_addr(true));
- EXPECT_TRUE(SocketOptions::set_reuse_addr(handle.get(), false));
+ EXPECT_TRUE(handle.set_reuse_addr(false));
TEST_DO(verifier.verify_reuse_addr(false));
}
@@ -352,9 +346,9 @@ TEST("require that ipv6_only can be set and cleared") {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_ipv6_only(-1, true));
- EXPECT_TRUE(SocketOptions::set_ipv6_only(handle.get(), true));
+ EXPECT_TRUE(handle.set_ipv6_only(true));
TEST_DO(verifier.verify_ipv6_only(true));
- EXPECT_TRUE(SocketOptions::set_ipv6_only(handle.get(), false));
+ EXPECT_TRUE(handle.set_ipv6_only(false));
TEST_DO(verifier.verify_ipv6_only(false));
} else {
fprintf(stderr, "WARNING: skipping ipv6_only test since ipv6 is disabled");
@@ -365,9 +359,9 @@ TEST("require that tcp keepalive can be set and cleared") {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_keepalive(-1, true));
- EXPECT_TRUE(SocketOptions::set_keepalive(handle.get(), true));
+ EXPECT_TRUE(handle.set_keepalive(true));
TEST_DO(verifier.verify_keepalive(true));
- EXPECT_TRUE(SocketOptions::set_keepalive(handle.get(), false));
+ EXPECT_TRUE(handle.set_keepalive(false));
TEST_DO(verifier.verify_keepalive(false));
}
@@ -375,13 +369,13 @@ TEST("require that tcp lingering can be adjusted") {
SocketHandle handle(socket(my_inet(), SOCK_STREAM, 0));
test::SocketOptionsVerifier verifier(handle.get());
EXPECT_TRUE(!SocketOptions::set_linger(-1, true, 0));
- EXPECT_TRUE(SocketOptions::set_linger(handle.get(), true, 0));
+ EXPECT_TRUE(handle.set_linger(true, 0));
TEST_DO(verifier.verify_linger(true, 0));
- EXPECT_TRUE(SocketOptions::set_linger(handle.get(), true, 10));
+ EXPECT_TRUE(handle.set_linger(true, 10));
TEST_DO(verifier.verify_linger(true, 10));
- EXPECT_TRUE(SocketOptions::set_linger(handle.get(), false, 0));
+ EXPECT_TRUE(handle.set_linger(false, 0));
TEST_DO(verifier.verify_linger(false, 0));
- EXPECT_TRUE(SocketOptions::set_linger(handle.get(), false, 10));
+ EXPECT_TRUE(handle.set_linger(false, 10));
TEST_DO(verifier.verify_linger(false, 0));
}
diff --git a/vespalib/src/tests/websocket/websocket_test.cpp b/vespalib/src/tests/websocket/websocket_test.cpp
index 962a78c5606..748b0fd5c1e 100644
--- a/vespalib/src/tests/websocket/websocket_test.cpp
+++ b/vespalib/src/tests/websocket/websocket_test.cpp
@@ -1,7 +1,6 @@
// Copyright 2016 Yahoo Inc. 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/websocket/socket.h>
-#include <vespa/vespalib/websocket/server_socket.h>
+#include <vespa/vespalib/net/socket_spec.h>
#include <vespa/vespalib/websocket/handler.h>
#include <vespa/vespalib/websocket/acceptor.h>
#include <vespa/vespalib/websocket/key.h>
@@ -11,6 +10,7 @@
#include <functional>
#include <chrono>
+using namespace vespalib;
using namespace vespalib::ws;
template <typename T>
@@ -62,14 +62,6 @@ void verify_socket_io_async(Socket &server, Socket &client) {
client_thread.join();
}
-Socket::UP connect_sockets(bool is_server, ServerSocket &server_socket) {
- if (is_server) {
- return server_socket.accept();
- } else {
- return Socket::UP(new Socket("localhost", server_socket.port()));
- }
-}
-
void check_buffer_stats(const Buffer &buffer, size_t dead, size_t used, size_t free) {
EXPECT_EQUAL(dead, buffer.dead());
EXPECT_EQUAL(used, buffer.used());
@@ -109,34 +101,13 @@ TEST("require that buffer moves contained data when more space is needed") {
EXPECT_EQUAL('z', *buffer.obtain());
}
-TEST_MT_F("require that basic socket io works", 2, ServerSocket(0)) {
- bool is_server = (thread_id == 0);
- Socket::UP socket = connect_sockets(is_server, f1);
- TEST_DO(verify_socket_io(is_server, *socket));
-}
-
-TEST_MT_F("require that server accept can be interrupted", 2, ServerSocket(0)) {
- bool is_server = (thread_id == 0);
- if (is_server) {
- fprintf(stderr, "--> calling accept\n");
- Socket::UP socket = f1.accept();
- fprintf(stderr, "<-- accept returned\n");
- EXPECT_TRUE(socket.get() == nullptr);
- EXPECT_TRUE(f1.is_closed());
- } else {
- std::this_thread::sleep_for(std::chrono::milliseconds(500));
- fprintf(stderr, "--- closing server socket\n");
- f1.close();
- }
-}
-
TEST("require that an acceptor can accept connections asynchronously") {
Receptor<Socket> server;
Acceptor acceptor(0, server);
- Socket::UP client(new Socket("localhost", acceptor.port()));
+ Socket::UP client = SimpleSocket::connect(SocketSpec::from_port(acceptor.port()));
server.gate.await(60000);
- EXPECT_TRUE(server.obj.get() != nullptr);
- EXPECT_TRUE(client.get() != nullptr);
+ ASSERT_TRUE(server.obj.get() != nullptr);
+ ASSERT_TRUE(client.get() != nullptr);
TEST_DO(verify_socket_io_async(*server.obj, *client));
}
diff --git a/vespalib/src/vespa/vespalib/net/server_socket.cpp b/vespalib/src/vespa/vespalib/net/server_socket.cpp
index 04be8fc8888..3f9237b3835 100644
--- a/vespalib/src/vespa/vespalib/net/server_socket.cpp
+++ b/vespalib/src/vespa/vespalib/net/server_socket.cpp
@@ -16,19 +16,54 @@ bool is_socket(const vespalib::string &path) {
return S_ISSOCK(info.st_mode);
}
-ServerSocket::ServerSocket(SocketHandle handle)
- : _handle(std::move(handle)),
- _path(SocketAddress::address_of(_handle.get()).path())
+void
+ServerSocket::cleanup()
{
+ if (valid() && is_socket(_path)) {
+ unlink(_path.c_str());
+ }
}
-ServerSocket::~ServerSocket()
+ServerSocket::ServerSocket(const SocketSpec &spec)
+ : _handle(spec.server_address().listen()),
+ _path(spec.path())
{
- if (is_socket(_path)) {
- unlink(_path.c_str());
+ if (!_handle.valid() && is_socket(_path)) {
+ if (!spec.client_address().connect().valid()) {
+ LOG(warning, "removing old socket: '%s'", _path.c_str());
+ unlink(_path.c_str());
+ _handle = spec.server_address().listen();
+ }
}
}
+ServerSocket::ServerSocket(const vespalib::string &spec)
+ : ServerSocket(SocketSpec(spec))
+{
+}
+
+ServerSocket::ServerSocket(int port)
+ : ServerSocket(SocketSpec::from_port(port))
+{
+}
+
+ServerSocket::ServerSocket(ServerSocket &&rhs)
+ : _handle(std::move(rhs._handle)),
+ _path(std::move(rhs._path))
+{
+ rhs._path.clear();
+}
+
+ServerSocket &
+ServerSocket::operator=(ServerSocket &&rhs)
+{
+ cleanup();
+ _handle = std::move(rhs._handle);
+ _path = std::move(rhs._path);
+ rhs._path.clear();
+ return *this;
+}
+
SocketAddress
ServerSocket::address() const
{
@@ -38,30 +73,13 @@ ServerSocket::address() const
void
ServerSocket::shutdown()
{
- if (valid()) {
- ::shutdown(_handle.get(), SHUT_RDWR);
- }
+ _handle.shutdown();
}
-Socket::UP
+SocketHandle
ServerSocket::accept()
{
- SocketHandle handle(::accept(_handle.get(), nullptr, 0));
- return std::make_unique<Socket>(std::move(handle));
-}
-
-ServerSocket::UP
-ServerSocket::listen(const SocketSpec &spec)
-{
- SocketHandle handle = spec.server_address().listen();
- if (!handle.valid() && is_socket(spec.path())) {
- if (!spec.client_address().connect().valid()) {
- LOG(warning, "removing old socket: '%s'", spec.path().c_str());
- unlink(spec.path().c_str());
- handle = spec.server_address().listen();
- }
- }
- return std::make_unique<ServerSocket>(std::move(handle));
+ return _handle.accept();
}
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/server_socket.h b/vespalib/src/vespa/vespalib/net/server_socket.h
index 1c4f41343d7..70cdd61b6d2 100644
--- a/vespalib/src/vespa/vespalib/net/server_socket.h
+++ b/vespalib/src/vespa/vespalib/net/server_socket.h
@@ -1,11 +1,9 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
#pragma once
#include "socket_handle.h"
#include "socket_address.h"
-#include "socket.h"
namespace vespalib {
@@ -17,17 +15,20 @@ private:
SocketHandle _handle;
vespalib::string _path;
-public:
- typedef std::unique_ptr<ServerSocket> UP;
- ServerSocket(const ServerSocket &rhs) = delete;
- ServerSocket &operator=(const ServerSocket &rhs) = delete;
explicit ServerSocket(SocketHandle handle);
- ~ServerSocket();
+ static ServerSocket listen(const SocketSpec &spec);
+ void cleanup();
+public:
+ explicit ServerSocket(const SocketSpec &spec);
+ explicit ServerSocket(const vespalib::string &spec);
+ explicit ServerSocket(int port);
+ ServerSocket(ServerSocket &&rhs);
+ ServerSocket &operator=(ServerSocket &&rhs);
+ ~ServerSocket() { cleanup(); }
bool valid() const { return _handle.valid(); }
SocketAddress address() const;
void shutdown();
- Socket::UP accept();
- static ServerSocket::UP listen(const SocketSpec &spec);
+ SocketHandle accept();
};
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/socket.cpp b/vespalib/src/vespa/vespalib/net/socket.cpp
index 8c016df3d6d..c0498e21324 100644
--- a/vespalib/src/vespa/vespalib/net/socket.cpp
+++ b/vespalib/src/vespa/vespalib/net/socket.cpp
@@ -1,57 +1,14 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "socket.h"
#include "socket_spec.h"
namespace vespalib {
-SocketAddress
-Socket::address() const
+std::unique_ptr<SimpleSocket>
+SimpleSocket::connect(const SocketSpec &spec)
{
- return SocketAddress::address_of(_handle.get());
-}
-
-SocketAddress
-Socket::peer_address() const
-{
- return SocketAddress::peer_address(_handle.get());
-}
-
-void
-Socket::shutdown()
-{
- if (valid()) {
- ::shutdown(_handle.get(), SHUT_RDWR);
- }
-}
-
-ssize_t
-Socket::read(char *buf, size_t len)
-{
- for (;;) {
- ssize_t result = ::read(_handle.get(), buf, len);
- if ((result >= 0) || (errno != EINTR)) {
- return result;
- }
- }
-}
-
-ssize_t
-Socket::write(const char *buf, size_t len)
-{
- for (;;) {
- ssize_t result = ::write(_handle.get(), buf, len);
- if ((result >= 0) || (errno != EINTR)) {
- return result;
- }
- }
-}
-
-Socket::UP
-Socket::connect(const SocketSpec &spec)
-{
- SocketHandle handle = spec.client_address().connect();
- return std::make_unique<Socket>(std::move(handle));
+ return std::make_unique<SimpleSocket>(spec.client_address().connect());
}
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/socket.h b/vespalib/src/vespa/vespalib/net/socket.h
index b83faf0a67c..1df5ee97c26 100644
--- a/vespalib/src/vespa/vespalib/net/socket.h
+++ b/vespalib/src/vespa/vespalib/net/socket.h
@@ -1,33 +1,30 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
+// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include <vespa/vespalib/stllike/string.h>
#include "socket_handle.h"
-#include "socket_address.h"
+#include <memory>
namespace vespalib {
class SocketSpec;
-class Socket
-{
-private:
- SocketHandle _handle;
+/**
+ * Abstract stream-based socket interface.
+ **/
+struct Socket {
+ using UP = std::unique_ptr<Socket>;
+ virtual ssize_t read(char *buf, size_t len) = 0;
+ virtual ssize_t write(const char *buf, size_t len) = 0;
+ virtual ~Socket() {}
+};
-public:
- typedef std::unique_ptr<Socket> UP;
- Socket(const Socket &rhs) = delete;
- Socket &operator=(const Socket &rhs) = delete;
- explicit Socket(SocketHandle handle) : _handle(std::move(handle)) {}
- bool valid() const { return _handle.valid(); }
- SocketAddress address() const;
- SocketAddress peer_address() const;
- void shutdown();
- ssize_t read(char *buf, size_t len);
- ssize_t write(const char *buf, size_t len);
- static Socket::UP connect(const SocketSpec &spec);
+struct SimpleSocket : public Socket {
+ SocketHandle handle;
+ explicit SimpleSocket(SocketHandle handle_in) : handle(std::move(handle_in)) {}
+ ssize_t read(char *buf, size_t len) final override { return handle.read(buf, len); }
+ ssize_t write(const char *buf, size_t len) final override { return handle.write(buf, len); }
+ static std::unique_ptr<SimpleSocket> connect(const SocketSpec &spec);
};
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/socket_address.cpp b/vespalib/src/vespa/vespalib/net/socket_address.cpp
index 6a70491beb8..9e862059ffa 100644
--- a/vespalib/src/vespa/vespalib/net/socket_address.cpp
+++ b/vespalib/src/vespa/vespalib/net/socket_address.cpp
@@ -133,7 +133,7 @@ SocketAddress::connect() const
{
if (valid()) {
SocketHandle handle(socket(_addr.ss_family, SOCK_STREAM, 0));
- if (handle && (::connect(handle.get(), addr(), _size) == 0)) {
+ if (handle.valid() && (::connect(handle.get(), addr(), _size) == 0)) {
return handle;
}
}
@@ -145,14 +145,12 @@ SocketAddress::listen(int backlog) const
{
if (valid()) {
SocketHandle handle(socket(_addr.ss_family, SOCK_STREAM, 0));
- if (handle) {
+ if (handle.valid()) {
if (is_ipv6()) {
- int disable = 0;
- setsockopt(handle.get(), IPPROTO_IPV6, IPV6_V6ONLY, &disable, sizeof(disable));
+ handle.set_ipv6_only(false);
}
if (port() > 0) {
- int enable = 1;
- setsockopt(handle.get(), SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
+ handle.set_reuse_addr(true);
}
if ((bind(handle.get(), addr(), _size) == 0) &&
(::listen(handle.get(), backlog) == 0))
diff --git a/vespalib/src/vespa/vespalib/net/socket_handle.cpp b/vespalib/src/vespa/vespalib/net/socket_handle.cpp
index 3e8afa66584..343bfc60924 100644
--- a/vespalib/src/vespa/vespalib/net/socket_handle.cpp
+++ b/vespalib/src/vespa/vespalib/net/socket_handle.cpp
@@ -1,7 +1,48 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "socket_handle.h"
+#include <sys/socket.h>
+#include <errno.h>
namespace vespalib {
+ssize_t
+SocketHandle::read(char *buf, size_t len)
+{
+ for (;;) {
+ ssize_t result = ::read(_fd, buf, len);
+ if ((result >= 0) || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
+
+ssize_t
+SocketHandle::write(const char *buf, size_t len)
+{
+ for (;;) {
+ ssize_t result = ::write(_fd, buf, len);
+ if ((result >= 0) || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
+
+SocketHandle
+SocketHandle::accept()
+{
+ for (;;) {
+ SocketHandle result(::accept(_fd, nullptr, 0));
+ if (result.valid() || (errno != EINTR)) {
+ return result;
+ }
+ }
+}
+
+void
+SocketHandle::shutdown()
+{
+ ::shutdown(_fd, SHUT_RDWR);
+}
+
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/socket_handle.h b/vespalib/src/vespa/vespalib/net/socket_handle.h
index a7dc44c6f2b..baef0c04e19 100644
--- a/vespalib/src/vespa/vespalib/net/socket_handle.h
+++ b/vespalib/src/vespa/vespalib/net/socket_handle.h
@@ -2,6 +2,7 @@
#pragma once
+#include "socket_options.h"
#include <unistd.h>
namespace vespalib {
@@ -33,6 +34,7 @@ public:
_fd = rhs.release();
return *this;
}
+ ~SocketHandle() { maybe_close(_fd); }
bool valid() const { return (_fd >= 0); }
operator bool() const { return valid(); }
int get() const { return _fd; }
@@ -45,7 +47,18 @@ public:
maybe_close(_fd);
_fd = fd;
}
- ~SocketHandle() { maybe_close(_fd); }
+
+ bool set_blocking(bool value) { return SocketOptions::set_blocking(_fd, value); }
+ bool set_nodelay(bool value) { return SocketOptions::set_nodelay(_fd, value); }
+ bool set_reuse_addr(bool value) { return SocketOptions::set_reuse_addr(_fd, value); }
+ bool set_ipv6_only(bool value) { return SocketOptions::set_ipv6_only(_fd, value); }
+ bool set_keepalive(bool value) { return SocketOptions::set_keepalive(_fd, value); }
+ bool set_linger(bool enable, int value) { return SocketOptions::set_linger(_fd, enable, value); }
+
+ ssize_t read(char *buf, size_t len);
+ ssize_t write(const char *buf, size_t len);
+ SocketHandle accept();
+ void shutdown();
};
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/websocket/CMakeLists.txt b/vespalib/src/vespa/vespalib/websocket/CMakeLists.txt
index 172008d2a73..c7a7e5d63af 100644
--- a/vespalib/src/vespa/vespalib/websocket/CMakeLists.txt
+++ b/vespalib/src/vespa/vespalib/websocket/CMakeLists.txt
@@ -8,8 +8,6 @@ vespa_add_library(vespalib_vespalib_websocket OBJECT
handler.cpp
key.cpp
request.cpp
- server_socket.cpp
- socket.cpp
websocket_server.cpp
DEPENDS
)
diff --git a/vespalib/src/vespa/vespalib/websocket/acceptor.cpp b/vespalib/src/vespa/vespalib/websocket/acceptor.cpp
index 53b6f64ceee..d5d92285cd9 100644
--- a/vespalib/src/vespa/vespalib/websocket/acceptor.cpp
+++ b/vespalib/src/vespa/vespalib/websocket/acceptor.cpp
@@ -3,6 +3,7 @@
#include <vespa/fastos/fastos.h>
#include "acceptor.h"
#include <functional>
+#include <vespa/vespalib/net/socket_spec.h>
namespace vespalib {
namespace ws {
@@ -10,23 +11,25 @@ namespace ws {
void
Acceptor::accept_main(Handler<Socket> &socket_handler)
{
- while (!_server_socket.is_closed()) {
- Socket::UP socket = _server_socket.accept();
- if (socket) {
- socket_handler.handle(std::move(socket));
+ while (!_is_closed) {
+ SocketHandle handle = _server_socket.accept();
+ if (handle.valid()) {
+ socket_handler.handle(std::make_unique<SimpleSocket>(std::move(handle)));
}
}
}
Acceptor::Acceptor(int port_in, Handler<Socket> &socket_handler)
: _server_socket(port_in),
- _accept_thread(&Acceptor::accept_main, this, std::ref(socket_handler))
+ _accept_thread(&Acceptor::accept_main, this, std::ref(socket_handler)),
+ _is_closed(false)
{
}
Acceptor::~Acceptor()
{
- _server_socket.close();
+ _server_socket.shutdown();
+ _is_closed = true;
_accept_thread.join();
}
diff --git a/vespalib/src/vespa/vespalib/websocket/acceptor.h b/vespalib/src/vespa/vespalib/websocket/acceptor.h
index 329c5a0f998..8c85c4d524b 100644
--- a/vespalib/src/vespa/vespalib/websocket/acceptor.h
+++ b/vespalib/src/vespa/vespalib/websocket/acceptor.h
@@ -3,8 +3,10 @@
#pragma once
#include "handler.h"
-#include "server_socket.h"
+#include <vespa/vespalib/net/socket.h>
+#include <vespa/vespalib/net/server_socket.h>
#include <thread>
+#include <atomic>
namespace vespalib {
namespace ws {
@@ -13,13 +15,14 @@ class Acceptor {
private:
ServerSocket _server_socket;
std::thread _accept_thread;
+ std::atomic<bool> _is_closed;
void accept_main(Handler<Socket> &socket_handler);
public:
Acceptor(int port_in, Handler<Socket> &socket_handler);
~Acceptor();
- int port() { return _server_socket.port(); }
+ int port() { return _server_socket.address().port(); }
};
} // namespace vespalib::ws
diff --git a/vespalib/src/vespa/vespalib/websocket/connection.h b/vespalib/src/vespa/vespalib/websocket/connection.h
index 0cb3433ce4f..d2cf18e7fbf 100644
--- a/vespalib/src/vespa/vespalib/websocket/connection.h
+++ b/vespalib/src/vespa/vespalib/websocket/connection.h
@@ -3,7 +3,7 @@
#pragma once
-#include "socket.h"
+#include <vespa/vespalib/net/socket.h>
#include "buffer.h"
#include "frame.h"
diff --git a/vespalib/src/vespa/vespalib/websocket/server_socket.cpp b/vespalib/src/vespa/vespalib/websocket/server_socket.cpp
deleted file mode 100644
index 18f95cf4220..00000000000
--- a/vespalib/src/vespa/vespalib/websocket/server_socket.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-
-#include <vespa/fastos/fastos.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <sys/socket.h>
-#include "server_socket.h"
-
-namespace vespalib {
-namespace ws {
-
-ServerSocket::ServerSocket(int port_in)
- : _server_socket(port_in),
- _closed(false)
-{
- _server_socket.SetSoBlocking(true);
- if (!_server_socket.Listen()) {
- throw PortListenException(port_in, "tcp");
- }
-}
-
-Socket::UP
-ServerSocket::accept()
-{
- std::unique_ptr<FastOS_Socket> socket(_server_socket.AcceptPlain());
- if (!socket) {
- return Socket::UP();
- }
- socket->SetSoBlocking(true);
- return Socket::UP(new Socket(std::move(socket)));
-}
-
-void
-ServerSocket::close()
-{
- _closed = true;
- int fd = _server_socket.get_fd();
- if (fd >= 0) {
- shutdown(fd, SHUT_RDWR);
- }
-}
-
-} // namespace vespalib::ws
-} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/websocket/server_socket.h b/vespalib/src/vespa/vespalib/websocket/server_socket.h
deleted file mode 100644
index 664056d82dc..00000000000
--- a/vespalib/src/vespa/vespalib/websocket/server_socket.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-
-#pragma once
-
-#include "socket.h"
-#include <vespa/fastos/serversocket.h>
-
-namespace vespalib {
-namespace ws {
-
-class ServerSocket
-{
-private:
- struct ServerSocketWrapper : public FastOS_ServerSocket {
- ServerSocketWrapper(int port) : FastOS_ServerSocket(port, 50) {}
- int get_fd() const { return _socketHandle; }
- };
- ServerSocketWrapper _server_socket;
- volatile bool _closed;
-
-public:
- ServerSocket(int port_in);
- Socket::UP accept();
- void close();
- int port() { return _server_socket.GetLocalPort(); }
- bool is_closed() const { return _closed; }
-};
-
-} // namespace vespalib::ws
-} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/websocket/socket.cpp b/vespalib/src/vespa/vespalib/websocket/socket.cpp
deleted file mode 100644
index 3bdea494201..00000000000
--- a/vespalib/src/vespa/vespalib/websocket/socket.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-
-#include "socket.h"
-#include <vespa/fastos/socket.h>
-
-namespace vespalib {
-namespace ws {
-
-Socket::Socket(std::unique_ptr<FastOS_SocketInterface> socket)
- : _socket(std::move(socket))
-{
-}
-
-Socket::Socket(const vespalib::string &host, int port)
- : _socket(new FastOS_Socket())
-{
- if (!_socket->SetAddressByHostName(port, host.c_str()) ||
- !_socket->SetSoBlocking(true) ||
- !_socket->Connect())
- {
- _socket->Close();
- }
-}
-
-Socket::~Socket()
-{
- _socket->Close();
-}
-
-ssize_t
-Socket::read(char *buf, size_t len)
-{
- return _socket->Read(buf, len);
-}
-
-ssize_t
-Socket::write(const char *buf, size_t len)
-{
- return _socket->Write(buf, len);
-}
-
-} // namespace vespalib::ws
-} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/websocket/socket.h b/vespalib/src/vespa/vespalib/websocket/socket.h
deleted file mode 100644
index cced2a8b505..00000000000
--- a/vespalib/src/vespa/vespalib/websocket/socket.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-
-
-#pragma once
-
-#include <memory>
-#include <vespa/vespalib/stllike/string.h>
-
-class FastOS_SocketInterface;
-
-namespace vespalib {
-namespace ws {
-
-class Socket
-{
-private:
- std::unique_ptr<FastOS_SocketInterface> _socket;
-
-public:
- typedef std::unique_ptr<Socket> UP;
- Socket(std::unique_ptr<FastOS_SocketInterface> socket);
- Socket(const vespalib::string &host, int port);
- virtual ~Socket();
- ssize_t read(char *buf, size_t len);
- ssize_t write(const char *buf, size_t len);
-};
-
-} // namespace vespalib::ws
-} // namespace vespalib