sock: Add a function to check if a socket is connected

This is useful for detecting sockets that have been disconnected
by the other end without reading data.

Change-Id: Ieb6529984d282d48373766d9f5555cf11720f19b
Signed-off-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/470513
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Ben Walker 2019-10-04 10:48:32 -07:00 committed by Tomasz Zawadzki
parent 85d9f0a9ab
commit a0889ece60
7 changed files with 72 additions and 0 deletions

View File

@ -195,6 +195,15 @@ bool spdk_sock_is_ipv6(struct spdk_sock *sock);
*/
bool spdk_sock_is_ipv4(struct spdk_sock *sock);
/**
* Check whether the socket is currently connected.
*
* \param sock Socket to check
*
* \return true if the socket is connected or false otherwise.
*/
bool spdk_sock_is_connected(struct spdk_sock *sock);
/**
* Callback function for spdk_sock_group_add_sock().
*

View File

@ -86,6 +86,7 @@ struct spdk_net_impl {
bool (*is_ipv6)(struct spdk_sock *sock);
bool (*is_ipv4)(struct spdk_sock *sock);
bool (*is_connected)(struct spdk_sock *sock);
int (*get_placement_id)(struct spdk_sock *sock, int *placement_id);
struct spdk_sock_group_impl *(*group_impl_create)(void);

View File

@ -308,6 +308,12 @@ spdk_sock_is_ipv4(struct spdk_sock *sock)
return sock->net_impl->is_ipv4(sock);
}
bool
spdk_sock_is_connected(struct spdk_sock *sock)
{
return sock->net_impl->is_connected(sock);
}
struct spdk_sock_group *
spdk_sock_group_create(void *ctx)
{

View File

@ -529,6 +529,29 @@ spdk_posix_sock_is_ipv4(struct spdk_sock *_sock)
return (sa.ss_family == AF_INET);
}
static bool
spdk_posix_sock_is_connected(struct spdk_sock *_sock)
{
struct spdk_posix_sock *sock = __posix_sock(_sock);
uint8_t byte;
int rc;
rc = recv(sock->fd, &byte, 1, MSG_PEEK);
if (rc == 0) {
return false;
}
if (rc < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return true;
}
return false;
}
return true;
}
static int
spdk_posix_sock_get_placement_id(struct spdk_sock *_sock, int *placement_id)
{
@ -686,6 +709,7 @@ static struct spdk_net_impl g_posix_net_impl = {
.set_priority = spdk_posix_sock_set_priority,
.is_ipv6 = spdk_posix_sock_is_ipv6,
.is_ipv4 = spdk_posix_sock_is_ipv4,
.is_connected = spdk_posix_sock_is_connected,
.get_placement_id = spdk_posix_sock_get_placement_id,
.group_impl_create = spdk_posix_sock_group_impl_create,
.group_impl_add_sock = spdk_posix_sock_group_impl_add_sock,

View File

@ -1006,6 +1006,14 @@ spdk_vpp_sock_is_ipv4(struct spdk_sock *_sock)
return __vpp_session(_sock)->app_session.transport.is_ip4;
}
static bool
spdk_vpp_sock_is_connected(struct spdk_sock *_sock)
{
assert(g_svm.vpp_initialized);
return (__vpp_session(_sock)->app_session.session_state == VPP_SESSION_STATE_READY);
}
static int
spdk_vpp_sock_get_placement_id(struct spdk_sock *_sock, int *placement_id)
{
@ -1440,6 +1448,7 @@ static struct spdk_net_impl g_vpp_net_impl = {
.set_priority = spdk_vpp_sock_set_priority,
.is_ipv6 = spdk_vpp_sock_is_ipv6,
.is_ipv4 = spdk_vpp_sock_is_ipv4,
.is_connected = spdk_vpp_sock_is_connected,
.get_placement_id = spdk_vpp_sock_get_placement_id,
.group_impl_create = spdk_vpp_sock_group_impl_create,
.group_impl_add_sock = spdk_vpp_sock_group_impl_add_sock,

View File

@ -50,6 +50,7 @@ DEFINE_STUB(spdk_sock_set_recvbuf, int, (struct spdk_sock *sock, int sz), 0);
DEFINE_STUB(spdk_sock_set_sendbuf, int, (struct spdk_sock *sock, int sz), 0);
DEFINE_STUB(spdk_sock_is_ipv6, bool, (struct spdk_sock *sock), false);
DEFINE_STUB(spdk_sock_is_ipv4, bool, (struct spdk_sock *sock), true);
DEFINE_STUB(spdk_sock_is_connected, bool, (struct spdk_sock *sock), true);
DEFINE_STUB(spdk_sock_group_create, struct spdk_sock_group *, (void *ctx), NULL);
DEFINE_STUB(spdk_sock_group_add_sock, int, (struct spdk_sock_group *group, struct spdk_sock *sock,
spdk_sock_cb cb_fn, void *cb_arg), 0);

View File

@ -130,6 +130,7 @@ spdk_ut_sock_accept(struct spdk_sock *_sock)
SPDK_CU_ASSERT_FATAL(g_ut_client_sock != NULL);
g_ut_client_sock->peer = new_sock;
new_sock->peer = g_ut_client_sock;
return &new_sock->base;
}
@ -145,6 +146,11 @@ spdk_ut_sock_close(struct spdk_sock *_sock)
if (sock == g_ut_client_sock) {
g_ut_client_sock = NULL;
}
if (sock->peer != NULL) {
sock->peer->peer = NULL;
}
free(_sock);
return 0;
@ -244,6 +250,14 @@ spdk_ut_sock_is_ipv4(struct spdk_sock *_sock)
return true;
}
static bool
spdk_ut_sock_is_connected(struct spdk_sock *_sock)
{
struct spdk_ut_sock *sock = __ut_sock(_sock);
return (sock->peer != NULL);
}
static int
spdk_ut_sock_get_placement_id(struct spdk_sock *_sock, int *placement_id)
{
@ -331,6 +345,7 @@ static struct spdk_net_impl g_ut_net_impl = {
.set_priority = spdk_ut_sock_set_priority,
.is_ipv6 = spdk_ut_sock_is_ipv6,
.is_ipv4 = spdk_ut_sock_is_ipv4,
.is_connected = spdk_ut_sock_is_connected,
.get_placement_id = spdk_ut_sock_get_placement_id,
.group_impl_create = spdk_ut_sock_group_impl_create,
.group_impl_add_sock = spdk_ut_sock_group_impl_add_sock,
@ -371,6 +386,8 @@ _sock(const char *ip, int port)
server_sock = spdk_sock_accept(listen_sock);
SPDK_CU_ASSERT_FATAL(server_sock != NULL);
CU_ASSERT(spdk_sock_is_connected(client_sock) == true);
CU_ASSERT(spdk_sock_is_connected(server_sock) == true);
/* Test spdk_sock_recv */
iov.iov_base = test_string;
@ -418,6 +435,11 @@ _sock(const char *ip, int port)
CU_ASSERT(client_sock == NULL);
CU_ASSERT(rc == 0);
/* On FreeBSD, it takes a small amount of time for a close to propagate to the
* other side, even in loopback. Introduce a small sleep. */
sleep(1);
CU_ASSERT(spdk_sock_is_connected(server_sock) == false);
rc = spdk_sock_close(&server_sock);
CU_ASSERT(server_sock == NULL);
CU_ASSERT(rc == 0);