/** * Closes the connection held by the PCB. * */ err_t tcp_close(struct tcp_pcb *pcb) { err_t err; #if TCP_DEBUG LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in state ")); tcp_debug_print_state(pcb->state); LWIP_DEBUGF(TCP_DEBUG, ("\n")); #endif /* TCP_DEBUG */ switch (pcb->state) { case CLOSED: /* Closing a pcb in the CLOSED state might seem erroneous, * however, it is in this state once allocated and as yet unused * and the user needs some way to free it should the need arise. * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) * or for a pcb that has been used and then entered the CLOSED state * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ err = ERR_OK; memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case LISTEN: err = ERR_OK; tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); memp_free(MEMP_TCP_PCB_LISTEN, pcb); pcb = NULL; break; case SYN_SENT: err = ERR_OK; tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case SYN_RCVD: case ESTABLISHED: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { pcb->state = FIN_WAIT_1; } break; case CLOSE_WAIT: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { pcb->state = LAST_ACK; } break; default: /* Has already been closed, do nothing. */ err = ERR_OK; pcb = NULL; break; } if (pcb != NULL && err == ERR_OK) { err = tcp_output(pcb); } return err; }
/*-----------------------------------------------------------------------------------*/ err_t tcp_close(struct tcp_pcb *pcb) { err_t err; #if TCP_DEBUG DEBUGF(TCP_DEBUG, ("tcp_close: closing in state ")); tcp_debug_print_state(pcb->state); DEBUGF(TCP_DEBUG, ("\n")); #endif /* TCP_DEBUG */ switch(pcb->state) { case LISTEN: err = ERR_OK; tcp_pcb_remove(TCP_LIST_LISTEN, pcb); memp_free(MEMP_TCP_PCB_LISTEN, pcb); pcb = NULL; break; case SYN_SENT: err = ERR_OK; tcp_pcb_remove(TCP_LIST_ACTIVE, pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case SYN_RCVD: err = tcp_send_ctrl(pcb, TCP_FIN); if(err == ERR_OK) { pcb->state = FIN_WAIT_1; } break; case ESTABLISHED: err = tcp_send_ctrl(pcb, TCP_FIN); if(err == ERR_OK) { pcb->state = FIN_WAIT_1; } break; case CLOSE_WAIT: err = tcp_send_ctrl(pcb, TCP_FIN); if(err == ERR_OK) { pcb->state = LAST_ACK; } break; default: /* Has already been closed, do nothing. */ err = ERR_OK; pcb = NULL; break; } if(pcb != NULL && err == ERR_OK) { err = tcp_output(pcb); } return err; }
/** * Closes the connection held by the PCB. * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced * any more. If a connection is established (at least SYN received or in * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it. * * @param pcb the tcp_pcb to close * @return ERR_OK if connection has been closed * another err_t if closing failed and pcb is not freed */ err_t tcp_close(struct tcp_pcb *pcb) { err_t err; #if TCP_DEBUG LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); tcp_debug_print_state(pcb->state); #endif /* TCP_DEBUG */ switch (pcb->state) { case CLOSED: /* Closing a pcb in the CLOSED state might seem erroneous, * however, it is in this state once allocated and as yet unused * and the user needs some way to free it should the need arise. * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) * or for a pcb that has been used and then entered the CLOSED state * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ err = ERR_OK; TCP_RMV(&tcp_bound_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case LISTEN: err = ERR_OK; tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); memp_free(MEMP_TCP_PCB_LISTEN, pcb); pcb = NULL; break; case SYN_SENT: err = ERR_OK; tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; snmp_inc_tcpattemptfails(); break; case SYN_RCVD: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { snmp_inc_tcpattemptfails(); pcb->state = FIN_WAIT_1; } break; case ESTABLISHED: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { snmp_inc_tcpestabresets(); pcb->state = FIN_WAIT_1; } break; case CLOSE_WAIT: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { snmp_inc_tcpestabresets(); pcb->state = LAST_ACK; } break; default: /* Has already been closed, do nothing. */ err = ERR_OK; pcb = NULL; break; } if (pcb != NULL && err == ERR_OK) { /* To ensure all data has been sent when tcp_close returns, we have to make sure tcp_output doesn't fail. Since we don't really have to ensure all data has been sent when tcp_close returns (unsent data is sent from tcp timer functions, also), we don't care for the return value of tcp_output for now. */ /* @todo: When implementing SO_LINGER, this must be changed somehow: If SOF_LINGER is set, the data should be sent when tcp_close returns. */ tcp_output(pcb); } return err; }
/** * Closes the connection held by the PCB. * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced * any more. If a connection is established (at least SYN received or in * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it. * * @param pcb the tcp_pcb to close * @return ERR_OK if connection has been closed * another uint8 if closing failed and pcb is not freed */ uint8 tcp_close(TCP_PCB *pcb) { uint8 err = ERR_OK; tcp_tick_ack_unable(pcb);//printf("pcb->timerackflag = 0\n"); switch (pcb->state) { case CLOSED: /* Closing a pcb in the CLOSED state might seem erroneous, * however, it is in this state once allocated and as yet unused * and the user needs some way to free it should the need arise. * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) * or for a pcb that has been used and then entered the CLOSED state * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ pcb->pcb_close(TCP_CLOSED);//Http_Check_Tcp_State memset(pcb, 0, sizeof(pcb)); pcb = NULL; break; case SYN_SENT: tcp_pcb_remove_nolist(pcb); if (pcb->unacked != NULL) { tcp_segs_free(pcb->unacked); pcb->unacked = NULL; } if (pcb->unsent != NULL) { tcp_segs_free(pcb->unsent); pcb->unsent = NULL; } pcb->pcb_close(TCP_CLOSED);//Http_Check_Tcp_State memset(pcb, 0, sizeof(pcb)); pcb = NULL; break; case ESTABLISHED: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { pcb->state = FIN_WAIT_1; } break; case CLOSE_WAIT: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { pcb->state = LAST_ACK; } break; default: /* Has already been closed, do nothing. */ pcb = NULL; break; } if (pcb != NULL && err == ERR_OK) { /* To ensure all data has been sent when tcp_close returns, we have to make sure tcp_output doesn't fail. Since we don't really have to ensure all data has been sent when tcp_close returns (unsent data is sent from tcp timer functions, also), we don't care for the return value of tcp_output for now. */ /* @todo: When implementing SO_LINGER, this must be changed somehow: If SOF_LINGER is set, the data should be sent when tcp_close returns. */ tcp_output(pcb); } return err; }
/** * Closes the connection held by the PCB. * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced * any more. If a connection is established (at least SYN received or in * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it. * * @param pcb the tcp_pcb to close * @return ERR_OK if connection has been closed * another err_t if closing failed and pcb is not freed */ err_t tcp_close(struct tcp_pcb *pcb) { err_t err; #if TCP_DEBUG LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); tcp_debug_print_state(pcb->state); #endif /* TCP_DEBUG */ switch (pcb->state) { /* 若TCP在CLOSE状态,即tcp_new()之后从未使用过 */ case CLOSED: /* Closing a pcb in the CLOSED state might seem erroneous, * however, it is in this state once allocated and as yet unused * and the user needs some way to free it should the need arise. * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) * or for a pcb that has been used and then entered the CLOSED state * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ err = ERR_OK; /* 从tcp_bound_pcbs链表上删除(如果已经调用tcp_bind()的话) */ TCP_RMV(&tcp_bound_pcbs, pcb); /* 释放TCP控制所占内存 */ memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case LISTEN: err = ERR_OK; /* 从LISTEN链表上删除,并发送可能存在的delayed ACKs */ tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); /* 释放LISTEN类型的TCP控制块 */ memp_free(MEMP_TCP_PCB_LISTEN, pcb); pcb = NULL; break; case SYN_SENT: err = ERR_OK; tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; snmp_inc_tcpattemptfails(); break; case SYN_RCVD: /* 构造FIN报文,主动关闭 */ err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { snmp_inc_tcpattemptfails(); /* 进入FIN_WAIT_1状态 */ pcb->state = FIN_WAIT_1; } break; case ESTABLISHED: /* 构造FIN报文,主动关闭 */ err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { snmp_inc_tcpestabresets(); /* 进入FIN_WAIT_1状态 */ pcb->state = FIN_WAIT_1; } break; /* 被动关闭,收到对方的FIN后,构造FIN关闭另一个方向传输 */ case CLOSE_WAIT: err = tcp_send_ctrl(pcb, TCP_FIN); if (err == ERR_OK) { snmp_inc_tcpestabresets(); /* 进入LAST_ACK状态 */ pcb->state = LAST_ACK; } break; /* 其他状态,用TCP定时器函数实现 */ default: /* Has already been closed, do nothing. */ err = ERR_OK; pcb = NULL; break; } /* 发送TCP控制块中剩余的报文段,包括FIN报文 */ if (pcb != NULL && err == ERR_OK) { /* To ensure all data has been sent when tcp_close returns, we have to make sure tcp_output doesn't fail. Since we don't really have to ensure all data has been sent when tcp_close returns (unsent data is sent from tcp timer functions, also), we don't care for the return value of tcp_output for now. */ /* @todo: When implementing SO_LINGER, this must be changed somehow: If SOF_LINGER is set, the data should be sent when tcp_close returns. */ tcp_output(pcb); } return err; }