📄 tcp.c
字号:
ip_header_t *ip = pkt->ip_hdr;
tcp_socket_t *prev,*s;
dword ack;
int queued = 0;
/* set length for pseudo sum calculation */
ip->length = htons(pkt->pkt_bytes);
if (__sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)) == 0) {
for (prev = NULL, s = tcp_list; s; prev = s, s = s->next) {
if (s->our_port == ntohs(tcp->dest_port)) {
if (s->his_port == 0)
break;
if (s->his_port == ntohs(tcp->src_port) &&
!memcmp(r->ip_addr, s->his_addr.ip_addr, sizeof(ip_addr_t)))
break;
}
}
if (s) {
/* found the socket this packet belongs to */
/* refresh his ethernet address */
memcpy(s->his_addr.enet_addr, r->enet_addr, sizeof(enet_addr_t));
if (s->state != _SYN_RCVD && tcp->flags & TCP_FLAG_RST) {
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 */
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;
s->ack_pending = 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 || s->ack_pending) {
/*
* we can't send an ack if our write packet is holding outgoing
* data pending an incoming ack.
*/
if (s->data_bytes == 0) {
BSPLOG(bsp_log("Sending ack: new[%x] old[%x]\n",
s->ack, ack));
__timer_cancel(&s->timer);
tcp_send(s, TCP_FLAG_ACK, 0);
s->ack_pending = 0;
} else
s->ack_pending = 1;
}
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;
tcp_send(s, TCP_FLAG_ACK, 0);
} else {
s->state = _FIN_WAIT_2;
BSPLOG(bsp_log("_FIN_WAIT_1 --> _FIN_WAIT_2\n"));
}
}
}
if (tcp->flags & TCP_FLAG_FIN) {
BSPLOG(bsp_log("_FIN_WAIT_1 --> _CLOSING\n"));
__timer_cancel(&s->timer);
s->ack++;
s->state = _CLOSING;
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;
tcp_send(s, TCP_FLAG_ACK, 0);
}
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 1
/* 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;
}
/*
* 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.
*/
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;
}
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -