diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 325bb8bfa9960..a2b8931caf09f 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -237,6 +237,7 @@ struct 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) */ + int s_error; /* Last error that occurred on this socket */ #ifdef CONFIG_NET_SOLINGER socktimeo_t s_linger; /* Linger timeout value (in deciseconds) */ #endif diff --git a/net/socket/accept.c b/net/socket/accept.c index bcfc368e9213b..39ed7a826f355 100644 --- a/net/socket/accept.c +++ b/net/socket/accept.c @@ -302,7 +302,7 @@ int accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) 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 13c6e19e214a5..00e0796c183b2 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 9e2c9aa336abf..3fdaac807f5de 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 098803208046c..4181117c36fb4 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 d2672781feb33..bed6217bccb49 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 d027da2fdf924..cb54abbbcd422 100644 --- a/net/socket/getsockopt.c +++ b/net/socket/getsockopt.c @@ -261,10 +261,20 @@ 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; + } + *(int *)value = 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 0b3f1176903b3..d267b38ef0d8f 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 faf715ef18285..a499504b126d0 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 4396255ea242f..c73bbddfb0370 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -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 */ + + psock = sockfd_socket(sockfd); + + /* Let psock_recvfrom() do all of the work */ - ret = nx_recvfrom(sockfd, buf, len, flags, from, fromlen); + 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 7d95a6f1f69b7..f75fdc32f7386 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 */ + + psock = sockfd_socket(sockfd); + + /* Let psock_send() do all of the work */ - ret = nx_send(sockfd, buf, len, flags); + 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 dbbe7019e6f7f..417afb951714e 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 608e44a3493fa..f1a9082d4f5ad 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -131,6 +131,14 @@ #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) if (s != NULL) { s->s_error = e; } set_errno(e) +#else +#define _SO_SETERRNO(s,e) set_errno(e) +#endif /* CONFIG_NET_SOCKOPTS */ + /**************************************************************************** * Public Data ****************************************************************************/