+ debug(" %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;
+}
+
+// Buffer functions
+// 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) {
+ if(buf->maxsize <= buf->used)
+ return 0;
+ if(len > buf->maxsize - buf->used)
+ len = buf->maxsize - buf->used;
+ if(len > buf->size - buf->used) {
+ size_t newsize = buf->size;
+ do {
+ newsize *= 2;
+ } while(newsize < buf->used + len);
+ if(newsize > buf->maxsize)
+ newsize = buf->maxsize;
+ char *newdata = realloc(buf->data, newsize);
+ if(!newdata)
+ return -1;
+ buf->data = newdata;
+ buf->size = newsize;
+ }
+ memcpy(buf->data + buf->used, data, len);
+ buf->used += len;
+ return 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)
+ len = buf->used;
+ if(data)
+ memcpy(data, buf->data, len);
+ if(len < buf->used)
+ memmove(buf->data, buf->data + len, buf->used - len);
+ buf->used -= len;
+ return len;
+}
+
+// Copy data from the buffer without removing it.
+static ssize_t buffer_copy(struct buffer *buf, void *data, size_t offset, size_t len) {
+ if(offset >= buf->used)
+ return 0;
+ if(offset + len > buf->used)
+ len = buf->used - offset;
+ memcpy(data, buf->data + offset, len);
+ return len;
+}
+
+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;
+ buf->size = len;
+ buf->maxsize = maxlen;
+ return true;
+}
+
+static void buffer_exit(struct buffer *buf) {
+ free(buf->data);
+ memset(buf, 0, sizeof *buf);
+}
+
+static uint32_t buffer_free(const struct buffer *buf) {
+ return buf->maxsize - buf->used;