From ce634578ddbdcc1f847eb74fa1efcb69ad3de6e6 Mon Sep 17 00:00:00 2001 From: liuhuahang Date: Tue, 24 Dec 2019 08:09:55 -0600 Subject: [PATCH] This change implements the SO_ERROR socket option that is used to obtain the last error reported by the network. Squashed commit of the following: Author: Gregory Nutt net/: Trivial changes to PR from review. Biggest difference: type of s_error changed to int16_t to save a byte or two. Author: liuhuahang Implement SO_ERROR for getsockopt() --- include/nuttx/net/net.h | 3 ++- net/socket/accept.c | 2 +- net/socket/bind.c | 2 +- net/socket/connect.c | 2 +- net/socket/getpeername.c | 2 +- net/socket/getsockname.c | 2 +- net/socket/getsockopt.c | 15 +++++++++++++-- net/socket/listen.c | 4 ++-- net/socket/net_sendfile.c | 4 ++-- net/socket/recvfrom.c | 15 ++++++++++----- net/socket/send.c | 11 ++++++++--- net/socket/sendto.c | 2 +- net/socket/socket.h | 17 +++++++++++++++++ 13 files changed, 60 insertions(+), 21 deletions(-) diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 325bb8bfa99..5ad141b4c17 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/net/net.h * - * Copyright (C) 2007, 2009-2014, 2016-2018 Gregory Nutt. All rights + * Copyright (C) 2007, 2009-2014, 2016-2019 Gregory Nutt. All rights * reserved. * Author: Gregory Nutt * @@ -234,6 +234,7 @@ struct socket /* Socket options */ #ifdef CONFIG_NET_SOCKOPTS + int16_t s_error; /* Last error that occurred on this socket */ sockopt_t s_options; /* Selected socket options */ socktimeo_t s_rcvtimeo; /* Receive timeout value (in deciseconds) */ socktimeo_t s_sndtimeo; /* Send timeout value (in deciseconds) */ diff --git a/net/socket/accept.c b/net/socket/accept.c index bcfc368e921..39ed7a826f3 100644 --- a/net/socket/accept.c +++ b/net/socket/accept.c @@ -302,7 +302,7 @@ errout_with_socket: errout: leave_cancellation_point(); - set_errno(errcode); + _SO_SETERRNO(psock, errcode); return ERROR; } diff --git a/net/socket/bind.c b/net/socket/bind.c index 13c6e19e214..00e0796c183 100644 --- a/net/socket/bind.c +++ b/net/socket/bind.c @@ -159,7 +159,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) ret = psock_bind(psock, addr, addrlen); if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); return ERROR; } diff --git a/net/socket/connect.c b/net/socket/connect.c index 9e2c9aa336a..3fdaac807f5 100644 --- a/net/socket/connect.c +++ b/net/socket/connect.c @@ -246,7 +246,7 @@ int connect(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen) ret = psock_connect(psock, addr, addrlen); if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); ret = ERROR; } diff --git a/net/socket/getpeername.c b/net/socket/getpeername.c index 09880320804..4181117c36f 100644 --- a/net/socket/getpeername.c +++ b/net/socket/getpeername.c @@ -169,7 +169,7 @@ int getpeername(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) ret = psock_getpeername(psock, addr, addrlen); if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); return ERROR; } diff --git a/net/socket/getsockname.c b/net/socket/getsockname.c index d2672781feb..bed6217bccb 100644 --- a/net/socket/getsockname.c +++ b/net/socket/getsockname.c @@ -165,7 +165,7 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) ret = psock_getsockname(psock, addr, addrlen); if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); return ERROR; } diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c index d027da2fdf9..487642ca505 100644 --- a/net/socket/getsockopt.c +++ b/net/socket/getsockopt.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/getsockopt.c * - * Copyright (C) 2007-2009, 2012, 2014, 2017-2018 Gregory Nutt. All rights + * Copyright (C) 2007-2009, 2012, 2014, 2017-2019 Gregory Nutt. All rights * reserved. * Author: Gregory Nutt * @@ -261,10 +261,21 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option, } break; + case SO_ERROR: /* Reports and clears error status. */ + { + if (*value_len != sizeof(int)) + { + return -EINVAL; + } + + *(FAR int *)value = (int)psock->s_error; + psock->s_error = 0; + } + break; + /* The following are not yet implemented (return values other than {0,1) */ case SO_ACCEPTCONN: /* Reports whether socket listening is enabled */ - case SO_ERROR: /* Reports and clears error status. */ case SO_LINGER: /* Lingers on a close() if data is present */ case SO_RCVBUF: /* Sets receive buffer size */ case SO_RCVLOWAT: /* Sets the minimum number of bytes to input */ diff --git a/net/socket/listen.c b/net/socket/listen.c index 0b3f1176903..d267b38ef0d 100644 --- a/net/socket/listen.c +++ b/net/socket/listen.c @@ -164,7 +164,7 @@ int listen(int sockfd, int backlog) errcode = EBADF; } - set_errno(errcode); + _SO_SETERRNO(psock, errcode); return ERROR; } @@ -175,7 +175,7 @@ int listen(int sockfd, int backlog) ret = psock_listen(psock, backlog); if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); return ERROR; } diff --git a/net/socket/net_sendfile.c b/net/socket/net_sendfile.c index faf715ef182..a499504b126 100644 --- a/net/socket/net_sendfile.c +++ b/net/socket/net_sendfile.c @@ -131,7 +131,7 @@ ssize_t net_sendfile(int outfd, FAR struct file *infile, FAR off_t *offset, if (psock != NULL || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); - set_errno(EBADF); + _SO_SETERRNO(psock, EBADF); return ERROR; } @@ -152,7 +152,7 @@ ssize_t net_sendfile(int outfd, FAR struct file *infile, FAR off_t *offset, if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); return ERROR; } diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index 4396255ea24..79944c21b51 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/recvfrom.c * - * Copyright (C) 2007-2009, 2011-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2017, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -93,7 +93,7 @@ ssize_t psock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len, /* Verify that non-NULL pointers were passed */ #ifdef CONFIG_DEBUG_FEATURES - if (!buf) + if (buf == NULL) { return -EINVAL; } @@ -226,18 +226,23 @@ ssize_t nx_recvfrom(int sockfd, FAR void *buf, size_t len, int flags, 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(); - /* Let nx_recvfrom and psock_recvfrom() do all of the work */ + /* Get the underlying socket structure */ - ret = nx_recvfrom(sockfd, buf, len, flags, from, fromlen); + psock = sockfd_socket(sockfd); + + /* Let psock_recvfrom() do all of the work */ + + ret = psock_recvfrom(psock, buf, len, flags, from, fromlen); if (ret < 0) { - set_errno(-ret); + _SO_SETERRNO(psock, -ret); ret = ERROR; } diff --git a/net/socket/send.c b/net/socket/send.c index 7d95a6f1f69..f75fdc32f73 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -225,18 +225,23 @@ ssize_t nx_send(int sockfd, FAR const void *buf, size_t len, int flags) 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(); - /* Let nx_send() and psock_send() do all of the work */ + /* Get the underlying socket structure */ - ret = nx_send(sockfd, buf, len, flags); + psock = sockfd_socket(sockfd); + + /* Let psock_send() do all of the work */ + + ret = psock_send(psock, buf, len, flags); if (ret < 0) { - set_errno((int)-ret); + _SO_SETERRNO(psock, -ret); ret = ERROR; } diff --git a/net/socket/sendto.c b/net/socket/sendto.c index dbbe7019e6f..417afb95171 100644 --- a/net/socket/sendto.c +++ b/net/socket/sendto.c @@ -254,7 +254,7 @@ ssize_t sendto(int sockfd, FAR const void *buf, size_t len, int flags, ret = psock_sendto(psock, buf, len, flags, to, tolen); if (ret < 0) { - set_errno((int)-ret); + _SO_SETERRNO(psock, -ret); ret = ERROR; } diff --git a/net/socket/socket.h b/net/socket/socket.h index 608e44a3493..f826337baed 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -131,6 +131,23 @@ #define _SO_GETVALID(o) (((unsigned int)(o)) <= _SO_MAXOPT) #define _SO_SETVALID(o) ((((unsigned int)(o)) <= _SO_MAXOPT) && !_SO_GETONLY(o)) +/* Macro to set socket errors */ + +#ifdef CONFIG_NET_SOCKOPTS +# define _SO_SETERRNO(s,e) \ + do \ + { \ + if (s != NULL) \ + { \ + s->s_error = (int16_t)e; \ + } \ + set_errno(e); \ + } \ + while (0) +#else +# define _SO_SETERRNO(s,e) set_errno(e) +#endif /* CONFIG_NET_SOCKOPTS */ + /**************************************************************************** * Public Data ****************************************************************************/