diff options
-rw-r--r-- | nuttx/net/local/local.h | 48 | ||||
-rw-r--r-- | nuttx/net/local/local_fifo.c | 157 | ||||
-rw-r--r-- | nuttx/net/local/local_recvfrom.c | 251 |
3 files changed, 383 insertions, 73 deletions
diff --git a/nuttx/net/local/local.h b/nuttx/net/local/local.h index 668bca66b..7c0cf44a2 100644 --- a/nuttx/net/local/local.h +++ b/nuttx/net/local/local.h @@ -488,21 +488,41 @@ int local_sync(int fd); * Name: local_create_fifos * * Description: - * Create the FIFO pair needed for a connection. + * Create the FIFO pair needed for a SOCK_STREAM connection. * ****************************************************************************/ -int local_create_fifos(FAR struct local_conn_s *client); +int local_create_fifos(FAR struct local_conn_s *conn); + +/**************************************************************************** + * Name: local_create_halfduplex + * + * Description: + * Create the half-duplex FIFO needed for SOCK_DGRAM communication. + * + ****************************************************************************/ + +int local_create_halfduplex(FAR struct local_conn_s *conn); /**************************************************************************** * Name: local_destroy_fifos * * Description: - * Destroy the FIFO pair used for a connection. + * Destroy the FIFO pair used for a SOCK_STREAM connection. + * + ****************************************************************************/ + +int local_destroy_fifos(FAR struct local_conn_s *conn); + +/**************************************************************************** + * Name: local_destroy_halfduplex + * + * Description: + * Destroy the FIFO used for SOCK_DGRAM communication * ****************************************************************************/ -int local_destroy_fifos(FAR struct local_conn_s *client); +int local_destroy_halfduplex(FAR struct local_conn_s *conn); /**************************************************************************** * Name: local_open_client_rx @@ -544,6 +564,26 @@ int local_open_server_rx(FAR struct local_conn_s *server); int local_open_server_tx(FAR struct local_conn_s *server); +/**************************************************************************** + * Name: local_open_receiver + * + * Description: + * Only the receiving side of the half duplex FIFO. + * + ****************************************************************************/ + +int local_open_receiver(FAR struct local_conn_s *conn); + +/**************************************************************************** + * Name: local_open_sender + * + * Description: + * Only the sending side of the half duplex FIFO. + * + ****************************************************************************/ + +int local_open_sender(FAR struct local_conn_s *conn); + #undef EXTERN #ifdef __cplusplus } diff --git a/nuttx/net/local/local_fifo.c b/nuttx/net/local/local_fifo.c index ee5cb1072..0817f33bc 100644 --- a/nuttx/net/local/local_fifo.c +++ b/nuttx/net/local/local_fifo.c @@ -55,8 +55,9 @@ * Private Functions ****************************************************************************/ -#define LOCAL_RX_SUFFIX "RX" -#define LOCAL_TX_SUFFIX "TX" +#define LOCAL_CS_SUFFIX "CS" /* Name of the client-to-server FIFO */ +#define LOCAL_SC_SUFFIX "SC" /* Name of the server-to-client FIFO */ +#define LOCAL_HD_SUFFIX "HD" /* Name of the half duplex datagram FIFO */ #define LOCAL_SUFFIX_LEN 2 #define LOCAL_FULLPATH_LEN (UNIX_PATH_MAX + LOCAL_SUFFIX_LEN) @@ -66,33 +67,49 @@ ****************************************************************************/ /**************************************************************************** - * Name: local_rx_name + * Name: local_cs_name * * Description: - * Create the name of the RX (client-to-server) FIFO name. + * Create the name of the client-to-server FIFO. * ****************************************************************************/ -static inline void local_rx_name(FAR struct local_conn_s *conn, +static inline void local_cs_name(FAR struct local_conn_s *conn, FAR char *path) { - (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_RX_SUFFIX, + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_CS_SUFFIX, conn->lc_path); path[LOCAL_FULLPATH_LEN-1] = '\0'; } /**************************************************************************** - * Name: local_tx_name + * Name: local_sc_name * * Description: - * Create the name of the TX (server-to-client) FIFO name. + * Create the name of the server-to-client FIFO. * ****************************************************************************/ -static inline void local_tx_name(FAR struct local_conn_s *conn, +static inline void local_sc_name(FAR struct local_conn_s *conn, FAR char *path) { - (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_TX_SUFFIX, + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_SC_SUFFIX, + conn->lc_path); + path[LOCAL_FULLPATH_LEN-1] = '\0'; +} + +/**************************************************************************** + * Name: local_hd_name + * + * Description: + * Create the name of the half duplex, datagram FIFO. + * + ****************************************************************************/ + +static inline void local_hd_name(FAR struct local_conn_s *conn, + FAR char *path) +{ + (void)snprintf(path, LOCAL_FULLPATH_LEN-1, "%s" LOCAL_HD_SUFFIX, conn->lc_path); path[LOCAL_FULLPATH_LEN-1] = '\0'; } @@ -130,7 +147,7 @@ static bool local_fifo_exists(FAR const char *path) * Name: local_create_fifo * * Description: - * Create the one of FIFOs needed for a connection. + * Create the one FIFO. * ****************************************************************************/ @@ -172,7 +189,12 @@ static int local_destroy_fifo(FAR const char *path) { int ret; - /* Unlink the client-to-server FIFO if it exists. */ + /* Unlink the client-to-server FIFO if it exists. + * REVISIT: This is wrong! Un-linking the FIFO does not eliminate it. + * it only removes it from the namespace. A new interface will be required + * to remove the FIFO and all of its resources. + */ +#warning Missing logic if (local_fifo_exists(path)) { @@ -268,24 +290,24 @@ static inline int local_tx_open(FAR struct local_conn_s *conn, * Name: local_create_fifos * * Description: - * Create the FIFO pair needed for a connection. + * Create the FIFO pair needed for a SOCK_STREAM connection. * ****************************************************************************/ -int local_create_fifos(FAR struct local_conn_s *client) +int local_create_fifos(FAR struct local_conn_s *conn) { char path[LOCAL_FULLPATH_LEN]; int ret; /* Create the client-to-server FIFO if it does not already exist. */ - local_tx_name(client, path); + local_cs_name(conn, path); ret = local_create_fifo(path); if (ret >= 0) { /* Create the server-to-client FIFO if it does not already exist. */ - local_rx_name(client, path); + local_sc_name(conn, path); ret = local_create_fifo(path); } @@ -293,14 +315,32 @@ int local_create_fifos(FAR struct local_conn_s *client) } /**************************************************************************** + * Name: local_create_halfduplex + * + * Description: + * Create the half-duplex FIFO needed for SOCK_DGRAM communication. + * + ****************************************************************************/ + +int local_create_halfduplex(FAR struct local_conn_s *conn) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Create the half duplex FIFO if it does not already exist. */ + + local_hd_name(conn, path); + return local_create_fifo(path); +} + +/**************************************************************************** * Name: local_destroy_fifos * * Description: - * Destroy the FIFO pair used for a connection. + * Destroy the FIFO pair used for a SOCK_STREAM connection. * ****************************************************************************/ -int local_destroy_fifos(FAR struct local_conn_s *client) +int local_destroy_fifos(FAR struct local_conn_s *conn) { char path[LOCAL_FULLPATH_LEN]; int ret1; @@ -308,12 +348,12 @@ int local_destroy_fifos(FAR struct local_conn_s *client) /* Destroy the client-to-server FIFO if it exists. */ - local_tx_name(client, path); + local_sc_name(conn, path); ret1 = local_destroy_fifo(path); /* Destroy the server-to-client FIFO if it exists. */ - local_rx_name(client, path); + local_cs_name(conn, path); ret2 = local_create_fifo(path); /* Return a failure if one occurred. */ @@ -322,10 +362,28 @@ int local_destroy_fifos(FAR struct local_conn_s *client) } /**************************************************************************** + * Name: local_destroy_halfduplex + * + * Description: + * Destroy the FIFO used for SOCK_DGRAM communication + * + ****************************************************************************/ + +int local_destroy_halfduplex(FAR struct local_conn_s *conn) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Destroy the half duplex FIFO if it exists. */ + + local_hd_name(conn, path); + return local_destroy_fifo(path); +} + +/**************************************************************************** * Name: local_open_client_rx * * Description: - * Only the client-side Rx FIFO. + * Open the client-side of the server-to-client FIFO. * ****************************************************************************/ @@ -335,7 +393,7 @@ int local_open_client_rx(FAR struct local_conn_s *client) /* Get the server-to-client path name */ - local_tx_name(client, path); + local_sc_name(client, path); /* Then open the file for read-only access */ @@ -346,7 +404,7 @@ int local_open_client_rx(FAR struct local_conn_s *client) * Name: local_open_client_tx * * Description: - * Only the client-side Tx FIFO. + * Open the client-side of the client-to-server FIFO. * ****************************************************************************/ @@ -356,7 +414,7 @@ int local_open_client_tx(FAR struct local_conn_s *client) /* Get the client-to-server path name */ - local_rx_name(client, path); + local_cs_name(client, path); /* Then open the file for write-only access */ @@ -367,7 +425,7 @@ int local_open_client_tx(FAR struct local_conn_s *client) * Name: local_open_server_rx * * Description: - * Only the server-side Rx FIFO. + * Open the server-side of the client-to-server FIFO. * ****************************************************************************/ @@ -377,7 +435,7 @@ int local_open_server_rx(FAR struct local_conn_s *server) /* Get the client-to-server path name */ - local_rx_name(server, path); + local_cs_name(server, path); /* Then open the file for write-only access */ @@ -388,7 +446,7 @@ int local_open_server_rx(FAR struct local_conn_s *server) * Name: local_open_server_tx * * Description: - * Only the server-side Tx FIFO. + * Only the server-side of the server-to-client FIFO. * ****************************************************************************/ @@ -398,10 +456,53 @@ int local_open_server_tx(FAR struct local_conn_s *server) /* Get the server-to-client path name */ - local_tx_name(server, path); + local_sc_name(server, path); /* Then open the file for read-only access */ return local_tx_open(server, path); } + +/**************************************************************************** + * Name: local_open_receiver + * + * Description: + * Only the receiving side of the half duplex FIFO. + * + ****************************************************************************/ + +int local_open_receiver(FAR struct local_conn_s *conn) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the server-to-client path name */ + + local_hd_name(conn, path); + + /* Then open the file for read-only access */ + + return local_rx_open(conn, path); +} + +/**************************************************************************** + * Name: local_open_sender + * + * Description: + * Only the sending side of the half duplex FIFO. + * + ****************************************************************************/ + +int local_open_sender(FAR struct local_conn_s *conn) +{ + char path[LOCAL_FULLPATH_LEN]; + + /* Get the server-to-client path name */ + + local_hd_name(conn, path); + + /* Then open the file for read-only access */ + + return local_tx_open(conn, path); +} + #endif /* CONFIG_NET && CONFIG_NET_LOCAL */ diff --git a/nuttx/net/local/local_recvfrom.c b/nuttx/net/local/local_recvfrom.c index 7ce5bb0da..731b5cc99 100644 --- a/nuttx/net/local/local_recvfrom.c +++ b/nuttx/net/local/local_recvfrom.c @@ -42,6 +42,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <unistd.h> #include <errno.h> #include <assert.h> #include <debug.h> @@ -60,13 +61,14 @@ #endif /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ + /**************************************************************************** * Name: psock_fifo_read * * Description: - * A thin layer aroudn local_fifo_read that handles socket-related loss-of- + * A thin layer around local_fifo_read that handles socket-related loss-of- * connection events. * ****************************************************************************/ @@ -118,22 +120,12 @@ static int psock_fifo_read(FAR struct socket *psock, FAR void *buf, } /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: psock_recvfrom + * Function: psock_stream_recvfrom * * Description: - * recvfrom() receives messages from a local socket, and may be used to - * receive data on a socket whether or not it is connection-oriented. - * - * If from is not NULL, and the underlying protocol provides the source - * address, this source address is filled in. The argument fromlen - * initialized to the size of the buffer associated with from, and modified - * on return to indicate the actual size of the address stored there. + * psock_stream_recvfrom() receives messages from a local stream socket. * - * Parameters: + * Input Parameters: * psock A pointer to a NuttX-specific, internal socket structure * buf Buffer to receive data * len Length of buffer @@ -142,35 +134,34 @@ static int psock_fifo_read(FAR struct socket *psock, FAR void *buf, * fromlen The length of the address structure * * Returned Value: - * On success, returns the number of characters sent. If no data is + * On success, returns the number of characters received. If no data is * available to be received and the peer has performed an orderly shutdown, * recv() will return 0. Otherwise, on errors, -1 is returned, and errno * is set appropriately (see receive from for the complete list). * ****************************************************************************/ -ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, - size_t len, int flags, FAR struct sockaddr *from, - FAR socklen_t *fromlen) +static inline ssize_t +psock_stream_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen) { - FAR struct local_conn_s *conn; + FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn; size_t readlen; int ret; - DEBUGASSERT(psock && psock->s_conn && buf); - conn = (FAR struct local_conn_s *)psock->s_conn; - - /* Verify that this is a connected peer socket and that it has opened the - * incoming FIFO for read-only access. - */ + /* Verify that this is a connected peer socket */ - if (conn->lc_state != LOCAL_STATE_CONNECTED || - conn->lc_infd < 0) + if (conn->lc_state != LOCAL_STATE_CONNECTED) { ndbg("ERROR: not connected\n"); return -ENOTCONN; } + /* The incoming FIFO should be open */ + + DEBUGASSERT(conn->lc_infd >= 0); + /* Are there still bytes in the FIFO from the last packet? */ if (conn->u.peer.lc_remaining == 0) @@ -185,7 +176,7 @@ ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, ndbg("ERROR: Failed to get packet length: %d\n", ret); return ret; } - else if (ret > 0xffff) + else if (ret > UINT16_MAX) { ndbg("ERROR: Packet is too big: %d\n", ret); return -E2BIG; @@ -195,7 +186,6 @@ ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, } /* Read the packet */ - /* REVISIT: Does this make sense if the socket is SOCK_DGRAM? */ readlen = MIN(conn->u.peer.lc_remaining, len); ret = psock_fifo_read(psock, buf, &readlen); @@ -209,36 +199,154 @@ ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, DEBUGASSERT(readlen <= conn->u.peer.lc_remaining); conn->u.peer.lc_remaining -= readlen; - /* If this is a SOCK_STREAM socket and there are unread bytes remaining - * in the packet, we will get those bytes the next time recv is called. - * What if this is a SOCK_DRAM? REVISIT: Here we flush the remainder of - * the packet to the bit bucket. + /* Return the address family */ + + if (from) + { + ret = local_getaddr(conn, from, fromlen); + if (ret < 0) + { + return ret; + } + } + + return readlen; +} + +/**************************************************************************** + * Function: psock_dgram_recvfrom + * + * Description: + * psock_dgram_recvfrom() receives messages from a local datagram socket. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters received. Otherwise, on + * errors, -1 is returned, and errno is set appropriately (see receive + * from for the complete list). + * + ****************************************************************************/ + +static inline ssize_t +psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, + int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen) +{ + FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn; + uint16_t pktlen; + size_t readlen; + int ret; + + /* We keep packet sizes in a uint16_t, so there is a upper limit to the + * 'len' that can be supported. + */ + + DEBUGASSERT(len <= UINT16_MAX); + + /* Verify that this is a bound, un-connected peer socket */ + + if (conn->lc_state != LOCAL_STATE_BOUND) + { + /* Either not bound to address or it is connected */ + + ndbg("ERROR: Connected or not bound\n"); + return -EISCONN; + } + + /* The incoming FIFO should not be open */ + + DEBUGASSERT(conn->lc_infd < 0); + + /* Make sure that half duplex FIFO has been created */ + + ret = local_create_halfduplex(conn); + if (ret < 0) + { + ndbg("ERROR: Failed to create FIFO for %s: %d\n", + conn->lc_path, ret); + return ret; + } + + /* Open the receiving side of the transfer */ + + ret = local_open_receiver(conn); + if (ret < 0) + { + ndbg("ERROR: Failed to open FIFO for %s: %d\n", + conn->lc_path, ret); + return ret; + } + + /* Sync to the start of the next packet in the stream and get the size of + * the next packet. */ - if (psock->s_type == SOCK_DGRAM && conn->u.peer.lc_remaining > 0) + ret = local_sync(conn->lc_infd); + if (ret < 0) + { + ndbg("ERROR: Failed to get packet length: %d\n", ret); + goto errout_with_infd; + } + else if (ret > UINT16_MAX) + { + ndbg("ERROR: Packet is too big: %d\n", ret); + goto errout_with_infd; + } + + pktlen = ret; + + /* Read the packet */ + + readlen = MIN(pktlen, len); + ret = psock_fifo_read(psock, buf, &readlen); + if (ret < 0) + { + goto errout_with_infd; + } + + /* If there are unread bytes remaining in the packet, flush the remainder + * of the packet to the bit bucket. + */ + + DEBUGASSERT(readlen <= pktlen); + if (readlen < pktlen) { uint8_t bitbucket[32]; + uint16_t remaining; size_t tmplen; + remaining = pktlen - readlen; do { /* Read 32 bytes into the bit bucket */ - tmplen = MIN(conn->u.peer.lc_remaining, 32); - ret = psock_fifo_read(psock, bitbucket, &tmplen); + readlen = MIN(remaining, 32); + ret = psock_fifo_read(psock, bitbucket, &tmplen); if (ret < 0) { - return ret; + goto errout_with_infd; } /* Adjust the number of bytes remaining to be read from the packet */ - DEBUGASSERT(tmplen <= conn->u.peer.lc_remaining); - conn->u.peer.lc_remaining -= tmplen; + DEBUGASSERT(tmplen <= remain); + remaining -= tmplen; } - while (conn->u.peer.lc_remaining > 0); + while (remaining > 0); } + /* Now we can close the read-only socket descriptor */ + + close(conn->lc_infd); + conn->lc_infd = -1; + /* Return the address family */ if (from) @@ -251,6 +359,67 @@ ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, } return readlen; + +errout_with_infd: + close(conn->lc_infd); + conn->lc_infd = -1; + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: psock_local_recvfrom + * + * Description: + * psock_local_recvfrom() receives messages from a local socket and may be + * used to receive data on a socket whether or not it is connection-oriented. + * + * If from is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument fromlen + * initialized to the size of the buffer associated with from, and modified + * on return to indicate the actual size of the address stored there. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters received. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on errors, -1 is returned, and errno + * is set appropriately (see receive from for the complete list). + * + ****************************************************************************/ + +ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen) +{ + DEBUGASSERT(psock && psock->s_conn && buf); + + /* Check for a stream socket */ + + if (psock->s_type == SOCK_STREAM) + { + return psock_stream_recvfrom(psock, buf, len, flags, from, fromlen); + } + else if (psock->s_type == SOCK_DGRAM) + { + return psock_dgram_recvfrom(psock, buf, len, flags, from, fromlen); + } + else + { + DEBUGPANIC(); + ndbg("ERROR: Unrecognized socket type: %s\n", psock->s_type); + return -EINVAL; + } } #endif /* CONFIG_NET && CONFIG_NET_LOCAL */ |