247 |
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) |
248 |
{ |
{ |
249 |
struct tcp_pcb *cpcb; |
struct tcp_pcb *cpcb; |
250 |
|
#ifdef SO_REUSE |
251 |
|
int reuse_port_all_set = 1; |
252 |
|
#endif /* SO_REUSE */ |
253 |
|
|
254 |
if (port == 0) { |
if (port == 0) { |
255 |
port = tcp_new_port(); |
port = tcp_new_port(); |
256 |
} |
} |
257 |
|
#ifndef SO_REUSE |
258 |
/* Check if the address already is in use. */ |
/* Check if the address already is in use. */ |
259 |
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; |
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; |
260 |
cpcb != NULL; cpcb = cpcb->next) { |
cpcb != NULL; cpcb = cpcb->next) { |
276 |
} |
} |
277 |
} |
} |
278 |
} |
} |
279 |
|
#else /* SO_REUSE */ |
280 |
|
/* Search through list of PCB's in LISTEN state. |
281 |
|
|
282 |
|
If there is a PCB bound to specified port and IP_ADDR_ANY another PCB can be bound to the interface IP |
283 |
|
or to the loopback address on the same port if SOF_REUSEADDR is set. Any combination of PCB's bound to |
284 |
|
the same local port, but to one address out of {IP_ADDR_ANY, 127.0.0.1, interface IP} at a time is valid. |
285 |
|
But no two PCB's bound to same local port and same local address is valid. |
286 |
|
|
287 |
|
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then |
288 |
|
all PCB's must have the SOF_REUSEPORT option set. |
289 |
|
|
290 |
|
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that |
291 |
|
address is already in use. */ |
292 |
|
for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs; cpcb != NULL; cpcb = cpcb->next) { |
293 |
|
if(cpcb->local_port == port) { |
294 |
|
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { |
295 |
|
if(pcb->so_options & SOF_REUSEPORT) { |
296 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT set and same address.\n")); |
297 |
|
reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT)); |
298 |
|
} |
299 |
|
else { |
300 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's: SO_REUSEPORT not set and same address.\n")); |
301 |
|
return ERR_USE; |
302 |
|
} |
303 |
|
} |
304 |
|
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) || |
305 |
|
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) { |
306 |
|
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) { |
307 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n")); |
308 |
|
return ERR_USE; |
309 |
|
} |
310 |
|
else { |
311 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in listening PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n")); |
312 |
|
} |
313 |
|
} |
314 |
|
} |
315 |
|
} |
316 |
|
|
317 |
|
/* Search through list of PCB's in a state in which they can accept or send data. Same decription as for |
318 |
|
PCB's in state LISTEN applies to this PCB's regarding the options SOF_REUSEADDR and SOF_REUSEPORT. */ |
319 |
|
for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) { |
320 |
|
if(cpcb->local_port == port) { |
321 |
|
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { |
322 |
|
if(pcb->so_options & SOF_REUSEPORT) { |
323 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT set and same address.\n")); |
324 |
|
reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT)); |
325 |
|
} |
326 |
|
else { |
327 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT not set and same address.\n")); |
328 |
|
return ERR_USE; |
329 |
|
} |
330 |
|
} |
331 |
|
else if((ip_addr_isany(ipaddr) && !ip_addr_isany(&(cpcb->local_ip))) || |
332 |
|
(!ip_addr_isany(ipaddr) && ip_addr_isany(&(cpcb->local_ip)))) { |
333 |
|
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) { |
334 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR not set and not the same address.\n")); |
335 |
|
return ERR_USE; |
336 |
|
} |
337 |
|
else { |
338 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in active PCB's SO_REUSEPORT or SO_REUSEADDR set and not the same address.\n")); |
339 |
|
} |
340 |
|
} |
341 |
|
} |
342 |
|
} |
343 |
|
|
344 |
|
/* Search through list of PCB's in TIME_WAIT state. If SO_REUSEADDR is set a bound combination [IP, port} |
345 |
|
can be rebound. The same applies when SOF_REUSEPORT is set. |
346 |
|
|
347 |
|
If SOF_REUSEPORT is set several PCB's can be bound to same local port and same local address also. But then |
348 |
|
all PCB's must have the SOF_REUSEPORT option set. |
349 |
|
|
350 |
|
When the two options aren't set and specified port is already bound, ERR_USE is returned saying that |
351 |
|
address is already in use. */ |
352 |
|
for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) { |
353 |
|
if(cpcb->local_port == port) { |
354 |
|
if(ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { |
355 |
|
if(!(pcb->so_options & SOF_REUSEADDR) && !(pcb->so_options & SOF_REUSEPORT)) { |
356 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT or SO_REUSEADDR not set and same address.\n")); |
357 |
|
return ERR_USE; |
358 |
|
} |
359 |
|
else if(pcb->so_options & SOF_REUSEPORT) { |
360 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: in TIME_WAIT PCB's SO_REUSEPORT set and same address.\n")); |
361 |
|
reuse_port_all_set = (reuse_port_all_set && (cpcb->so_options & SOF_REUSEPORT)); |
362 |
|
} |
363 |
|
} |
364 |
|
} |
365 |
|
} |
366 |
|
|
367 |
|
/* If SOF_REUSEPORT isn't set in all PCB's bound to specified port and local address specified then |
368 |
|
{IP, port} can't be reused. */ |
369 |
|
if(!reuse_port_all_set) { |
370 |
|
LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: not all sockets have SO_REUSEPORT set.\n")); |
371 |
|
return ERR_USE; |
372 |
|
} |
373 |
|
#endif /* SO_REUSE */ |
374 |
|
|
375 |
if (!ip_addr_isany(ipaddr)) { |
if (!ip_addr_isany(ipaddr)) { |
376 |
pcb->local_ip = *ipaddr; |
pcb->local_ip = *ipaddr; |
377 |
} |
} |