📄 tcplib.c
字号:
} else {
printf("sending RST on bad data in state SYN_SENT\n");
// we'll just let the timeout eventually close the socket, though
tcplib_send_rst(iph, tcph);
break;
}
case TCP_SYN_RCVD:
case TCP_LISTEN:
/* not connected. */
if (tcph->flags & TCP_FLAG_SYN) {
struct tcplib_sock *new_sock;
if (this_conn->state == TCP_LISTEN) {
memcpy(&this_conn->r_ep.sin6_addr, &iph->ip6_src, 16);
this_conn->r_ep.sin6_port = tcph->srcport;
new_sock = tcplib_accept(this_conn, &this_conn->r_ep);
if (new_sock != this_conn) {
memset(this_conn->r_ep.sin6_addr.s6_addr, 0, 16);
this_conn->r_ep.sin6_port = 0;
if (new_sock != NULL) {
memcpy(&new_sock->r_ep.sin6_addr, &iph->ip6_src, 16);
new_sock->r_ep.sin6_port = tcph->srcport;
conn_add_once(new_sock);
}
}
if (new_sock == NULL) {
tcplib_send_rst(iph, tcph);
break;
}
memcpy(&new_sock->l_ep.sin6_addr, &iph->ip6_dst, 16);
new_sock->l_ep.sin6_port = tcph->dstport;
new_sock->ackno = hdr_seqno + 1;
circ_buf_init(new_sock->tx_buf, new_sock->tx_buf_len,
0xcafebabe + 1);
} else {
/* recieved a SYN retransmission. */
new_sock = this_conn;
}
if (new_sock != NULL) {
new_sock->seqno = 0xcafebabe + 1;
new_sock->state = TCP_SYN_RCVD;
tcplib_send_ack(new_sock, 0, TCP_FLAG_ACK | TCP_FLAG_SYN);
new_sock->seqno++;
} else {
memset(&this_conn->r_ep, 0, sizeof(struct sockaddr_in6));
}
} else if (this_conn->state == TCP_LISTEN) {
tcplib_send_rst(iph, tcph);
break;
}
/* this is SYN_RECVd */
if (tcph->flags & TCP_FLAG_ACK) {
this_conn->state = TCP_ESTABLISHED;
}
/* fall through to handle any data. */
case TCP_CLOSE_WAIT:
case TCP_ESTABLISHED:
ESTABLISHED:
/* ack any data in this packet */
if (this_conn->state == TCP_ESTABLISHED || this_conn->state == TCP_FIN_WAIT_1) {
if (payload_len > 0) {
if ((this_conn->flags & TCP_ACKPENDING) == TCP_ACKPENDING) {
// printf("Incr would overflow\n");
}
this_conn->flags ++;
}
// receive side sequence check and add data
printf("seqno: %u ackno: %u\n", hdr_seqno, hdr_ackno);
// send side recieve sequence check and congestion window updates.
if (hdr_ackno > circ_get_seqno(this_conn->tx_buf)) {
// new data is being ACKed
// or we haven't sent anything new
if (this_conn->cwnd <= this_conn->ssthresh) {
// in slow start; increase the cwnd by one segment
this_conn->cwnd += ONE_SEGMENT(this_conn);
// printf("in slow start\n");
} else {
// in congestion avoidance
this_conn->cwnd += (ONE_SEGMENT(this_conn) * ONE_SEGMENT(this_conn)) / this_conn->cwnd;
// printf("in congestion avoidence\n");
}
// printf("ACK new data: cwnd: %i ssthresh: %i\n", this_conn->cwnd, this_conn->ssthresh);
// reset the duplicate ack counter
UNSET_ACK_COUNT(this_conn->flags);
// truncates the ack buffer
circ_shorten_head(this_conn->tx_buf, hdr_ackno);
// printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
if (this_conn->seqno == hdr_ackno) {
tcplib_extern_acked(this_conn);
}
} else if (this_conn->seqno > circ_get_seqno(this_conn->tx_buf)) {
// this is a duplicate ACK
// - increase the counter of the number of duplicate ACKs
// - if we get to three duplicate ACK's, start resending at
// the ACK number because this probably means we lost a segment
INCR_ACK_COUNT(this_conn->flags);
// printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
// printf("dup ack count: %i\n", GET_ACK_COUNT(this_conn->flags));
// a "dup ack count" of 2 is really 3 total acks because we start with zero
if (GET_ACK_COUNT(this_conn->flags) == 2) {
UNSET_ACK_COUNT(this_conn->flags);
printf("detected multiple duplicate ACKs-- doing fast retransmit [%u, %u]\n",
circ_get_seqno(this_conn->tx_buf),
this_conn->seqno);
// this is our detection of a "duplicate ack" event.
// we are going to reset ssthresh and retransmit the data.
reset_ssthresh(this_conn);
tcplib_output(this_conn, circ_get_seqno(this_conn->tx_buf));
this_conn->timer.retx = 6;
}
}
if (hdr_seqno != this_conn->ackno) {
printf("==> received forward segment\n");
if ((hdr_seqno > this_conn->ackno + this_conn->my_wind) ||
(hdr_seqno < this_conn->ackno - this_conn->my_wind)) {
// send a RST on really wild data
tcplib_send_rst(iph, tcph);
} else {
tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
this_conn->flags |= TCP_ACKSENT;
}
} else { // (hdr_seqno == this_conn->ackno) {
receive_data(this_conn, tcph, len - sizeof(struct ip6_hdr));
if (this_conn->flags & TCP_ACKSENT) {
this_conn->flags &= ~TCP_ACKSENT;
tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
}
}
// reset the retransmission timer
if (this_conn->timer.retx == 0)
this_conn->timer.retx = 6;
}
case TCP_TIME_WAIT:
if ((payload_len > 0 && (this_conn->flags & TCP_ACKPENDING) >= 1)
|| tcph->flags & TCP_FLAG_FIN) {
tcplib_send_ack(this_conn, (payload_len == 0 && tcph->flags & TCP_FLAG_FIN), TCP_FLAG_ACK);
/* only close the connection if we've gotten all the data */
if (this_conn->state == TCP_ESTABLISHED
&& tcph->flags & TCP_FLAG_FIN
&& hdr_seqno == this_conn->ackno) {
this_conn->state = TCP_CLOSE_WAIT;
tcplib_extern_closed(this_conn);
}
}
break;
case TCP_CLOSED:
default:
rc = -1;
// printf("sending RST\n");
// tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK | TCP_FLAG_RST);
}
} else {
/* this_conn was NULL */
/* interestingly, TCP sends a RST on this condition, not an ICMP error. go figure. */
printf("sending rst on missing connection\n");
tcplib_send_rst(iph, tcph);
}
return rc;
}
/* bind the socket to a local address */
int tcplib_bind(struct tcplib_sock *sock,
struct sockaddr_in6 *addr) {
/* not using an already-bound port */
/* TODO : SDH : check local address */
if (conn_checkport(addr->sin6_port))
return -1;
memcpy(&sock->l_ep, addr, sizeof(struct sockaddr_in6));
/* passive open */
sock->state = TCP_LISTEN;
return 0;
}
/* connect the socket to a remote endpoint */
int tcplib_connect(struct tcplib_sock *sock,
struct sockaddr_in6 *serv_addr) {
if (sock->tx_buf == NULL)
return -1;
switch (sock->state) {
case TCP_CLOSED:
// passive open; need to set up the local endpoint.
memset(&sock->l_ep, 0, sizeof(struct sockaddr_in6));
sock->l_ep.sin6_port = htons(alloc_local_port());
break;
case TCP_LISTEN:
// we got here by calling bind, so we're cool.
break;
default:
return -1;
}
circ_buf_init(sock->tx_buf, sock->tx_buf_len,
0xcafebabe + 1);
sock->ackno = 0;
sock->seqno = 0xcafebabe;
memcpy(&sock->r_ep, serv_addr, sizeof(struct sockaddr_in6));
tcplib_send_ack(sock, 0, TCP_FLAG_SYN);
sock->state = TCP_SYN_SENT;
sock->seqno++;
sock->timer.retx = 6;
return 0;
}
int tcplib_send(struct tcplib_sock *sock, void *data, int len) {
/* have enough tx buffer left? */
if (sock->state != TCP_ESTABLISHED)
return -1;
if (sock->seqno - circ_get_seqno(sock->tx_buf) + len > sock->tx_buf_len) // circ_get_window(sock->tx_buf))
return -1;
if (circ_buf_write(sock->tx_buf, sock->seqno, data, len) < 0)
return -1;
sock->seqno += len;
// printf("tcplib_output from send\n");
tcplib_output(sock, sock->seqno - len);
// 3 seconds
if (sock->timer.retx == 0)
sock->timer.retx = 6;
return 0;
}
void tcplib_retx_expire(struct tcplib_sock *sock) {
// printf("retransmission timer expired!\n");
sock->retxcnt++;
switch (sock->state) {
case TCP_ESTABLISHED:
if (circ_get_seqno(sock->tx_buf) != sock->seqno) {
printf("retransmitting [%u, %u]\n", circ_get_seqno(sock->tx_buf),
sock->seqno);
reset_ssthresh(sock);
// restart slow start
sock->cwnd = ONE_SEGMENT(sock);
// printf("tcplib_output from timer\n");
tcplib_output(sock, circ_get_seqno(sock->tx_buf));
sock->timer.retx = 6;
} else {
sock->retxcnt--;
}
break;
case TCP_SYN_SENT:
tcplib_send_ack(sock, 0, TCP_FLAG_SYN);
sock->timer.retx = 6;
break;
case TCP_LAST_ACK:
case TCP_FIN_WAIT_1:
tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
sock->timer.retx = 6;
break;
case TCP_TIME_WAIT:
sock->state = TCP_CLOSED;
// exit TIME_WAIT
tcplib_extern_closedone(sock);
break;
default:
break;
}
/* if we've hit this timer a lot, give up
*
* do this by going into
* TIME_WAIT, which will generate a FIN if anyone sends to us but
* otherwise just do nothing.
*
* we don't do something like try to close it here, since we might
* have gotten here from doing that.
*/
if (sock->retxcnt > TCPLIB_GIVEUP) {
sock->state = TCP_TIME_WAIT;
sock->timer.retx = TCPLIB_TIMEWAIT_LEN;
}
}
int tcplib_abort(struct tcplib_sock *sock) {
switch (sock->state) {
// nothing to abort
case TCP_CLOSED:
case TCP_LISTEN:
break;
default:
tcplib_send_ack(sock, 0, TCP_FLAG_RST);
memset(&sock->l_ep, 0, sizeof(struct sockaddr_in6));
memset(&sock->r_ep, 0, sizeof(struct sockaddr_in6));
sock->state = TCP_CLOSED;
}
return 0;
}
int tcplib_close(struct tcplib_sock *sock) {
int rc = 0;
switch (sock->state) {
/* passive close */
case TCP_CLOSE_WAIT:
tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
sock->timer.retx = 6;
sock->state = TCP_LAST_ACK;
break;
/* active close */
case TCP_ESTABLISHED:
// kick off the close
tcplib_send_ack(sock, 0, TCP_FLAG_ACK | TCP_FLAG_FIN);
sock->timer.retx = 6;
sock->state = TCP_FIN_WAIT_1;
break;
case TCP_SYN_SENT:
sock->state = TCP_CLOSED;
break;
default:
/* this is meaningless in other states */
rc = -1;
}
return rc;
}
int tcplib_timer_process() {
struct tcplib_sock *iter;
for (iter = conns; iter != NULL; iter = iter->next) {
if (iter->timer.retx > 0 && (--iter->timer.retx) == 0)
tcplib_retx_expire(iter);
if ((iter->flags & TCP_ACKPENDING) >= 2) {
tcplib_send_ack(iter, 0, TCP_FLAG_ACK);
}
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -