]> git.meshlink.io Git - utcp/blob - utcp.c
Start of UTCP.
[utcp] / utcp.c
1 /*
2     utcp.c -- Userspace TCP
3     Copyright (C) 2014 Guus Sliepen <guus@tinc-vpn.org>
4
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.
9
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.
14
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.
18 */
19
20 #define _GNU_SOURCE
21
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/time.h>
30 #include <sys/socket.h>
31
32 #define UTCP_INTERNAL
33 #include "utcp.h"
34
35 #define PREP(l) char pkt[(l) + sizeof struct hdr]; struct hdr *hdr = &pkt;
36
37 #define SYN 1
38 #define ACK 2
39 #define FIN 4
40 #define RST 8
41
42 struct hdr {
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
50 };
51
52 enum state {
53         CLOSED,
54         LISTEN,
55         SYN_SENT,
56         SYN_RECEIVED,
57         ESTABLISHED,
58         FIN_WAIT_1,
59         FIN_WAIT_2,
60         CLOSE_WAIT,
61         CLOSING,
62         LAST_ACK,
63         TIME_WAIT
64 };
65
66 const char *strstate[] = {
67         "CLOSED",
68         "LISTEN",
69         "SYN_SENT",
70         "SYN_RECEIVED",
71         "ESTABLISHED",
72         "FIN_WAIT_1",
73         "FIN_WAIT_2",
74         "CLOSE_WAIT",
75         "CLOSING",
76         "LAST_ACK",
77         "TIME_WAIT"
78 };
79
80 struct utcp_connection {
81         void *priv;
82         struct utcp *utcp;
83         bool reapable;
84
85         uint16_t src;
86         uint16_t dst;
87         enum state state;
88
89         // The following two structures form the TCB
90
91         struct {
92                 uint32_t una;
93                 uint32_t nxt;
94                 uint32_t wnd;
95                 uint32_t up;
96                 uint32_t wl1;
97                 uint32_t wl2;
98                 uint32_t iss;
99         } snd;
100
101         struct {
102                 uint32_t nxt;
103                 uint32_t wnd;
104                 uint32_t up;
105                 uint32_t irs;
106         } rcv;
107
108         utcp_recv_t recv;
109
110         struct timeval conn_timeout;
111         struct timeval rtrx_timeout;
112 };
113
114 struct utcp {
115         void *priv;
116
117         utcp_accept_t accept;
118         utcp_pre_accept_t pre_accept;
119         utcp_send_t send;
120
121         uint16_t mtu;
122
123         struct utcp_connection **connections;
124         int nconnections;
125         int nallocated;
126         int gap;
127 };
128
129 static void set_state(struct utcp_connection *c, enum state state) {
130         c->state = state;
131         fprintf(stderr, "%p new state: %s\n", c->utcp, strstate[state]);
132 }
133
134 static void print_packet(void *pkt, size_t len) {
135         struct hdr hdr;
136         if(len < sizeof hdr) {
137                 fprintf(stderr, "short packet (%zu bytes)\n", len);
138                 return;
139         }
140
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);
143         if(hdr.ctl & SYN)
144                 fprintf(stderr, "SYN");
145         if(hdr.ctl & RST)
146                 fprintf(stderr, "RST");
147         if(hdr.ctl & FIN)
148                 fprintf(stderr, "FIN");
149         if(hdr.ctl & ACK)
150                 fprintf(stderr, "ACK");
151
152         if(len > sizeof hdr) {
153                 fprintf(stderr, " data=");
154                 for(int i = sizeof hdr; i < len; i++) {
155                         char *data = pkt;
156                         fprintf(stderr, "%c", data[i] >= 32 ? data[i] : '.');
157                 }
158         }
159
160         fprintf(stderr, "\n");
161 }
162
163 static struct utcp_connection *allocate_connection(struct utcp *utcp) {
164         struct utcp_connection *c;
165
166         // Initial allocation?
167
168         if(!utcp->nconnections) {
169                 utcp->nallocated = 4;
170                 utcp->nconnections = 1; // Skip 0
171                 utcp->connections = calloc(utcp->nallocated, sizeof *utcp->connections);
172         }
173
174         // If there is a hole in the list of connections, use it.
175         // Otherwise, add a new connection to the end.
176
177         if(utcp->gap >= 0) {
178                 c = utcp->connections[utcp->gap] = calloc(1, sizeof *c);
179                 c->src = utcp->gap;
180                 while(++utcp->gap < utcp->nconnections)
181                         if(!utcp->connections[utcp->gap])
182                                 break;
183
184                 if(utcp->gap >= utcp->nconnections)
185                         utcp->gap = -1;
186         } else {
187                 // Too many connections?
188
189                 if(utcp->nconnections >= 65536) {
190                         errno = ENOMEM;
191                         return NULL;
192                 }
193
194                 // Need to reserve more memory?
195
196                 if(utcp->nconnections >= utcp->nallocated) {
197                         utcp->nallocated *= 2;
198                         utcp->connections = realloc(utcp->connections, utcp->nallocated * sizeof *utcp->connections);
199                 }
200
201                 c = utcp->connections[utcp->nconnections] = calloc(1, sizeof *c);
202                 c->src = utcp->nconnections++;
203         }
204
205         c->snd.iss = rand();
206         c->snd.una = c->snd.iss;
207         c->snd.nxt = c->snd.iss + 1;
208         c->rcv.wnd = utcp->mtu;
209         c->utcp = utcp;
210         return c;
211 }
212
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];
216
217         errno = EINVAL;
218         return NULL;
219 }
220
221 static void free_connection(struct utcp_connection *c) {
222         if(!c)
223                 return;
224         if(c->utcp->gap < 0 || c->src < c->utcp->gap)
225                 c->utcp->gap = c->src;
226         c->utcp->connections[c->src] = NULL;
227         free(c);
228 }
229
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);
232         if(!c)
233                 return NULL;
234
235         c->recv = recv;
236
237         struct {
238                 struct hdr hdr;
239                 char data[len];
240         } pkt;
241
242         pkt.hdr.src = c->src;
243         pkt.hdr.dst = 0;
244         pkt.hdr.seq = c->snd.iss;
245         pkt.hdr.ack = 0;
246         pkt.hdr.ctl = SYN;
247         pkt.hdr.wnd = c->rcv.wnd;
248         memcpy(pkt.data, data, len);
249
250         set_state(c, SYN_SENT);
251
252         utcp->send(utcp, &pkt, sizeof pkt.hdr + len);
253
254         // Set timeout?
255
256         return c;
257 }
258
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]);
262                 return;
263         }
264
265         fprintf(stderr, "%p accepted, %p %p\n", c, recv, priv);
266         c->recv = recv;
267         c->priv = priv;
268         set_state(c, ESTABLISHED);
269 }
270
271 int utcp_send(struct utcp_connection *c, void *data, size_t len) {
272         if(c->reapable) {
273                 fprintf(stderr, "Error: send() called on closed connection %p\n", c);
274                 errno = EBADF;
275                 return -1;
276         }
277
278         switch(c->state) {
279         case CLOSED:
280         case LISTEN:
281         case SYN_SENT:
282         case SYN_RECEIVED:
283                 fprintf(stderr, "Error: send() called on unconnected connection %p\n", c);
284                 errno = ENOTCONN;
285                 return -1;
286         case ESTABLISHED:
287         case CLOSE_WAIT:
288                 break;
289         case FIN_WAIT_1:
290         case FIN_WAIT_2:
291         case CLOSING:
292         case LAST_ACK:
293         case TIME_WAIT:
294                 fprintf(stderr, "Error: send() called on closing connection %p\n", c);
295                 errno = EPIPE;
296                 return -1;
297         }
298         
299         struct {
300                 struct hdr hdr;
301                 char data[len];
302         } pkt;
303
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;
309         pkt.hdr.ctl = ACK;
310
311         memcpy(pkt.data, data, len);
312
313         c->snd.nxt += len;
314
315         c->utcp->send(c->utcp, &pkt, sizeof pkt.hdr + len);
316         //
317         // Can we add it to the send window?
318         
319         // Do we need to kick some timers?
320         
321         return 0;
322 }
323
324 static void swap_ports(struct hdr *hdr) {
325         uint16_t tmp = hdr->src;
326         hdr->src = hdr->dst;
327         hdr->dst = tmp;
328 }
329
330 int utcp_recv(struct utcp *utcp, void *data, size_t len) {
331         fprintf(stderr, "%p got: ", utcp);
332         print_packet(data, len);
333
334         struct hdr hdr;
335         if(len < sizeof hdr) {
336                 errno = EBADMSG;
337                 return -1;
338         }
339
340         memcpy(&hdr, data, sizeof hdr);
341         data += sizeof hdr;
342         len -= sizeof hdr;
343
344         if(hdr.ctl & ~(SYN | ACK | RST | FIN)) {
345                 errno = EBADMSG;
346                 return -1;
347         }
348
349         struct utcp_connection *c = find_connection(utcp, hdr.dst);
350
351         // Is it for a new connection?
352
353         if(!c) {
354                 if(hdr.ctl & RST)
355                         return 0;
356
357                 if(hdr.ctl & SYN && !(hdr.ctl & ACK) && utcp->accept && (!utcp->pre_accept || utcp->pre_accept(utcp, data, len)) && (c = allocate_connection(utcp))) { // LISTEN
358                         // Return SYN+ACK
359                         c->snd.wnd = hdr.wnd;
360                         c->rcv.irs = hdr.seq;
361                         c->snd.iss = rand();
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);
366
367                         hdr.dst = c->dst = hdr.src;
368                         hdr.src = c->src;
369                         hdr.ack = c->rcv.irs + 1;
370                         hdr.seq = c->snd.iss;
371                         hdr.ctl = SYN | ACK;
372                         utcp->send(utcp, &hdr, sizeof hdr);
373                         return 0;
374                 } else { // CLOSED
375                         len = 1;
376                         goto reset;
377                 }
378         }
379
380         fprintf(stderr, "%p state %s\n", c->utcp, strstate[c->state]);
381
382         if(c->state == CLOSED) {
383                 fprintf(stderr, "Error: packet recv()d on closed connection %p\n", c);
384                 errno = EBADF;
385                 return -1;
386         }
387
388         // It is for an existing connection.
389         
390         if(c->state == SYN_SENT) {
391                 if(hdr.ctl & ACK) {
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);
394                                 goto reset;
395                         }
396                 }
397                 if(hdr.ctl & RST) {
398                         if(!(hdr.ctl & ACK))
399                                 return 0;
400                         set_state(c, CLOSED);
401                         errno = ECONNREFUSED;
402                         c->recv(c, NULL, 0);
403                         return 0;
404                 }
405                 if(hdr.ctl & SYN) {
406                         c->dst = hdr.src;
407                         c->rcv.nxt = hdr.seq + 1;
408                         c->rcv.irs = hdr.seq;
409                         c->snd.wnd = hdr.wnd;
410
411                         if(hdr.ctl & ACK)
412                                 c->snd.una = hdr.ack;
413                         if(c->snd.una > c->snd.iss) {
414                                 set_state(c, ESTABLISHED);
415                                 // TODO: signal app?
416                                 swap_ports(&hdr);
417                                 hdr.seq = c->snd.nxt;
418                                 hdr.ack = c->rcv.nxt;
419                                 hdr.ctl = ACK;
420                         } else {
421                                 set_state(c, SYN_RECEIVED);
422                                 swap_ports(&hdr);
423                                 hdr.seq = c->snd.iss;
424                                 hdr.ack = c->rcv.nxt;
425                                 hdr.ctl = SYN | ACK;
426                         }
427                         utcp->send(utcp, &hdr, sizeof hdr);
428                         // TODO: queue any data?
429                 }
430
431                 return 0;
432         }
433
434         bool acceptable;
435
436         if(len == 0)
437                 if(c->rcv.wnd == 0)
438                         acceptable = hdr.seq == c->rcv.nxt;
439                 else
440                         acceptable = (hdr.seq >= c->rcv.nxt && hdr.seq < c->rcv.nxt + c->rcv.wnd);
441         else
442                 if(c->rcv.wnd == 0)
443                         acceptable = false;
444                 else
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);
447
448         if(!acceptable) {
449                 fprintf(stderr, "Packet not acceptable, %u %u %u %zu\n", hdr.seq, c->rcv.nxt, c->rcv.wnd, len);
450                 if(hdr.ctl & RST)
451                         return 0;
452                 goto ack_and_drop;
453         }
454
455         c->snd.wnd = hdr.wnd;
456
457         // TODO: check whether segment really starts at rcv.nxt, otherwise trim it.
458         
459         if(hdr.ctl & RST) {
460                 switch(c->state) {
461                 case SYN_RECEIVED:
462                         // TODO: delete connection?
463                         break;
464                 case ESTABLISHED:
465                 case FIN_WAIT_1:
466                 case FIN_WAIT_2:
467                 case CLOSE_WAIT:
468                         set_state(c, CLOSED);
469                         errno = ECONNRESET;
470                         c->recv(c, NULL, 0);
471                         break;
472                 case CLOSING:
473                 case LAST_ACK:
474                 case TIME_WAIT:
475                         // TODO: delete connection?
476                         break;
477                 default:
478                         // TODO: wtf?
479                         return 0;
480                 }
481                 set_state(c, CLOSED);
482                 return 0;
483         }
484
485         if(hdr.ctl & SYN) {
486                 switch(c->state) {
487                 case SYN_RECEIVED:
488                 case ESTABLISHED:
489                 case FIN_WAIT_1:
490                 case FIN_WAIT_2:
491                 case CLOSE_WAIT:
492                 case CLOSING:
493                 case LAST_ACK:
494                 case TIME_WAIT:
495                         set_state(c, CLOSED);
496                         errno = ECONNRESET;
497                         c->recv(c, NULL, 0);
498                         goto reset;
499                         break;
500                 default:
501                         // TODO: wtf?
502                         return 0;
503                 }
504         }
505
506         if(!(hdr.ctl & ACK))
507                 return 0;
508
509         switch(c->state) {
510         case SYN_RECEIVED:
511                 if(hdr.ack >= c->snd.una && hdr.ack <= c->snd.nxt)
512                         c->utcp->accept(c, NULL, 0);
513                 
514                 if(c->state != ESTABLISHED)
515                         goto reset;
516                 break;
517         case ESTABLISHED:
518         case CLOSE_WAIT:
519                 if(hdr.ack < c->snd.una)
520                         return 0;
521                 if(hdr.ack > c->snd.nxt)
522                         goto ack_and_drop;
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;
529                         }
530                 }
531                 break;
532         case FIN_WAIT_1:
533                 if(hdr.ack == c->snd.nxt)
534                         set_state(c, FIN_WAIT_2);
535                 break;
536         case FIN_WAIT_2:
537                 // TODO: If nothing left to send, close.
538                 break;
539         case CLOSING:
540                 if(hdr.ack == c->snd.nxt) {
541                         set_state(c, TIME_WAIT);
542                 }
543                 break;
544         case LAST_ACK:
545                 if(hdr.ack == c->snd.nxt) {
546                         set_state(c, CLOSED);
547                 }
548                 return 0;
549         case TIME_WAIT:
550                 // TODO: retransmission of remote FIN, ACK and restart 2 MSL timeout
551                 break;
552         default:
553                 goto reset;
554         }
555
556         // Process data
557
558         switch(c->state) {
559         case ESTABLISHED:
560         case FIN_WAIT_1:
561         case FIN_WAIT_2:
562                 // TODO: process the data, see page 74
563                 break;
564         case CLOSE_WAIT:
565         case CLOSING:
566         case LAST_ACK:
567         case TIME_WAIT:
568                 break;
569         default:
570                 abort();
571         }
572
573         if(hdr.ctl & FIN) {
574                 switch(c->state) {
575                 case CLOSED:
576                 case LISTEN:
577                 case SYN_SENT:
578                         return 0;
579                 case SYN_RECEIVED:
580                 case ESTABLISHED:
581                         set_state(c, CLOSE_WAIT);
582                         c->rcv.nxt++;
583                         goto ack_and_drop;
584                 case FIN_WAIT_1:
585                         set_state(c, CLOSING);
586                         c->rcv.nxt++;
587                         goto ack_and_drop;
588                 case FIN_WAIT_2:
589                         set_state(c, TIME_WAIT);
590                         c->rcv.nxt++;
591                         goto ack_and_drop;
592                 case CLOSE_WAIT:
593                 case CLOSING:
594                 case LAST_ACK:
595                 case TIME_WAIT:
596                         break;
597                 default:
598                         abort();
599                 }
600         }
601
602         // Process the data
603         
604         if(len && c->recv) {
605                 c->recv(c, data, len);
606                 c->rcv.nxt += len;
607                 goto ack_and_drop;
608         }
609
610         return 0;
611
612 reset:
613         swap_ports(&hdr);
614         hdr.wnd = 0;
615         if(hdr.ctl & ACK) {
616                 hdr.seq = hdr.ack;
617                 hdr.ctl = RST;
618         } else {
619                 hdr.ack = hdr.seq + len;
620                 hdr.seq = 0;
621                 hdr.ctl = RST | ACK;
622         }
623         utcp->send(utcp, &hdr, sizeof hdr);
624         return 0;
625
626 ack_and_drop:
627         swap_ports(&hdr);
628         hdr.seq = c->snd.nxt;
629         hdr.ack = c->rcv.nxt;
630         hdr.ctl = ACK;
631         utcp->send(utcp, &hdr, sizeof hdr);
632         if(c->state == CLOSE_WAIT || c->state == TIME_WAIT) {
633                 errno = 0;
634                 c->recv(c, NULL, 0);
635         }
636         return 0;
637 }
638
639 void utcp_shutdown(struct utcp_connection *c, int dir) {
640         if(c->reapable) {
641                 fprintf(stderr, "Error: shutdown() called on closed connection %p\n", c);
642                 return;
643         }
644
645         // TODO: handle dir
646
647         switch(c->state) {
648         case CLOSED:
649                 return;
650         case LISTEN:
651         case SYN_SENT:
652                 set_state(c, CLOSED);
653                 return;
654
655         case SYN_RECEIVED:
656         case ESTABLISHED:
657                 set_state(c, FIN_WAIT_1);
658                 break;
659         case FIN_WAIT_1:
660         case FIN_WAIT_2:
661                 return;
662         case CLOSE_WAIT:
663                 set_state(c, LAST_ACK);
664                 break;
665
666         case CLOSING:
667         case LAST_ACK:
668         case TIME_WAIT:
669                 return;
670         }
671
672         // Send FIN
673
674         struct hdr hdr;
675
676         hdr.src = c->src;
677         hdr.dst = c->dst;
678         hdr.seq = c->snd.nxt;
679         hdr.ack = c->rcv.nxt;
680         hdr.wnd = c->snd.wnd;
681         hdr.ctl = FIN | ACK;
682
683         c->snd.nxt += 1;
684
685         c->utcp->send(c->utcp, &hdr, sizeof hdr);
686 }
687
688 void utcp_close(struct utcp_connection *c) {
689         utcp_shutdown(c, SHUT_RDWR);
690         c->reapable = true;
691 }
692
693 void utcp_abort(struct utcp_connection *c) {
694         if(c->reapable) {
695                 fprintf(stderr, "Error: abort() called on closed connection %p\n", c);
696                 return;
697         }
698
699         c->reapable = true;
700
701         switch(c->state) {
702         case CLOSED:
703                 return;
704         case LISTEN:
705         case SYN_SENT:
706         case CLOSING:
707         case LAST_ACK:
708         case TIME_WAIT:
709                 set_state(c, CLOSED);
710                 return;
711
712         case SYN_RECEIVED:
713         case ESTABLISHED:
714         case FIN_WAIT_1:
715         case FIN_WAIT_2:
716         case CLOSE_WAIT:
717                 set_state(c, CLOSED);
718                 break;
719         }
720
721         // Send RST
722
723         struct hdr hdr;
724
725         hdr.src = c->src;
726         hdr.dst = c->dst;
727         hdr.seq = c->snd.nxt;
728         hdr.ack = 0;
729         hdr.wnd = 0;
730         hdr.ctl = RST;
731
732         c->utcp->send(c->utcp, &hdr, sizeof hdr);
733 }
734
735 void utcp_timeout(struct utcp *utcp) {
736         struct timeval now;
737         gettimeofday(&now, NULL);
738
739         for(int i = 0; i < utcp->nconnections; i++) {
740                 struct utcp_connection *c = utcp->connections[i];
741                 if(!c)
742                         continue;
743
744                 if(c->reapable) {
745                         fprintf(stderr, "Reaping %p\n", c);
746                         free_connection(c);
747                         continue;
748                 }
749
750                 if(c->state == CLOSED)
751                         return;
752
753                 if(c->conn_timeout.tv_sec && timercmp(&c->conn_timeout, &now, <)) {
754                         if(!c->reapable) {
755                                 errno = ETIMEDOUT;
756                                 c->recv(c, NULL, 0);
757                         }
758                         c->state = CLOSED;
759                         return;
760                 }
761
762                 if(c->rtrx_timeout.tv_sec && timercmp(&c->rtrx_timeout, &now, <)) {
763                         // TODO: retransmit stuff;
764                 }
765         }
766 }
767
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);
770         if(!utcp)
771                 return NULL;
772
773         utcp->accept = accept;
774         utcp->pre_accept = pre_accept;
775         utcp->send = send;
776         utcp->priv = priv;
777         utcp->gap = -1;
778         utcp->mtu = 1000;
779
780         return utcp;
781 }
782
783 void utcp_exit(struct utcp *utcp) {
784         if(!utcp)
785                 return;
786         for(int i = 0; i < utcp->nconnections; i++)
787                 free_connection(utcp->connections[i]);
788         free(utcp);
789 }