net: sockets: tcp: Fix possible race between connect/recv

Installing recv callback with net_context_recv() after
net_context_connect() left an opening for a possible race - in case the
server send some data immediately after establishing TCP connection, and
Zephyr did not manage to install the callback on time, the data would be
lost, corrupting the stream.

This can be avoided, by installing the recv callback before the
connection is triggered. As net_context_recv() called w/o timeout only
registers the callback function, it should have no negative impact. The
only change on the TCP side is when the connection is closed - in case
TCP is in connect stage, do not call the recv callback (before this
change it'd be NULL at that point).

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c
index d262475..641c0d2 100644
--- a/subsys/net/ip/tcp.c
+++ b/subsys/net/ip/tcp.c
@@ -497,9 +497,7 @@
 			/* Make sure the connect_cb is only called once. */
 			conn->connect_cb = NULL;
 		}
-	}
-
-	if (conn->context->recv_cb) {
+	} else if (conn->context->recv_cb) {
 		conn->context->recv_cb(conn->context, NULL, NULL, NULL,
 				       status, conn->recv_user_data);
 	}
diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c
index 660b64d..3effec4 100644
--- a/subsys/net/lib/sockets/sockets.c
+++ b/subsys/net/lib/sockets/sockets.c
@@ -490,15 +490,12 @@
 	if (status < 0) {
 		ctx->user_data = INT_TO_POINTER(-status);
 		sock_set_error(ctx);
-	} else if (status == 0) {
-		(void)net_context_recv(ctx, zsock_received_cb, K_NO_WAIT, ctx->user_data);
 	}
 }
 
 int zsock_connect_ctx(struct net_context *ctx, const struct sockaddr *addr,
 		      socklen_t addrlen)
 {
-	k_timeout_t timeout;
 
 #if defined(CONFIG_SOCKS)
 	if (net_context_is_proxy_enabled(ctx)) {
@@ -516,17 +513,19 @@
 		} else {
 			SET_ERRNO(-EALREADY);
 		}
-	} else if (sock_is_nonblock(ctx)) {
-		timeout = K_NO_WAIT;
-		SET_ERRNO(net_context_connect(ctx, addr, addrlen,
-					      zsock_connected_cb, timeout,
-					      ctx->user_data));
 	} else {
-		timeout = K_MSEC(CONFIG_NET_SOCKETS_CONNECT_TIMEOUT);
-		SET_ERRNO(net_context_connect(ctx, addr, addrlen, NULL,
-					      timeout, NULL));
+		k_timeout_t timeout = K_MSEC(CONFIG_NET_SOCKETS_CONNECT_TIMEOUT);
+		net_context_connect_cb_t cb = NULL;
+
+		if (sock_is_nonblock(ctx)) {
+			timeout = K_NO_WAIT;
+			cb = zsock_connected_cb;
+		}
+
 		SET_ERRNO(net_context_recv(ctx, zsock_received_cb, K_NO_WAIT,
 					   ctx->user_data));
+		SET_ERRNO(net_context_connect(ctx, addr, addrlen, cb, timeout,
+					      ctx->user_data));
 	}
 
 	return 0;