X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=utcp.c;h=9434c70170e5a6f9b9de5f0b8743e7fed9914223;hb=3c10b4a62f71cdc92e7dea3ace931ec1f497a660;hp=062cc5af09380d4c2fe1d46496dae4200b6bf48b;hpb=88d085b7252643ceec0c9ac646b6d6f680157617;p=utcp diff --git a/utcp.c b/utcp.c index 062cc5a..9434c70 100644 --- a/utcp.c +++ b/utcp.c @@ -130,16 +130,30 @@ static int32_t seqdiff(uint32_t a, uint32_t b) { // TODO: convert to ringbuffers to avoid memmove() operations. // Store data into the buffer -static ssize_t buffer_put(struct buffer *buf, const void *data, size_t len) { +static ssize_t buffer_put_at(struct buffer *buf, size_t offset, const void *data, size_t len) { if(buf->maxsize <= buf->used) return 0; - if(len > buf->maxsize - buf->used) - len = buf->maxsize - buf->used; - if(len > buf->size - buf->used) { + + debug("buffer_put_at %zu %zu %zu\n", buf->used, offset, len); + + size_t required = offset + len; + if(required > buf->maxsize) { + if(offset >= buf->maxsize) + return 0; + abort(); + len = buf->maxsize - offset; + required = buf->maxsize; + } + + if(required > buf->size) { size_t newsize = buf->size; - do { - newsize *= 2; - } while(newsize < buf->used + len); + if(!newsize) { + newsize = required; + } else { + do { + newsize *= 2; + } while(newsize < buf->used + len); + } if(newsize > buf->maxsize) newsize = buf->maxsize; char *newdata = realloc(buf->data, newsize); @@ -148,11 +162,17 @@ static ssize_t buffer_put(struct buffer *buf, const void *data, size_t len) { buf->data = newdata; buf->size = newsize; } - memcpy(buf->data + buf->used, data, len); - buf->used += len; + + memcpy(buf->data + offset, data, len); + if(required > buf->used) + buf->used = required; return len; } +static ssize_t buffer_put(struct buffer *buf, const void *data, size_t len) { + return buffer_put_at(buf, buf->used, data, len); +} + // Get data from the buffer. data can be NULL. static ssize_t buffer_get(struct buffer *buf, void *data, size_t len) { if(len > buf->used) @@ -177,9 +197,11 @@ static ssize_t buffer_copy(struct buffer *buf, void *data, size_t offset, size_t static bool buffer_init(struct buffer *buf, uint32_t len, uint32_t maxlen) { memset(buf, 0, sizeof *buf); - buf->data = malloc(len); - if(!len) - return false; + if(len) { + buf->data = malloc(len); + if(!buf->data) + return false; + } buf->size = len; buf->maxsize = maxlen; return true; @@ -282,7 +304,12 @@ static struct utcp_connection *allocate_connection(struct utcp *utcp, uint16_t s c->src = src; c->dst = dst; +#ifdef UTCP_DEBUG +#warning debugging + c->snd.iss = 0; +#else c->snd.iss = rand(); +#endif c->snd.una = c->snd.iss; c->snd.nxt = c->snd.iss + 1; c->rcv.wnd = utcp->mtu; @@ -360,7 +387,7 @@ static void ack(struct utcp_connection *c, bool sendatleastone) { } *pkt; pkt = malloc(sizeof pkt->hdr + c->utcp->mtu); - if(!pkt->data) + if(!pkt) return; pkt->hdr.src = c->src; @@ -500,6 +527,7 @@ static void retransmit(struct utcp_connection *c) { len--; pkt->hdr.ctl |= FIN; } + c->snd.nxt = c->snd.una + len; buffer_copy(&c->sndbuf, pkt->data, 0, len); print_packet(c->utcp, "rtrx", pkt, sizeof pkt->hdr + len); utcp->send(utcp, pkt, sizeof pkt->hdr + len); @@ -988,7 +1016,7 @@ reset: } int utcp_shutdown(struct utcp_connection *c, int dir) { - debug("%p shutdown %d at %u\n", c ? c->utcp : NULL, dir, c->snd.last); + debug("%p shutdown %d at %u\n", c ? c->utcp : NULL, dir, c ? c->snd.last : 0); if(!c) { errno = EFAULT; return -1; @@ -1000,13 +1028,26 @@ int utcp_shutdown(struct utcp_connection *c, int dir) { return -1; } - // TODO: handle dir - // TODO: check that repeated calls with the same parameters should have no effect + if(!(dir == UTCP_SHUT_RD || dir == UTCP_SHUT_WR || dir == UTCP_SHUT_RDWR)) { + errno = EINVAL; + return -1; + } + + // TCP does not have a provision for stopping incoming packets. + // The best we can do is to just ignore them. + if(dir == UTCP_SHUT_RD || dir == UTCP_SHUT_RDWR) + c->recv = NULL; + + // The rest of the code deals with shutting down writes. + if(dir == UTCP_SHUT_RD) + return 0; switch(c->state) { case CLOSED: - return 0; case LISTEN: + errno = ENOTCONN; + return -1; + case SYN_SENT: set_state(c, CLOSED); return 0; @@ -1154,6 +1195,17 @@ struct timeval utcp_timeout(struct utcp *utcp) { return diff; } +bool utcp_is_active(struct utcp *utcp) { + if(!utcp) + return false; + + for(int i = 0; i < utcp->nconnections; i++) + if(utcp->connections[i]->state != CLOSED && utcp->connections[i]->state != TIME_WAIT) + return true; + + return false; +} + struct utcp *utcp_init(utcp_accept_t accept, utcp_pre_accept_t pre_accept, utcp_send_t send, void *priv) { struct utcp *utcp = calloc(1, sizeof *utcp); if(!utcp)