📄 tcp.c
字号:
/*-----------------------------------------------------------------------------------*/
#if MEMP_RECLAIM
static u8_t
tcp_memp_reclaim(void *arg, memp_t type)
{
struct tcp_pcb *pcb, *inactive;
u32_t inactivity;
switch(type) {
case MEMP_TCP_SEG:
#if TCP_QUEUE_OOSEQ
/* Try to find any buffered out of sequence data. */
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
if(pcb->ooseq) {
DEBUGF(TCP_DEBUG, ("tcp_memp_reclaim: reclaiming memory from PCB 0x%lx\n", (long)pcb));
tcp_segs_free(pcb->ooseq);
pcb->ooseq = NULL;
return 1;
}
}
#else /* TCP_QUEUE_OOSEQ */
return 0;
#endif /* TCP_QUEUE_OOSEQ */
break;
case MEMP_PBUF:
return tcp_memp_reclaim(arg, MEMP_TCP_SEG);
case MEMP_TCP_PCB:
/* We either kill off a connection in TIME-WAIT, or the oldest
active connection. */
pcb = tcp_tw_pcbs;
if(pcb != NULL) {
tcp_tw_pcbs = tcp_tw_pcbs->next;
memp_free(MEMP_TCP_PCB, pcb);
return 1;
} else {
inactivity = 0;
inactive = NULL;
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
if((u32_t)(tcp_ticks - pcb->tmr) > inactivity) {
inactivity = tcp_ticks - pcb->tmr;
inactive = pcb;
}
}
if(inactive != NULL) {
DEBUGF(TCP_DEBUG, ("tcp_mem_reclaim: killing oldest PCB 0x%p (%ld)\n",
inactive, inactivity));
tcp_abort(inactive);
return 1;
}
}
break;
default:
ASSERT("tcp_memp_reclaim: called with wrong type", 0);
break;
}
return 0;
}
#endif /* MEM_RECLAIM */
/*-----------------------------------------------------------------------------------*/
/*
* tcp_arg():
*
* Used to specify the argument that should be passed callback
* functions.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_arg(struct tcp_pcb *pcb, void *arg)
{
pcb->callback_arg = arg;
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_recv():
*
* Used to specify the function that should be called when a TCP
* connection receives data.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_recv(struct tcp_pcb *pcb,
err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))
{
pcb->recv = recv;
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_sent():
*
* Used to specify the function that should be called when TCP data
* has been successfully delivered to the remote host.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_sent(struct tcp_pcb *pcb,
err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))
{
pcb->sent = sent;
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_err():
*
* Used to specify the function that should be called when a fatal error
* has occured on the connection.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_err(struct tcp_pcb *pcb,
void (* errf)(void *arg, err_t err))
{
pcb->errf = errf;
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_poll():
*
* Used to specify the function that should be called periodically
* from TCP. The interval is specified in terms of the TCP coarse
* timer interval, which is called twice a second.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_poll(struct tcp_pcb *pcb,
err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)
{
pcb->poll = poll;
pcb->pollinterval = interval;
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_accept():
*
* Used for specifying the function that should be called when a
* LISTENing connection has been connected to another host.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))
{
pcb->accept = accept;
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_pcb_purge():
*
* Purges a TCP PCB. Removes any buffered data and frees the buffer memory.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_pcb_purge(struct tcp_pcb *pcb)
{
if(pcb->state != CLOSED &&
pcb->state != TIME_WAIT &&
pcb->state != LISTEN) {
#if TCP_DEBUG
if(pcb->unsent != NULL) {
DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
}
if(pcb->unacked != NULL) {
DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
}
if(pcb->ooseq != NULL) {
DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
}
#endif /* TCP_DEBUG */
tcp_segs_free(pcb->unsent);
#if TCP_QUEUE_OOSEQ
tcp_segs_free(pcb->ooseq);
#endif /* TCP_QUEUE_OOSEQ */
tcp_segs_free(pcb->unacked);
pcb->unacked = pcb->unsent =
#if TCP_QUEUE_OOSEQ
pcb->ooseq =
#endif /* TCP_QUEUE_OOSEQ */
NULL;
}
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_pcb_remove():
*
* Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
*
*/
/*-----------------------------------------------------------------------------------*/
void
tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
{
TCP_RMV(pcblist, pcb);
tcp_pcb_purge(pcb);
/* if there is an outstanding delayed ACKs, send it */
if(pcb->state != TIME_WAIT &&
pcb->state != LISTEN &&
pcb->flags & TF_ACK_DELAY) {
pcb->flags |= TF_ACK_NOW;
tcp_output(pcb);
}
pcb->state = CLOSED;
ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
}
/*-----------------------------------------------------------------------------------*/
/*
* tcp_next_iss():
*
* Calculates a new initial sequence number for new connections.
*
*/
/*-----------------------------------------------------------------------------------*/
u32_t
tcp_next_iss(void)
{
static u32_t iss = 6510;
iss += tcp_ticks; /* XXX */
return iss;
}
/*-----------------------------------------------------------------------------------*/
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
void
tcp_debug_print(struct tcp_hdr *tcphdr)
{
DEBUGF(TCP_DEBUG, ("TCP header:\n"));
DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
DEBUGF(TCP_DEBUG, ("| %04x | %04x | (src port, dest port)\n",
tcphdr->src, tcphdr->dest));
DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
DEBUGF(TCP_DEBUG, ("| %08lu | (seq no)\n",
tcphdr->seqno));
DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
DEBUGF(TCP_DEBUG, ("| %08lu | (ack no)\n",
tcphdr->ackno));
DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
DEBUGF(TCP_DEBUG, ("| %2d | |%d%d%d%d%d| %5d | (offset, flags (",
TCPH_FLAGS(tcphdr) >> 4 & 1,
TCPH_FLAGS(tcphdr) >> 4 & 1,
TCPH_FLAGS(tcphdr) >> 3 & 1,
TCPH_FLAGS(tcphdr) >> 2 & 1,
TCPH_FLAGS(tcphdr) >> 1 & 1,
TCPH_FLAGS(tcphdr) & 1,
tcphdr->wnd));
tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
DEBUGF(TCP_DEBUG, ("), win)\n"));
DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
DEBUGF(TCP_DEBUG, ("| 0x%04x | %5d | (chksum, urgp)\n",
ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
}
/*-----------------------------------------------------------------------------------*/
void
tcp_debug_print_state(enum tcp_state s)
{
DEBUGF(TCP_DEBUG, ("State: "));
switch(s) {
case CLOSED:
DEBUGF(TCP_DEBUG, ("CLOSED\n"));
break;
case LISTEN:
DEBUGF(TCP_DEBUG, ("LISTEN\n"));
break;
case SYN_SENT:
DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));
break;
case SYN_RCVD:
DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));
break;
case ESTABLISHED:
DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));
break;
case FIN_WAIT_1:
DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));
break;
case FIN_WAIT_2:
DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));
break;
case CLOSE_WAIT:
DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));
break;
case CLOSING:
DEBUGF(TCP_DEBUG, ("CLOSING\n"));
break;
case LAST_ACK:
DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));
break;
case TIME_WAIT:
DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));
break;
}
}
/*-----------------------------------------------------------------------------------*/
void
tcp_debug_print_flags(u8_t flags)
{
if(flags & TCP_FIN) {
DEBUGF(TCP_DEBUG, ("FIN "));
}
if(flags & TCP_SYN) {
DEBUGF(TCP_DEBUG, ("SYN "));
}
if(flags & TCP_RST) {
DEBUGF(TCP_DEBUG, ("RST "));
}
if(flags & TCP_PSH) {
DEBUGF(TCP_DEBUG, ("PSH "));
}
if(flags & TCP_ACK) {
DEBUGF(TCP_DEBUG, ("ACK "));
}
if(flags & TCP_URG) {
DEBUGF(TCP_DEBUG, ("URG "));
}
}
/*-----------------------------------------------------------------------------------*/
void
tcp_debug_print_pcbs(void)
{
struct tcp_pcb *pcb;
DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
DEBUGF(TCP_DEBUG, ("Local port %d, foreign port %d snd_nxt %lu rcv_nxt %lu ",
pcb->local_port, pcb->remote_port,
pcb->snd_nxt, pcb->rcv_nxt));
tcp_debug_print_state(pcb->state);
}
DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
DEBUGF(TCP_DEBUG, ("Local port %d, foreign port %d snd_nxt %lu rcv_nxt %lu ",
pcb->local_port, pcb->remote_port,
pcb->snd_nxt, pcb->rcv_nxt));
tcp_debug_print_state(pcb->state);
}
DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
DEBUGF(TCP_DEBUG, ("Local port %d, foreign port %d snd_nxt %lu rcv_nxt %lu ",
pcb->local_port, pcb->remote_port,
pcb->snd_nxt, pcb->rcv_nxt));
tcp_debug_print_state(pcb->state);
}
}
/*-----------------------------------------------------------------------------------*/
int
tcp_pcbs_sane(void)
{
struct tcp_pcb *pcb;
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
}
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
}
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {
ASSERT("tcp_pcbs_sane: listen pcb->state == LISTEN", pcb->state == LISTEN);
}
return 1;
}
#endif /* TCP_DEBUG */
/*-----------------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -