From c65d8e6a2355d4fa312faea7c5856693fdda58f5 Mon Sep 17 00:00:00 2001 From: "chao.an" Date: Wed, 19 Feb 2020 12:21:28 -0600 Subject: [PATCH] net/socket: add MSG_DONTWAIT support MSG_DONTWAIT (since Linux 2.2) Enables nonblocking operation; if the operation would block, the call fails with the error EAGAIN or EWOULDBLOCK. This provides similar behavior to setting the O_NONBLOCK flag (via the fcntl(2) F_SETFL operation), but differs in that MSG_DONTWAIT is a per-call option, whereas O_NONBLOCK is a setting on the open file description (see open(2)), which will affect all threads in the calling process and as well as other processes that hold file descriptors referring to the same open file description. --- net/inet/inet_sockif.c | 20 +++++++++++++------- net/local/local_recvfrom.c | 3 ++- net/local/local_sendto.c | 3 ++- net/netlink/netlink_route.c | 15 ++++++++------- net/tcp/tcp.h | 15 +++++++++------ net/tcp/tcp_recvfrom.c | 17 ++++++++++------- net/tcp/tcp_send_buffered.c | 14 +++++++++----- net/tcp/tcp_send_unbuffered.c | 3 ++- net/udp/udp.h | 12 +++++++----- net/udp/udp_recvfrom.c | 10 ++++++---- net/udp/udp_sendto_buffered.c | 9 ++++++--- net/usrsock/usrsock_recvfrom.c | 2 +- net/usrsock/usrsock_sendto.c | 2 +- 13 files changed, 76 insertions(+), 49 deletions(-) diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c index 27f2acf43b..912f437db6 100644 --- a/net/inet/inet_sockif.c +++ b/net/inet/inet_sockif.c @@ -87,8 +87,9 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen); #ifdef CONFIG_NET_SENDFILE -static ssize_t inet_sendfile(FAR struct socket *psock, FAR struct file *infile, - FAR off_t *offset, size_t count); +static ssize_t inet_sendfile(FAR struct socket *psock, + FAR struct file *infile, FAR off_t *offset, + size_t count); #endif static ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from, @@ -410,7 +411,9 @@ static int inet_bind(FAR struct socket *psock, ret = tcp_bind(psock->s_conn, addr); #else - nwarn("WARNING: TCP/IP stack is not available in this configuration\n"); + nwarn("WARNING: TCP/IP stack is not available in this " + "configuration\n"); + return -ENOSYS; #endif } @@ -1076,11 +1079,12 @@ static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, { /* TCP/IP packet send */ - ret = psock_tcp_send(psock, buf, len); + ret = psock_tcp_send(psock, buf, len, flags); } #endif /* NET_TCP_HAVE_STACK */ + #elif defined(NET_TCP_HAVE_STACK) - ret = psock_tcp_send(psock, buf, len); + ret = psock_tcp_send(psock, buf, len, flags); #else ret = -ENOSYS; #endif /* CONFIG_NET_6LOWPAN */ @@ -1105,6 +1109,7 @@ static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, psock_udp_sendto(psock, buf, len, 0, NULL, 0) : -ENOTCONN; } #endif /* NET_UDP_HAVE_STACK */ + #elif defined(NET_UDP_HAVE_STACK) /* Only UDP/IP packet send */ @@ -1212,6 +1217,7 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); } #endif /* NET_UDP_HAVE_STACK */ + #elif defined(NET_UDP_HAVE_STACK) nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); #else @@ -1348,7 +1354,7 @@ static ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, case SOCK_STREAM: { #ifdef NET_TCP_HAVE_STACK - ret = psock_tcp_recvfrom(psock, buf, len, from, fromlen); + ret = psock_tcp_recvfrom(psock, buf, len, flags, from, fromlen); #else ret = -ENOSYS; #endif @@ -1360,7 +1366,7 @@ static ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, case SOCK_DGRAM: { #ifdef NET_UDP_HAVE_STACK - ret = psock_udp_recvfrom(psock, buf, len, from, fromlen); + ret = psock_udp_recvfrom(psock, buf, len, flags, from, fromlen); #else ret = -ENOSYS; #endif diff --git a/net/local/local_recvfrom.c b/net/local/local_recvfrom.c index c34e9e0bb7..45fb7d7ef9 100644 --- a/net/local/local_recvfrom.c +++ b/net/local/local_recvfrom.c @@ -279,7 +279,8 @@ psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, /* Open the receiving side of the transfer */ - ret = local_open_receiver(conn, _SS_ISNONBLOCK(psock->s_flags)); + ret = local_open_receiver(conn, _SS_ISNONBLOCK(psock->s_flags) || + (flags & MSG_DONTWAIT) != 0); if (ret < 0) { nerr("ERROR: Failed to open FIFO for %s: %d\n", diff --git a/net/local/local_sendto.c b/net/local/local_sendto.c index 4ac35b4ee1..8db7c01824 100644 --- a/net/local/local_sendto.c +++ b/net/local/local_sendto.c @@ -138,7 +138,8 @@ ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf, /* Open the sending side of the transfer */ ret = local_open_sender(conn, unaddr->sun_path, - _SS_ISNONBLOCK(psock->s_flags)); + _SS_ISNONBLOCK(psock->s_flags) || + (flags & MSG_DONTWAIT) != 0); if (ret < 0) { nerr("ERROR: Failed to open FIFO for %s: %d\n", diff --git a/net/netlink/netlink_route.c b/net/netlink/netlink_route.c index 0b0984b31a..48651c8e52 100644 --- a/net/netlink/netlink_route.c +++ b/net/netlink/netlink_route.c @@ -318,8 +318,8 @@ static int netlink_device_callback(FAR struct net_driver_s *dev, #endif #ifdef CONFIG_NET_IPv6 - /* Should have devinfo->psock->s_domain == PF_INET6 but d_lltype could be - * several things. + /* Should have devinfo->psock->s_domain == PF_INET6 but d_lltype + * could be several things. */ case AF_INET6: @@ -335,8 +335,8 @@ static int netlink_device_callback(FAR struct net_driver_s *dev, #endif #ifdef CONFIG_NET_BLUETOOTH - /* Should have devinfo->psock->s_domain == PF_PACKET and d_lltype should be - * NET_LL_BLUETOOTH. + /* Should have devinfo->psock->s_domain == PF_PACKET and d_lltype + * should be NET_LL_BLUETOOTH. */ case AF_BLUETOOTH: @@ -679,8 +679,9 @@ static int netlink_get_nbtable(FAR struct socket *psock, ****************************************************************************/ #ifndef CONFIG_NETLINK_DISABLE_GETROUTE -static int netlink_route_terminator(FAR struct socket *psock, - FAR const struct getroute_sendto_request_s *req) +static int + netlink_route_terminator(FAR struct socket *psock, + FAR const struct getroute_sendto_request_s *req) { FAR struct nlroute_msgdone_rsplist_s *alloc; FAR struct nlroute_msgdone_response_s *resp; @@ -1058,7 +1059,7 @@ ssize_t netlink_route_recvfrom(FAR struct socket *psock, * select Netlink non-blocking sockets. */ - if (_SS_ISNONBLOCK(psock->s_flags)) + if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0) { return -EAGAIN; } diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 39727f8342..32cea07069 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -1274,10 +1274,12 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, * Perform the recvfrom operation for a TCP/IP SOCK_STREAM * * Input Parameters: - * psock Pointer to the socket structure for the SOCK_DRAM socket - * buf Buffer to receive data - * len Length of buffer - * from INET address of source (may be NULL) + * psock Pointer to the socket structure for the SOCK_DRAM socket + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from INET address of source (may be NULL) + * fromlen The length of the address structure * * Returned Value: * On success, returns the number of characters received. On error, @@ -1288,7 +1290,7 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr, ****************************************************************************/ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, - size_t len, FAR struct sockaddr *from, + size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen); /**************************************************************************** @@ -1302,6 +1304,7 @@ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, * psock An instance of the internal socket structure. * buf Data to send * len Length of data to send + * flags Send flags * * Returned Value: * On success, returns the number of characters sent. On error, @@ -1350,7 +1353,7 @@ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, struct socket; ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, - size_t len); + size_t len, int flags); /**************************************************************************** * Name: tcp_setsockopt diff --git a/net/tcp/tcp_recvfrom.c b/net/tcp/tcp_recvfrom.c index dba3acfd6a..bef1791cef 100644 --- a/net/tcp/tcp_recvfrom.c +++ b/net/tcp/tcp_recvfrom.c @@ -194,7 +194,8 @@ static inline void tcp_newdata(FAR struct net_driver_s *dev, if (recvlen < dev->d_len) { - FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pstate->ir_sock->s_conn; + FAR struct tcp_conn_s *conn = + (FAR struct tcp_conn_s *)pstate->ir_sock->s_conn; FAR uint8_t *buffer = (FAR uint8_t *)dev->d_appdata + recvlen; uint16_t buflen = dev->d_len - recvlen; #ifdef CONFIG_DEBUG_NET @@ -628,10 +629,12 @@ static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate) * Perform the recvfrom operation for a TCP/IP SOCK_STREAM * * Input Parameters: - * psock Pointer to the socket structure for the SOCK_DRAM socket - * buf Buffer to receive data - * len Length of buffer - * from INET address of source (may be NULL) + * psock Pointer to the socket structure for the SOCK_DRAM socket + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from INET address of source (may be NULL) + * fromlen The length of the address structure * * Returned Value: * On success, returns the number of characters received. On error, @@ -642,7 +645,7 @@ static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate) ****************************************************************************/ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, - size_t len, FAR struct sockaddr *from, + size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { struct tcp_recvfrom_s state; @@ -702,7 +705,7 @@ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, * if no data was obtained from the read-ahead buffers. */ - else if (_SS_ISNONBLOCK(psock->s_flags)) + else if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0) { /* Return the number of bytes read from the read-ahead buffer if * something was received (already in 'ret'); EAGAIN if not. diff --git a/net/tcp/tcp_send_buffered.c b/net/tcp/tcp_send_buffered.c index 76d4af2a9c..78d535bb83 100644 --- a/net/tcp/tcp_send_buffered.c +++ b/net/tcp/tcp_send_buffered.c @@ -886,6 +886,7 @@ static inline void send_txnotify(FAR struct socket *psock, * psock An instance of the internal socket structure. * buf Data to send * len Length of data to send + * flags Send flags * * Returned Value: * On success, returns the number of characters sent. On error, @@ -931,11 +932,12 @@ static inline void send_txnotify(FAR struct socket *psock, ****************************************************************************/ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, - size_t len) + size_t len, int flags) { FAR struct tcp_conn_s *conn; FAR struct tcp_wrbuffer_s *wrb; ssize_t result = 0; + bool nonblock; int ret = OK; if (psock == NULL || psock->s_crefs <= 0) @@ -990,6 +992,8 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ + nonblock = _SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0; + /* Dump the incoming buffer */ BUF_DUMP("psock_tcp_send", buf, len); @@ -1001,7 +1005,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, */ net_lock(); - if (_SS_ISNONBLOCK(psock->s_flags)) + if (nonblock) { wrb = tcp_wrbuffer_tryalloc(); } @@ -1015,7 +1019,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate write buffer\n"); - ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM; + ret = nonblock ? -EAGAIN : -ENOMEM; goto errout_with_lock; } @@ -1033,7 +1037,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate callback\n"); - ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM; + ret = nonblock ? -EAGAIN : -ENOMEM; goto errout_with_wrb; } @@ -1053,7 +1057,7 @@ ssize_t psock_tcp_send(FAR struct socket *psock, FAR const void *buf, * buffer space if the socket was opened non-blocking. */ - if (_SS_ISNONBLOCK(psock->s_flags)) + if (nonblock) { /* The return value from TCP_WBTRYCOPYIN is either OK or * -ENOMEM if less than the entire data chunk could be allocated. diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 1ff0406ca9..189afb1387 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -537,6 +537,7 @@ static inline void send_txnotify(FAR struct socket *psock, * psock An instance of the internal socket structure. * buf Data to send * len Length of data to send + * flags Send flags * * Returned Value: * On success, returns the number of characters sent. On error, @@ -582,7 +583,7 @@ static inline void send_txnotify(FAR struct socket *psock, ****************************************************************************/ ssize_t psock_tcp_send(FAR struct socket *psock, - FAR const void *buf, size_t len) + FAR const void *buf, size_t len, int flags) { FAR struct tcp_conn_s *conn; struct send_s state; diff --git a/net/udp/udp.h b/net/udp/udp.h index 454b29f177..165d0c166d 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -644,10 +644,12 @@ uint16_t udp_callback(FAR struct net_driver_s *dev, * Perform the recvfrom operation for a UDP SOCK_DGRAM * * Input Parameters: - * psock Pointer to the socket structure for the SOCK_DRAM socket - * buf Buffer to receive data - * len Length of buffer - * from INET address of source (may be NULL) + * psock Pointer to the socket structure for the SOCK_DRAM socket + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from INET address of source (may be NULL) + * fromlen The length of the address structure * * Returned Value: * On success, returns the number of characters received. On error, @@ -658,7 +660,7 @@ uint16_t udp_callback(FAR struct net_driver_s *dev, ****************************************************************************/ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf, - size_t len, FAR struct sockaddr *from, + size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen); /**************************************************************************** diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c index 7a320a7359..af62ee595b 100644 --- a/net/udp/udp_recvfrom.c +++ b/net/udp/udp_recvfrom.c @@ -235,7 +235,8 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate) if (pstate->ir_from) { socklen_t len = *pstate->ir_fromlen; - len = (socklen_t)src_addr_size > len ? len : (socklen_t)src_addr_size; + len = (socklen_t) + src_addr_size > len ? len : (socklen_t)src_addr_size; recvlen = iob_copyout((FAR uint8_t *)pstate->ir_from, iob, len, sizeof(uint8_t)); @@ -347,7 +348,8 @@ static inline void udp_sender(FAR struct net_driver_s *dev, if (conn->domain == PF_INET6) { - FAR struct sockaddr_in6 *infrom6 = (FAR struct sockaddr_in6 *)infrom; + FAR struct sockaddr_in6 *infrom6 = + (FAR struct sockaddr_in6 *)infrom; FAR socklen_t *fromlen = pstate->ir_fromlen; FAR struct udp_hdr_s *udp = UDPIPv6BUF; FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; @@ -606,7 +608,7 @@ static ssize_t udp_recvfrom_result(int result, struct udp_recvfrom_s *pstate) ****************************************************************************/ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf, - size_t len, FAR struct sockaddr *from, + size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)psock->s_conn; @@ -637,7 +639,7 @@ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf, /* Handle non-blocking UDP sockets */ - if (_SS_ISNONBLOCK(psock->s_flags)) + if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0) { /* Return the number of bytes read from the read-ahead buffer if * something was received (already in 'ret'); EAGAIN if not. diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c index 8428482431..231728d81e 100644 --- a/net/udp/udp_sendto_buffered.c +++ b/net/udp/udp_sendto_buffered.c @@ -504,6 +504,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, { FAR struct udp_conn_s *conn; FAR struct udp_wrbuffer_s *wrb; + bool nonblock; bool empty; int ret = OK; @@ -628,6 +629,8 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ + nonblock = _SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0; + /* Dump the incoming buffer */ BUF_DUMP("psock_udp_sendto", buf, len); @@ -640,7 +643,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, * unlocked here. */ - if (_SS_ISNONBLOCK(psock->s_flags)) + if (nonblock) { wrb = udp_wrbuffer_tryalloc(); } @@ -654,7 +657,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, /* A buffer allocation error occurred */ nerr("ERROR: Failed to allocate write buffer\n"); - ret = _SS_ISNONBLOCK(psock->s_flags) ? -EAGAIN : -ENOMEM; + ret = nonblock ? -EAGAIN : -ENOMEM; goto errout_with_lock; } @@ -707,7 +710,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, * buffer space if the socket was opened non-blocking. */ - if (_SS_ISNONBLOCK(psock->s_flags)) + if (nonblock) { ret = iob_trycopyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false, IOBUSER_NET_SOCK_UDP); diff --git a/net/usrsock/usrsock_recvfrom.c b/net/usrsock/usrsock_recvfrom.c index 2f12f10ac4..8f7d51e4d9 100644 --- a/net/usrsock/usrsock_recvfrom.c +++ b/net/usrsock/usrsock_recvfrom.c @@ -308,7 +308,7 @@ ssize_t usrsock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, if (!(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL)) { - if (_SS_ISNONBLOCK(psock->s_flags)) + if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0) { /* Nothing to receive from daemon side. */ diff --git a/net/usrsock/usrsock_sendto.c b/net/usrsock/usrsock_sendto.c index ed302a823a..16d3708799 100644 --- a/net/usrsock/usrsock_sendto.c +++ b/net/usrsock/usrsock_sendto.c @@ -294,7 +294,7 @@ ssize_t usrsock_sendto(FAR struct socket *psock, FAR const void *buf, if (!(conn->flags & USRSOCK_EVENT_SENDTO_READY)) { - if (_SS_ISNONBLOCK(psock->s_flags)) + if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0) { /* Send busy at daemon side. */