Applied patch #1912, but had to make changes to get it to compile

This commit is contained in:
kieranm 2003-09-22 09:38:09 +00:00
parent 385a8845c9
commit dff08f9739
5 changed files with 331 additions and 12 deletions

View File

@ -1007,8 +1007,10 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt
/* UNIMPL case SO_SNDBUF: */ /* UNIMPL case SO_SNDBUF: */
/* UNIMPL case SO_RCVLOWAT: */ /* UNIMPL case SO_RCVLOWAT: */
/* UNIMPL case SO_SNDLOWAT: */ /* UNIMPL case SO_SNDLOWAT: */
/* UNIMPL case SO_REUSEADDR: */ #ifdef SO_REUSE
/* UNIMPL case SO_REUSEPORT: */ case SO_REUSEADDR:
case SO_REUSEPORT:
#endif /* SO_REUSE */
case SO_TYPE: case SO_TYPE:
/* UNIMPL case SO_USELOOPBACK: */ /* UNIMPL case SO_USELOOPBACK: */
if( *optlen < sizeof(int) ) { if( *optlen < sizeof(int) ) {
@ -1091,8 +1093,10 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt
/* UNIMPL case SO_DONTROUTE: */ /* UNIMPL case SO_DONTROUTE: */
case SO_KEEPALIVE: case SO_KEEPALIVE:
/* UNIMPL case SO_OOBINCLUDE: */ /* UNIMPL case SO_OOBINCLUDE: */
/* UNIMPL case SO_REUSEADDR: */ #ifdef SO_REUSE
/* UNIMPL case SO_REUSEPORT: */ case SO_REUSEADDR:
case SO_REUSEPORT:
#endif /* SO_REUSE */
/*case SO_USELOOPBACK: UNIMPL */ /*case SO_USELOOPBACK: UNIMPL */
*(int*)optval = sock->conn->pcb.tcp->so_options & optname; *(int*)optval = sock->conn->pcb.tcp->so_options & optname;
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off"))); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));
@ -1192,8 +1196,10 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_
/* UNIMPL case SO_SNDBUF: */ /* UNIMPL case SO_SNDBUF: */
/* UNIMPL case SO_RCVLOWAT: */ /* UNIMPL case SO_RCVLOWAT: */
/* UNIMPL case SO_SNDLOWAT: */ /* UNIMPL case SO_SNDLOWAT: */
/* UNIMPL case SO_REUSEADDR: */ #ifdef SO_REUSE
/* UNIMPL case SO_REUSEPORT: */ case SO_REUSEADDR:
case SO_REUSEPORT:
#endif /* SO_REUSE */
/* UNIMPL case SO_USELOOPBACK: */ /* UNIMPL case SO_USELOOPBACK: */
if( optlen < sizeof(int) ) { if( optlen < sizeof(int) ) {
err = EINVAL; err = EINVAL;
@ -1272,8 +1278,10 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_
/* UNIMPL case SO_DONTROUTE: */ /* UNIMPL case SO_DONTROUTE: */
case SO_KEEPALIVE: case SO_KEEPALIVE:
/* UNIMPL case SO_OOBINCLUDE: */ /* UNIMPL case SO_OOBINCLUDE: */
/* UNIMPL case SO_REUSEADDR: */ #ifdef SO_REUSE
/* UNIMPL case SO_REUSEPORT: */ case SO_REUSEADDR:
case SO_REUSEPORT:
#endif /* SO_REUSE */
/* UNIMPL case SO_USELOOPBACK: */ /* UNIMPL case SO_USELOOPBACK: */
if ( *(int*)optval ) { if ( *(int*)optval ) {
sock->conn->pcb.tcp->so_options |= optname; sock->conn->pcb.tcp->so_options |= optname;

View File

@ -247,11 +247,14 @@ err_t
tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{ {
struct tcp_pcb *cpcb; struct tcp_pcb *cpcb;
#ifdef SO_REUSE
int reuse_port_all_set = 1;
#endif /* SO_REUSE */
if (port == 0) { if (port == 0) {
port = tcp_new_port(); port = tcp_new_port();
} }
#ifndef SO_REUSE
/* Check if the address already is in use. */ /* Check if the address already is in use. */
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs;
cpcb != NULL; cpcb = cpcb->next) { cpcb != NULL; cpcb = cpcb->next) {
@ -273,6 +276,102 @@ tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
} }
} }
} }
#else /* SO_REUSE */
/* Search through list of PCB's in LISTEN state.
If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to
the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
But no two PCB's bound to same local port and same local address is valid.
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
all PCB's must have the SOF_REUSEPORT option set.
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
address is already in use. */
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; cpcb != NULL; cpcb = cpcb->next) {
if(cpcb->local_port == port) {
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
if(pcb->so_options & SOF_REUSEPORT) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT set and same address.\n"));
reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
}
else {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT not set and same address.\n"));
return ERR_USE;
}
}
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) {
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
return ERR_USE;
}
else {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n"));
}
}
}
}
/* Search through list of PCB's in a state in which they can accept or send data. Same decription as for
PCB's in state LISTEN applies to this PCB's regarding the options SOF_REUSEADDR and SOF_REUSEPORT. */
for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) {
if(cpcb->local_port == port) {
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
if(pcb->so_options & SOF_REUSEPORT) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT set and same address.\n"));
reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
}
else {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT not set and same address.\n"));
return ERR_USE;
}
}
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) ||
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) {
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
return ERR_USE;
}
else {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n"));
}
}
}
}
/* Search through list of PCB's in TIME_WAIT state. If SO_REUSEADDR is set a bound combination [IP, port}
can be rebound. The same applies when SOF_REUSEPORT is set.
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
all PCB's must have the SOF_REUSEPORT option set.
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
address is already in use. */
for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {
if(cpcb->local_port == port) {
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT or SO_REUSEADDR not set and same address.\n"));
return ERR_USE;
}
else if(pcb->so_options & SOF_REUSEPORT) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT set and same address.\n"));
reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT));
}
}
}
}
/* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
{IP, port} can't be reused. */
if(!reuse_port_all_set) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: not all sockets have SO_REUSEPORT set.\n"));
return ERR_USE;
}
#endif /* SO_REUSE */
if (!ip_addr_isany(ipaddr)) { if (!ip_addr_isany(ipaddr)) {
pcb->local_ip = *ipaddr; pcb->local_ip = *ipaddr;
} }

