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 <gnutt@nuttx.org>

    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 <liuhuahang@xiaomi.com>

    Implement SO_ERROR for getsockopt()
This commit is contained in:
liuhuahang 2019-12-24 08:09:55 -06:00 committed by Gregory Nutt
parent 10c4aff6ca
commit ce634578dd
13 changed files with 60 additions and 21 deletions

View File

@ -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 <gnutt@nuttx.org>
*
@ -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) */

View File

@ -302,7 +302,7 @@ errout_with_socket:
errout:
leave_cancellation_point();
set_errno(errcode);
_SO_SETERRNO(psock, errcode);
return ERROR;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <gnutt@nuttx.org>
*
@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 <gnutt@nuttx.org>
*
* 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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
****************************************************************************/