?? tcp.c
字號:
/** * @file * * Transmission Control Protocol for IP * * This file contains common functions for the TCP implementation, such as functinos * for manipulating the data structures and the TCP timer functions. TCP functions * related to input and output is found in tcp_in.c and tcp_out.c respectively. * *//* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels <adam@sics.se> * */#include <string.h>#include "lwip/opt.h"#include "lwip/def.h"#include "lwip/mem.h"#include "lwip/memp.h"#include "lwip/tcp.h"#include "uart.h"#if LWIP_TCP/* Incremented every coarse grained timer shot (typically every 500 ms, determined by TCP_COARSE_TIMEOUT). */u32_t tcp_ticks;const u8_t tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};/* The TCP PCB lists. *//** List of all TCP PCBs in LISTEN state */union tcp_listen_pcbs_t tcp_listen_pcbs;/** List of all TCP PCBs that are in a state in which * they accept or send data. */struct tcp_pcb *tcp_active_pcbs; /** List of all TCP PCBs in TIME-WAIT state */struct tcp_pcb *tcp_tw_pcbs;struct tcp_pcb *tcp_tmp_pcb;static u8_t tcp_timer;static u16_t tcp_new_port(void);/** * Initializes the TCP layer. */voidtcp_init(void){ /* Clear globals. */ tcp_listen_pcbs.listen_pcbs = NULL; tcp_active_pcbs = NULL; tcp_tw_pcbs = NULL; tcp_tmp_pcb = NULL; /* initialize timer */ tcp_ticks = 0; tcp_timer = 0; }/**this fun will be called ,when some EVENT happed to TCP CONNECT* created by skier 2006.01.30*/#if LWIP_EVENT_APItypedef enum{ PPP_DEAD = 0, PPP_ESTABLISHED, UDP_ESTABLISHED, TCP_CONNECTING, TCP_ESTABLISHED, TCP_CLOSING, TCPIP_STATE_UNKNOWN, }MY_TCPIP_STATE;extern void set_Mytcpip_state(MY_TCPIP_STATE state);extern void tcp_data_ind(u8_t *buf, u16_t len);extern void clear_sys_err(void);extern void add_sys_err(void);/**create by skier 2006.01.31*this func will be called when the state of TCP Connect is changed.*this fun is very simple, you shuold complete it very carefully.*/err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, LWIP_STATE lwip_event, struct pbuf *p, u16_t size, err_t err){ struct pbuf *temp = p; //DEBUG_FUNCTION("lwip_tcp_event()"); switch(lwip_event) { case LWIP_EVENT_ACCEPT: //tcp listen. accept a TCP Connect. DEBUG_EVENT("LWIP_EVENT_ACCEPT"); break; case LWIP_EVENT_SENT: //receive the ACK from TCP Peer. //Data send successful! DEBUG_EVENT("LWIP_EVENT_SENT"); clear_sys_err(); break; /* *receive some data from TCP Peer */ case LWIP_EVENT_RECV: DEBUG_EVENT("LWIP_EVENT_RECV"); while(temp != NULL) { tcp_data_ind((u8_t *)temp->payload, temp->len); temp = temp->next; } clear_sys_err(); break; case LWIP_EVENT_CONNECTED: //I this the connect of My TCP connect successful! DEBUG_EVENT("LWIP_EVENT_CONNECTED"); set_Mytcpip_state(TCP_ESTABLISHED); break; case LWIP_EVENT_POLL: // DEBUG_EVENT("LWIP_EVENT_POLL"); break; case LWIP_EVENT_ERR: DEBUG_EVENT("LWIP_EVENT_ERR"); set_Mytcpip_state(PPP_ESTABLISHED); add_sys_err(); break; default : break; } return ERR_OK; }#endif#if LWIP_TCPstatic int tcpip_tcp_timer_active = 0;static voidtcpip_tcp_timer(void *arg){ (void)arg; /* call TCP timer handler */ tcp_tmr(); /* timer still needed? */ if (tcp_active_pcbs || tcp_tw_pcbs) { /* restart timer */ //TIMEOUT(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); TCP_TIMER_START(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); } else { /* disable timer */ tcpip_tcp_timer_active = 0; /* *new added by skier 2006.01.29 */ TCP_TIMER_STOP(tcpip_tcp_timer, NULL); }}#if !NO_SYSvoidtcp_timer_needed(void){ /* timer is off but needed again? */ if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { /* enable and start timer */ tcpip_tcp_timer_active = 1; TCP_TIMER_START(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); }}#endif /* !NO_SYS */#endif /* LWIP_TCP *//** * Called periodically to dispatch TCP timers. * */voidtcp_tmr(void){ /* Call tcp_fasttmr() every 250 ms */ tcp_fasttmr(); if (++tcp_timer & 1) { /* Call tcp_tmr() every 500 ms, i.e., every other timer tcp_tmr() is called. */ tcp_slowtmr(); }}/** * Closes the connection held by the PCB. * */err_ttcp_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;}/** * Aborts a connection by sending a RST to the remote host and deletes * the local protocol control block. This is done when a connection is * killed because of shortage of memory. * */voidtcp_abort(struct tcp_pcb *pcb){ u32_t seqno, ackno; u16_t remote_port, local_port; struct ip_addr remote_ip, local_ip;#if LWIP_CALLBACK_API void (* errf)(void *arg, err_t err);#endif /* LWIP_CALLBACK_API */ void *errf_arg; /* Figure out on which TCP PCB list we are, and remove us. If we are in an active state, call the receive function associated with the PCB with a NULL argument, and send an RST to the remote end. */ if (pcb->state == TIME_WAIT) { tcp_pcb_remove(&tcp_tw_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); } else { seqno = pcb->snd_nxt; ackno = pcb->rcv_nxt; ip_addr_set(&local_ip, &(pcb->local_ip)); ip_addr_set(&remote_ip, &(pcb->remote_ip)); local_port = pcb->local_port; remote_port = pcb->remote_port;#if LWIP_CALLBACK_API errf = pcb->errf;#endif /* LWIP_CALLBACK_API */ errf_arg = pcb->callback_arg; tcp_pcb_remove(&tcp_active_pcbs, pcb); if (pcb->unacked != NULL) { tcp_segs_free(pcb->unacked); } if (pcb->unsent != NULL) { tcp_segs_free(pcb->unsent); }#if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL) { tcp_segs_free(pcb->ooseq); }#endif /* TCP_QUEUE_OOSEQ */ memp_free(MEMP_TCP_PCB, pcb); TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n")); tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); }}/** * Binds the connection to a local portnumber and IP address. If the * IP address is not given (i.e., ipaddr == NULL), the IP address of * the outgoing network interface is used instead. * */err_ttcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port){ struct tcp_pcb *cpcb;#if SO_REUSE int reuse_port_all_set = 1;#endif /* SO_REUSE */ if (port == 0) { port = tcp_new_port(); }#if SO_REUSE == 0 /* Check if the address already is in use. */ for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) { if (ip_addr_isany(&(cpcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { return ERR_USE; } } } for(cpcb = tcp_active_pcbs; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) { if (ip_addr_isany(&(cpcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { return ERR_USE; } } }#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.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}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -