net/udp: Correct an error introduce in recent fixes for UDP connected sockets. The interaction between psock_udp_send() and psock_udp_sendto() was perverse: It should always pass a NULL destinatino address.

This commit is contained in:
Gregory Nutt 2018-04-26 21:58:09 -06:00
parent 77d7856642
commit 434da18cd7
3 changed files with 75 additions and 45 deletions

View File

@ -1,7 +1,7 @@
/****************************************************************************
* net/udp/udp_psock_send.c
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2015, 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -65,17 +65,6 @@ ssize_t psock_udp_send(FAR struct socket *psock, FAR const void *buf,
size_t len)
{
FAR struct udp_conn_s *conn;
union
{
struct sockaddr addr;
#ifdef CONFIG_NET_IPv4
struct sockaddr_in addr4;
#endif
#ifdef CONFIG_NET_IPv6
struct sockaddr_in6 addr6;
#endif
} to;
socklen_t tolen;
DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
DEBUGASSERT(psock->s_type == SOCK_DGRAM);
@ -94,29 +83,5 @@ ssize_t psock_udp_send(FAR struct socket *psock, FAR const void *buf,
/* Yes, then let psock_sendto to the work */
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (conn->domain == PF_INET)
#endif
{
tolen = sizeof(struct sockaddr_in);
to.addr4.sin_family = AF_INET;
to.addr4.sin_port = conn->rport;
net_ipv4addr_copy(to.addr4.sin_addr.s_addr, conn->u.ipv4.raddr);
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
tolen = sizeof(struct sockaddr_in6);
to.addr6.sin6_family = AF_INET6;
to.addr6.sin6_port = conn->rport;
net_ipv6addr_copy(to.addr6.sin6_addr.s6_addr, conn->u.ipv6.raddr);
}
#endif /* CONFIG_NET_IPv6 */
return psock_udp_sendto(psock, buf, len, 0, &to.addr, tolen);
return psock_udp_sendto(psock, buf, len, 0, NULL, 0);
}

View File

@ -630,6 +630,15 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
return -EISCONN;
}
/* Otherwise, if the socket is not connected, then a destination address
* must be provided.
*/
else if (to == NULL && !_SS_ISCONNECTED(psock->s_flags))
{
return -EDESTADDRREQ;
}
/* Make sure that we have the IP address mapping */
conn = (FAR struct udp_conn_s *)psock->s_conn;
@ -693,8 +702,48 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
}
/* Initialize the write buffer */
/* Check if the socket is connected */
if (!_SS_ISCONNECTED(psock->s_flags))
{
/* Yes.. get the connection address from the connection structure */
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (conn->domain == PF_INET)
#endif
{
FAR struct sockaddr_in *addr4 =
(FAR struct sockaddr_in *)&wrb->wb_dest;
addr4->sin_family = AF_INET;
addr4->sin_port = conn->rport;
net_ipv4addr_copy(addr4->sin_addr.s_addr, conn->u.ipv4.raddr);
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
FAR struct sockaddr_in6 *addr6 =
(FAR struct sockaddr_in6 *)&wrb->wb_dest;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = conn->rport;
net_ipv6addr_copy(addr6->sin6_addr.s6_addr, conn->u.ipv6.raddr);
}
#endif /* CONFIG_NET_IPv6 */
}
/* Not connected. Use the provided destination address */
else
{
memcpy(&wrb->wb_dest, to, tolen);
}
memcpy(&wrb->wb_dest, to, tolen);
#ifdef CONFIG_NET_SOCKOPTS
wrb->wb_start = clock_systimer();
#endif

View File

@ -335,6 +335,15 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
return -EISCONN;
}
/* Otherwise, if the socket is not connected, then a destination address
* must be provided.
*/
else if (to == NULL && !_SS_ISCONNECTED(psock->s_flags))
{
return -EDESTADDRREQ;
}
#if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR)
#ifdef CONFIG_NET_ARP_SEND
#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
@ -409,18 +418,25 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
state.st_time = clock_systimer();
#endif
/* Setup the UDP socket. udp_connect will set the remote address in the
* connection structure.
*/
/* Setup the UDP socket. */
conn = (FAR struct udp_conn_s *)psock->s_conn;
DEBUGASSERT(conn);
ret = udp_connect(conn, to);
if (ret < 0)
/* Check if the socket is connected */
if (!_SS_ISCONNECTED(psock->s_flags))
{
nerr("ERROR: udp_connect failed: %d\n", ret);
goto errout_with_lock;
/* No.. Call udp_connect() to set the remote address in the connection
* structure to the sendto() destination address.
*/
ret = udp_connect(conn, to);
if (ret < 0)
{
nerr("ERROR: udp_connect failed: %d\n", ret);
goto errout_with_lock;
}
}
/* Get the device that will handle the remote packet transfers. This