Unix domain: Add initial cut at redvfrom() for Unix domain datagram sockets

This commit is contained in:
Gregory Nutt 2015-01-29 07:47:09 -06:00
parent 1c8ddae655
commit ffb16f658f
3 changed files with 403 additions and 93 deletions

View File

@ -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 *client);
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_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
}

View File

@ -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_destroy_fifos
* Name: local_create_halfduplex
*
* Description:
* Destroy the FIFO pair used for a connection.
* Create the half-duplex FIFO needed for SOCK_DGRAM communication.
*
****************************************************************************/
int local_destroy_fifos(FAR struct local_conn_s *client)
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 SOCK_STREAM connection.
*
****************************************************************************/
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. */
@ -321,11 +361,29 @@ int local_destroy_fifos(FAR struct local_conn_s *client)
return ret1 < 0 ? ret1 : ret2;
}
/****************************************************************************
* 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 */

View File

@ -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.
* psock_stream_recvfrom() receives messages from a local stream socket.
*
* 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.
*
* 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 */
/* Verify that this is a connected peer socket and that it has opened the
* incoming FIFO for read-only access.
*/
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,6 @@ 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.
*/
if (psock->s_type == SOCK_DGRAM && conn->u.peer.lc_remaining > 0)
{
uint8_t bitbucket[32];
size_t tmplen;
do
{
/* Read 32 bytes into the bit bucket */
tmplen = MIN(conn->u.peer.lc_remaining, 32);
ret = psock_fifo_read(psock, bitbucket, &tmplen);
if (ret < 0)
{
return ret;
}
/* 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;
}
while (conn->u.peer.lc_remaining > 0);
}
/* Return the address family */
if (from)
@ -253,4 +213,213 @@ ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf,
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.
*/
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 */
readlen = MIN(remaining, 32);
ret = psock_fifo_read(psock, bitbucket, &tmplen);
if (ret < 0)
{
goto errout_with_infd;
}
/* Adjust the number of bytes remaining to be read from the packet */
DEBUGASSERT(tmplen <= remain);
remaining -= tmplen;
}
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)
{
ret = local_getaddr(conn, from, fromlen);
if (ret < 0)
{
return ret;
}
}
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 */