+ uint32_t offset = seqdiff(hdr->seq, c->rcv.nxt);
+
+ if(offset) {
+ handle_out_of_order(c, offset, data, len);
+ } else {
+ handle_in_order(c, data, len);
+ }
+}
+
+
+ssize_t utcp_recv(struct utcp *utcp, const void *data, size_t len) {
+ const uint8_t *ptr = data;
+
+ if(!utcp) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if(!len) {
+ return 0;
+ }
+
+ if(!data) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ // Drop packets smaller than the header
+
+ struct hdr hdr;
+
+ if(len < sizeof(hdr)) {
+ print_packet(NULL, "recv", data, len);
+ errno = EBADMSG;
+ return -1;
+ }
+
+ // Make a copy from the potentially unaligned data to a struct hdr
+
+ memcpy(&hdr, ptr, sizeof(hdr));
+
+ // Try to match the packet to an existing connection
+
+ struct utcp_connection *c = find_connection(utcp, hdr.dst, hdr.src);
+ print_packet(c, "recv", data, len);
+
+ // Process the header
+
+ ptr += sizeof(hdr);
+ len -= sizeof(hdr);
+
+ // Drop packets with an unknown CTL flag
+
+ if(hdr.ctl & ~(SYN | ACK | RST | FIN | MF)) {
+ print_packet(NULL, "recv", data, len);
+ errno = EBADMSG;
+ 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 = ptr;
+ break;
+
+ default:
+ errno = EBADMSG;
+ return -1;
+ }
+
+ len -= auxlen;
+ ptr += auxlen;
+
+ if(!(aux & 0x800)) {
+ break;
+ }
+
+ if(len < 2) {
+ errno = EBADMSG;
+ return -1;
+ }
+
+ memcpy(&aux, ptr, 2);
+ len -= 2;
+ ptr += 2;
+ }
+
+ bool has_data = len || (hdr.ctl & (SYN | FIN));
+
+ // Is it for a new connection?
+
+ if(!c) {
+ // Ignore RST packets
+
+ if(hdr.ctl & RST) {
+ return 0;
+ }
+
+ // Is it a SYN packet and are we LISTENing?
+
+ if(hdr.ctl & SYN && !(hdr.ctl & ACK) && utcp->accept) {
+ // If we don't want to accept it, send a RST back
+ if((utcp->pre_accept && !utcp->pre_accept(utcp, hdr.dst))) {
+ len = 1;
+ goto reset;
+ }
+
+ // Try to allocate memory, otherwise send a RST back
+ c = allocate_connection(utcp, hdr.dst, hdr.src);
+
+ if(!c) {
+ len = 1;
+ 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;
+ }
+
+synack:
+ // 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);
+
+ 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->rcvbuf.maxsize;
+ 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, "send", &pkt, sizeof(hdr) + 4);
+ utcp->send(utcp, &pkt, sizeof(hdr) + 4);
+ } else {
+ pkt.hdr.aux = 0;
+ print_packet(c, "send", &pkt, sizeof(hdr));
+ utcp->send(utcp, &pkt, sizeof(hdr));
+ }
+
+ start_retransmit_timer(c);
+ } else {
+ // No, we don't want your packets, send a RST back
+ len = 1;
+ goto reset;
+ }
+
+ return 0;
+ }
+
+ debug(c, "state %s\n", strstate[c->state]);
+
+ // In case this is for a CLOSED connection, ignore the packet.
+ // TODO: make it so incoming packets can never match a CLOSED connection.
+
+ if(c->state == CLOSED) {
+ debug(c, "got packet for closed connection\n");
+ return 0;
+ }
+
+ // It is for an existing connection.
+
+ // 1. Drop invalid packets.
+
+ // 1a. Drop packets that should not happen in our current state.
+
+ switch(c->state) {
+ case SYN_SENT:
+ case SYN_RECEIVED:
+ case ESTABLISHED:
+ case FIN_WAIT_1:
+ case FIN_WAIT_2:
+ case CLOSE_WAIT:
+ case CLOSING:
+ case LAST_ACK:
+ case TIME_WAIT:
+ break;
+
+ default:
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ break;
+ }
+
+ // 1b. Discard data that is not in our receive window.
+
+ if(is_reliable(c)) {
+ bool acceptable;
+
+ if(c->state == SYN_SENT) {
+ acceptable = true;
+ } else if(len == 0) {
+ acceptable = seqdiff(hdr.seq, c->rcv.nxt) >= 0;
+ } else {
+ int32_t rcv_offset = seqdiff(hdr.seq, c->rcv.nxt);
+
+ // cut already accepted front overlapping
+ if(rcv_offset < 0) {
+ acceptable = len > (size_t) - rcv_offset;
+
+ if(acceptable) {
+ ptr -= 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;
+ }
+ }
+
+ if(!acceptable) {
+ debug(c, "packet not acceptable, %u <= %u + %lu < %u\n", c->rcv.nxt, hdr.seq, (unsigned long)len, c->rcv.nxt + c->rcvbuf.maxsize);
+
+ // Ignore unacceptable RST packets.
+ if(hdr.ctl & RST) {
+ return 0;
+ }
+
+ // Otherwise, continue processing.
+ len = 0;
+ }
+ } else {
+#if UTCP_DEBUG
+ int32_t rcv_offset = seqdiff(hdr.seq, c->rcv.nxt);
+
+ if(rcv_offset) {
+ debug(c, "packet out of order, offset %u bytes", rcv_offset);
+ }
+
+#endif
+ }
+
+ c->snd.wnd = hdr.wnd; // TODO: move below
+
+ // 1c. Drop packets with an invalid ACK.
+ // ackno should not roll back, and it should also not be bigger than what we ever could have sent
+ // (= snd.una + c->sndbuf.used).
+
+ if(!is_reliable(c)) {
+ if(hdr.ack != c->snd.last && c->state >= ESTABLISHED) {
+ hdr.ack = c->snd.una;
+ }
+ }
+
+ if(hdr.ctl & ACK && (seqdiff(hdr.ack, c->snd.last) > 0 || seqdiff(hdr.ack, c->snd.una) < 0)) {
+ debug(c, "packet ack seqno out of range, %u <= %u < %u\n", c->snd.una, hdr.ack, c->snd.una + c->sndbuf.used);
+
+ // Ignore unacceptable RST packets.
+ if(hdr.ctl & RST) {
+ return 0;
+ }
+
+ goto reset;
+ }
+
+ // 2. Handle RST packets
+
+ if(hdr.ctl & RST) {
+ switch(c->state) {
+ case SYN_SENT:
+ if(!(hdr.ctl & ACK)) {
+ return 0;
+ }
+
+ // The peer has refused our connection.
+ set_state(c, CLOSED);
+ errno = ECONNREFUSED;
+
+ if(c->recv) {
+ c->recv(c, NULL, 0);
+ }
+
+ if(c->poll && !c->reapable) {
+ c->poll(c, 0);
+ }
+
+ return 0;
+
+ case SYN_RECEIVED:
+ if(hdr.ctl & ACK) {
+ return 0;
+ }
+
+ // We haven't told the application about this connection yet. Silently delete.
+ free_connection(c);
+ return 0;
+
+ case ESTABLISHED:
+ case FIN_WAIT_1:
+ case FIN_WAIT_2:
+ case CLOSE_WAIT:
+ if(hdr.ctl & ACK) {
+ return 0;
+ }
+
+ // The peer has aborted our connection.
+ set_state(c, CLOSED);
+ errno = ECONNRESET;
+
+ if(c->recv) {
+ c->recv(c, NULL, 0);
+ }
+
+ if(c->poll && !c->reapable) {
+ c->poll(c, 0);
+ }
+
+ return 0;
+
+ case CLOSING:
+ case LAST_ACK:
+ case TIME_WAIT:
+ if(hdr.ctl & ACK) {
+ return 0;
+ }
+
+ // As far as the application is concerned, the connection has already been closed.
+ // If it has called utcp_close() already, we can immediately free this connection.
+ if(c->reapable) {
+ free_connection(c);
+ return 0;
+ }
+
+ // Otherwise, immediately move to the CLOSED state.
+ set_state(c, CLOSED);
+ return 0;
+
+ default:
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ break;
+ }
+ }
+
+ uint32_t advanced;
+
+ if(!(hdr.ctl & ACK)) {
+ advanced = 0;
+ goto skip_ack;
+ }
+
+ // 3. Advance snd.una
+
+ advanced = seqdiff(hdr.ack, c->snd.una);
+
+ if(advanced) {
+ // RTT measurement
+ if(c->rtt_start.tv_sec) {
+ if(c->rtt_seq == hdr.ack) {
+ struct timespec now;
+ clock_gettime(UTCP_CLOCK, &now);
+ int32_t diff = timespec_diff_usec(&now, &c->rtt_start);
+ update_rtt(c, diff);
+ c->rtt_start.tv_sec = 0;
+ } else if(c->rtt_seq < hdr.ack) {
+ debug(c, "cancelling RTT measurement: %u < %u\n", c->rtt_seq, hdr.ack);
+ c->rtt_start.tv_sec = 0;
+ }
+ }
+
+ int32_t data_acked = advanced;
+
+ switch(c->state) {
+ case SYN_SENT:
+ case SYN_RECEIVED:
+ data_acked--;
+ break;
+
+ // TODO: handle FIN as well.
+ default:
+ break;
+ }
+
+ assert(data_acked >= 0);
+
+#ifndef NDEBUG
+ int32_t bufused = seqdiff(c->snd.last, c->snd.una);
+ assert(data_acked <= bufused);
+#endif
+
+ if(data_acked) {
+ buffer_discard(&c->sndbuf, data_acked);
+
+ if(is_reliable(c)) {
+ c->do_poll = true;
+ }
+ }
+
+ // Also advance snd.nxt if possible
+ if(seqdiff(c->snd.nxt, hdr.ack) < 0) {
+ c->snd.nxt = hdr.ack;
+ }
+
+ c->snd.una = hdr.ack;
+
+ if(c->dupack) {
+ if(c->dupack >= 3) {
+ debug(c, "fast recovery ended\n");
+ c->snd.cwnd = c->snd.ssthresh;
+ }
+
+ c->dupack = 0;
+ }
+
+ // Increase the congestion window according to RFC 5681
+ if(c->snd.cwnd < c->snd.ssthresh) {
+ c->snd.cwnd += min(advanced, utcp->mss); // eq. 2
+ } else {
+ c->snd.cwnd += max(1, (utcp->mss * utcp->mss) / c->snd.cwnd); // eq. 3
+ }
+
+ if(c->snd.cwnd > c->sndbuf.maxsize) {
+ c->snd.cwnd = c->sndbuf.maxsize;
+ }
+
+ debug_cwnd(c);
+
+ // Check if we have sent a FIN that is now ACKed.
+ switch(c->state) {
+ case FIN_WAIT_1:
+ if(c->snd.una == c->snd.last) {
+ set_state(c, FIN_WAIT_2);
+ }
+
+ break;
+
+ case CLOSING:
+ if(c->snd.una == c->snd.last) {
+ clock_gettime(UTCP_CLOCK, &c->conn_timeout);
+ c->conn_timeout.tv_sec += utcp->timeout;
+ set_state(c, TIME_WAIT);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ if(!len && is_reliable(c) && c->snd.una != c->snd.last) {
+ c->dupack++;
+ debug(c, "duplicate ACK %d\n", c->dupack);
+
+ if(c->dupack == 3) {
+ // RFC 5681 fast recovery
+ debug(c, "fast recovery started\n", c->dupack);
+ uint32_t flightsize = seqdiff(c->snd.nxt, c->snd.una);
+ c->snd.ssthresh = max(flightsize / 2, utcp->mss * 2); // eq. 4
+ c->snd.cwnd = min(c->snd.ssthresh + 3 * utcp->mss, c->sndbuf.maxsize);
+
+ if(c->snd.cwnd > c->sndbuf.maxsize) {
+ c->snd.cwnd = c->sndbuf.maxsize;
+ }
+
+ debug_cwnd(c);
+
+ fast_retransmit(c);
+ } else if(c->dupack > 3) {
+ c->snd.cwnd += utcp->mss;
+
+ if(c->snd.cwnd > c->sndbuf.maxsize) {
+ c->snd.cwnd = c->sndbuf.maxsize;
+ }
+
+ debug_cwnd(c);
+ }
+
+ // We got an ACK which indicates the other side did get one of our packets.
+ // Reset the retransmission timer to avoid going to slow start,
+ // but don't touch the connection timeout.
+ start_retransmit_timer(c);
+ }
+ }
+
+ // 4. Update timers
+
+ if(advanced) {
+ if(c->snd.una == c->snd.last) {
+ stop_retransmit_timer(c);
+ timespec_clear(&c->conn_timeout);
+ } else if(is_reliable(c)) {
+ start_retransmit_timer(c);
+ clock_gettime(UTCP_CLOCK, &c->conn_timeout);
+ c->conn_timeout.tv_sec += utcp->timeout;
+ }
+ }
+
+skip_ack:
+ // 5. Process SYN stuff
+
+ if(hdr.ctl & SYN) {
+ switch(c->state) {
+ case SYN_SENT:
+
+ // This is a SYNACK. It should always have ACKed the SYN.
+ if(!advanced) {
+ goto reset;
+ }
+
+ c->rcv.irs = hdr.seq;
+ c->rcv.nxt = hdr.seq + 1;
+
+ if(c->shut_wr) {
+ c->snd.last++;
+ set_state(c, FIN_WAIT_1);
+ } else {
+ set_state(c, ESTABLISHED);
+ }
+
+ break;
+
+ case SYN_RECEIVED:
+ // This is a retransmit of a SYN, send back the SYNACK.
+ goto synack;
+
+ case ESTABLISHED:
+ case FIN_WAIT_1:
+ case FIN_WAIT_2:
+ case CLOSE_WAIT:
+ case CLOSING:
+ case LAST_ACK:
+ case TIME_WAIT:
+ // This could be a retransmission. Ignore the SYN flag, but send an ACK back.
+ break;
+
+ default:
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ return 0;
+ }
+ }
+
+ // 6. Process new data
+
+ if(c->state == SYN_RECEIVED) {
+ // This is the ACK after the SYNACK. It should always have ACKed the SYNACK.
+ if(!advanced) {
+ goto reset;
+ }
+
+ // Are we still LISTENing?
+ if(utcp->accept) {
+ utcp->accept(c, c->src);
+ }
+
+ if(c->state != ESTABLISHED) {
+ set_state(c, CLOSED);
+ c->reapable = true;
+ goto reset;
+ }
+ }
+
+ if(len) {
+ switch(c->state) {
+ case SYN_SENT:
+ case SYN_RECEIVED:
+ // This should never happen.
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ return 0;
+
+ case ESTABLISHED:
+ case FIN_WAIT_1:
+ case FIN_WAIT_2:
+ break;
+
+ case CLOSE_WAIT:
+ case CLOSING:
+ case LAST_ACK:
+ case TIME_WAIT:
+ // Ehm no, We should never receive more data after a FIN.
+ goto reset;
+
+ default:
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ return 0;
+ }
+
+ handle_incoming_data(c, &hdr, ptr, len);
+ }
+
+ // 7. Process FIN stuff
+
+ if((hdr.ctl & FIN) && (!is_reliable(c) || hdr.seq + len == c->rcv.nxt)) {
+ switch(c->state) {
+ case SYN_SENT:
+ case SYN_RECEIVED:
+ // This should never happen.
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ break;
+
+ case ESTABLISHED:
+ set_state(c, CLOSE_WAIT);
+ break;
+
+ case FIN_WAIT_1:
+ set_state(c, CLOSING);
+ break;
+
+ case FIN_WAIT_2:
+ clock_gettime(UTCP_CLOCK, &c->conn_timeout);
+ c->conn_timeout.tv_sec += utcp->timeout;
+ set_state(c, TIME_WAIT);
+ break;
+
+ case CLOSE_WAIT:
+ case CLOSING:
+ case LAST_ACK:
+ case TIME_WAIT:
+ // Ehm, no. We should never receive a second FIN.
+ goto reset;
+
+ default:
+#ifdef UTCP_DEBUG
+ abort();
+#endif
+ break;
+ }
+
+ // FIN counts as one sequence number
+ c->rcv.nxt++;
+ len++;
+
+ // Inform the application that the peer closed its end of the connection.
+ if(c->recv) {
+ errno = 0;
+ c->recv(c, NULL, 0);
+ }
+ }
+
+ // Now we send something back if:
+ // - we received data, so we have to send back an ACK
+ // -> sendatleastone = true
+ // - or we got an ack, so we should maybe send a bit more data
+ // -> sendatleastone = false
+
+ if(is_reliable(c) || hdr.ctl & SYN || hdr.ctl & FIN) {
+ ack(c, has_data);
+ }
+
+ return 0;
+
+reset:
+ swap_ports(&hdr);
+ hdr.wnd = 0;
+ hdr.aux = 0;
+
+ if(hdr.ctl & ACK) {
+ hdr.seq = hdr.ack;
+ hdr.ctl = RST;
+ } else {
+ hdr.ack = hdr.seq + len;
+ hdr.seq = 0;
+ hdr.ctl = RST | ACK;
+ }
+
+ print_packet(c, "send", &hdr, sizeof(hdr));
+ utcp->send(utcp, &hdr, sizeof(hdr));
+ return 0;
+
+}
+
+int utcp_shutdown(struct utcp_connection *c, int dir) {
+ debug(c, "shutdown %d at %u\n", dir, c ? c->snd.last : 0);
+
+ if(!c) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if(c->reapable) {
+ debug(c, "shutdown() called on closed connection\n");