2 utcp.c -- Userspace TCP
3 Copyright (C) 2014 Guus Sliepen <guus@tinc-vpn.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <sys/socket.h>
35 #define PREP(l) char pkt[(l) + sizeof struct hdr]; struct hdr *hdr = &pkt;
43 uint16_t src; // Source port
44 uint16_t dst; // Destination port
45 uint32_t seq; // Sequence number
46 uint32_t ack; // Acknowledgement number
47 uint32_t wnd; // Window size
48 uint16_t ctl; // Flags (SYN, ACK, FIN, RST)
49 uint16_t aux; // other stuff
66 const char *strstate[] = {
80 struct utcp_connection {
89 // The following two structures form the TCB
110 struct timeval conn_timeout;
111 struct timeval rtrx_timeout;
117 utcp_accept_t accept;
118 utcp_pre_accept_t pre_accept;
123 struct utcp_connection **connections;
129 static void set_state(struct utcp_connection *c, enum state state) {
131 fprintf(stderr, "%p new state: %s\n", c->utcp, strstate[state]);
134 static void print_packet(void *pkt, size_t len) {
136 if(len < sizeof hdr) {
137 fprintf(stderr, "short packet (%zu bytes)\n", len);
141 memcpy(&hdr, pkt, sizeof hdr);
142 fprintf (stderr, "src=%u dst=%u seq=%u ack=%u wnd=%u ctl=", hdr.src, hdr.dst, hdr.seq, hdr.ack, hdr.wnd);
144 fprintf(stderr, "SYN");
146 fprintf(stderr, "RST");
148 fprintf(stderr, "FIN");
150 fprintf(stderr, "ACK");
152 if(len > sizeof hdr) {
153 fprintf(stderr, " data=");
154 for(int i = sizeof hdr; i < len; i++) {
156 fprintf(stderr, "%c", data[i] >= 32 ? data[i] : '.');
160 fprintf(stderr, "\n");
163 static struct utcp_connection *allocate_connection(struct utcp *utcp) {
164 struct utcp_connection *c;
166 // Initial allocation?
168 if(!utcp->nconnections) {
169 utcp->nallocated = 4;
170 utcp->nconnections = 1; // Skip 0
171 utcp->connections = calloc(utcp->nallocated, sizeof *utcp->connections);
174 // If there is a hole in the list of connections, use it.
175 // Otherwise, add a new connection to the end.
178 c = utcp->connections[utcp->gap] = calloc(1, sizeof *c);
180 while(++utcp->gap < utcp->nconnections)
181 if(!utcp->connections[utcp->gap])
184 if(utcp->gap >= utcp->nconnections)
187 // Too many connections?
189 if(utcp->nconnections >= 65536) {
194 // Need to reserve more memory?
196 if(utcp->nconnections >= utcp->nallocated) {
197 utcp->nallocated *= 2;
198 utcp->connections = realloc(utcp->connections, utcp->nallocated * sizeof *utcp->connections);
201 c = utcp->connections[utcp->nconnections] = calloc(1, sizeof *c);
202 c->src = utcp->nconnections++;
206 c->snd.una = c->snd.iss;
207 c->snd.nxt = c->snd.iss + 1;
208 c->rcv.wnd = utcp->mtu;
213 static struct utcp_connection *find_connection(struct utcp *utcp, uint16_t src) {
214 if(src < utcp->nconnections && utcp->connections[src])
215 return utcp->connections[src];
221 static void free_connection(struct utcp_connection *c) {
224 if(c->utcp->gap < 0 || c->src < c->utcp->gap)
225 c->utcp->gap = c->src;
226 c->utcp->connections[c->src] = NULL;
230 struct utcp_connection *utcp_connect(struct utcp *utcp, void *data, size_t len, utcp_recv_t recv, void *priv) {
231 struct utcp_connection *c = allocate_connection(utcp);
242 pkt.hdr.src = c->src;
244 pkt.hdr.seq = c->snd.iss;
247 pkt.hdr.wnd = c->rcv.wnd;
248 memcpy(pkt.data, data, len);
250 set_state(c, SYN_SENT);
252 utcp->send(utcp, &pkt, sizeof pkt.hdr + len);
259 void utcp_accept(struct utcp_connection *c, utcp_recv_t recv, void *priv) {
260 if(c->reapable || c->state != SYN_RECEIVED) {
261 fprintf(stderr, "Error: accept() called on invalid connection %p in state %s\n", c, strstate[c->state]);
265 fprintf(stderr, "%p accepted, %p %p\n", c, recv, priv);
268 set_state(c, ESTABLISHED);
271 int utcp_send(struct utcp_connection *c, void *data, size_t len) {
273 fprintf(stderr, "Error: send() called on closed connection %p\n", c);
283 fprintf(stderr, "Error: send() called on unconnected connection %p\n", c);
294 fprintf(stderr, "Error: send() called on closing connection %p\n", c);
304 pkt.hdr.src = c->src;
305 pkt.hdr.dst = c->dst;
306 pkt.hdr.seq = c->snd.nxt;
307 pkt.hdr.ack = c->rcv.nxt;
308 pkt.hdr.wnd = c->snd.wnd;
311 memcpy(pkt.data, data, len);
315 c->utcp->send(c->utcp, &pkt, sizeof pkt.hdr + len);
317 // Can we add it to the send window?
319 // Do we need to kick some timers?
324 static void swap_ports(struct hdr *hdr) {
325 uint16_t tmp = hdr->src;
330 int utcp_recv(struct utcp *utcp, void *data, size_t len) {
331 fprintf(stderr, "%p got: ", utcp);
332 print_packet(data, len);
335 if(len < sizeof hdr) {
340 memcpy(&hdr, data, sizeof hdr);
344 if(hdr.ctl & ~(SYN | ACK | RST | FIN)) {
349 struct utcp_connection *c = find_connection(utcp, hdr.dst);
351 // Is it for a new connection?
357 if(hdr.ctl & SYN && !(hdr.ctl & ACK) && utcp->accept && (!utcp->pre_accept || utcp->pre_accept(utcp, data, len)) && (c = allocate_connection(utcp))) { // LISTEN
359 c->snd.wnd = hdr.wnd;
360 c->rcv.irs = hdr.seq;
362 c->snd.una = c->snd.iss;
363 c->snd.nxt = c->snd.iss + 1;
364 c->rcv.nxt = c->rcv.irs + 1;
365 set_state(c, SYN_RECEIVED);
367 hdr.dst = c->dst = hdr.src;
369 hdr.ack = c->rcv.irs + 1;
370 hdr.seq = c->snd.iss;
372 utcp->send(utcp, &hdr, sizeof hdr);
380 fprintf(stderr, "%p state %s\n", c->utcp, strstate[c->state]);
382 if(c->state == CLOSED) {
383 fprintf(stderr, "Error: packet recv()d on closed connection %p\n", c);
388 // It is for an existing connection.
390 if(c->state == SYN_SENT) {
392 if(hdr.ack <= c->snd.iss || hdr.ack > c->snd.nxt) {
393 fprintf(stderr, "Invalid ACK, %u %u %u\n", hdr.ack, c->snd.iss, c->snd.nxt);
400 set_state(c, CLOSED);
401 errno = ECONNREFUSED;
407 c->rcv.nxt = hdr.seq + 1;
408 c->rcv.irs = hdr.seq;
409 c->snd.wnd = hdr.wnd;
412 c->snd.una = hdr.ack;
413 if(c->snd.una > c->snd.iss) {
414 set_state(c, ESTABLISHED);
417 hdr.seq = c->snd.nxt;
418 hdr.ack = c->rcv.nxt;
421 set_state(c, SYN_RECEIVED);
423 hdr.seq = c->snd.iss;
424 hdr.ack = c->rcv.nxt;
427 utcp->send(utcp, &hdr, sizeof hdr);
428 // TODO: queue any data?
438 acceptable = hdr.seq == c->rcv.nxt;
440 acceptable = (hdr.seq >= c->rcv.nxt && hdr.seq < c->rcv.nxt + c->rcv.wnd);
445 acceptable = (hdr.seq >= c->rcv.nxt && hdr.seq < c->rcv.nxt + c->rcv.wnd)
446 || (hdr.seq + len - 1 >= c->rcv.nxt && hdr.seq + len - 1 < c->rcv.nxt + c->rcv.wnd);
449 fprintf(stderr, "Packet not acceptable, %u %u %u %zu\n", hdr.seq, c->rcv.nxt, c->rcv.wnd, len);
455 c->snd.wnd = hdr.wnd;
457 // TODO: check whether segment really starts at rcv.nxt, otherwise trim it.
462 // TODO: delete connection?
468 set_state(c, CLOSED);
475 // TODO: delete connection?
481 set_state(c, CLOSED);
495 set_state(c, CLOSED);
511 if(hdr.ack >= c->snd.una && hdr.ack <= c->snd.nxt)
512 c->utcp->accept(c, NULL, 0);
514 if(c->state != ESTABLISHED)
519 if(hdr.ack < c->snd.una)
521 if(hdr.ack > c->snd.nxt)
523 if(hdr.ack > c->snd.una && hdr.ack <= c->snd.nxt) {
524 c->snd.una = hdr.ack;
525 if(c->snd.wl1 < hdr.seq || (c->snd.wl1 == hdr.seq && c->snd.wl2 <= hdr.ack)) {
526 c->snd.wnd = hdr.wnd;
527 c->snd.wl1 = hdr.seq;
528 c->snd.wl2 = hdr.ack;
533 if(hdr.ack == c->snd.nxt)
534 set_state(c, FIN_WAIT_2);
537 // TODO: If nothing left to send, close.
540 if(hdr.ack == c->snd.nxt) {
541 set_state(c, TIME_WAIT);
545 if(hdr.ack == c->snd.nxt) {
546 set_state(c, CLOSED);
550 // TODO: retransmission of remote FIN, ACK and restart 2 MSL timeout
562 // TODO: process the data, see page 74
581 set_state(c, CLOSE_WAIT);
585 set_state(c, CLOSING);
589 set_state(c, TIME_WAIT);
605 c->recv(c, data, len);
619 hdr.ack = hdr.seq + len;
623 utcp->send(utcp, &hdr, sizeof hdr);
628 hdr.seq = c->snd.nxt;
629 hdr.ack = c->rcv.nxt;
631 utcp->send(utcp, &hdr, sizeof hdr);
632 if(c->state == CLOSE_WAIT || c->state == TIME_WAIT) {
639 void utcp_shutdown(struct utcp_connection *c, int dir) {
641 fprintf(stderr, "Error: shutdown() called on closed connection %p\n", c);
652 set_state(c, CLOSED);
657 set_state(c, FIN_WAIT_1);
663 set_state(c, LAST_ACK);
678 hdr.seq = c->snd.nxt;
679 hdr.ack = c->rcv.nxt;
680 hdr.wnd = c->snd.wnd;
685 c->utcp->send(c->utcp, &hdr, sizeof hdr);
688 void utcp_close(struct utcp_connection *c) {
689 utcp_shutdown(c, SHUT_RDWR);
693 void utcp_abort(struct utcp_connection *c) {
695 fprintf(stderr, "Error: abort() called on closed connection %p\n", c);
709 set_state(c, CLOSED);
717 set_state(c, CLOSED);
727 hdr.seq = c->snd.nxt;
732 c->utcp->send(c->utcp, &hdr, sizeof hdr);
735 void utcp_timeout(struct utcp *utcp) {
737 gettimeofday(&now, NULL);
739 for(int i = 0; i < utcp->nconnections; i++) {
740 struct utcp_connection *c = utcp->connections[i];
745 fprintf(stderr, "Reaping %p\n", c);
750 if(c->state == CLOSED)
753 if(c->conn_timeout.tv_sec && timercmp(&c->conn_timeout, &now, <)) {
762 if(c->rtrx_timeout.tv_sec && timercmp(&c->rtrx_timeout, &now, <)) {
763 // TODO: retransmit stuff;
768 struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_send_t send, void *priv) {
769 struct utcp *utcp = calloc(1, sizeof *utcp);
773 utcp->accept = accept;
774 utcp->pre_accept = pre_accept;
783 void utcp_exit(struct utcp *utcp) {
786 for(int i = 0; i < utcp->nconnections; i++)
787 free_connection(utcp->connections[i]);