View File

@ -102,6 +102,11 @@ tcp_input(struct pbuf *p, struct netif *inp)
u8_t hdrlen; u8_t hdrlen;
err_t err; err_t err;
#ifdef SO_REUSE
struct tcp_pcb *pcb_temp;
int reuse = 0;
int reuse_port = 0;
#endif /* SO_REUSE */
PERF_START; PERF_START;
@ -174,7 +179,17 @@ tcp_input(struct pbuf *p, struct netif *inp)
/* Demultiplex an incoming segment. First, we check if it is destined /* Demultiplex an incoming segment. First, we check if it is destined
for an active connection. */ for an active connection. */
prev = NULL; prev = NULL;
#ifdef SO_REUSE
pcb_temp = tcp_active_pcbs;
again_1:
/* Iterate through the TCP pcb list for a fully matching pcb */
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
@ -183,6 +198,32 @@ tcp_input(struct pbuf *p, struct netif *inp)
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
#ifdef SO_REUSE
if(pcb->so_options & SOF_REUSEPORT) {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(TCP_INPUT_DEBUG,("tcp_input: second or later PCB and SOF_REUSEPORT set.\n"));
} else {
/* First PCB with this address */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: first PCB and SOF_REUSEPORT set.\n"));
reuse = 1;
}
reuse_port = 1;
p->ref++;
/* We want to search on next socket after receiving */
pcb_temp = pcb->next;
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
}
#endif /* SO_REUSE */
/* Move this PCB to the front of the list so that subsequent /* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment lookups will be faster (we exploit locality in TCP segment
arrivals). */ arrivals). */
@ -327,8 +368,25 @@ tcp_input(struct pbuf *p, struct netif *inp)
tcp_debug_print_state(pcb->state); tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */ #endif /* TCP_DEBUG */
#endif /* TCP_INPUT_DEBUG */ #endif /* TCP_INPUT_DEBUG */
#ifdef SO_REUSE
/* First socket should receive now */
if(reuse_port) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: searching next PCB.\n"));
reuse_port = 0;
/* We are searching connected sockets */
goto again_1;
}
#endif /* SO_REUSE */
} else { } else {
#ifdef SO_REUSE
if(reuse) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: freeing PBUF with reference counter set to %i\n", p->ref));
pbuf_free(p);
goto end;
}
#endif /* SO_REUSE */
/* If no matching PCB was found, send a TCP RST (reset) to the /* If no matching PCB was found, send a TCP RST (reset) to the
sender. */ sender. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
@ -343,7 +401,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
} }
pbuf_free(p); pbuf_free(p);
} }
#ifdef SO_REUSE
end:
#endif /* SO_REUSE */
LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
PERF_STOP("tcp_input"); PERF_STOP("tcp_input");
} }

