net: tcp2: Implement a blocking connect
In order to implement a blocking connect, add a semaphore and block on it in net_tcp_connect(). The semaphore is released when ESTABLISHED state is reached. In case tcp_conn_unref() is called while waiting on the semaphore, defer the unreference, tcp_conn_unref() will be called from net_tcp_connect(). Signed-off-by: Oleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>
This commit is contained in:
parent
ff8e08e6c7
commit
87577cb599
2 changed files with 29 additions and 4 deletions
|
@ -281,11 +281,20 @@ static void tcp_send_queue_flush(struct tcp *conn)
|
|||
|
||||
static int tcp_conn_unref(struct tcp *conn)
|
||||
{
|
||||
int ref_count = atomic_dec(&conn->ref_count) - 1;
|
||||
int key;
|
||||
int key, ref_count = atomic_get(&conn->ref_count);
|
||||
|
||||
NET_DBG("conn: %p, ref_count=%d", conn, ref_count);
|
||||
|
||||
#if !defined(CONFIG_NET_TEST_PROTOCOL)
|
||||
if (conn->in_connect) {
|
||||
NET_DBG("conn: %p is waiting on connect semaphore", conn);
|
||||
tcp_send_queue_flush(conn);
|
||||
goto out;
|
||||
}
|
||||
#endif /* CONFIG_NET_TEST_PROTOCOL */
|
||||
|
||||
ref_count = atomic_dec(&conn->ref_count) - 1;
|
||||
|
||||
if (ref_count) {
|
||||
tp_out(net_context_get_family(conn->context), conn->iface,
|
||||
"TP_TRACE", "event", "CONN_DELETE");
|
||||
|
@ -871,6 +880,9 @@ static struct tcp *tcp_conn_alloc(void)
|
|||
conn->send_data = tcp_pkt_alloc(conn, 0);
|
||||
k_delayed_work_init(&conn->send_data_timer, tcp_resend_data);
|
||||
|
||||
k_sem_init(&conn->connect_sem, 0, UINT_MAX);
|
||||
conn->in_connect = false;
|
||||
|
||||
tcp_conn_ref(conn);
|
||||
|
||||
sys_slist_append(&tcp_conns, (sys_snode_t *)conn);
|
||||
|
@ -1140,6 +1152,7 @@ next_state:
|
|||
}
|
||||
conn_ack(conn, + len);
|
||||
}
|
||||
k_sem_give(&conn->connect_sem);
|
||||
next = TCP_ESTABLISHED;
|
||||
net_context_set_state(conn->context,
|
||||
NET_CONTEXT_CONNECTED);
|
||||
|
@ -1376,8 +1389,6 @@ int net_tcp_connect(struct net_context *context,
|
|||
struct tcp *conn;
|
||||
int ret = 0;
|
||||
|
||||
ARG_UNUSED(timeout);
|
||||
|
||||
NET_DBG("context: %p, local: %s, remote: %s", context,
|
||||
log_strdup(net_sprint_addr(
|
||||
local_addr->sa_family,
|
||||
|
@ -1460,6 +1471,18 @@ int net_tcp_connect(struct net_context *context,
|
|||
*/
|
||||
tcp_in(conn, NULL);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NET_TEST_PROTOCOL)) {
|
||||
conn->in_connect = true;
|
||||
|
||||
if (k_sem_take(&conn->connect_sem, timeout) != 0 &&
|
||||
conn->state != TCP_ESTABLISHED) {
|
||||
conn->in_connect = false;
|
||||
tcp_conn_unref(conn);
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
conn->in_connect = false;
|
||||
}
|
||||
out:
|
||||
NET_DBG("conn: %p, ret=%d", conn, ret);
|
||||
|
||||
|
|
|
@ -201,6 +201,8 @@ struct tcp { /* TCP connection */
|
|||
size_t send_retries;
|
||||
struct k_delayed_work timewait_timer;
|
||||
struct net_if *iface;
|
||||
struct k_sem connect_sem; /* semaphore for blocking connect */
|
||||
bool in_connect;
|
||||
net_tcp_accept_cb_t accept_cb;
|
||||
atomic_t ref_count;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue