diff --git a/drivers/pipes/pipe_common.c b/drivers/pipes/pipe_common.c index daf3eb3e7a..576f4b79fd 100644 --- a/drivers/pipes/pipe_common.c +++ b/drivers/pipes/pipe_common.c @@ -838,6 +838,16 @@ int pipecommon_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + case PIPEIOC_PEEK: + { + FAR struct pipe_peek_s *peek = (FAR struct pipe_peek_s *)arg; + + DEBUGASSERT(peek && peek->buf); + + ret = circbuf_peek(&dev->d_buffer, peek->buf, peek->size); + } + break; + case FIONWRITE: /* Number of bytes waiting in send queue */ case FIONREAD: /* Number of bytes available for reading */ { diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 3fed64f823..1ccf37cf23 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -26,6 +26,7 @@ ****************************************************************************/ #include +#include /**************************************************************************** * Pre-processor Definitions @@ -447,6 +448,10 @@ * threshold. * OUT: None */ +#define PIPEIOC_PEEK _PIPEIOC(0x0004) /* Pipe peek interface + * IN: pipe_peek_s + * OUT: Length of data */ + /* RTC driver ioctl definitions *********************************************/ /* (see nuttx/include/rtc.h */ @@ -661,6 +666,12 @@ * Public Type Definitions ****************************************************************************/ +struct pipe_peek_s +{ + FAR void *buf; + size_t size; +}; + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/net/local/local.h b/net/local/local.h index 83f70c4320..cb9c00d5b8 100644 --- a/net/local/local.h +++ b/net/local/local.h @@ -122,6 +122,10 @@ struct local_conn_s char lc_path[UNIX_PATH_MAX]; /* Path assigned by bind() */ int32_t lc_instance_id; /* Connection instance ID for stream * server<->client connection pair */ +#ifdef CONFIG_NET_LOCAL_DGRAM + uint16_t pktlen; /* Read-ahead packet length */ +#endif /* CONFIG_NET_LOCAL_DGRAM */ + FAR struct local_conn_s * lc_peer; /* Peer connection instance */ #ifdef CONFIG_NET_LOCAL_SCM diff --git a/net/local/local_recvmsg.c b/net/local/local_recvmsg.c index 1f8df8a87a..fb3b3d3e62 100644 --- a/net/local/local_recvmsg.c +++ b/net/local/local_recvmsg.c @@ -56,12 +56,27 @@ ****************************************************************************/ static int psock_fifo_read(FAR struct socket *psock, FAR void *buf, - FAR size_t *readlen, bool once) + FAR size_t *readlen, int flags, bool once) { FAR struct local_conn_s *conn = psock->s_conn; int ret; - ret = local_fifo_read(&conn->lc_infile, buf, readlen, once); + if (flags & MSG_PEEK) + { + struct pipe_peek_s peek = + { + buf, + *readlen + }; + + ret = file_ioctl(&conn->lc_infile, PIPEIOC_PEEK, + (unsigned long)((uintptr_t)&peek)); + } + else + { + ret = local_fifo_read(&conn->lc_infile, buf, readlen, once); + } + if (ret < 0) { /* -ECONNRESET is a special case. We may or not have received @@ -245,7 +260,7 @@ psock_stream_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, /* Read the packet */ - ret = psock_fifo_read(psock, buf, &readlen, true); + ret = psock_fifo_read(psock, buf, &readlen, flags, true); if (ret < 0) { return ret; @@ -294,10 +309,9 @@ psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, FAR socklen_t *fromlen) { FAR struct local_conn_s *conn = psock->s_conn; - uint16_t pktlen; size_t readlen; bool bclose = false; - int ret; + int ret = 0; /* We keep packet sizes in a uint16_t, so there is a upper limit to the * 'len' that can be supported. @@ -346,24 +360,28 @@ psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, * the next packet. */ - ret = local_sync(&conn->lc_infile); - if (ret < 0) + if (conn->pktlen <= 0) { - nerr("ERROR: Failed to get packet length: %d\n", ret); - goto errout_with_infd; - } - else if (ret > UINT16_MAX) - { - nerr("ERROR: Packet is too big: %d\n", ret); - goto errout_with_infd; - } + ret = local_sync(&conn->lc_infile); - pktlen = ret; + if (ret < 0) + { + nerr("ERROR: Failed to get packet length: %d\n", ret); + goto errout_with_infd; + } + else if (ret > UINT16_MAX) + { + nerr("ERROR: Packet is too big: %d\n", ret); + goto errout_with_infd; + } + + conn->pktlen = ret; + } /* Read the packet */ - readlen = MIN(pktlen, len); - ret = psock_fifo_read(psock, buf, &readlen, false); + readlen = MIN(conn->pktlen, len); + ret = psock_fifo_read(psock, buf, &readlen, flags, false); if (ret < 0) { goto errout_with_infd; @@ -373,20 +391,25 @@ psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, * of the packet to the bit bucket. */ - DEBUGASSERT(readlen <= pktlen); - if (readlen < pktlen) + if (flags & MSG_PEEK) + { + goto skip_flush; + } + + DEBUGASSERT(readlen <= conn->pktlen); + if (readlen < conn->pktlen) { uint8_t bitbucket[32]; uint16_t remaining; size_t tmplen; - remaining = pktlen - readlen; + remaining = conn->pktlen - readlen; do { /* Read 32 bytes into the bit bucket */ tmplen = MIN(remaining, 32); - ret = psock_fifo_read(psock, bitbucket, &tmplen, false); + ret = psock_fifo_read(psock, bitbucket, &tmplen, flags, false); if (ret < 0) { goto errout_with_infd; @@ -402,6 +425,12 @@ psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, while (remaining > 0); } + /* The fifo has been read and the pktlen needs to be cleared */ + + conn->pktlen = 0; + +skip_flush: + /* Return the address family */ if (from)