X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=utcp.c;h=f46cdf7f649f0ee4ef77b0c8ebe0a673d5f24af0;hb=0325c97f314cbab10cf9fce374598502e43341e6;hp=df2a31ec6a5f7bcad210170eace9a7dda4a78c8e;hpb=d6fd886cef9bc465c03a95e9b89f44b2810066aa;p=utcp diff --git a/utcp.c b/utcp.c index df2a31e..f46cdf7 100644 --- a/utcp.c +++ b/utcp.c @@ -130,13 +130,11 @@ static ssize_t buffer_put(struct buffer *buf, const void *data, size_t len) { if(newsize > buf->maxsize) newsize = buf->maxsize; char *newdata = realloc(buf->data, newsize); - fprintf(stderr, "%p = realloc(%p, %zu)\n", newdata, buf->data, newsize); if(!newdata) return -1; buf->data = newdata; buf->size = newsize; } - fprintf(stderr, "memcpy(%p, %p, %zu)\n", buf->data + buf->used, data, len); memcpy(buf->data + buf->used, data, len); buf->used += len; return len; @@ -442,6 +440,75 @@ static void swap_ports(struct hdr *hdr) { hdr->dst = tmp; } +static void retransmit(struct utcp_connection *c) { + if(c->state == CLOSED || c->snd.nxt == c->snd.una) + return; + + struct utcp *utcp = c->utcp; + + struct { + struct hdr hdr; + char data[]; + } *pkt; + + pkt = malloc(sizeof pkt->hdr + c->utcp->mtu); + if(!pkt) + return; + + pkt->hdr.src = c->src; + pkt->hdr.dst = c->dst; + + switch(c->state) { + case LISTEN: + // TODO: this should not happen + break; + + case SYN_SENT: + pkt->hdr.seq = c->snd.iss; + pkt->hdr.ack = 0; + pkt->hdr.wnd = c->rcv.wnd; + pkt->hdr.ctl = SYN; + print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr); + utcp->send(utcp, pkt, sizeof pkt->hdr); + break; + + case SYN_RECEIVED: + pkt->hdr.seq = c->snd.nxt; + pkt->hdr.ack = c->rcv.nxt; + pkt->hdr.ctl = SYN | ACK; + print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr); + utcp->send(utcp, pkt, sizeof pkt->hdr); + break; + + case ESTABLISHED: + case FIN_WAIT_1: + pkt->hdr.seq = c->snd.una; + pkt->hdr.ack = c->rcv.nxt; + pkt->hdr.ctl = ACK; + uint32_t len = seqdiff(c->snd.nxt, c->snd.una); + fprintf(stderr, "retransmit %u %u %u\n", pkt->hdr.seq, pkt->hdr.ack, len); + if(c->state == FIN_WAIT_1) + len--; + if(len > utcp->mtu) + len = utcp->mtu; + else { + if(c->state == FIN_WAIT_1) + pkt->hdr.ctl |= FIN; + } + buffer_copy(&c->sndbuf, pkt->data, 0, len); + print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr + len); + utcp->send(utcp, pkt, sizeof pkt->hdr + len); + break; + + default: + // TODO: implement + abort(); + } + + free(pkt); +} + + ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { if(!utcp) { errno = EFAULT; @@ -589,12 +656,13 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { #endif if(!acceptable) { - debug("Packet not acceptable, %u <= %u + %zu < %u\n", c->rcv.nxt, hdr.seq, len, c->rcv.nxt + c->rcv.wnd); + debug("Packet not acceptable, %u <= %u + %zu < %u\n", c->rcv.nxt, hdr.seq, len, c->rcv.nxt + c->rcv.wnd); // Ignore unacceptable RST packets. if(hdr.ctl & RST) return 0; // Otherwise, send an ACK back in the hope things improve. - goto ack; + ack(c, true); + return 0; } c->snd.wnd = hdr.wnd; // TODO: move below @@ -712,10 +780,14 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { } else { if(!len) { c->dupack++; - if(c->dupack >= 3) { + if(c->dupack == 3) { debug("Triplicate ACK\n"); + fprintf(stderr, "Triplicate ACK\n"); //TODO: Resend one packet and go to fast recovery mode. See RFC 6582. - //abort(); + //We do a very simple variant here; reset the nxt pointer to the last acknowledged packet from the peer. + //This will cause us to start retransmitting, but at the same speed as the incoming ACKs arrive, + //thus preventing a drop in speed. + c->snd.nxt = c->snd.una; } } } @@ -803,7 +875,6 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { rxd = c->recv(c, data, len); if(rxd != len) { // TODO: once we have a receive buffer, handle the application not accepting all data. - fprintf(stderr, "c->recv(%p, %p, %zu) returned %zd\n", c, data, len, rxd); abort(); } if(rxd < 0) @@ -933,6 +1004,8 @@ int utcp_shutdown(struct utcp_connection *c, int dir) { int utcp_close(struct utcp_connection *c) { if(utcp_shutdown(c, SHUT_RDWR)) return -1; + c->recv = NULL; + c->poll = NULL; c->reapable = true; return 0; } @@ -949,6 +1022,8 @@ int utcp_abort(struct utcp_connection *c) { return -1; } + c->recv = NULL; + c->poll = NULL; c->reapable = true; switch(c->state) { @@ -987,80 +1062,13 @@ int utcp_abort(struct utcp_connection *c) { return 0; } -static void retransmit(struct utcp_connection *c) { - if(c->state == CLOSED || c->snd.nxt == c->snd.una) - return; - - struct utcp *utcp = c->utcp; - - struct { - struct hdr hdr; - char data[]; - } *pkt; - - pkt = malloc(sizeof pkt->hdr + c->utcp->mtu); - if(!pkt) - return; - - pkt->hdr.src = c->src; - pkt->hdr.dst = c->dst; - - switch(c->state) { - case LISTEN: - // TODO: this should not happen - break; - - case SYN_SENT: - pkt->hdr.seq = c->snd.iss; - pkt->hdr.ack = 0; - pkt->hdr.wnd = c->rcv.wnd; - pkt->hdr.ctl = SYN; - print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr); - utcp->send(utcp, pkt, sizeof pkt->hdr); - break; - - case SYN_RECEIVED: - pkt->hdr.seq = c->snd.nxt; - pkt->hdr.ack = c->rcv.nxt; - pkt->hdr.ctl = SYN | ACK; - print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr); - utcp->send(utcp, pkt, sizeof pkt->hdr); - break; - - case ESTABLISHED: - case FIN_WAIT_1: - pkt->hdr.seq = c->snd.una; - pkt->hdr.ack = c->rcv.nxt; - pkt->hdr.ctl = ACK; - uint32_t len = seqdiff(c->snd.nxt, c->snd.una); - if(c->state == FIN_WAIT_1) - len--; - if(len > utcp->mtu) - len = utcp->mtu; - else { - if(c->state == FIN_WAIT_1) - pkt->hdr.ctl |= FIN; - } - buffer_copy(&c->sndbuf, pkt->data, 0, len); - print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr + len); - utcp->send(utcp, pkt, sizeof pkt->hdr + len); - break; - - default: - // TODO: implement - abort(); - } - - free(pkt); -} - /* Handle timeouts. * One call to this function will loop through all connections, * checking if something needs to be resent or not. * The return value is the time to the next timeout in milliseconds, * or maybe a negative value if the timeout is infinite. */ -int utcp_timeout(struct utcp *utcp) { +struct timeval utcp_timeout(struct utcp *utcp) { struct timeval now; gettimeofday(&now, NULL); struct timeval next = {now.tv_sec + 3600, now.tv_usec}; @@ -1110,9 +1118,7 @@ int utcp_timeout(struct utcp *utcp) { struct timeval diff; timersub(&next, &now, &diff); - if(diff.tv_sec < 0) - return 0; - return diff.tv_sec * 1000 + diff.tv_usec / 1000; + return diff; } struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_send_t send, void *priv) {