summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArne H Juul <arnej27959@users.noreply.github.com>2017-04-25 14:36:26 +0200
committerGitHub <noreply@github.com>2017-04-25 14:36:26 +0200
commite18aacbe5755d1cb16b7f4651cec0b91085cb7d9 (patch)
tree8b4e4851ee03b095fe7e627ebcaf827959e43c54
parent550cb45bb27efd2da34d678f3b2b15a338f0bf06 (diff)
parent7085f3e6162e4186811a32c214e9d855d712cda7 (diff)
Merge pull request #2248 from yahoo/havardpe/more-socket-options-and-testing
support async connect (and listen)
-rw-r--r--vespalib/src/tests/net/socket/socket_test.cpp55
-rw-r--r--vespalib/src/tests/net/socket_spec/socket_spec_test.cpp8
-rw-r--r--vespalib/src/vespa/vespalib/net/server_socket.cpp2
-rw-r--r--vespalib/src/vespa/vespalib/net/server_socket.h2
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_address.cpp8
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_address.h7
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_handle.cpp16
-rw-r--r--vespalib/src/vespa/vespalib/net/socket_handle.h1
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