Tue 22 Aug 2017 06:47:51 PM UTC, comment #2:
Yes, TCP_EVENT_CLOSED.
Below is the routine that calls tcp_close(pcb) if the user has not registered a call back function. This is in tcp.c:
#if LWIP_CALLBACK_API
/**
- Default receive callback that is called if the user didn't register
- a recv callback for the pcb.
*/
err_t
tcp_recv_null(void arg, struct tcp_pcb pcb, struct pbuf *p, err_t err)
{
LWIP_UNUSED_ARG(arg);
if (p != NULL) {
tcp_recved(pcb, p->tot_len);
pbuf_free(p);
} else if (err == ERR_OK) {
return tcp_close(pcb);
}
return ERR_OK;
}
#endif /* LWIP_CALLBACK_API */
Further, tcp_close(pcb) will free the pcb if the pcb state is SYN_SENT:
case SYN_SENT:
err = ERR_OK;
TCP_PCB_REMOVE_ACTIVE(pcb);
memp_free(MEMP_TCP_PCB, pcb);
pcb = NULL;
MIB2_STATS_INC(mib2.tcpattemptfails);
break;
Further, the remote might have sent a FIN while not in the ESTABLISHED state but rather in the SYN_RECEIVED state, as does LwIP:
case SYN_RCVD:
err = tcp_send_fin(pcb);
So, specifically, the call back function called when a FIN is received calls tcp_close() which in turn will free the PCB and then, after the call back function is called, (via TCP_EVENT_CLOSED), tcp_output(pcb) is called, referencing a free pcb erroneously:
TCP_EVENT_CLOSED(pcb, err);
if (err == ERR_ABRT) {
goto aborted;
}
}
}
tcp_input_pcb = NULL;
/* Try to send something out. */
tcp_output(pcb);
|