⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 redboot 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		BSPLOG(bsp_log("TCP_FLAG_RST rcvd\n"));		do_reset(s);		__pktbuf_free(pkt);		return;	    }	    switch (s->state) {	      case _SYN_SENT:		/* active open not supported */                  if (tcp->flags != (TCP_FLAG_SYN | TCP_FLAG_ACK)) {                      do_reset(s);                      __pktbuf_free(pkt);                      return;                  }                  s->state = _ESTABLISHED;                  s->ack = ntohl(tcp->seqnum) + 1;                  s->seq = ntohl(tcp->acknum);                  send_ack(s);		break;	      case _LISTEN:		if (tcp->flags & TCP_FLAG_SYN) {		    s->state = _SYN_RCVD;		    s->ack = ntohl(tcp->seqnum) + 1;		    s->his_port = ntohs(tcp->src_port);		    memcpy(s->his_addr.ip_addr, r->ip_addr, sizeof(ip_addr_t));		    s->data_bytes = 0;		    BSPLOG(bsp_log("SYN from %d.%d.%d.%d:%d (seq %x)\n",			       s->his_addr.ip_addr[0],s->his_addr.ip_addr[1],			       s->his_addr.ip_addr[2],s->his_addr.ip_addr[3],			       s->his_port, ntohl(tcp->seqnum)));		    tcp_send(s, TCP_FLAG_SYN | TCP_FLAG_ACK, 0);		}		else		    send_reset(pkt, r);		break;	      case _SYN_RCVD:		BSPLOG(bsp_log("_SYN_RCVD timer cancel.\n"));		__timer_cancel(&s->timer);		/* go back to _LISTEN state if reset */		if (tcp->flags & TCP_FLAG_RST) {		    s->state = _LISTEN;		    BSPLOG(bsp_log("_SYN_RCVD --> _LISTEN\n"));		} else if (tcp->flags & TCP_FLAG_SYN) {		    /* apparently our SYN/ACK was lost? */		    tcp_send(s, 0, 1);		    BSPLOG(bsp_log("retransmitting SYN/ACK\n"));		} else if ((tcp->flags & TCP_FLAG_ACK) &&			   ntohl(tcp->acknum) == (s->seq + 1)) {		    /* we've established the connection */		    s->state = _ESTABLISHED;		    s->seq++;		    BSPLOG(bsp_log("ACK received - connection established\n"));		}		break;	      case _ESTABLISHED:	      case _CLOSE_WAIT:		ack = s->ack;  /* save original ack */		if (tcp->flags & TCP_FLAG_ACK)		    handle_ack(s, pkt);		queued = handle_data(s, pkt);		if ((tcp->flags & TCP_FLAG_FIN) &&		    ntohl(tcp->seqnum) == s->ack) {		    BSPLOG(bsp_log("FIN received - going to _CLOSE_WAIT\n"));		    s->ack++;		    s->state = _CLOSE_WAIT;		}		/*		 * Send an ack if neccessary.		 */		if (s->ack != ack || pkt->pkt_bytes > (tcp->hdr_len << 2))		    send_ack(s);		break;	      case _LAST_ACK:		if (tcp->flags & TCP_FLAG_ACK) {		    handle_ack(s, pkt);		    if (ntohl(tcp->acknum) == (s->seq + 1)) {			BSPLOG(bsp_log("_LAST_ACK --> _CLOSED\n"));			s->state = _CLOSED;			unlink_socket(s);		    }		}		break;	      case _FIN_WAIT_1:		if (tcp->flags & TCP_FLAG_ACK) {		    handle_ack(s, pkt);		    if (ntohl(tcp->acknum) == (s->seq + 1)) {			/* got ACK for FIN packet */			s->seq++;			if (tcp->flags & TCP_FLAG_FIN) {			    BSPLOG(bsp_log("_FIN_WAIT_1 --> _TIME_WAIT\n"));			    s->ack++;			    s->state = _TIME_WAIT;			    send_ack(s);			} else {			    s->state = _FIN_WAIT_2;			    BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));			}                        break; /* All done for now */		    }		}                /* At this point, no ACK for FIN has been seen, so check for                   simultaneous close */		if (tcp->flags & TCP_FLAG_FIN) {		    BSPLOG(bsp_log("_FIN_WAIT_1 --> _CLOSING\n"));		    __timer_cancel(&s->timer);		    s->ack++;		    s->state = _CLOSING;                    /* FIN is resent so the timeout and retry for this packet                       will also take care of timeout and resend of the                       previously sent FIN (which got us to FIN_WAIT_1). While                       not technically correct, resending FIN only causes a                       duplicate FIN (same sequence number) which should be                       ignored by the other end. */		    tcp_send(s, TCP_FLAG_FIN | TCP_FLAG_ACK, 0);		}		break;	      case _FIN_WAIT_2:		queued = handle_data(s, pkt);		if (tcp->flags & TCP_FLAG_FIN) {		    BSPLOG(bsp_log("_FIN_WAIT_2 --> _TIME_WAIT\n"));		    s->ack++;		    s->state = _TIME_WAIT;		    send_ack(s);		}		break;	      case _CLOSING:		if (tcp->flags & TCP_FLAG_ACK) {		    handle_ack(s, pkt);		    if (ntohl(tcp->acknum) == (s->seq + 1)) {			/* got ACK for FIN packet */			BSPLOG(bsp_log("_CLOSING --> _TIME_WAIT\n"));			__timer_cancel(&s->timer);			s->state = _TIME_WAIT;		    }		}		break;	      case _TIME_WAIT:		BSPLOG(bsp_log("_TIME_WAIT resend.\n"));		if (tcp->flags & TCP_FLAG_FIN)		    tcp_send(s, 0, 1); /* just resend ack */		break;	    }	} else {	    BSPLOG(bsp_log("Unexpected segment from: %d.%d.%d.%d:%d\n",			   r->ip_addr[0], r->ip_addr[1], r->ip_addr[3],			   r->ip_addr[4], ntohs(tcp->src_port)));	    send_reset(pkt, r);	}    }    if (!queued)	__pktbuf_free(pkt);}void__tcp_poll(void){    __enet_poll();    MS_TICKS_DELAY();    __timer_poll();}int__tcp_listen(tcp_socket_t *s, word port){    BSPLOG(bsp_log("tcp_listen: s[%p] port[%x]\n", s, port));    memset(s, 0, sizeof(tcp_socket_t));    s->state    = _LISTEN;    s->our_port = port;    s->pkt.buf = (word *)s->pktbuf;    s->pkt.bufsize = ETH_MAX_PKTLEN;    s->pkt.ip_hdr  = (ip_header_t *)s->pkt.buf;    s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);    s->next = tcp_list;#if 0    /* limit to one open socket at a time */    if (s->next) {	BSPLOG(bsp_log("tcp_listen: recursion error\n"));	BSPLOG(while(1));    }#endif        tcp_list = s;    return 0;}/* * SO_REUSEADDR, no 2MSL. */void__tcp_so_reuseaddr(tcp_socket_t *s){//    BSPLOG(bsp_log("__tcp_so_reuseaddr.\n"));    s->reuse = 0x01;}/* * Block while waiting for all data to be transmitted. */void__tcp_drain(tcp_socket_t *s){//    BSPLOG(bsp_log("__tcp_drain.\n"));    while (s->state != _CLOSED && s->data_bytes)	__tcp_poll();//    BSPLOG(bsp_log("__tcp_drain done.\n"));}/* * Close the tcp connection. */static voiddo_abort(void *s){    BSPLOG(bsp_log("do_abort: send RST\n"));    tcp_send((tcp_socket_t *)s, TCP_FLAG_ACK | TCP_FLAG_RST, 0);    __timer_cancel(&abort_timer);    ((tcp_socket_t *)s)->state = _CLOSED;    free_rxlist((tcp_socket_t *)s);    unlink_socket((tcp_socket_t *)s);}void__tcp_abort(tcp_socket_t *s, unsigned long delay){  __timer_set(&abort_timer, delay, do_abort, s);}/* * Close the tcp connection. */void__tcp_close(tcp_socket_t *s){    __tcp_drain(s);    if (s->state == _ESTABLISHED || s->state == _SYN_RCVD) {	BSPLOG(bsp_log("__tcp_close: going to _FIN_WAIT_1\n"));	s->state = _FIN_WAIT_1;	tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);    } else if (s->state == _CLOSE_WAIT) {	BSPLOG(bsp_log("__tcp_close: going to _LAST_ACK\n"));	s->state = _LAST_ACK;	tcp_send(s, TCP_FLAG_ACK | TCP_FLAG_FIN, 0);    }    free_rxlist(s);}/* * Wait for connection to be fully closed. */void__tcp_close_wait(tcp_socket_t *s){    BSPLOG(bsp_log("__tcp_close_wait.\n"));    while (s->state != _CLOSED)	__tcp_poll();    BSPLOG(bsp_log("__tcp_close_wait done.\n"));}/* * Read up to 'len' bytes without blocking. */int__tcp_read(tcp_socket_t *s, char *buf, int len){    int          nread;    pktbuf_t     *pkt;    tcp_header_t *tcp;    if (len <= 0 || s->rxcnt == 0)	return 0;    if (s->state != _ESTABLISHED && s->rxcnt == 0)	return -1;    nread = 0;    while (len) {	if (len < s->rxcnt) {	    memcpy(buf, s->rxptr, len);	    BSPLOG(bsp_log("tcp_read: read %d bytes.\n", len));	    s->rxptr += len;	    s->rxcnt -= len;	    nread    += len;	    BSPLOG(bsp_log("tcp_read: %d bytes left in rxlist head.\n",		       s->rxcnt));	    break;	} else {	    memcpy(buf, s->rxptr, s->rxcnt);	    BSPLOG(bsp_log("tcp_read: read %d bytes. pkt[%x] freed.\n",			   s->rxcnt, s->rxlist));	    nread += s->rxcnt;	    buf   += s->rxcnt;	    len   -= s->rxcnt;	    /* setup for next packet in list */	    pkt = s->rxlist;	    s->rxlist = pkt->next;	    __pktbuf_free(pkt);	    if ((pkt = s->rxlist) != NULL) {		tcp = pkt->tcp_hdr;		s->rxcnt = pkt->pkt_bytes - (tcp->hdr_len << 2);		s->rxptr = ((char *)tcp)  + (tcp->hdr_len << 2);		BSPLOG(bsp_log("tcp_read: next pkt[%x] has %d bytes.\n",			   s->rxlist, s->rxcnt));	    } else {		BSPLOG(bsp_log("tcp_read: no more data.\n"));		s->rxcnt = 0;		break;	    }	}    }    return nread;}/* * Write up to 'len' bytes without blocking */int__tcp_write(tcp_socket_t *s, char *buf, int len){    tcp_header_t *tcp = s->pkt.tcp_hdr;    if (len <= 0)	return 0;    if (s->state != _ESTABLISHED && s->state != _CLOSE_WAIT)	return -1;    if (s->data_bytes)	return 0;    if (len > MAX_TCP_DATA)	len = MAX_TCP_DATA;    memcpy(tcp + 1, buf, len);    s->data_bytes = len;    tcp_send(s, TCP_FLAG_ACK, 0);    return len;}/* * Write 'len' bytes from 'buf', blocking until sent. * If connection collapses, return -1 */int__tcp_write_block(tcp_socket_t *s, char *buf, int len){    int total = 0;    int n;    while (len) {        if (s->state == _CLOSE_WAIT) {            // This connection is tring to close            // This connection is breaking            if (s->data_bytes == 0 && s->rxcnt == 0)                __tcp_close(s);        }        if (s->state == _CLOSED) {            // The connection is gone!            return -1;        }        n = __tcp_write(s, buf, len);        if (n > 0) {            len -= n;            buf += n;        }        __tcp_poll();    }    __tcp_drain(s);    return total;}/* * Establish a new [outgoing] connection, with a timeout. */int __tcp_open(tcp_socket_t *s, struct sockaddr_in *host,            word port, int timeout, int *err){    // Fill in socket details    memset(s, 0, sizeof(tcp_socket_t));    s->state = _SYN_SENT;    s->our_port = port;    s->his_port = host->sin_port;    s->pkt.buf = (word *)s->pktbuf;    s->pkt.bufsize = ETH_MAX_PKTLEN;    s->pkt.ip_hdr  = (ip_header_t *)s->pkt.buf;    s->pkt.tcp_hdr = (tcp_header_t *)(s->pkt.ip_hdr + 1);    s->seq = (port << 16) | 0xDE77;    s->ack = 0;    if (__arp_lookup((ip_addr_t *)&host->sin_addr, &s->his_addr) < 0) {        diag_printf("%s: Can't find address of server\n", __FUNCTION__);        return -1;    }    s->next = tcp_list;    tcp_list = s;    // Send off the SYN packet to open the connection    tcp_send(s, TCP_FLAG_SYN, 0);    // Wait for connection to establish    while (s->state != _ESTABLISHED) {        if (s->state == _CLOSED) {            diag_printf("TCP open - host closed connection\n");            return -1;        }        if (--timeout <= 0) {            diag_printf("TCP open - connection timed out\n");            return -1;        }        MS_TICKS_DELAY();        __tcp_poll();    }    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -