X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=utcp.c;h=97c43637f4ce52ceb74efd978c278f3e0df1eafb;hb=4368d8c9956242f0bdc00d43ebf32a72332522c1;hp=436c9e8cdcd4703e39e88401fe35fa02a47c0934;hpb=e5db16f2c3e5debdc60b129f8f271faa1c482959;p=utcp diff --git a/utcp.c b/utcp.c index 436c9e8..97c4363 100644 --- a/utcp.c +++ b/utcp.c @@ -29,101 +29,7 @@ #include #include -#define UTCP_INTERNAL -#include "utcp.h" - -#define PREP(l) char pkt[(l) + sizeof struct hdr]; struct hdr *hdr = &pkt; - -#define SYN 1 -#define ACK 2 -#define FIN 4 -#define RST 8 - -struct hdr { - uint16_t src; // Source port - uint16_t dst; // Destination port - uint32_t seq; // Sequence number - uint32_t ack; // Acknowledgement number - uint32_t wnd; // Window size - uint16_t ctl; // Flags (SYN, ACK, FIN, RST) - uint16_t aux; // other stuff -}; - -enum state { - CLOSED, - LISTEN, - SYN_SENT, - SYN_RECEIVED, - ESTABLISHED, - FIN_WAIT_1, - FIN_WAIT_2, - CLOSE_WAIT, - CLOSING, - LAST_ACK, - TIME_WAIT -}; - -const char *strstate[] = { - "CLOSED", - "LISTEN", - "SYN_SENT", - "SYN_RECEIVED", - "ESTABLISHED", - "FIN_WAIT_1", - "FIN_WAIT_2", - "CLOSE_WAIT", - "CLOSING", - "LAST_ACK", - "TIME_WAIT" -}; - -struct utcp_connection { - void *priv; - struct utcp *utcp; - bool reapable; - - uint16_t src; - uint16_t dst; - enum state state; - - // The following two structures form the TCB - - struct { - uint32_t una; - uint32_t nxt; - uint32_t wnd; - uint32_t iss; - } snd; - - struct { - uint32_t nxt; - uint32_t wnd; - uint32_t irs; - } rcv; - - utcp_recv_t recv; - - struct timeval conn_timeout; - struct timeval rtrx_timeout; - - char *sndbuf; - uint32_t sndbufsize; -}; - -struct utcp { - void *priv; - - utcp_accept_t accept; - utcp_pre_accept_t pre_accept; - utcp_send_t send; - - uint16_t mtu; - int timeout; - - struct utcp_connection **connections; - int nconnections; - int nallocated; -}; +#include "utcp_priv.h" static void set_state(struct utcp_connection *c, enum state state) { c->state = state; @@ -167,6 +73,10 @@ static inline void list_connections(struct utcp *utcp) { fprintf(stderr, " %u -> %u state %s\n", utcp->connections[i]->src, utcp->connections[i]->dst, strstate[utcp->connections[i]->state]); } +static int32_t seqdiff(uint32_t a, uint32_t b) { + return a - b; +} + // Connections are stored in a sorted list. // This gives O(log(N)) lookup time, O(N log(N)) insertion time and O(N) deletion time. @@ -232,16 +142,20 @@ static struct utcp_connection *allocate_connection(struct utcp *utcp, uint16_t s else utcp->nallocated *= 2; struct utcp_connection **new_array = realloc(utcp->connections, utcp->nallocated * sizeof *utcp->connections); - if(!new_array) { - errno = ENOMEM; + if(!new_array) return NULL; - } utcp->connections = new_array; } struct utcp_connection *c = calloc(1, sizeof *c); - if(!c) { - errno = ENOMEM; + if(!c) + return NULL; + + c->sndbufsize = DEFAULT_SNDBUFSIZE; + c->maxsndbufsize = DEFAULT_MAXSNDBUFSIZE; + c->sndbuf = malloc(c->sndbufsize); + if(!c->sndbuf) { + free(c); return NULL; } @@ -254,10 +168,6 @@ static struct utcp_connection *allocate_connection(struct utcp *utcp, uint16_t s c->snd.nxt = c->snd.iss + 1; c->rcv.wnd = utcp->mtu; c->utcp = utcp; - c->sndbufsize = 65536; - c->sndbuf = malloc(c->sndbufsize); - if(!c->sndbuf) - c->sndbufsize = 0; // Add it to the sorted list of connections @@ -344,12 +254,31 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) { return -1; } - uint32_t bufused = c->snd.nxt - c->snd.una; + uint32_t bufused = seqdiff(c->snd.nxt, c->snd.una); + + /* Check our send buffer. + * - If it's big enough, just put the data in there. + * - If not, decide whether to enlarge if possible. + * - Cap len so it doesn't overflow our buffer. + */ + + if(len > c->sndbufsize - bufused && c->sndbufsize < c->maxsndbufsize) { + if(c->sndbufsize > c->maxsndbufsize / 2) + c->sndbufsize = c->maxsndbufsize; + else + c->sndbufsize *= 2; + c->sndbuf = realloc(c->sndbuf, c->sndbufsize); + } if(len > c->sndbufsize - bufused) len = c->sndbufsize - bufused; - memcpy(c->sndbuf + (c->snd.nxt - c->snd.una), data, len); + if(!len) { + errno == EWOULDBLOCK; + return 0; + } + + memcpy(c->sndbuf + bufused, data, len); // Send segments @@ -390,10 +319,6 @@ static void swap_ports(struct hdr *hdr) { hdr->dst = tmp; } -static int32_t seqdiff(uint32_t a, uint32_t b) { - return a - b; -} - int utcp_recv(struct utcp *utcp, const void *data, size_t len) { if(!utcp) { errno = EFAULT; @@ -938,12 +863,19 @@ static void retransmit(struct utcp_connection *c) { break; case ESTABLISHED: + case FIN_WAIT_1: pkt.hdr.seq = c->snd.una; pkt.hdr.ack = c->rcv.nxt; pkt.hdr.ctl = ACK; uint32_t len = seqdiff(c->snd.nxt, c->snd.una); + if(c->state == FIN_WAIT_1) + len--; if(len > utcp->mtu) len = utcp->mtu; + else { + if(c->state == FIN_WAIT_1) + pkt.hdr.ctl |= FIN; + } memcpy(pkt.data, c->sndbuf, len); print_packet(c->utcp, "rtrx", &pkt, sizeof pkt.hdr + len); utcp->send(utcp, &pkt, sizeof pkt.hdr + len); @@ -1041,8 +973,49 @@ void utcp_exit(struct utcp *utcp) { free(utcp); } -int utcp_set_connection_timeout(struct utcp *u, int timeout) { - int prev = u->timeout; +uint16_t utcp_get_mtu(struct utcp *utcp) { + return utcp->mtu; +} + +void utcp_set_mtu(struct utcp *utcp, uint16_t mtu) { + // TODO: handle overhead of the header + utcp->mtu = mtu; +} + +int utcp_get_user_timeout(struct utcp *u) { + return u->timeout; +} + +void utcp_set_user_timeout(struct utcp *u, int timeout) { u->timeout = timeout; - return prev; +} + +size_t utcp_get_sndbuf(struct utcp_connection *c) { + return c->maxsndbufsize; +} + +void utcp_set_sndbuf(struct utcp_connection *c, size_t size) { + c->maxsndbufsize = size; + if(c->maxsndbufsize != size) + c->maxsndbufsize = -1; +} + +bool utcp_get_nodelay(struct utcp_connection *c) { + return c->nodelay; +} + +void utcp_set_nodelay(struct utcp_connection *c, bool nodelay) { + c->nodelay = nodelay; +} + +bool utcp_get_keepalive(struct utcp_connection *c) { + return c->keepalive; +} + +void utcp_set_keepalive(struct utcp_connection *c, bool keepalive) { + c->keepalive = keepalive; +} + +size_t utcp_get_outq(struct utcp_connection *c) { + return seqdiff(c->snd.nxt, c->snd.una); }