From af072d52bcdf45ee385474656a337455350b350f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 11 Oct 2017 09:25:43 -0600 Subject: [PATCH] Adds OS internal functions nx_send(), ns_recv(), and nx_recvfrom() which are functionally equivalent to send(), recv(), and recvfrom() except that they do not set the errno variable and do not cause cancellation points. --- drivers/wireless/cc3000/socket_imp.c | 9 -- fs/vfs/fs_read.c | 7 +- fs/vfs/fs_write.c | 11 +- include/nuttx/net/net.h | 224 ++++++++++++++++----------- libc/netdb/lib_dnsquery.c | 9 +- net/socket/recvfrom.c | 119 ++++++++------ net/socket/send.c | 129 +++++++-------- 7 files changed, 287 insertions(+), 221 deletions(-) diff --git a/drivers/wireless/cc3000/socket_imp.c b/drivers/wireless/cc3000/socket_imp.c index e3f7c86207..a9a830e6ef 100644 --- a/drivers/wireless/cc3000/socket_imp.c +++ b/drivers/wireless/cc3000/socket_imp.c @@ -66,15 +66,6 @@ # define close(sd) closesocket(sd) #endif -/* Enable this flag if and only if you must comply with BSD socket read() and - * write() functions - */ - -#ifdef _API_USE_BSD_READ_WRITE -# define read(sd, buf, len, flags) recv(sd, buf, len, flags) -# define write(sd, buf, len, flags) send(sd, buf, len, flags) -#endif - #define SOCKET_OPEN_PARAMS_LEN (12) #define SOCKET_CLOSE_PARAMS_LEN (4) #define SOCKET_ACCEPT_PARAMS_LEN (4) diff --git a/fs/vfs/fs_read.c b/fs/vfs/fs_read.c index 9cd139703c..23b2ef9707 100644 --- a/fs/vfs/fs_read.c +++ b/fs/vfs/fs_read.c @@ -48,6 +48,7 @@ #include #include +#include #include "inode/inode.h" @@ -145,7 +146,11 @@ ssize_t read(int fd, FAR void *buf, size_t nbytes) * the errno variable. */ - ret = recv(fd, buf, nbytes, 0); + ret = nx_recv(fd, buf, nbytes, 0); + if (ret < 0) + { + goto errout; + } #else /* No networking... it is a bad descriptor in any event */ diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c index b180988a34..cdd1299fc1 100644 --- a/fs/vfs/fs_write.c +++ b/fs/vfs/fs_write.c @@ -52,6 +52,7 @@ #endif #include +#include #include "inode/inode.h" @@ -167,11 +168,13 @@ ssize_t write(int fd, FAR const void *buf, size_t nbytes) #endif { #if defined(CONFIG_NET_TCP) && CONFIG_NSOCKET_DESCRIPTORS > 0 - /* Write to a socket descriptor is equivalent to send with flags == 0. - * Note that send() will set the errno on failure. - */ + /* Write to a socket descriptor is equivalent to send with flags == 0. */ - ret = send(fd, buf, nbytes, 0); + ret = nx_send(fd, buf, nbytes, 0); + if (ret < 0) + { + goto errout; + } #else ret = -EBADF; goto errout; diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 4e35903c7e..0ba8e0fa87 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -53,6 +53,39 @@ * Pre-processor Definitions ****************************************************************************/ +/* Most internal network OS interfaces are not available in the user space in + * PROTECTED and KERNEL builds. In that context, the corresponding + * application network interfaces must be used. The differences between the two + * sets of interfaces are: The internal OS interfaces (1) do not cause + * cancellation points and (2) they do not modify the errno variable. + * + * This is only important when compiling libraries (libc or libnx) that are + * used both by the OS (libkc.a and libknx.a) or by the applications + * (libuc.a and libunx.a). The that case, the correct interface must be + * used for the build context. + * + * The interfaces accept(), read(), recv(), recvfrom(), write(), send(), + * sendto() are all cancellation points. + * + * REVISIT: These cancellation points are an issue and may cause + * violations: It use of these internally will cause the calling function + * to become a cancellation points! + */ + +#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__) +# define _NX_SEND(s,b,l,f) nx_send(s,b,l,f) +# define _NX_RECV(s,b,l,f) nx_recv(s,b,l,f) +# define _NX_RECVFROM(s,b,l,f,a,n) nx_recvfrom(s,b,l,f,a,n) +# define _NX_ERRNO(r) (-(r)) +# define _NX_ERRVAL(r) (r) +#else +# define _NX_SEND(s,b,l,f) send(s,b,l,f) +# define _NX_RECV(s,b,l,f) recv(s,b,l,f) +# define _NX_RECVFROM(s,b,l,f,a,n) recvfrom(s,b,l,f,a,n) +# define _NX_ERRNO(r) errno +# define _NX_ERRVAL(r) (-errno) +#endif + /* Socket descriptors are the index into the TCB sockets list, offset by the * following amount. This offset is used to distinguish file descriptors from * socket descriptors @@ -697,69 +730,65 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, * Name: psock_send * * Description: - * The send() call may be used only when the socket is in a connected state - * (so that the intended recipient is known). The only difference between - * send() and write() is the presence of flags. With zero flags parameter, - * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is - * equivalent to sendto(sockfd,buf,len,flags,NULL,0). + * The psock_send() call may be used only when the socket is in a + * connected state (so that the intended recipient is known). This is an + * internal OS interface. It is functionally equivalent to send() except + * that: + * + * - It is not a cancellation point, + * - It does not modify the errno variable, and + * - I accepts the internal socket structure as an input rather than an + * task-specific socket descriptor. + * + * See comments with send() for more a more complete description of the + * functionality. * * Parameters: - * psock An instance of the internal socket structure. - * buf Data to send - * len Length of data to send - * flags Send flags + * 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 any failure, a - * negated errno value is returned. One of: - * - * EAGAIN or EWOULDBLOCK - * The socket is marked non-blocking and the requested operation - * would block. - * EBADF - * An invalid descriptor was specified. - * ECONNRESET - * Connection reset by peer. - * EDESTADDRREQ - * The socket is not connection-mode, and no peer address is set. - * EFAULT - * An invalid user space address was specified for a parameter. - * EINTR - * A signal occurred before any data was transmitted. - * EINVAL - * Invalid argument passed. - * EISCONN - * The connection-mode socket was connected already but a recipient - * was specified. (Now either this error is returned, or the recipient - * specification is ignored.) - * EMSGSIZE - * The socket type requires that message be sent atomically, and the - * size of the message to be sent made this impossible. - * ENOBUFS - * The output queue for a network interface was full. This generally - * indicates that the interface has stopped sending, but may be - * caused by transient congestion. - * ENOMEM - * No memory available. - * ENOTCONN - * The socket is not connected, and no target has been given. - * ENOTSOCK - * The argument s is not a socket. - * EOPNOTSUPP - * Some bit in the flags argument is inappropriate for the socket - * type. - * EPIPE - * The local end has been shut down on a connection oriented socket. - * In this case the process will also receive a SIGPIPE unless - * MSG_NOSIGNAL is set. - * - * Assumptions: + * negated errno value is returned (See comments with send() for a list + * of the appropriate errno value). * ****************************************************************************/ ssize_t psock_send(FAR struct socket *psock, const void *buf, size_t len, int flags); +/**************************************************************************** + * Name: nx_send + * + * Description: + * The nx_send() call may be used only when the socket is in a + * connected state (so that the intended recipient is known). This is an + * internal OS interface. It is functionally equivalent to send() except + * that: + * + * - It is not a cancellation point, and + * - It does not modify the errno variable. + * + * See comments with send() for more a more complete description of the + * functionality. + * + * Parameters: + * sockfd - Socket descriptor of the socket + * buf - Data to send + * len - Length of data to send + * flags - Send flags + * + * Returned Value: + * On success, returns the number of characters sent. On any failure, a + * negated errno value is returned (See comments with send() for a list + * of the appropriate errno value). + * + ****************************************************************************/ + +ssize_t nx_send(int sockfd, FAR const void *buf, size_t len, int flags); + /**************************************************************************** * Name: psock_sendto * @@ -831,51 +860,30 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, * Name: psock_recvfrom * * Description: - * recvfrom() receives messages from a socket, and may be used to receive - * data on a socket whether or not it is connection-oriented. + * psock_recvfrom() receives messages from a socket, and may be used to + * receive data on a socket whether or not it is connection-oriented. + * This is an internal OS interface. It is functionally equivalent to + * recvfrom() except that: * - * 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. + * - It is not a cancellation point, + * - It does not modify the errno variable, and + * - I accepts the internal socket structure as an input rather than an + * task-specific socket descriptor. * - * 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 + * 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 sent. If no data is * available to be received and the peer has performed an orderly shutdown, * recv() will return 0. Otherwise, on any failure, a negated errno value - * is returned. One of: - * - * EAGAIN - * The socket is marked non-blocking and the receive operation would block, - * or a receive timeout had been set and the timeout expired before data - * was received. - * EBADF - * The argument sockfd is an invalid descriptor. - * ECONNREFUSED - * A remote host refused to allow the network connection (typically because - * it is not running the requested service). - * EFAULT - * The receive buffer pointer(s) point outside the process's address space. - * EINTR - * The receive was interrupted by delivery of a signal before any data were - * available. - * EINVAL - * Invalid argument passed. - * ENOMEM - * Could not allocate memory. - * ENOTCONN - * The socket is associated with a connection-oriented protocol and has - * not been connected. - * ENOTSOCK - * The argument sockfd does not refer to a socket. + * is returned (see comments with send() for a list of appropriate errno + * values). * ****************************************************************************/ @@ -888,6 +896,42 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, #define psock_recv(psock,buf,len,flags) \ psock_recvfrom(psock,buf,len,flags,NULL,0) +/**************************************************************************** + * Name: nx_recvfrom + * + * Description: + * nx_recvfrom() receives messages from a socket, and may be used to + * receive data on a socket whether or not it is connection-oriented. + * This is an internal OS interface. It is functionally equivalent to + * recvfrom() except that: + * + * - It is not a cancellation point, and + * - It does not modify the errno variable. + * + * Input Parameters: + * sockfd - Socket descriptor of socket + * 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 sent. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on any failure, a negated errno value + * is returned (see comments with send() for a list of appropriate errno + * values). + * + ****************************************************************************/ + +ssize_t nx_recvfrom(int sockfd, FAR void *buf, size_t len, int flags, + FAR struct sockaddr *from, FAR socklen_t *fromlen); + +/* Internal version os recv */ + +#define nx_recv(psock,buf,len,flags) nx_recvfrom(psock,buf,len,flags,NULL,0) + /**************************************************************************** * Name: psock_getsockopt * diff --git a/libc/netdb/lib_dnsquery.c b/libc/netdb/lib_dnsquery.c index 073ff7ee13..9e349ae374 100644 --- a/libc/netdb/lib_dnsquery.c +++ b/libc/netdb/lib_dnsquery.c @@ -5,7 +5,8 @@ * The DNS resolver functions are used to lookup a hostname and map it to a * numerical IP address. * - * Copyright (C) 2007, 2009, 2012, 2014-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2012, 2014-2017 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Based heavily on portions of uIP: @@ -17,6 +18,7 @@ * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright @@ -52,6 +54,7 @@ #include +#include #include #include "netdb/lib_dns.h" @@ -249,10 +252,10 @@ static int dns_recv_response(int sd, FAR struct sockaddr *addr, /* Receive the response */ - ret = recv(sd, buffer, RECV_BUFFER_SIZE, 0); + ret = _NX_RECV(sd, buffer, RECV_BUFFER_SIZE, 0); if (ret < 0) { - errcode = get_errno(); + errcode = _NX_ERRNO(ret); nerr("ERROR: recv failed: %d\n", errcode); return -errcode; } diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index 0f78d08a7f..4a57a3169f 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -57,51 +57,30 @@ * Name: psock_recvfrom * * Description: - * recvfrom() receives messages from a socket, and may be used to receive - * data on a socket whether or not it is connection-oriented. + * psock_recvfrom() receives messages from a socket, and may be used to + * receive data on a socket whether or not it is connection-oriented. + * This is an internal OS interface. It is functionally equivalent to + * recvfrom() except that: * - * 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. + * - It is not a cancellation point, + * - It does not modify the errno variable, and + * - I accepts the internal socket structure as an input rather than an + * task-specific socket descriptor. * - * 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 + * 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 sent. If no data is * available to be received and the peer has performed an orderly shutdown, * recv() will return 0. Otherwise, on any failure, a negated errno value - * is returned. One of: - * - * EAGAIN - * The socket is marked non-blocking and the receive operation would block, - * or a receive timeout had been set and the timeout expired before data - * was received. - * EBADF - * The argument sockfd is an invalid descriptor. - * ECONNREFUSED - * A remote host refused to allow the network connection (typically because - * it is not running the requested service). - * EFAULT - * The receive buffer pointer(s) point outside the process's address space. - * EINTR - * The receive was interrupted by delivery of a signal before any data were - * available. - * EINVAL - * Invalid argument passed. - * ENOMEM - * Could not allocate memory. - * ENOTCONN - * The socket is associated with a connection-oriented protocol and has - * not been connected. - * ENOTSOCK - * The argument sockfd does not refer to a socket. + * is returned (see comments with send() for a list of appropriate errno + * values). * ****************************************************************************/ @@ -151,6 +130,49 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, return ret; } +/**************************************************************************** + * Name: nx_recvfrom + * + * Description: + * nx_recvfrom() receives messages from a socket, and may be used to + * receive data on a socket whether or not it is connection-oriented. + * This is an internal OS interface. It is functionally equivalent to + * recvfrom() except that: + * + * - It is not a cancellation point, and + * - It does not modify the errno variable. + * + * Input Parameters: + * sockfd - Socket descriptor of socket + * 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 sent. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on any failure, a negated errno value + * is returned (see comments with send() for a list of appropriate errno + * values). + * + ****************************************************************************/ + +ssize_t nx_recvfrom(int sockfd, FAR void *buf, size_t len, int flags, + FAR struct sockaddr *from, FAR socklen_t *fromlen) +{ + FAR struct socket *psock; + + /* Get the underlying socket structure */ + + psock = sockfd_socket(sockfd); + + /* Then let psock_recvfrom() do all of the work */ + + return psock_recvfrom(psock, buf, len, flags, from, fromlen); +} + /**************************************************************************** * Name: recvfrom * @@ -164,12 +186,12 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, * on return to indicate the actual size of the address stored there. * * Parameters: - * sockfd Socket descriptor of socket - * 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 + * sockfd - Socket descriptor of socket + * 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. On error, @@ -204,20 +226,15 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags, FAR struct sockaddr *from, FAR socklen_t *fromlen) { - FAR struct socket *psock; ssize_t ret; /* recvfrom() is a cancellation point */ (void)enter_cancellation_point(); - /* Get the underlying socket structure */ + /* Let nx_recvfrom and psock_recvfrom() do all of the work */ - psock = sockfd_socket(sockfd); - - /* Then let psock_recvfrom() do all of the work */ - - ret = psock_recvfrom(psock, buf, len, flags, from, fromlen); + ret = nx_recvfrom(sockfd, buf, len, flags, from, fromlen); if (ret < 0) { set_errno(-ret); diff --git a/net/socket/send.c b/net/socket/send.c index fd4599fb3c..2794b93e92 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -46,6 +46,7 @@ #include #include +#include #include "socket/socket.h" @@ -57,63 +58,29 @@ * Name: psock_send * * Description: - * The send() call may be used only when the socket is in a connected state - * (so that the intended recipient is known). The only difference between - * send() and write() is the presence of flags. With zero flags parameter, - * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is - * equivalent to sendto(sockfd,buf,len,flags,NULL,0). + * The psock_send() call may be used only when the socket is in a + * connected state (so that the intended recipient is known). This is an + * internal OS interface. It is functionally equivalent to send() except + * that: + * + * - It is not a cancellation point, + * - It does not modify the errno variable, and + * - I accepts the internal socket structure as an input rather than an + * task-specific socket descriptor. + * + * See comments with send() for more a more complete description of the + * functionality. * * Parameters: - * psock An instance of the internal socket structure. - * buf Data to send - * len Length of data to send - * flags Send flags + * 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 any failure, a - * negated errno value is returned. One of: - * - * EAGAIN or EWOULDBLOCK - * The socket is marked non-blocking and the requested operation - * would block. - * EBADF - * An invalid descriptor was specified. - * ECONNRESET - * Connection reset by peer. - * EDESTADDRREQ - * The socket is not connection-mode, and no peer address is set. - * EFAULT - * An invalid user space address was specified for a parameter. - * EINTR - * A signal occurred before any data was transmitted. - * EINVAL - * Invalid argument passed. - * EISCONN - * The connection-mode socket was connected already but a recipient - * was specified. (Now either this error is returned, or the recipient - * specification is ignored.) - * EMSGSIZE - * The socket type requires that message be sent atomically, and the - * size of the message to be sent made this impossible. - * ENOBUFS - * The output queue for a network interface was full. This generally - * indicates that the interface has stopped sending, but may be - * caused by transient congestion. - * ENOMEM - * No memory available. - * ENOTCONN - * The socket is not connected, and no target has been given. - * ENOTSOCK - * The argument s is not a socket. - * EOPNOTSUPP - * Some bit in the flags argument is inappropriate for the socket - * type. - * EPIPE - * The local end has been shut down on a connection oriented socket. - * In this case the process will also receive a SIGPIPE unless - * MSG_NOSIGNAL is set. - * - * Assumptions: + * negated errno value is returned (See comments with send() for a list + * of the appropriate errno value). * ****************************************************************************/ @@ -144,6 +111,47 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, return ret; } +/**************************************************************************** + * Name: nx_send + * + * Description: + * The nx_send() call may be used only when the socket is in a + * connected state (so that the intended recipient is known). This is an + * internal OS interface. It is functionally equivalent to send() except + * that: + * + * - It is not a cancellation point, and + * - It does not modify the errno variable. + * + * See comments with send() for more a more complete description of the + * functionality. + * + * Parameters: + * sockfd - Socket descriptor of the socket + * buf - Data to send + * len - Length of data to send + * flags - Send flags + * + * Returned Value: + * On success, returns the number of characters sent. On any failure, a + * negated errno value is returned (See comments with send() for a list + * of the appropriate errno value). + * + ****************************************************************************/ + +ssize_t nx_send(int sockfd, FAR const void *buf, size_t len, int flags) +{ + FAR struct socket *psock; + + /* Get the underlying socket structure */ + + psock = sockfd_socket(sockfd); + + /* And let psock_send do all of the work */ + + return psock_send(psock, buf, len, flags); +} + /**************************************************************************** * Name: send * @@ -155,10 +163,10 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, * equivalent to sendto(sockfd,buf,len,flags,NULL,0). * * Parameters: - * sockfd Socket descriptor of socket - * buf Data to send - * len Length of data to send - * flags Send flags + * sockfd - Socket descriptor of the socket + * 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, @@ -210,20 +218,15 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, ssize_t send(int sockfd, FAR const void *buf, size_t len, int flags) { - FAR struct socket *psock; ssize_t ret; /* send() is a cancellation point */ (void)enter_cancellation_point(); - /* Get the underlying socket structure */ + /* Let nx_send() and psock_send() do all of the work*/ - psock = sockfd_socket(sockfd); - - /* And let psock_send do all of the work */ - - ret = psock_send(psock, buf, len, flags); + ret = nx_send(sockfd, buf, len, flags); if (ret < 0) { set_errno((int)-ret);