X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=utcp.c;h=f20d86e97e58bf247a782cbb34d549fcbdf63075;hb=13a73b80113568338e654aa1cb9dfb02d40b97c1;hp=b0ba05428926ba1dd11c7b91c942d27d1fae97e7;hpb=7271cf87721ab667a03f50bd40b4a8ec83b989d3;p=utcp diff --git a/utcp.c b/utcp.c index b0ba054..f20d86e 100644 --- a/utcp.c +++ b/utcp.c @@ -1,6 +1,6 @@ /* utcp.c -- Userspace TCP - Copyright (C) 2014 Guus Sliepen + Copyright (C) 2014-2017 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -69,13 +69,13 @@ static void debug(const char *format, ...) { static void print_packet(struct utcp *utcp, const char *dir, const void *pkt, size_t len) { struct hdr hdr; - if(len < sizeof hdr) { + if(len < sizeof(hdr)) { debug("%p %s: short packet (%lu bytes)\n", utcp, dir, (unsigned long)len); return; } - memcpy(&hdr, pkt, sizeof hdr); - debug("%p %s: len=%lu, src=%u dst=%u seq=%u ack=%u wnd=%u ctl=", utcp, dir, (unsigned long)len, hdr.src, hdr.dst, hdr.seq, hdr.ack, hdr.wnd); + memcpy(&hdr, pkt, sizeof(hdr)); + debug("%p %s: len=%lu, src=%u dst=%u seq=%u ack=%u wnd=%u aux=%x ctl=", utcp, dir, (unsigned long)len, hdr.src, hdr.dst, hdr.seq, hdr.ack, hdr.wnd, hdr.aux); if(hdr.ctl & SYN) debug("SYN"); if(hdr.ctl & RST) @@ -85,9 +85,9 @@ static void print_packet(struct utcp *utcp, const char *dir, const void *pkt, si if(hdr.ctl & ACK) debug("ACK"); - if(len > sizeof hdr) { - uint32_t datalen = len - sizeof hdr; - const uint8_t *data = (uint8_t *)pkt + sizeof hdr; + if(len > sizeof(hdr)) { + uint32_t datalen = len - sizeof(hdr); + const uint8_t *data = (uint8_t *)pkt + sizeof(hdr); char str[datalen * 2 + 1]; char *p = str; @@ -103,8 +103,8 @@ static void print_packet(struct utcp *utcp, const char *dir, const void *pkt, si debug("\n"); } #else -#define debug(...) -#define print_packet(...) +#define debug(...) do {} while(0) +#define print_packet(...) do {} while(0) #endif static void set_state(struct utcp_connection *c, enum state state) { @@ -127,10 +127,8 @@ static bool fin_wanted(struct utcp_connection *c, uint32_t seq) { } } -static inline void list_connections(struct utcp *utcp) { - debug("%p has %d connections:\n", utcp, utcp->nconnections); - for(int i = 0; i < utcp->nconnections; i++) - debug(" %u -> %u state %s\n", utcp->connections[i]->src, utcp->connections[i]->dst, strstate[utcp->connections[i]->state]); +static bool is_reliable(struct utcp_connection *c) { + return c->flags & UTCP_RELIABLE; } static int32_t seqdiff(uint32_t a, uint32_t b) { @@ -142,9 +140,6 @@ static int32_t seqdiff(uint32_t a, uint32_t b) { // Store data into the buffer static ssize_t buffer_put_at(struct buffer *buf, size_t offset, const void *data, size_t len) { - if(buf->maxsize <= buf->used) - return 0; - debug("buffer_put_at %lu %lu %lu\n", (unsigned long)buf->used, (unsigned long)offset, (unsigned long)len); size_t required = offset + len; @@ -206,7 +201,7 @@ static ssize_t buffer_copy(struct buffer *buf, void *data, size_t offset, size_t } static bool buffer_init(struct buffer *buf, uint32_t len, uint32_t maxlen) { - memset(buf, 0, sizeof *buf); + memset(buf, 0, sizeof(*buf)); if(len) { buf->data = malloc(len); if(!buf->data) @@ -219,7 +214,7 @@ static bool buffer_init(struct buffer *buf, uint32_t len, uint32_t maxlen) { static void buffer_exit(struct buffer *buf) { free(buf->data); - memset(buf, 0, sizeof *buf); + memset(buf, 0, sizeof(*buf)); } static uint32_t buffer_free(const struct buffer *buf) { @@ -252,18 +247,18 @@ static struct utcp_connection *find_connection(const struct utcp *utcp, uint16_t .src = src, .dst = dst, }, *keyp = &key; - struct utcp_connection **match = bsearch(&keyp, utcp->connections, utcp->nconnections, sizeof *utcp->connections, compare); + struct utcp_connection **match = bsearch(&keyp, utcp->connections, utcp->nconnections, sizeof(*utcp->connections), compare); return match ? *match : NULL; } static void free_connection(struct utcp_connection *c) { struct utcp *utcp = c->utcp; - struct utcp_connection **cp = bsearch(&c, utcp->connections, utcp->nconnections, sizeof *utcp->connections, compare); + struct utcp_connection **cp = bsearch(&c, utcp->connections, utcp->nconnections, sizeof(*utcp->connections), compare); assert(cp); int i = cp - utcp->connections; - memmove(cp, cp + 1, (utcp->nconnections - i - 1) * sizeof *cp); + memmove(cp, cp + 1, (utcp->nconnections - i - 1) * sizeof(*cp)); utcp->nconnections--; buffer_exit(&c->rcvbuf); @@ -296,13 +291,13 @@ static struct utcp_connection *allocate_connection(struct utcp *utcp, uint16_t s utcp->nallocated = 4; else utcp->nallocated *= 2; - struct utcp_connection **new_array = realloc(utcp->connections, utcp->nallocated * sizeof *utcp->connections); + struct utcp_connection **new_array = realloc(utcp->connections, utcp->nallocated * sizeof(*utcp->connections)); if(!new_array) return NULL; utcp->connections = new_array; } - struct utcp_connection *c = calloc(1, sizeof *c); + struct utcp_connection *c = calloc(1, sizeof(*c)); if(!c) return NULL; @@ -336,11 +331,18 @@ static struct utcp_connection *allocate_connection(struct utcp *utcp, uint16_t s // Add it to the sorted list of connections utcp->connections[utcp->nconnections++] = c; - qsort(utcp->connections, utcp->nconnections, sizeof *utcp->connections, compare); + qsort(utcp->connections, utcp->nconnections, sizeof(*utcp->connections), compare); return c; } +static inline uint32_t absdiff(uint32_t a, uint32_t b) { + if(a > b) + return a - b; + else + return b - a; +} + // Update RTT variables. See RFC 6298. static void update_rtt(struct utcp_connection *c, uint32_t rtt) { if(!rtt) { @@ -355,7 +357,7 @@ static void update_rtt(struct utcp_connection *c, uint32_t rtt) { utcp->rttvar = rtt / 2; utcp->rto = rtt + max(2 * rtt, CLOCK_GRANULARITY); } else { - utcp->rttvar = (utcp->rttvar * 3 + abs(utcp->srtt - rtt)) / 4; + utcp->rttvar = (utcp->rttvar * 3 + absdiff(utcp->srtt, rtt)) / 4; utcp->srtt = (utcp->srtt * 7 + rtt) / 8; utcp->rto = utcp->srtt + max(utcp->rttvar, CLOCK_GRANULARITY); } @@ -381,35 +383,51 @@ static void stop_retransmit_timer(struct utcp_connection *c) { debug("timeout cleared\n"); } -struct utcp_connection *utcp_connect(struct utcp *utcp, uint16_t dst, utcp_recv_t recv, void *priv) { +struct utcp_connection *utcp_connect_ex(struct utcp *utcp, uint16_t dst, utcp_recv_t recv, void *priv, uint32_t flags) { struct utcp_connection *c = allocate_connection(utcp, 0, dst); if(!c) return NULL; + assert((flags & ~0xf) == 0); + + c->flags = flags; c->recv = recv; c->priv = priv; - struct hdr hdr; - - hdr.src = c->src; - hdr.dst = c->dst; - hdr.seq = c->snd.iss; - hdr.ack = 0; - hdr.wnd = c->rcv.wnd; - hdr.ctl = SYN; - hdr.aux = 0; + struct { + struct hdr hdr; + uint8_t init[4]; + } pkt; + + pkt.hdr.src = c->src; + pkt.hdr.dst = c->dst; + pkt.hdr.seq = c->snd.iss; + pkt.hdr.ack = 0; + pkt.hdr.wnd = c->rcv.wnd; + pkt.hdr.ctl = SYN; + pkt.hdr.aux = 0x0101; + pkt.init[0] = 1; + pkt.init[1] = 0; + pkt.init[2] = 0; + pkt.init[3] = flags & 0x7; set_state(c, SYN_SENT); - print_packet(utcp, "send", &hdr, sizeof hdr); - utcp->send(utcp, &hdr, sizeof hdr); + print_packet(utcp, "send", &pkt, sizeof(pkt)); + utcp->send(utcp, &pkt, sizeof(pkt)); gettimeofday(&c->conn_timeout, NULL); c->conn_timeout.tv_sec += utcp->timeout; + start_retransmit_timer(c); + return c; } +struct utcp_connection *utcp_connect(struct utcp *utcp, uint16_t dst, utcp_recv_t recv, void *priv) { + return utcp_connect_ex(utcp, dst, recv, priv, UTCP_TCP); +} + void utcp_accept(struct utcp_connection *c, utcp_recv_t recv, void *priv) { if(c->reapable || c->state != SYN_RECEIVED) { debug("Error: accept() called on invalid connection %p in state %s\n", c, strstate[c->state]); @@ -440,10 +458,10 @@ static void ack(struct utcp_connection *c, bool sendatleastone) { struct { struct hdr hdr; - char data[]; + uint8_t data[]; } *pkt; - pkt = malloc(sizeof pkt->hdr + c->utcp->mtu); + pkt = malloc(sizeof(pkt->hdr) + c->utcp->mtu); if(!pkt) return; @@ -475,8 +493,8 @@ static void ack(struct utcp_connection *c, bool sendatleastone) { debug("Starting RTT measurement, expecting ack %u\n", c->rtt_seq); } - print_packet(c->utcp, "send", pkt, sizeof pkt->hdr + seglen); - c->utcp->send(c->utcp, pkt, sizeof pkt->hdr + seglen); + print_packet(c->utcp, "send", pkt, sizeof(pkt->hdr) + seglen); + c->utcp->send(c->utcp, pkt, sizeof(pkt->hdr) + seglen); } while(left); free(pkt); @@ -510,7 +528,7 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) { return -1; } - // Add data to send buffer + // Exit early if we have nothing to send. if(!len) return 0; @@ -520,6 +538,8 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) { return -1; } + // Add data to send buffer. + len = buffer_put(&c->sndbuf, data, len); if(len <= 0) { errno = EWOULDBLOCK; @@ -528,7 +548,11 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) { c->snd.last += len; ack(c, false); - if(!timerisset(&c->rtrx_timeout)) + if(!is_reliable(c)) { + c->snd.una = c->snd.nxt = c->snd.last; + buffer_get(&c->sndbuf, NULL, c->sndbuf.used); + } + if(is_reliable(c) && !timerisset(&c->rtrx_timeout)) start_retransmit_timer(c); return len; } @@ -550,10 +574,10 @@ static void retransmit(struct utcp_connection *c) { struct { struct hdr hdr; - char data[]; + uint8_t data[]; } *pkt; - pkt = malloc(sizeof pkt->hdr + c->utcp->mtu); + pkt = malloc(sizeof(pkt->hdr) + c->utcp->mtu); if(!pkt) return; @@ -568,8 +592,13 @@ static void retransmit(struct utcp_connection *c) { pkt->hdr.seq = c->snd.iss; pkt->hdr.ack = 0; pkt->hdr.ctl = SYN; - print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr); - utcp->send(utcp, pkt, sizeof pkt->hdr); + pkt->hdr.aux = 0x0101; + pkt->data[0] = 1; + pkt->data[1] = 0; + pkt->data[2] = 0; + pkt->data[3] = c->flags & 0x7; + print_packet(c->utcp, "rtrx", pkt, sizeof(pkt->hdr) + 4); + utcp->send(utcp, pkt, sizeof(pkt->hdr) + 4); break; case SYN_RECEIVED: @@ -577,8 +606,8 @@ static void retransmit(struct utcp_connection *c) { 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); + print_packet(c->utcp, "rtrx", pkt, sizeof(pkt->hdr)); + utcp->send(utcp, pkt, sizeof(pkt->hdr)); break; case ESTABLISHED: @@ -600,8 +629,8 @@ static void retransmit(struct utcp_connection *c) { c->snd.nxt = c->snd.una + len; c->snd.cwnd = utcp->mtu; // reduce cwnd on retransmit 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); + print_packet(c->utcp, "rtrx", pkt, sizeof(pkt->hdr) + len); + utcp->send(utcp, pkt, sizeof(pkt->hdr) + len); break; case CLOSED: @@ -664,7 +693,7 @@ static void sack_consume(struct utcp_connection *c, size_t len) { i++; } else { if(i < NSACKS - 1) { - memmove(&c->sacks[i], &c->sacks[i + 1], (NSACKS - 1 - i) * sizeof c->sacks[i]); + memmove(&c->sacks[i], &c->sacks[i + 1], (NSACKS - 1 - i) * sizeof(c->sacks)[i]); c->sacks[NSACKS - 1].len = 0; } else { c->sacks[i].len = 0; @@ -681,7 +710,7 @@ static void handle_out_of_order(struct utcp_connection *c, uint32_t offset, cons debug("out of order packet, offset %u\n", offset); // Packet loss or reordering occured. Store the data in the buffer. ssize_t rxd = buffer_put_at(&c->rcvbuf, offset, data, len); - if(rxd < len) + if(rxd < 0 || (size_t)rxd < len) abort(); // Make note of where we put it. @@ -695,7 +724,7 @@ static void handle_out_of_order(struct utcp_connection *c, uint32_t offset, cons if(offset + rxd < c->sacks[i].offset) { // insert before if(!c->sacks[NSACKS - 1].len) { // only if room left debug("Insert SACK entry at %d\n", i); - memmove(&c->sacks[i + 1], &c->sacks[i], (NSACKS - i - 1) * sizeof c->sacks[i]); + memmove(&c->sacks[i + 1], &c->sacks[i], (NSACKS - i - 1) * sizeof(c->sacks)[i]); c->sacks[i].offset = offset; c->sacks[i].len = rxd; } else { @@ -732,7 +761,7 @@ static void handle_in_order(struct utcp_connection *c, const void *data, size_t if(c->recv) { ssize_t rxd = c->recv(c, data, len); - if(rxd != len) { + if(rxd < 0 || (size_t)rxd != len) { // TODO: handle the application not accepting all data. abort(); } @@ -746,6 +775,12 @@ static void handle_in_order(struct utcp_connection *c, const void *data, size_t static void handle_incoming_data(struct utcp_connection *c, uint32_t seq, const void *data, size_t len) { + if(!is_reliable(c)) { + c->recv(c, data, len); + c->rcv.nxt = seq + len; + return; + } + uint32_t offset = seqdiff(seq, c->rcv.nxt); if(offset + len > c->rcvbuf.maxsize) abort(); @@ -776,16 +811,16 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { // Drop packets smaller than the header struct hdr hdr; - if(len < sizeof hdr) { + if(len < sizeof(hdr)) { errno = EBADMSG; return -1; } // Make a copy from the potentially unaligned data to a struct hdr - memcpy(&hdr, data, sizeof hdr); - data += sizeof hdr; - len -= sizeof hdr; + memcpy(&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); // Drop packets with an unknown CTL flag @@ -794,6 +829,49 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { return -1; } + // Check for auxiliary headers + + const uint8_t *init = NULL; + + uint16_t aux = hdr.aux; + while(aux) { + size_t auxlen = 4 * (aux >> 8) & 0xf; + uint8_t auxtype = aux & 0xff; + + if(len < auxlen) { + errno = EBADMSG; + return -1; + } + + switch(auxtype) { + case AUX_INIT: + if(!(hdr.ctl & SYN) || auxlen != 4) { + errno = EBADMSG; + return -1; + } + init = data; + break; + default: + errno = EBADMSG; + return -1; + } + + len -= auxlen; + data += auxlen; + + if(!(aux & 0x800)) + break; + + if(len < 2) { + errno = EBADMSG; + return -1; + } + + memcpy(&aux, data, 2); + len -= 2; + data += 2; + } + // Try to match the packet to an existing connection struct utcp_connection *c = find_connection(utcp, hdr.dst, hdr.src); @@ -822,19 +900,47 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { goto reset; } + // Parse auxilliary information + if(init) { + if(init[0] < 1) { + len = 1; + goto reset; + } + c->flags = init[3] & 0x7; + } else { + c->flags = UTCP_TCP; + } + // Return SYN+ACK, go to SYN_RECEIVED state c->snd.wnd = hdr.wnd; c->rcv.irs = hdr.seq; c->rcv.nxt = c->rcv.irs + 1; set_state(c, SYN_RECEIVED); - hdr.dst = c->dst; - hdr.src = c->src; - hdr.ack = c->rcv.irs + 1; - hdr.seq = c->snd.iss; - hdr.ctl = SYN | ACK; - print_packet(c->utcp, "send", &hdr, sizeof hdr); - utcp->send(utcp, &hdr, sizeof hdr); + struct { + struct hdr hdr; + uint8_t data[4]; + } pkt; + + pkt.hdr.src = c->src; + pkt.hdr.dst = c->dst; + pkt.hdr.ack = c->rcv.irs + 1; + pkt.hdr.seq = c->snd.iss; + pkt.hdr.wnd = c->rcv.wnd; + pkt.hdr.ctl = SYN | ACK; + if(init) { + pkt.hdr.aux = 0x0101; + pkt.data[0] = 1; + pkt.data[1] = 0; + pkt.data[2] = 0; + pkt.data[3] = c->flags & 0x7; + print_packet(c->utcp, "send", &pkt, sizeof(hdr) + 4); + utcp->send(utcp, &pkt, sizeof(hdr) + 4); + } else { + pkt.hdr.aux = 0; + print_packet(c->utcp, "send", &pkt, sizeof(hdr)); + utcp->send(utcp, &pkt, sizeof(hdr)); + } } else { // No, we don't want your packets, send a RST back len = 1; @@ -893,14 +999,15 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { // cut already accepted front overlapping if(rcv_offset < 0) { - acceptable = rcv_offset + len >= 0; + acceptable = len > (size_t)-rcv_offset; if(acceptable) { data -= rcv_offset; len += rcv_offset; + hdr.seq -= rcv_offset; } + } else { + acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0 && seqdiff(hdr.seq, c->rcv.nxt) + len <= c->rcvbuf.maxsize; } - - acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0 && seqdiff(hdr.seq, c->rcv.nxt) + len <= c->rcvbuf.maxsize; } if(!acceptable) { @@ -908,9 +1015,8 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { // Ignore unacceptable RST packets. if(hdr.ctl & RST) return 0; - // Otherwise, send an ACK back in the hope things improve. - ack(c, true); - return 0; + // Otherwise, continue processing. + len = 0; } c->snd.wnd = hdr.wnd; // TODO: move below @@ -980,6 +1086,9 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { } } + if(!(hdr.ctl & ACK)) + goto skip_ack; + // 3. Advance snd.una uint32_t advanced = seqdiff(hdr.ack, c->snd.una); @@ -1048,7 +1157,7 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { break; } } else { - if(!len) { + if(!len && is_reliable(c)) { c->dupack++; if(c->dupack == 3) { debug("Triplicate ACK\n"); @@ -1068,10 +1177,11 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { timerclear(&c->conn_timeout); // It will be set anew in utcp_timeout() if c->snd.una != c->snd.nxt. if(c->snd.una == c->snd.last) stop_retransmit_timer(c); - else + else if(is_reliable(c)) start_retransmit_timer(c); } +skip_ack: // 5. Process SYN stuff if(hdr.ctl & SYN) { @@ -1094,7 +1204,7 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { case LAST_ACK: case TIME_WAIT: // Ehm, no. We should never receive a second SYN. - goto reset; + return 0; default: #ifdef UTCP_DEBUG abort(); @@ -1211,6 +1321,7 @@ ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) { reset: swap_ports(&hdr); hdr.wnd = 0; + hdr.aux = 0; if(hdr.ctl & ACK) { hdr.seq = hdr.ack; hdr.ctl = RST; @@ -1219,8 +1330,8 @@ reset: hdr.seq = 0; hdr.ctl = RST | ACK; } - print_packet(utcp, "send", &hdr, sizeof hdr); - utcp->send(utcp, &hdr, sizeof hdr); + print_packet(utcp, "send", &hdr, sizeof(hdr)); + utcp->send(utcp, &hdr, sizeof(hdr)); return 0; } @@ -1343,8 +1454,8 @@ int utcp_abort(struct utcp_connection *c) { hdr.wnd = 0; hdr.ctl = RST; - print_packet(c->utcp, "send", &hdr, sizeof hdr); - c->utcp->send(c->utcp, &hdr, sizeof hdr); + print_packet(c->utcp, "send", &hdr, sizeof(hdr)); + c->utcp->send(c->utcp, &hdr, sizeof(hdr)); return 0; } @@ -1387,8 +1498,15 @@ struct timeval utcp_timeout(struct utcp *utcp) { retransmit(c); } - if(c->poll && buffer_free(&c->sndbuf) && (c->state == ESTABLISHED || c->state == CLOSE_WAIT)) - c->poll(c, buffer_free(&c->sndbuf)); + if(c->poll) { + if((c->state == ESTABLISHED || c->state == CLOSE_WAIT)) { + uint32_t len = buffer_free(&c->sndbuf); + if(len) + c->poll(c, len); + } else if(c->state == CLOSED) { + c->poll(c, 0); + } + } if(timerisset(&c->conn_timeout) && timercmp(&c->conn_timeout, &next, <)) next = c->conn_timeout; @@ -1419,7 +1537,7 @@ struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_ return NULL; } - struct utcp *utcp = calloc(1, sizeof *utcp); + struct utcp *utcp = calloc(1, sizeof(*utcp)); if(!utcp) return NULL; @@ -1438,11 +1556,13 @@ void utcp_exit(struct utcp *utcp) { if(!utcp) return; for(int i = 0; i < utcp->nconnections; i++) { - if(!utcp->connections[i]->reapable) - debug("Warning, freeing unclosed connection %p\n", utcp->connections[i]); - buffer_exit(&utcp->connections[i]->rcvbuf); - buffer_exit(&utcp->connections[i]->sndbuf); - free(utcp->connections[i]); + struct utcp_connection *c = utcp->connections[i]; + if(!c->reapable) + if(c->recv) + c->recv(c, NULL, 0); + buffer_exit(&c->rcvbuf); + buffer_exit(&c->sndbuf); + free(c); } free(utcp->connections); free(utcp); @@ -1458,6 +1578,22 @@ void utcp_set_mtu(struct utcp *utcp, uint16_t mtu) { utcp->mtu = mtu; } +void utcp_reset_timers(struct utcp *utcp) { + if(!utcp) + return; + struct timeval now, then; + gettimeofday(&now, NULL); + then = now; + then.tv_sec += utcp->timeout; + for(int i = 0; i < utcp->nconnections; i++) { + utcp->connections[i]->rtrx_timeout = now; + utcp->connections[i]->conn_timeout = then; + utcp->connections[i]->rtt_start.tv_sec = 0; + } + if(utcp->rto > START_RTO) + utcp->rto = START_RTO; +} + int utcp_get_user_timeout(struct utcp *u) { return u ? u->timeout : 0; }