From d50b1778f721b9c4fb9a8db6ac866d381935e0b7 Mon Sep 17 00:00:00 2001 From: zhanghongyu Date: Tue, 19 Dec 2023 17:37:08 +0800 Subject: [PATCH] net/local: make the call return of each process consistent with linux move the accept logic into connect flow. In order to successfully establish a blocking connection between the client and server on the same thread. nonblock is not affected, and the block connect is now the same as the nonblock flow, other apis are not affected. Signed-off-by: zhanghongyu --- net/local/local.h | 31 ++++++++-- net/local/local_accept.c | 122 +++++++------------------------------- net/local/local_conn.c | 83 +++++++++++++++++++++++++- net/local/local_connect.c | 71 +++++++++------------- net/local/local_fifo.c | 26 ++++++++ net/local/local_netpoll.c | 6 +- net/local/local_recvmsg.c | 5 -- net/local/local_release.c | 42 ++----------- net/local/local_sendmsg.c | 5 -- 9 files changed, 188 insertions(+), 203 deletions(-) diff --git a/net/local/local.h b/net/local/local.h index 411d45b8f9..ad74deb212 100644 --- a/net/local/local.h +++ b/net/local/local.h @@ -80,7 +80,6 @@ enum local_state_s /* SOCK_STREAM peers only */ LOCAL_STATE_ACCEPT, /* Client waiting for a connection */ - LOCAL_STATE_CONNECTING, /* Non-blocking connect */ LOCAL_STATE_CONNECTED, /* Peer connected */ LOCAL_STATE_DISCONNECTED /* Peer disconnected */ }; @@ -144,7 +143,6 @@ struct local_conn_s /* SOCK_STREAM fields common to both client and server */ sem_t lc_waitsem; /* Use to wait for a connection to be accepted */ - sem_t lc_donesem; /* Use to wait for client connected done */ FAR struct socket *lc_psock; /* A reference to the socket structure */ /* The following is a list if poll structures of threads waiting for @@ -169,13 +167,12 @@ struct local_conn_s dq_queue_t lc_waiters; /* List of connections waiting to be accepted */ } server; - /* Fields unique to the connecting client side */ + /* Fields unique to the connecting accept side */ struct { - volatile int lc_result; /* Result of the connection operation (client) */ dq_entry_t lc_waiter; /* Linked to the lc_waiters lists */ - } client; + } accept; } u; #endif /* CONFIG_NET_LOCAL_STREAM */ }; @@ -214,6 +211,20 @@ struct socket; /* Forward reference */ FAR struct local_conn_s *local_alloc(void); +/**************************************************************************** + * Name: local_alloc_accept + * + * Description: + * Called when a client calls connect and can find the appropriate + * connection in LISTEN. In that case, this function will create + * a new connection and initialize it. + * + ****************************************************************************/ + +int local_alloc_accept(FAR struct local_conn_s *server, + FAR struct local_conn_s *client, + FAR struct local_conn_s **accept); + /**************************************************************************** * Name: local_free * @@ -699,6 +710,16 @@ int local_set_pollthreshold(FAR struct local_conn_s *conn, unsigned long threshold); #endif +/**************************************************************************** + * Name: local_set_nonblocking + * + * Description: + * Set the local conntion to nonblocking mode + * + ****************************************************************************/ + +int local_set_nonblocking(FAR struct local_conn_s *conn); + #undef EXTERN #ifdef __cplusplus } diff --git a/net/local/local_accept.c b/net/local/local_accept.c index 9621335c81..387996a324 100644 --- a/net/local/local_accept.c +++ b/net/local/local_accept.c @@ -62,7 +62,7 @@ static int local_waitlisten(FAR struct local_conn_s *server) } } - /* There is a client waiting for the connection */ + /* There is an accept conn waiting to be processed */ return OK; } @@ -100,11 +100,10 @@ int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, int flags) { FAR struct local_conn_s *server; - FAR struct local_conn_s *client; FAR struct local_conn_s *conn; FAR dq_entry_t *waiter; bool nonblock = !!(flags & SOCK_NONBLOCK); - int ret; + int ret = OK; /* Some sanity checks */ @@ -133,7 +132,7 @@ int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, for (; ; ) { - /* Are there pending connections. Remove the client from the + /* Are there pending connections. Remove the accpet from the * head of the waiting list. */ @@ -141,116 +140,35 @@ int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, if (waiter) { - client = container_of(waiter, struct local_conn_s, - u.client.lc_waiter); + conn = container_of(waiter, struct local_conn_s, + u.accept.lc_waiter); - local_addref(client); - - /* Decrement the number of pending clients */ + /* Decrement the number of pending accpets */ DEBUGASSERT(server->u.server.lc_pending > 0); server->u.server.lc_pending--; - /* Create a new connection structure for the server side of the - * connection. - */ + /* Setup the accpet socket structure */ - conn = local_alloc(); - if (!conn) + conn->lc_psock = newsock; + + newsock->s_domain = psock->s_domain; + newsock->s_type = SOCK_STREAM; + newsock->s_sockif = psock->s_sockif; + newsock->s_conn = (FAR void *)conn; + + /* Return the address family */ + + if (addr != NULL) { - nerr("ERROR: Failed to allocate new connection structure\n"); - ret = -ENOMEM; - } - else - { - /* Initialize the new connection structure */ - - local_addref(conn); - - conn->lc_proto = SOCK_STREAM; - conn->lc_type = LOCAL_TYPE_PATHNAME; - conn->lc_state = LOCAL_STATE_CONNECTED; - conn->lc_psock = psock; - conn->lc_peer = client; - client->lc_peer = conn; - - strlcpy(conn->lc_path, client->lc_path, sizeof(conn->lc_path)); - conn->lc_instance_id = client->lc_instance_id; - - /* Open the server-side write-only FIFO. This should not - * block. - */ - - ret = local_open_server_tx(conn, nonblock); - if (ret < 0) - { - nerr("ERROR: Failed to open write-only FIFOs for %s: %d\n", - conn->lc_path, ret); - } + ret = local_getaddr(conn, addr, addrlen); } - /* Do we have a connection? Is the write-side FIFO opened? */ - - if (ret == OK) + if (ret == OK && nonblock) { - DEBUGASSERT(conn->lc_outfile.f_inode != NULL); - - /* Open the server-side read-only FIFO. This should not - * block because the client side has already opening it - * for writing. - */ - - ret = local_open_server_rx(conn, nonblock); - if (ret < 0) - { - nerr("ERROR: Failed to open read-only FIFOs for %s: %d\n", - conn->lc_path, ret); - } + ret = local_set_nonblocking(conn); } - /* Do we have a connection? Are the FIFOs opened? */ - - if (ret == OK) - { - DEBUGASSERT(conn->lc_infile.f_inode != NULL); - - /* Return the address family */ - - if (addr != NULL) - { - ret = local_getaddr(client, addr, addrlen); - } - } - - if (ret == OK) - { - /* Setup the client socket structure */ - - newsock->s_domain = psock->s_domain; - newsock->s_type = SOCK_STREAM; - newsock->s_sockif = psock->s_sockif; - newsock->s_conn = (FAR void *)conn; - } - - /* Signal the client with the result of the connection */ - - client->u.client.lc_result = ret; - if (client->lc_state == LOCAL_STATE_CONNECTING) - { - client->lc_state = LOCAL_STATE_CONNECTED; - _SO_SETERRNO(client->lc_psock, ret); - local_event_pollnotify(client, POLLOUT); - } - - nxsem_post(&client->lc_waitsem); - - if (ret == OK) - { - ret = net_sem_wait(&client->lc_donesem); - } - - local_subref(client); - return ret; } diff --git a/net/local/local_conn.c b/net/local/local_conn.c index 0fcbee4daf..d8797c53fa 100644 --- a/net/local/local_conn.c +++ b/net/local/local_conn.c @@ -120,7 +120,6 @@ FAR struct local_conn_s *local_alloc(void) #ifdef CONFIG_NET_LOCAL_STREAM nxsem_init(&conn->lc_waitsem, 0, 0); - nxsem_init(&conn->lc_donesem, 0, 0); #endif @@ -147,6 +146,87 @@ FAR struct local_conn_s *local_alloc(void) return conn; } +/**************************************************************************** + * Name: local_alloc_accept + * + * Description: + * Called when a client calls connect and can find the appropriate + * connection in LISTEN. In that case, this function will create + * a new connection and initialize it. + * + ****************************************************************************/ + +int local_alloc_accept(FAR struct local_conn_s *server, + FAR struct local_conn_s *client, + FAR struct local_conn_s **accept) +{ + FAR struct local_conn_s *conn; + int ret; + + /* Create a new connection structure for the server side of the + * connection. + */ + + conn = local_alloc(); + if (conn == NULL) + { + nerr("ERROR: Failed to allocate new connection structure\n"); + return -ENOMEM; + } + + /* Initialize the new connection structure */ + + local_addref(conn); + + conn->lc_proto = SOCK_STREAM; + conn->lc_type = LOCAL_TYPE_PATHNAME; + conn->lc_state = LOCAL_STATE_CONNECTED; + conn->lc_peer = client; + client->lc_peer = conn; + + strlcpy(conn->lc_path, client->lc_path, sizeof(conn->lc_path)); + conn->lc_instance_id = client->lc_instance_id; + + /* Open the server-side write-only FIFO. This should not + * block. + */ + + ret = local_open_server_tx(conn, false); + if (ret < 0) + { + nerr("ERROR: Failed to open write-only FIFOs for %s: %d\n", + conn->lc_path, ret); + goto err; + } + + /* Do we have a connection? Is the write-side FIFO opened? */ + + DEBUGASSERT(conn->lc_outfile.f_inode != NULL); + + /* Open the server-side read-only FIFO. This should not + * block because the client side has already opening it + * for writing. + */ + + ret = local_open_server_rx(conn, false); + if (ret < 0) + { + nerr("ERROR: Failed to open read-only FIFOs for %s: %d\n", + conn->lc_path, ret); + goto err; + } + + /* Do we have a connection? Are the FIFOs opened? */ + + DEBUGASSERT(conn->lc_infile.f_inode != NULL); + *accept = conn; + return OK; + +err: + local_free(conn); + return ret; +} + /**************************************************************************** * Name: local_free() * @@ -212,7 +292,6 @@ void local_free(FAR struct local_conn_s *conn) local_release_fifos(conn); #ifdef CONFIG_NET_LOCAL_STREAM nxsem_destroy(&conn->lc_waitsem); - nxsem_destroy(&conn->lc_donesem); #endif /* Destory sem associated with the connection */ diff --git a/net/local/local_connect.c b/net/local/local_connect.c index 265856cc30..538bed5d0b 100644 --- a/net/local/local_connect.c +++ b/net/local/local_connect.c @@ -68,6 +68,7 @@ static int inline local_stream_connect(FAR struct local_conn_s *client, FAR struct local_conn_s *server, bool nonblock) { + FAR struct local_conn_s *conn; int ret; int sval; @@ -86,11 +87,6 @@ static int inline local_stream_connect(FAR struct local_conn_s *client, return -ECONNREFUSED; } - /* Increment the number of pending server connection s */ - - server->u.server.lc_pending++; - DEBUGASSERT(server->u.server.lc_pending != 0); - /* Create the FIFOs needed for the connection */ ret = local_create_fifos(client); @@ -117,41 +113,17 @@ static int inline local_stream_connect(FAR struct local_conn_s *client, DEBUGASSERT(client->lc_outfile.f_inode != NULL); - /* Set the busy "result" before giving the semaphore. */ + ret = local_alloc_accept(server, client, &conn); + if (ret < 0) + { + nerr("ERROR: Failed to alloc accept conn %s: %d\n", + client->lc_path, ret); + + goto errout_with_outfd; + } - client->u.client.lc_result = -EBUSY; client->lc_state = LOCAL_STATE_ACCEPT; - /* Add ourself to the list of waiting connections and notify the server. */ - - dq_addlast(&client->u.client.lc_waiter, &server->u.server.lc_waiters); - local_event_pollnotify(server, POLLIN); - - if (nxsem_get_value(&server->lc_waitsem, &sval) >= 0 && sval < 1) - { - nxsem_post(&server->lc_waitsem); - } - - /* Wait for the server to accept the connections */ - - if (!nonblock) - { - do - { - net_sem_wait_uninterruptible(&client->lc_waitsem); - ret = client->u.client.lc_result; - } - while (ret == -EBUSY); - - /* Did we successfully connect? */ - - if (ret < 0) - { - nerr("ERROR: Failed to connect: %d\n", ret); - goto errout_with_outfd; - } - } - /* Yes.. open the read-only FIFO */ ret = local_open_client_rx(client, nonblock); @@ -159,21 +131,32 @@ static int inline local_stream_connect(FAR struct local_conn_s *client, { nerr("ERROR: Failed to open write-only FIFOs for %s: %d\n", client->lc_path, ret); - goto errout_with_outfd; + + goto errout_with_conn; } DEBUGASSERT(client->lc_infile.f_inode != NULL); - nxsem_post(&client->lc_donesem); + /* Increment the number of pending server connections */ - if (!nonblock) + server->u.server.lc_pending++; + DEBUGASSERT(server->u.server.lc_pending != 0); + + /* Add ourself to the list of waiting connections and notify the server. */ + + dq_addlast(&conn->u.accept.lc_waiter, &server->u.server.lc_waiters); + local_event_pollnotify(server, POLLIN); + + if (nxsem_get_value(&server->lc_waitsem, &sval) >= 0 && sval < 1) { - client->lc_state = LOCAL_STATE_CONNECTED; - return ret; + nxsem_post(&server->lc_waitsem); } - client->lc_state = LOCAL_STATE_CONNECTING; - return -EINPROGRESS; + client->lc_state = LOCAL_STATE_CONNECTED; + return ret; + +errout_with_conn: + local_free(conn); errout_with_outfd: file_close(&client->lc_outfile); diff --git a/net/local/local_fifo.c b/net/local/local_fifo.c index 35f2fe4a34..4f555c57fd 100644 --- a/net/local/local_fifo.c +++ b/net/local/local_fifo.c @@ -738,4 +738,30 @@ int local_open_sender(FAR struct local_conn_s *conn, FAR const char *path, } #endif /* CONFIG_NET_LOCAL_DGRAM */ +/**************************************************************************** + * Name: local_set_nonblocking + * + * Description: + * Set the local conntion to nonblocking mode + * + ****************************************************************************/ + +int local_set_nonblocking(FAR struct local_conn_s *conn) +{ + int nonblock = 1; + int ret; + + /* Set the conn to nonblocking mode */ + + ret = file_ioctl(&conn->lc_infile, FIONBIO, &nonblock); + ret |= file_ioctl(&conn->lc_outfile, FIONBIO, &nonblock); + + if (ret < 0) + { + nerr("ERROR: Failed to set the conn to nonblocking mode: %d\n", ret); + } + + return ret; +} + #endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/net/local/local_netpoll.c b/net/local/local_netpoll.c index 0941e52a87..4c9b520697 100644 --- a/net/local/local_netpoll.c +++ b/net/local/local_netpoll.c @@ -171,8 +171,7 @@ int local_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds) } #ifdef CONFIG_NET_LOCAL_STREAM - if (conn->lc_state == LOCAL_STATE_LISTENING || - conn->lc_state == LOCAL_STATE_CONNECTING) + if (conn->lc_state == LOCAL_STATE_LISTENING) { return local_event_pollsetup(conn, fds, true); } @@ -324,8 +323,7 @@ int local_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds) } #ifdef CONFIG_NET_LOCAL_STREAM - if (conn->lc_state == LOCAL_STATE_LISTENING || - conn->lc_state == LOCAL_STATE_CONNECTING) + if (conn->lc_state == LOCAL_STATE_LISTENING) { return local_event_pollsetup(conn, fds, false); } diff --git a/net/local/local_recvmsg.c b/net/local/local_recvmsg.c index 05e6006f64..3ad99e6ade 100644 --- a/net/local/local_recvmsg.c +++ b/net/local/local_recvmsg.c @@ -240,11 +240,6 @@ psock_stream_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, if (conn->lc_state != LOCAL_STATE_CONNECTED || conn->lc_infile.f_inode == NULL) { - if (conn->lc_state == LOCAL_STATE_CONNECTING) - { - return -EAGAIN; - } - nerr("ERROR: not connected\n"); return -ENOTCONN; } diff --git a/net/local/local_release.c b/net/local/local_release.c index 575b90a528..1d302f3ffe 100644 --- a/net/local/local_release.c +++ b/net/local/local_release.c @@ -66,39 +66,11 @@ int local_release(FAR struct local_conn_s *conn) DEBUGASSERT(conn->lc_state != LOCAL_STATE_ACCEPT); - if (conn->lc_state == LOCAL_STATE_CONNECTING) - { - FAR struct local_conn_s *server = NULL; - FAR struct local_conn_s *client; - FAR dq_entry_t *waiter = NULL; - - while ((server = local_nextconn(server)) && waiter == NULL) - { - if (server->lc_state == LOCAL_STATE_LISTENING) - { - for (waiter = dq_peek(&server->u.server.lc_waiters); - waiter; - waiter = dq_next(&client->u.client.lc_waiter)) - { - if (&conn->u.client.lc_waiter == waiter) - { - dq_rem(waiter, &server->u.server.lc_waiters); - server->u.server.lc_pending--; - break; - } - - client = container_of(waiter, struct local_conn_s, - u.client.lc_waiter); - } - } - } - } - /* Is the socket is listening socket (SOCK_STREAM server) */ - else if (conn->lc_state == LOCAL_STATE_LISTENING) + if (conn->lc_state == LOCAL_STATE_LISTENING) { - FAR struct local_conn_s *client; + FAR struct local_conn_s *accept; FAR dq_entry_t *waiter; DEBUGASSERT(conn->lc_proto == SOCK_STREAM); @@ -107,13 +79,11 @@ int local_release(FAR struct local_conn_s *conn) for (waiter = dq_peek(&conn->u.server.lc_waiters); waiter; - waiter = dq_next(&client->u.client.lc_waiter)) + waiter = dq_next(&accept->u.accept.lc_waiter)) { - client = container_of(waiter, struct local_conn_s, - u.client.lc_waiter); - client->u.client.lc_result = -ENOTCONN; - nxsem_post(&client->lc_waitsem); - local_event_pollnotify(client, POLLOUT); + accept = container_of(waiter, struct local_conn_s, + u.accept.lc_waiter); + local_subref(accept); } conn->u.server.lc_pending = 0; diff --git a/net/local/local_sendmsg.c b/net/local/local_sendmsg.c index 40c1d6c016..6068f5ceaf 100644 --- a/net/local/local_sendmsg.c +++ b/net/local/local_sendmsg.c @@ -189,11 +189,6 @@ static ssize_t local_send(FAR struct socket *psock, if (peer->lc_state != LOCAL_STATE_CONNECTED || peer->lc_outfile.f_inode == NULL) { - if (peer->lc_state == LOCAL_STATE_CONNECTING) - { - return -EAGAIN; - } - nerr("ERROR: not connected\n"); return -ENOTCONN; }