net/sockopt: Try usrsock further if the protocol not available

fallback to usrsock if the features are not implemented locally

Change-Id: I46e2d6452d7edd3fa5b3d508945511cd48f22ebb
Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
chao.an 2020-12-01 20:03:00 +08:00 committed by Alin Jerpelea
parent 51efe468b9
commit 316cdccf82
2 changed files with 105 additions and 133 deletions

View File

@ -103,37 +103,47 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
return -EINVAL;
}
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
DEBUGASSERT(conn);
/* Some of the socket options are handled from this function. */
switch (option)
{
case SO_TYPE: /* Type can be read from NuttX psock structure. */
case SO_RCVTIMEO: /* Rx timeouts can be handled at NuttX side, thus
* simplify daemon implementation. */
case SO_SNDTIMEO: /* Rx timeouts can be handled at NuttX side, thus
* simplify daemon implementation. */
break;
default: /* Other options are passed to usrsock daemon. */
{
return usrsock_getsockopt(conn, SOL_SOCKET,
option, value, value_len);
}
}
}
#endif
/* Process the option */
switch (option)
{
/* The following are valid only if the OS CLOCK feature is enabled */
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
socktimeo_t timeo;
/* Verify that option is the size of an 'int'. Should also check
* that 'value' is properly aligned for an 'int'
*/
if (*value_len < sizeof(struct timeval))
{
return -EINVAL;
}
/* Get the timeout value. This is a atomic operation and should
* require no special operation.
*/
if (option == SO_RCVTIMEO)
{
timeo = psock->s_rcvtimeo;
}
else
{
timeo = psock->s_sndtimeo;
}
/* Then return the timeout value to the caller */
net_dsec2timeval(timeo, (struct timeval *)value);
*value_len = sizeof(struct timeval);
}
break;
#ifndef CONFIG_NET_USRSOCK
case SO_ACCEPTCONN: /* Reports whether socket listening is enabled */
if (*value_len < sizeof(int))
{
@ -231,42 +241,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
}
break;
/* The following are valid only if the OS CLOCK feature is enabled */
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
socktimeo_t timeo;
/* Verify that option is the size of an 'int'. Should also check
* that 'value' is properly aligned for an 'int'
*/
if (*value_len < sizeof(struct timeval))
{
return -EINVAL;
}
/* Get the timeout value. This is a atomic operation and should
* require no special operation.
*/
if (option == SO_RCVTIMEO)
{
timeo = psock->s_rcvtimeo;
}
else
{
timeo = psock->s_sndtimeo;
}
/* Then return the timeout value to the caller */
net_dsec2timeval(timeo, (struct timeval *)value);
*value_len = sizeof(struct timeval);
}
break;
case SO_ERROR: /* Reports and clears error status. */
{
if (*value_len != sizeof(int))
@ -301,6 +275,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
case SO_RCVLOWAT: /* Sets the minimum number of bytes to input */
case SO_SNDBUF: /* Sets send buffer size */
case SO_SNDLOWAT: /* Sets the minimum number of bytes to output */
#endif
default:
return -ENOPROTOOPT;
@ -360,7 +335,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
int psock_getsockopt(FAR struct socket *psock, int level, int option,
FAR void *value, FAR socklen_t *value_len)
{
int ret = OK;
int ret;
/* Verify that the sockfd corresponds to valid, allocated socket */
@ -403,6 +378,16 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
break;
}
#ifdef CONFIG_NET_USRSOCK
/* Try usrsock further if the protocol not available */
if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE)
{
ret = usrsock_getsockopt(psock->s_conn, level,
option, value, value_len);
}
#endif
return ret;
}

View File

@ -98,32 +98,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
return -EINVAL;
}
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
DEBUGASSERT(conn);
/* Some of the socket options are handled from this function. */
switch (option)
{
case SO_RCVTIMEO: /* Rx timeouts can be handled at NuttX side, thus
* simplify daemon implementation. */
case SO_SNDTIMEO: /* Rx timeouts can be handled at NuttX side, thus
* simplify daemon implementation. */
break;
default: /* Other options are passed to usrsock daemon. */
{
return usrsock_setsockopt(conn, SOL_SOCKET, option, value,
value_len);
}
}
}
#endif
/* Process the option */
switch (option)
@ -133,6 +107,51 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
* is outside of the scope of setsockopt.
*/
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
FAR struct timeval *tv = (FAR struct timeval *)value;
socktimeo_t timeo;
/* Verify that option is the size of an 'struct timeval'. */
if (tv == NULL || value_len != sizeof(struct timeval))
{
return -EINVAL;
}
/* Get the timeout value. Any microsecond remainder will be
* forced to the next larger, whole decisecond value.
*/
timeo = (socktimeo_t)net_timeval2dsec(tv, TV2DS_CEIL);
/* Save the timeout value */
if (option == SO_RCVTIMEO)
{
psock->s_rcvtimeo = timeo;
}
else
{
psock->s_sndtimeo = timeo;
}
/* Set/clear the corresponding enable/disable bit */
if (timeo)
{
_SO_CLROPT(psock->s_options, option);
}
else
{
_SO_SETOPT(psock->s_options, option);
}
}
break;
#ifndef CONFIG_NET_USRSOCK
case SO_BROADCAST: /* Permits sending of broadcast messages */
case SO_DEBUG: /* Enables recording of debugging information */
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
@ -196,49 +215,6 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
return tcp_setsockopt(psock, option, value, value_len);
#endif
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
FAR struct timeval *tv = (FAR struct timeval *)value;
socktimeo_t timeo;
/* Verify that option is the size of an 'struct timeval'. */
if (tv == NULL || value_len != sizeof(struct timeval))
{
return -EINVAL;
}
/* Get the timeout value. Any microsecond remainder will be
* forced to the next larger, whole decisecond value.
*/
timeo = (socktimeo_t)net_timeval2dsec(tv, TV2DS_CEIL);
/* Save the timeout value */
if (option == SO_RCVTIMEO)
{
psock->s_rcvtimeo = timeo;
}
else
{
psock->s_sndtimeo = timeo;
}
/* Set/clear the corresponding enable/disable bit */
if (timeo)
{
_SO_CLROPT(psock->s_options, option);
}
else
{
_SO_SETOPT(psock->s_options, option);
}
}
break;
#ifdef CONFIG_NET_SOLINGER
case SO_LINGER: /* Lingers on a close() if data is present */
{
@ -316,6 +292,7 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
case SO_ERROR: /* Reports and clears error status. */
case SO_TYPE: /* Reports the socket type */
#endif
default:
return -ENOPROTOOPT;
}
@ -434,6 +411,16 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
break;
}
#ifdef CONFIG_NET_USRSOCK
/* Try usrsock further if the protocol not available */
if (ret == -ENOPROTOOPT && psock->s_type == SOCK_USRSOCK_TYPE)
{
ret = usrsock_setsockopt(psock->s_conn, level,
option, value, value_len);
}
#endif
return ret;
}