View File

@ -163,6 +163,13 @@ udp_input(struct pbuf *p, struct netif *inp)
struct ip_hdr *iphdr; struct ip_hdr *iphdr;
u16_t src, dest; u16_t src, dest;
#ifdef SO_REUSE
struct udp_pcb *pcb_temp;
int reuse = 0;
int reuse_port_1 = 0;
int reuse_port_2 = 0;
#endif /* SO_REUSE */
PERF_START; PERF_START;
#ifdef UDP_STATS #ifdef UDP_STATS
@ -200,8 +207,18 @@ udp_input(struct pbuf *p, struct netif *inp)
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
#ifdef SO_REUSE
pcb_temp = udp_pcbs;
again_1:
/* Iterate through the UDP pcb list for a fully matching pcb */
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
/* Iterate through the UDP pcb list for a fully matching pcb */ /* Iterate through the UDP pcb list for a fully matching pcb */
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
/* print the PCB local and remote address */ /* print the PCB local and remote address */
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n", LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
@ -221,6 +238,27 @@ udp_input(struct pbuf *p, struct netif *inp)
(ip_addr_isany(&pcb->local_ip) || (ip_addr_isany(&pcb->local_ip) ||
/* PCB local IP address matches UDP destination IP address? */ /* PCB local IP address matches UDP destination IP address? */
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
#ifdef SO_REUSE
if(pcb->so_options & SOF_REUSEPORT) {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
} else {
/* First PCB with this address */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n"));
reuse = 1;
}
reuse_port_1 = 1;
p->ref++;
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
}
#endif /* SO_REUSE */
break; break;
} }
} }
@ -228,7 +266,16 @@ udp_input(struct pbuf *p, struct netif *inp)
if (pcb == NULL) { if (pcb == NULL) {
/* Iterate through the UDP PCB list for a pcb that matches /* Iterate through the UDP PCB list for a pcb that matches
the local address. */ the local address. */
#ifdef SO_REUSE
pcb_temp = udp_pcbs;
again_2:
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next) {
#else /* SO_REUSE */
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n", LWIP_DEBUGF(UDP_DEBUG, ("pcb (%u.%u.%u.%u, %u) --- (%u.%u.%u.%u, %u)\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
@ -242,7 +289,28 @@ udp_input(struct pbuf *p, struct netif *inp)
(ip_addr_isany(&pcb->local_ip) || (ip_addr_isany(&pcb->local_ip) ||
/* ...matching interface address? */ /* ...matching interface address? */
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) {
break; #ifdef SO_REUSE
if(pcb->so_options & SOF_REUSEPORT) {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB and SOF_REUSEPORT set.\n"));
} else {
/* First PCB with this address */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: first PCB and SOF_REUSEPORT set.\n"));
reuse = 1;
}
reuse_port_2 = 1;
p->ref++;
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: reference counter on PBUF set to %i\n", p->ref));
} else {
if(reuse) {
/* We processed one PCB already */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: second or later PCB but SOF_REUSEPORT not set !\n"));
}
}
#endif /* SO_REUSE */
break;
} }
} }
} }
@ -291,7 +359,33 @@ udp_input(struct pbuf *p, struct netif *inp)
if (pcb != NULL) { if (pcb != NULL) {
snmp_inc_udpindatagrams(); snmp_inc_udpindatagrams();
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
#ifdef SO_REUSE
/* First socket should receive now */
if(reuse_port_1 || reuse_port_2) {
/* We want to search on next socket after receiving */
pcb_temp = pcb->next;
if(reuse_port_1) {
/* We are searching connected sockets */
reuse_port_1 = 0;
reuse_port_2 = 0;
goto again_1;
} else {
/* We are searching unconnected sockets */
reuse_port_1 = 0;
reuse_port_2 = 0;
goto again_2;
}
}
#endif /* SO_REUSE */
} else { } else {
#ifdef SO_REUSE
if(reuse) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: freeing PBUF with reference counter set to %i\n", p->ref));
pbuf_free(p);
goto end;
}
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n")); LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE, ("udp_input: not for us.\n"));
/* No match was found, send ICMP destination port unreachable unless /* No match was found, send ICMP destination port unreachable unless
@ -457,9 +551,13 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
{ {
struct udp_pcb *ipcb; struct udp_pcb *ipcb;
u8_t rebind; u8_t rebind;
#ifdef SO_REUSE
int reuse_port_all_set = 1;
#endif /* SO_REUSE */
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = ")); LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("udp_bind(ipaddr = "));
ip_addr_debug_print(UDP_DEBUG, ipaddr); ip_addr_debug_print(UDP_DEBUG, ipaddr);
LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %u)\n", port)); LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, (", port = %u)\n", port));
rebind = 0; rebind = 0;
/* Check for double bind and rebind of the same pcb */ /* Check for double bind and rebind of the same pcb */
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
@ -470,6 +568,8 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
/* pcb already in list, just rebind */ /* pcb already in list, just rebind */
rebind = 1; rebind = 1;
} }
#ifndef SO_REUSE
/* this code does not allow upper layer to share a UDP port for /* this code does not allow upper layer to share a UDP port for
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
@ -486,8 +586,52 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
return ERR_USE; return ERR_USE;
} }
#endif #endif
#else /* SO_REUSE */
/* Search through list of PCB's.
If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP
or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to
the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid.
But no two PCB's bound to same local port and same local address is valid.
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then
all PCB's must have the SOF_REUSEPORT option set.
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that
address is already in use. */
else if (ipcb->local_port == port) {
if(ip_addr_cmp(&(ipcb->local_ip), ipaddr)) {
if(pcb->so_options & SOF_REUSEPORT) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT set and same address.\n"));
reuse_port_all_set = (reuse_port_all_set && (ipcb->so_options & SOF_REUSEPORT));
}
else {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT not set and same address.\n"));
return ERR_USE;
}
}
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(ipcb->local_ip))) ||
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(ipcb->local_ip)))) {
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: in UDP PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n"));
return ERR_USE;
}
}
}
#endif /* SO_REUSE */
} }
/* bind local address */
#ifdef SO_REUSE
/* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then
{IP, port} can't be reused. */
if(!reuse_port_all_set) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: not all sockets have SO_REUSEPORT set.\n"));
return ERR_USE;
}
#endif /* SO_REUSE */
ip_addr_set(&pcb->local_ip, ipaddr); ip_addr_set(&pcb->local_ip, ipaddr);
/* no port specified? */ /* no port specified? */
if (port == 0) { if (port == 0) {

View File

@ -325,6 +325,14 @@ a lot of data that needs to be copied, this should be set high. */
#define DEFAULT_THREAD_PRIO 1 #define DEFAULT_THREAD_PRIO 1
#endif #endif
/* ---------- Socket Options ---------- */
/* Enable SO_REUSEADDR and SO_REUSEPORT options */
#ifndef SO_REUSE
# define SO_REUSE 1
#endif
/* ---------- Statistics options ---------- */ /* ---------- Statistics options ---------- */
#ifndef LWIP_STATS #ifndef LWIP_STATS
#define LWIP_STATS 1 #define LWIP_STATS 1