Basically, never retransmit, and whatever we get we immediately pass up to
the application. The only thing we do handle the TCP way is the FIN packet.
This also introduces the use of the aux entry in the header. We know that
older versions of UTCP ignore this field, and also ignore any extra data
in SYN packets, so we can add anything here in a backwards-compatible way.
+static bool is_reliable(struct utcp_connection *c) {
+ return c->flags & UTCP_RELIABLE;
+}
+
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++)
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++)
c->recv = recv;
c->priv = priv;
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;
- 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;
gettimeofday(&c->conn_timeout, NULL);
c->conn_timeout.tv_sec += utcp->timeout;
- // Add data to send buffer
+ // Exit early if we have nothing to send.
+ // Add data to send buffer.
+
len = buffer_put(&c->sndbuf, data, len);
if(len <= 0) {
errno = EWOULDBLOCK;
len = buffer_put(&c->sndbuf, data, len);
if(len <= 0) {
errno = EWOULDBLOCK;
c->snd.last += len;
ack(c, false);
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;
}
start_retransmit_timer(c);
return len;
}
static void handle_incoming_data(struct utcp_connection *c, uint32_t seq, const void *data, size_t len) {
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();
uint32_t offset = seqdiff(seq, c->rcv.nxt);
if(offset + len > c->rcvbuf.maxsize)
abort();
+ // Parse auxilliary information
+ if(hdr.aux) {
+ if(hdr.aux != 0x0101 || len < 4 || ((uint8_t *)data)[0] != 1) {
+ len = 1;
+ goto reset;
+ }
+ c->flags = ((uint8_t *)data)[3] & 0x7;
+ data += 4;
+ len -= 4;
+ } else {
+ c->flags = UTCP_TCP;
+ }
+
// Return SYN+ACK, go to SYN_RECEIVED state
c->snd.wnd = hdr.wnd;
c->rcv.irs = hdr.seq;
// Return SYN+ACK, go to SYN_RECEIVED state
c->snd.wnd = hdr.wnd;
c->rcv.irs = hdr.seq;
+ if(!len && is_reliable(c)) {
c->dupack++;
if(c->dupack == 3) {
debug("Triplicate ACK\n");
c->dupack++;
if(c->dupack == 3) {
debug("Triplicate ACK\n");
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);
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 if(is_reliable(c))
start_retransmit_timer(c);
}
start_retransmit_timer(c);
}