?? tcp.c
字號:
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 void
do_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 + -