diff options
author | Arne H Juul <arnej27959@users.noreply.github.com> | 2017-04-25 14:36:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-25 14:36:26 +0200 |
commit | e18aacbe5755d1cb16b7f4651cec0b91085cb7d9 (patch) | |
tree | 8b4e4851ee03b095fe7e627ebcaf827959e43c54 | |
parent | 550cb45bb27efd2da34d678f3b2b15a338f0bf06 (diff) | |
parent | 7085f3e6162e4186811a32c214e9d855d712cda7 (diff) |
Merge pull request #2248 from yahoo/havardpe/more-socket-options-and-testing
support async connect (and listen)
8 files changed, 93 insertions, 6 deletions
diff --git a/vespalib/src/tests/net/socket/socket_test.cpp b/vespalib/src/tests/net/socket/socket_test.cpp index c4b1e5286b2..67b4afb042a 100644 --- a/vespalib/src/tests/net/socket/socket_test.cpp +++ b/vespalib/src/tests/net/socket/socket_test.cpp @@ -1,5 +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/net/selector.h> #include <vespa/vespalib/net/socket_spec.h> #include <vespa/vespalib/net/server_socket.h> #include <vespa/vespalib/net/socket_options.h> @@ -217,7 +218,7 @@ TEST_MT_FF("require that server accept can be interrupted", 2, ServerSocket("tcp fprintf(stderr, "<-- accept returned\n"); EXPECT_TRUE(!socket.valid()); } else { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); fprintf(stderr, "--- closing server socket\n"); f1.shutdown(); } @@ -379,4 +380,56 @@ TEST("require that tcp lingering can be adjusted") { TEST_DO(verifier.verify_linger(false, 0)); } +SocketHandle connect_async(const SocketAddress &addr) { + struct ConnectContext { + SocketHandle handle; + bool connect_done = false; + int error = 0; + }; + struct ConnectHandler { + using context_type = ConnectContext; + int get_fd(ConnectContext &ctx) const { return ctx.handle.get(); } + void handle_wakeup() {} + void handle_event(ConnectContext &ctx, bool read, bool write) { + (void) read; + if (write) { + ctx.connect_done = true; + ctx.error = ctx.handle.get_so_error(); + } + } + }; + ConnectHandler handler; + Selector<ConnectHandler> selector(handler, 4096); + ConnectContext ctx; + ctx.handle = addr.connect_async(); + EXPECT_TRUE(ctx.handle.valid()); + test::SocketOptionsVerifier verifier(ctx.handle.get()); + TEST_DO(verifier.verify_blocking(false)); + if (ctx.handle.valid()) { + selector.add(ctx, true); + while (!ctx.connect_done) { + selector.poll(1000); + selector.dispatch(); + } + selector.remove(ctx); + } + EXPECT_EQUAL(ctx.error, 0); + return std::move(ctx.handle); +} + +TEST_MT_FF("require that async connect pattern works", 2, ServerSocket("tcp/0"), TimeBomb(60)) { + if (thread_id == 0) { + SocketHandle socket = f1.accept(); + EXPECT_TRUE(socket.valid()); + TEST_DO(verify_socket_io(true, socket)); + } else { + SocketAddress addr = SocketSpec::from_port(f1.address().port()).client_address(); + SocketHandle socket = connect_async(addr); + socket.set_blocking(true); + TEST_DO(verify_socket_io(false, socket)); + // TEST_DO(connect_async(SocketAddress::select_remote(80, "www.yahoo.com"))); + // TEST_DO(connect_async(SocketAddress::select_remote(85, "myinternalhost"))); + } +} + TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp b/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp index 9cb88993c97..d3ce9bfd6b2 100644 --- a/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp +++ b/vespalib/src/tests/net/socket_spec/socket_spec_test.cpp @@ -99,4 +99,12 @@ TEST("require that socket spec to string transform works as expected") { TEST_DO(verify_spec("tcp/[host]:123", "tcp/host:123")); } +TEST("require that port-only spec resolves to wildcard server address") { + EXPECT_TRUE(SocketSpec("tcp/123").server_address().is_wildcard()); +} + +TEST("require that port-only spec resolves to non-wildcard client address") { + EXPECT_TRUE(!SocketSpec("tcp/123").client_address().is_wildcard()); +} + TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/vespa/vespalib/net/server_socket.cpp b/vespalib/src/vespa/vespalib/net/server_socket.cpp index 3f9237b3835..0f99e6e9840 100644 --- a/vespalib/src/vespa/vespalib/net/server_socket.cpp +++ b/vespalib/src/vespa/vespalib/net/server_socket.cpp @@ -29,7 +29,7 @@ ServerSocket::ServerSocket(const SocketSpec &spec) _path(spec.path()) { if (!_handle.valid() && is_socket(_path)) { - if (!spec.client_address().connect().valid()) { + if (!spec.client_address().connect_async().valid()) { LOG(warning, "removing old socket: '%s'", _path.c_str()); unlink(_path.c_str()); _handle = spec.server_address().listen(); diff --git a/vespalib/src/vespa/vespalib/net/server_socket.h b/vespalib/src/vespa/vespalib/net/server_socket.h index 70cdd61b6d2..b61549277ac 100644 --- a/vespalib/src/vespa/vespalib/net/server_socket.h +++ b/vespalib/src/vespa/vespalib/net/server_socket.h @@ -26,8 +26,10 @@ public: ServerSocket &operator=(ServerSocket &&rhs); ~ServerSocket() { cleanup(); } bool valid() const { return _handle.valid(); } + int get_fd() const { return _handle.get(); } SocketAddress address() const; void shutdown(); + bool set_blocking(bool value) { return _handle.set_blocking(value); } SocketHandle accept(); }; diff --git a/vespalib/src/vespa/vespalib/net/socket_address.cpp b/vespalib/src/vespa/vespalib/net/socket_address.cpp index 9e862059ffa..c5221d6329d 100644 --- a/vespalib/src/vespa/vespalib/net/socket_address.cpp +++ b/vespalib/src/vespa/vespalib/net/socket_address.cpp @@ -129,12 +129,14 @@ SocketAddress::spec() const } SocketHandle -SocketAddress::connect() const +SocketAddress::connect(const std::function<bool(SocketHandle&)> &tweak) const { if (valid()) { SocketHandle handle(socket(_addr.ss_family, SOCK_STREAM, 0)); - if (handle.valid() && (::connect(handle.get(), addr(), _size) == 0)) { - return handle; + if (handle.valid() && tweak(handle)) { + if ((::connect(handle.get(), addr(), _size) == 0) || (errno == EINPROGRESS)) { + return handle; + } } } return SocketHandle(); diff --git a/vespalib/src/vespa/vespalib/net/socket_address.h b/vespalib/src/vespa/vespalib/net/socket_address.h index c6810ad6108..23ac635c4a6 100644 --- a/vespalib/src/vespa/vespalib/net/socket_address.h +++ b/vespalib/src/vespa/vespalib/net/socket_address.h @@ -6,6 +6,7 @@ #include "socket_handle.h" #include <vector> #include <sys/socket.h> +#include <functional> struct sockaddr_in; struct sockaddr_in6; @@ -45,7 +46,11 @@ public: vespalib::string path() const; vespalib::string name() const; vespalib::string spec() const; - SocketHandle connect() const; + SocketHandle connect(const std::function<bool(SocketHandle&)> &tweak) const; + SocketHandle connect() const { return connect([](SocketHandle&){ return true; }); } + SocketHandle connect_async() const { + return connect([](SocketHandle &handle){ return handle.set_blocking(false); }); + } SocketHandle listen(int backlog = 500) const; static SocketAddress address_of(int sockfd); static SocketAddress peer_address(int sockfd); diff --git a/vespalib/src/vespa/vespalib/net/socket_handle.cpp b/vespalib/src/vespa/vespalib/net/socket_handle.cpp index 343bfc60924..3b71cfd268a 100644 --- a/vespalib/src/vespa/vespalib/net/socket_handle.cpp +++ b/vespalib/src/vespa/vespalib/net/socket_handle.cpp @@ -3,6 +3,7 @@ #include "socket_handle.h" #include <sys/socket.h> #include <errno.h> +#include <assert.h> namespace vespalib { @@ -45,4 +46,19 @@ SocketHandle::shutdown() ::shutdown(_fd, SHUT_RDWR); } +int +SocketHandle::get_so_error() const +{ + if (!valid()) { + return EBADF; + } + int so_error = 0; + socklen_t opt_len = sizeof(so_error); + if (getsockopt(_fd, SOL_SOCKET, SO_ERROR, &so_error, &opt_len) != 0) { + return errno; + } + assert(opt_len == sizeof(so_error)); + return so_error; +} + } // namespace vespalib diff --git a/vespalib/src/vespa/vespalib/net/socket_handle.h b/vespalib/src/vespa/vespalib/net/socket_handle.h index baef0c04e19..624c16548d0 100644 --- a/vespalib/src/vespa/vespalib/net/socket_handle.h +++ b/vespalib/src/vespa/vespalib/net/socket_handle.h @@ -59,6 +59,7 @@ public: ssize_t write(const char *buf, size_t len); SocketHandle accept(); void shutdown(); + int get_so_error() const; }; } // namespace vespalib |