Skip to content

Commit aad1a70

Browse files
wengzhejerpelea
authored andcommitted
net/udp: Support binding to same addr/port if SO_REUSEADDR is specified.
Ref: On Linux, if SO_REUSEADDR(sk_reuse) is set for both sockets, port will not be regarded as inuse. https://github.com/torvalds/linux/blob/v6.1/net/ipv4/udp.c#L146 Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
1 parent 80ebff9 commit aad1a70

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

net/udp/udp_conn.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@
6464
#include <nuttx/net/udp.h>
6565

6666
#include "devif/devif.h"
67+
#include "inet/inet.h"
6768
#include "nat/nat.h"
6869
#include "netdev/netdev.h"
69-
#include "inet/inet.h"
70+
#include "socket/socket.h"
7071
#include "udp/udp.h"
7172

7273
/****************************************************************************
@@ -98,21 +99,42 @@ static dq_queue_t g_active_udp_connections;
9899
* Description:
99100
* Find the UDP connection that uses this local port number.
100101
*
102+
* Input Parameters:
103+
* domain - IP domain (PF_INET or PF_INET6)
104+
* ipaddr - The IP address to use in the lookup
105+
* portno - The port to use in the lookup
106+
* opt - The option from another conn to match the conflict conn
107+
* SO_REUSEADDR: If both sockets have this, they never confilct.
108+
*
101109
* Assumptions:
102110
* This function must be called with the network locked.
103111
*
104112
****************************************************************************/
105113

106114
static FAR struct udp_conn_s *udp_find_conn(uint8_t domain,
107115
FAR union ip_binding_u *ipaddr,
108-
uint16_t portno)
116+
uint16_t portno, sockopt_t opt)
109117
{
110118
FAR struct udp_conn_s *conn = NULL;
119+
#ifdef CONFIG_NET_SOCKOPTS
120+
bool skip_reusable = _SO_GETOPT(opt, SO_REUSEADDR);
121+
#endif
111122

112123
/* Now search each connection structure. */
113124

114125
while ((conn = udp_nextconn(conn)) != NULL)
115126
{
127+
/* With SO_REUSEADDR set for both sockets, we do not need to check its
128+
* address and port.
129+
*/
130+
131+
#ifdef CONFIG_NET_SOCKOPTS
132+
if (skip_reusable && _SO_GETOPT(conn->sconn.s_options, SO_REUSEADDR))
133+
{
134+
continue;
135+
}
136+
#endif
137+
116138
/* If the port local port number assigned to the connections matches
117139
* AND the IP address of the connection matches, then return a
118140
* reference to the connection structure. INADDR_ANY is a special
@@ -534,7 +556,7 @@ uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
534556
g_last_udp_port = 4096;
535557
}
536558
}
537-
while (udp_find_conn(domain, u, HTONS(g_last_udp_port)) != NULL
559+
while (udp_find_conn(domain, u, HTONS(g_last_udp_port), 0) != NULL
538560
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
539561
|| (domain == PF_INET &&
540562
ipv4_nat_port_inuse(IP_PROTO_UDP, u->ipv4.laddr,
@@ -823,7 +845,13 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr)
823845
* and port ?
824846
*/
825847

826-
if (udp_find_conn(conn->domain, &conn->u, portno) == NULL
848+
if (udp_find_conn(conn->domain, &conn->u, portno,
849+
#ifdef CONFIG_NET_SOCKOPTS
850+
conn->sconn.s_options
851+
#else
852+
0
853+
#endif
854+
) == NULL
827855
#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
828856
&& !(conn->domain == PF_INET &&
829857
ipv4_nat_port_inuse(IP_PROTO_UDP, conn->u.ipv4.laddr,

0 commit comments

Comments
 (0)