mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 07:37:46 +00:00
[tcp] add TCPlp data buffering code (used instead of FreeBSD's data buffering) (#6926)
This commit the libraries that I wrote as part of TCPlp to handle data buffering. These libraries are intended to replace the mbuf-based data buffering in the FreeBSD TCP implementation. They implement the send buffer as a linked buffer chain (consistent with otLinkedBuffer in OpenThread's TCP API) and the receive buffer as a circular buffer and bitmap (used to keep track of which bytes were received out-of-order).
This commit is contained in:
Vendored
+3
-1
@@ -29,7 +29,9 @@
|
||||
project("TCPlp" C)
|
||||
|
||||
set(src_tcplp
|
||||
tcplp.c
|
||||
lib/bitmap.c
|
||||
lib/cbuf.c
|
||||
lib/lbuf.c
|
||||
)
|
||||
|
||||
set(tcplp_static_target "tcplp")
|
||||
|
||||
Vendored
+6
-1
@@ -29,6 +29,9 @@
|
||||
include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
|
||||
|
||||
EXTRA_DIST = \
|
||||
lib/bitmap.h \
|
||||
lib/cbuf.h \
|
||||
lib/lbuf.h \
|
||||
tcplp.h \
|
||||
$(NULL)
|
||||
|
||||
@@ -62,7 +65,9 @@ libtcplp_a_CPPFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
libtcplp_a_SOURCES = \
|
||||
tcplp.c
|
||||
lib/bitmap.c \
|
||||
lib/cbuf.c \
|
||||
lib/lbuf.c \
|
||||
$(NULL)
|
||||
|
||||
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
|
||||
|
||||
Vendored
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* BITMAP */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitmap.h"
|
||||
|
||||
void bmp_init(uint8_t* buf, size_t numbytes) {
|
||||
memset(buf, 0x00, numbytes);
|
||||
}
|
||||
|
||||
#define _bmp_getrangeinfo(buf, start, len, first_bit_id, first_byte_ptr, last_bit_id, last_byte_ptr) \
|
||||
do { \
|
||||
first_bit_id = (start & 0x7); \
|
||||
first_byte_ptr = buf + (start >> 3); \
|
||||
last_bit_id = (len & 0x7) + first_bit_id; \
|
||||
last_byte_ptr = first_byte_ptr + (len >> 3) + (last_bit_id >> 3); \
|
||||
last_bit_id &= 0x7; \
|
||||
} while (0)
|
||||
|
||||
void bmp_setrange(uint8_t* buf, size_t start, size_t len) {
|
||||
uint8_t first_bit_id;
|
||||
uint8_t* first_byte_set;
|
||||
uint8_t last_bit_id;
|
||||
uint8_t* last_byte_set;
|
||||
uint8_t first_byte_mask, last_byte_mask;
|
||||
_bmp_getrangeinfo(buf, start, len, first_bit_id, first_byte_set,
|
||||
last_bit_id, last_byte_set);
|
||||
|
||||
first_byte_mask = (uint8_t) (0xFF >> first_bit_id);
|
||||
last_byte_mask = (uint8_t) (0xFF << (8 - last_bit_id));
|
||||
|
||||
/* Set the bits. */
|
||||
if (first_byte_set == last_byte_set) {
|
||||
*first_byte_set |= (first_byte_mask & last_byte_mask);
|
||||
} else {
|
||||
*first_byte_set |= first_byte_mask;
|
||||
memset(first_byte_set + 1, 0xFF, (size_t) (last_byte_set - first_byte_set - 1));
|
||||
*last_byte_set |= last_byte_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void bmp_clrrange(uint8_t* buf, size_t start, size_t len) {
|
||||
uint8_t first_bit_id;
|
||||
uint8_t* first_byte_clear;
|
||||
uint8_t last_bit_id;
|
||||
uint8_t* last_byte_clear;
|
||||
uint8_t first_byte_mask, last_byte_mask;
|
||||
_bmp_getrangeinfo(buf, start, len, first_bit_id, first_byte_clear,
|
||||
last_bit_id, last_byte_clear);
|
||||
|
||||
first_byte_mask = (uint8_t) (0xFF << (8 - first_bit_id));
|
||||
last_byte_mask = (uint8_t) (0xFF >> last_bit_id);
|
||||
|
||||
/* Clear the bits. */
|
||||
if (first_byte_clear == last_byte_clear) {
|
||||
*first_byte_clear &= (first_byte_mask | last_byte_mask);
|
||||
} else {
|
||||
*first_byte_clear &= first_byte_mask;
|
||||
memset(first_byte_clear + 1, 0x00, (size_t) (last_byte_clear - first_byte_clear - 1));
|
||||
*last_byte_clear &= last_byte_mask;
|
||||
}
|
||||
}
|
||||
|
||||
size_t bmp_countset(uint8_t* buf, size_t buflen, size_t start, size_t limit) {
|
||||
uint8_t first_bit_id;
|
||||
uint8_t first_byte;
|
||||
uint8_t ideal_first_byte;
|
||||
size_t numset;
|
||||
uint8_t curr_byte;
|
||||
size_t curr_index = start >> 3;
|
||||
first_bit_id = start & 0x7;
|
||||
first_byte = *(buf + curr_index);
|
||||
|
||||
numset = 8 - first_bit_id; // initialize optimistically, assuming that the first byte will have all 1's in the part we care about
|
||||
ideal_first_byte = (uint8_t) (0xFF >> first_bit_id);
|
||||
first_byte &= ideal_first_byte;
|
||||
if (first_byte == ideal_first_byte) {
|
||||
// All bits in the first byte starting at first_bit_id are set
|
||||
for (curr_index = curr_index + 1; curr_index < buflen && numset < limit; curr_index++) {
|
||||
curr_byte = buf[curr_index];
|
||||
if (curr_byte == (uint8_t) 0xFF) {
|
||||
numset += 8;
|
||||
} else {
|
||||
while (curr_byte & (uint8_t) 0x80) { // we could add a numset < limit check here, but it probably isn't worth it
|
||||
curr_byte <<= 1;
|
||||
numset++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The streak ends within the first byte
|
||||
do {
|
||||
first_byte >>= 1;
|
||||
ideal_first_byte >>= 1;
|
||||
numset--;
|
||||
} while (first_byte != ideal_first_byte);
|
||||
}
|
||||
return numset;
|
||||
}
|
||||
|
||||
int bmp_isempty(uint8_t* buf, size_t buflen) {
|
||||
uint8_t* bufend = buf + buflen;
|
||||
while (buf < bufend) {
|
||||
if (*(buf++)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bmp_print(uint8_t* buf, size_t buflen) {
|
||||
size_t i;
|
||||
for (i = 0; i < buflen; i++) {
|
||||
printf("%02X", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BITMAP_H_
|
||||
#define BITMAP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Computes the number of bytes required to store the specified number of bits. */
|
||||
#define BITS_TO_BYTES(bits) (((bits) >> 3) + (((bits) & 0x7) ? 1 : 0))
|
||||
|
||||
/* Initializes a bitmap to all zeros. */
|
||||
void bmp_init(uint8_t* buf, size_t numbytes);
|
||||
|
||||
/* Sets the specified range of bits. START is the index
|
||||
of the first bit to be set. LEN is the number of bits
|
||||
to be set. */
|
||||
void bmp_setrange(uint8_t* buf, size_t start, size_t len);
|
||||
|
||||
/* Clears the specified range of bits. START is the index
|
||||
of the first bit to be cleared. LEN is the number of bits
|
||||
to be cleared. */
|
||||
void bmp_clrrange(uint8_t* buf, size_t start, size_t len);
|
||||
|
||||
/* Counts the number of set bits in BUF starting at START. BUF has length
|
||||
BUFLEN, in bytes. Counts the number of set bits until it either (1) finds
|
||||
a bit that isn't set, in which case it returns the number of set bits,
|
||||
(2) it has counted at least LIMIT bits, in which case it returns a number
|
||||
greater than or equal to LIMIT, or (3) reaches the end of the buffer, in
|
||||
which case it returns exactly the number of set bits it found. */
|
||||
size_t bmp_countset(uint8_t* buf, size_t buflen, size_t start, size_t limit);
|
||||
|
||||
/* Returns 1 if the bitmap is all zeros, and 0 otherwise. */
|
||||
int bmp_isempty(uint8_t* buf, size_t buflen);
|
||||
|
||||
/* Prints out the bitmap in hexadecimal (used for debugging). */
|
||||
void bmp_print(uint8_t* buf, size_t buflen);
|
||||
|
||||
#endif
|
||||
Vendored
+264
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* CIRCULAR BUFFER */
|
||||
#include "cbuf.h"
|
||||
#include "bitmap.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openthread/message.h>
|
||||
#include <openthread/tcp.h>
|
||||
|
||||
/*
|
||||
* Copiers for copying from/into cbufs into/from arrays or OpenThraed messages
|
||||
*/
|
||||
|
||||
void cbuf_copy_into_buffer(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes) {
|
||||
uint8_t* bufptr = (uint8_t*) buffer;
|
||||
const uint8_t* arrptr = (const uint8_t*) arr;
|
||||
memcpy(bufptr + buffer_offset, arrptr + arr_offset, num_bytes);
|
||||
}
|
||||
|
||||
void cbuf_copy_from_buffer(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes) {
|
||||
uint8_t* arrptr = (uint8_t*) arr;
|
||||
const uint8_t* bufptr = (const uint8_t*) buffer;
|
||||
memcpy(arrptr + arr_offset, bufptr + buffer_offset, num_bytes);
|
||||
}
|
||||
|
||||
void cbuf_copy_into_message(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes) {
|
||||
otMessage* message = (otMessage*) buffer;
|
||||
uint8_t* arrptr = (uint8_t*) arr;
|
||||
otMessageWrite(message, (uint16_t) buffer_offset, arrptr + arr_offset, (uint16_t) num_bytes);
|
||||
}
|
||||
|
||||
void cbuf_copy_from_message(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes) {
|
||||
uint8_t* arrptr = (uint8_t*) arr;
|
||||
const otMessage* message = (const otMessage*) buffer;
|
||||
otMessageRead(message, (uint16_t) buffer_offset, arrptr + arr_offset, (uint16_t) num_bytes);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cbuf implementation.
|
||||
*/
|
||||
|
||||
void cbuf_init(struct cbufhead* chdr, uint8_t* buf, size_t len) {
|
||||
chdr->r_index = 0;
|
||||
chdr->w_index = 0;
|
||||
chdr->size = len;
|
||||
chdr->buf = buf;
|
||||
}
|
||||
|
||||
size_t cbuf_used_space(struct cbufhead* chdr) {
|
||||
if (chdr->w_index >= chdr->r_index) {
|
||||
return chdr->w_index - chdr->r_index;
|
||||
} else {
|
||||
return chdr->size + chdr->w_index - chdr->r_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* There's always one byte of lost space so I can distinguish between a full
|
||||
buffer and an empty buffer. */
|
||||
size_t cbuf_free_space(struct cbufhead* chdr) {
|
||||
return chdr->size - 1 - cbuf_used_space(chdr);
|
||||
}
|
||||
|
||||
size_t cbuf_size(struct cbufhead* chdr) {
|
||||
return chdr->size - 1;
|
||||
}
|
||||
|
||||
bool cbuf_empty(struct cbufhead* chdr) {
|
||||
return (chdr->w_index == chdr->r_index);
|
||||
}
|
||||
|
||||
size_t cbuf_write(struct cbufhead* chdr, const void* data, size_t data_offset, size_t data_len, cbuf_copier_t copy_from) {
|
||||
size_t free_space = cbuf_free_space(chdr);
|
||||
uint8_t* buf_data;
|
||||
size_t fw_index;
|
||||
size_t bytes_to_end;
|
||||
if (free_space < data_len) {
|
||||
data_len = free_space;
|
||||
}
|
||||
buf_data = chdr->buf;
|
||||
fw_index = (chdr->w_index + data_len) % chdr->size;
|
||||
if (fw_index >= chdr->w_index) {
|
||||
copy_from(buf_data, chdr->w_index, data, data_offset, data_len);
|
||||
} else {
|
||||
bytes_to_end = chdr->size - chdr->w_index;
|
||||
copy_from(buf_data, chdr->w_index, data, data_offset, bytes_to_end);
|
||||
copy_from(buf_data, 0, data, data_offset + bytes_to_end, data_len - bytes_to_end);
|
||||
}
|
||||
chdr->w_index = fw_index;
|
||||
return data_len;
|
||||
}
|
||||
|
||||
void cbuf_read_unsafe(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into) {
|
||||
uint8_t* buf_data = chdr->buf;
|
||||
size_t fr_index = (chdr->r_index + numbytes) % chdr->size;
|
||||
size_t bytes_to_end;
|
||||
if (fr_index >= chdr->r_index) {
|
||||
copy_into(data, data_offset, buf_data, chdr->r_index, numbytes);
|
||||
} else {
|
||||
bytes_to_end = chdr->size - chdr->r_index;
|
||||
copy_into(data, data_offset, buf_data, chdr->r_index, bytes_to_end);
|
||||
copy_into(data, data_offset + bytes_to_end, buf_data, 0, numbytes - bytes_to_end);
|
||||
}
|
||||
if (pop) {
|
||||
chdr->r_index = fr_index;
|
||||
}
|
||||
}
|
||||
|
||||
size_t cbuf_read(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into) {
|
||||
size_t used_space = cbuf_used_space(chdr);
|
||||
if (used_space < numbytes) {
|
||||
numbytes = used_space;
|
||||
}
|
||||
cbuf_read_unsafe(chdr, data, data_offset, numbytes, pop, copy_into);
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
size_t cbuf_read_offset(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, size_t offset, cbuf_copier_t copy_into) {
|
||||
size_t used_space = cbuf_used_space(chdr);
|
||||
size_t oldpos;
|
||||
if (used_space <= offset) {
|
||||
return 0;
|
||||
} else if (used_space < offset + numbytes) {
|
||||
numbytes = used_space - offset;
|
||||
}
|
||||
oldpos = chdr->r_index;
|
||||
chdr->r_index = (chdr->r_index + offset) % chdr->size;
|
||||
cbuf_read_unsafe(chdr, data, data_offset, numbytes, 0, copy_into);
|
||||
chdr->r_index = oldpos;
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
size_t cbuf_pop(struct cbufhead* chdr, size_t numbytes) {
|
||||
size_t used_space = cbuf_used_space(chdr);
|
||||
if (used_space < numbytes) {
|
||||
numbytes = used_space;
|
||||
}
|
||||
chdr->r_index = (chdr->r_index + numbytes) % chdr->size;
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
void cbuf_reference(const struct cbufhead* chdr, otLinkedBuffer* first, otLinkedBuffer* second) {
|
||||
if (chdr->w_index >= chdr->r_index) {
|
||||
first->mNext = NULL;
|
||||
first->mData = &chdr->buf[chdr->r_index];
|
||||
first->mLength = (uint16_t) (chdr->w_index - chdr->r_index);
|
||||
} else {
|
||||
first->mNext = second;
|
||||
first->mData = &chdr->buf[chdr->r_index];
|
||||
first->mLength = (uint16_t) (chdr->size - chdr->r_index);
|
||||
|
||||
second->mNext = NULL;
|
||||
second->mData = &chdr->buf[0];
|
||||
second->mLength = (uint16_t) chdr->w_index;
|
||||
}
|
||||
}
|
||||
|
||||
size_t cbuf_reass_write(struct cbufhead* chdr, size_t offset, const void* data, size_t data_offset, size_t numbytes, uint8_t* bitmap, size_t* firstindex, cbuf_copier_t copy_from) {
|
||||
uint8_t* buf_data = chdr->buf;
|
||||
size_t free_space = cbuf_free_space(chdr);
|
||||
size_t start_index;
|
||||
size_t end_index;
|
||||
size_t bytes_to_end;
|
||||
if (offset > free_space) {
|
||||
return 0;
|
||||
} else if (offset + numbytes > free_space) {
|
||||
numbytes = free_space - offset;
|
||||
}
|
||||
start_index = (chdr->w_index + offset) % chdr->size;
|
||||
end_index = (start_index + numbytes) % chdr->size;
|
||||
if (end_index >= start_index) {
|
||||
copy_from(buf_data, start_index, data, data_offset, numbytes);
|
||||
if (bitmap) {
|
||||
bmp_setrange(bitmap, start_index, numbytes);
|
||||
}
|
||||
} else {
|
||||
bytes_to_end = chdr->size - start_index;
|
||||
copy_from(buf_data, start_index, data, data_offset, bytes_to_end);
|
||||
copy_from(buf_data, 0, data, data_offset + bytes_to_end, numbytes - bytes_to_end);
|
||||
if (bitmap) {
|
||||
bmp_setrange(bitmap, start_index, bytes_to_end);
|
||||
bmp_setrange(bitmap, 0, numbytes - bytes_to_end);
|
||||
}
|
||||
}
|
||||
if (firstindex) {
|
||||
*firstindex = start_index;
|
||||
}
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
size_t cbuf_reass_merge(struct cbufhead* chdr, size_t numbytes, uint8_t* bitmap) {
|
||||
size_t old_w = chdr->w_index;
|
||||
size_t free_space = cbuf_free_space(chdr);
|
||||
size_t bytes_to_end;
|
||||
if (numbytes > free_space) {
|
||||
numbytes = free_space;
|
||||
}
|
||||
chdr->w_index = (chdr->w_index + numbytes) % chdr->size;
|
||||
if (bitmap) {
|
||||
if (chdr->w_index >= old_w) {
|
||||
bmp_clrrange(bitmap, old_w, numbytes);
|
||||
} else {
|
||||
bytes_to_end = chdr->size - old_w;
|
||||
bmp_clrrange(bitmap, old_w, bytes_to_end);
|
||||
bmp_clrrange(bitmap, 0, numbytes - bytes_to_end);
|
||||
}
|
||||
}
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
size_t cbuf_reass_count_set(struct cbufhead* chdr, size_t offset, uint8_t* bitmap, size_t limit) {
|
||||
size_t bitmap_size = BITS_TO_BYTES(chdr->size);
|
||||
size_t until_end;
|
||||
offset = (chdr->w_index + offset) % chdr->size;
|
||||
until_end = bmp_countset(bitmap, bitmap_size, offset, limit);
|
||||
if (until_end >= limit || until_end < (chdr->size - offset)) {
|
||||
// If we already hit the limit, or if the streak ended before wrapping, then stop here
|
||||
return until_end;
|
||||
}
|
||||
limit -= until_end; // effectively, this is our limit when continuing
|
||||
// Continue until either the new limit or until we have scanned OFFSET bits (if we scan more than OFFSET bits, we'll wrap and scan some parts twice)
|
||||
return until_end + bmp_countset(bitmap, bitmap_size, 0, limit < offset ? limit : offset);
|
||||
}
|
||||
|
||||
int cbuf_reass_within_offset(struct cbufhead* chdr, size_t offset, size_t index) {
|
||||
size_t range_start = chdr->w_index;
|
||||
size_t range_end = (range_start + offset) % chdr->size;
|
||||
if (range_end >= range_start) {
|
||||
return index >= range_start && index < range_end;
|
||||
} else {
|
||||
return index < range_end || (index >= range_start && index < chdr->size);
|
||||
}
|
||||
}
|
||||
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CBUF_H_
|
||||
#define CBUF_H_
|
||||
|
||||
/* CIRCULAR BUFFER */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct otLinkedBuffer;
|
||||
|
||||
/* Represents a circular buffer. */
|
||||
struct cbufhead {
|
||||
size_t r_index;
|
||||
size_t w_index;
|
||||
size_t size;
|
||||
uint8_t* buf;
|
||||
};
|
||||
|
||||
/* Initializes a circular buffer (chdr is the header storing metadata). */
|
||||
void cbuf_init(struct cbufhead* chdr, uint8_t* buf, size_t len);
|
||||
|
||||
/* Function type for copying data into or out of a circular buffer. */
|
||||
typedef void(*cbuf_copier_t)(void*, size_t, const void*, size_t, size_t);
|
||||
|
||||
/* Instantiations of cbuf_copier_t, for copying data between circular buffers and regular buffers. */
|
||||
void cbuf_copy_into_buffer(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes);
|
||||
void cbuf_copy_from_buffer(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes);
|
||||
|
||||
/* Instantiations of cbuf_copier_t, for copying data between circular buffers and otMessages. */
|
||||
void cbuf_copy_into_message(void* buffer, size_t buffer_offset, const void* arr, size_t arr_offset, size_t num_bytes);
|
||||
void cbuf_copy_from_message(void* arr, size_t arr_offset, const void* buffer, size_t buffer_offset, size_t num_bytes);
|
||||
|
||||
/* Writes data to the back of the circular buffer using the specified copier. */
|
||||
size_t cbuf_write(struct cbufhead* chdr, const void* data, size_t data_offset, size_t data_len, cbuf_copier_t copy_from);
|
||||
|
||||
/* Reads data from the front ofthe circular buffer using the specified copier. */
|
||||
size_t cbuf_read(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, int pop, cbuf_copier_t copy_into);
|
||||
|
||||
/* Reads data at the specified offset, in bytes, from the front of the circular buffer using the specified copier. */
|
||||
size_t cbuf_read_offset(struct cbufhead* chdr, void* data, size_t data_offset, size_t numbytes, size_t offset, cbuf_copier_t copy_into);
|
||||
|
||||
/* Drops bytes from the front of the circular buffer. */
|
||||
size_t cbuf_pop(struct cbufhead* chdr, size_t numbytes);
|
||||
|
||||
/* Returns the number of bytes available for reading from the circular buffer. */
|
||||
size_t cbuf_used_space(struct cbufhead* chdr);
|
||||
|
||||
/* Returns the number of bytes that can be written to the circular buffer before it is full. */
|
||||
size_t cbuf_free_space(struct cbufhead* chdr);
|
||||
|
||||
/* Returns the total capacity of the circular buffer, in bytes. */
|
||||
size_t cbuf_size(struct cbufhead* chdr);
|
||||
|
||||
/* Returns true if the circular buffer is empty, and false if it is not empty. */
|
||||
bool cbuf_empty(struct cbufhead* chdr);
|
||||
|
||||
/* Populates the provided otLinkedBuffers to reference the data currently in the circular buffer. */
|
||||
void cbuf_reference(const struct cbufhead* chdr, struct otLinkedBuffer* first, struct otLinkedBuffer* second);
|
||||
|
||||
/* Writes DATA at the end of the circular buffer without making it available for
|
||||
reading. This data is said to be "out-of-sequence". OFFSET is position at
|
||||
which to write these bytes, relative to the positoin where cbuf_write would
|
||||
write them. Each bit in the BITMAP corresponds to a byte in the circular
|
||||
buffer; the bits corresponding to the bytes containing the newly written
|
||||
data are set. The index of the first byte written is stored into FIRSTINDEX,
|
||||
if it is not NULL. */
|
||||
size_t cbuf_reass_write(struct cbufhead* chdr, size_t offset, const void* data, size_t data_offset, size_t numbytes, uint8_t* bitmap, size_t* firstindex, cbuf_copier_t copy_from);
|
||||
|
||||
/* Makes NUMBYTES out-of-seqence bytes available for reading in the circular
|
||||
buffer. No data is copied; the out-of-sequence bytes made available are the
|
||||
bytes currently at the position where cbuf_write would write them. The bytes
|
||||
are taken from the unused space of the buffer, and can be set using
|
||||
cbuf_reass_write. */
|
||||
size_t cbuf_reass_merge(struct cbufhead* chdr, size_t numbytes, uint8_t* bitmap);
|
||||
|
||||
/* Counts the number of contiguous out-of-sequence bytes at the specified
|
||||
OFFSET, until the count reaches the specified LIMIT. */
|
||||
size_t cbuf_reass_count_set(struct cbufhead* chdr, size_t offset, uint8_t* bitmap, size_t limit);
|
||||
|
||||
/* Returns a true value iff INDEX is the index of a byte within OFFSET bytes
|
||||
past the end of the buffer. */
|
||||
int cbuf_reass_within_offset(struct cbufhead* chdr, size_t offset, size_t index);
|
||||
|
||||
#endif
|
||||
Vendored
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* LINKED BUFFER */
|
||||
|
||||
#include "lbuf.h"
|
||||
#include <string.h>
|
||||
#include <openthread/tcp.h>
|
||||
|
||||
void lbuf_init(struct lbufhead* buffer) {
|
||||
memset(buffer, 0x00, sizeof(struct lbufhead));
|
||||
}
|
||||
|
||||
void lbuf_append(struct lbufhead* buffer, otLinkedBuffer* newentry) {
|
||||
otLinkedBuffer* tail = buffer->tail;
|
||||
if (tail == NULL) {
|
||||
buffer->head = newentry;
|
||||
buffer->tail = newentry;
|
||||
buffer->offset = 0;
|
||||
buffer->length = newentry->mLength;
|
||||
newentry->mNext = NULL;
|
||||
} else {
|
||||
tail->mNext = newentry;
|
||||
buffer->tail = newentry;
|
||||
buffer->length += newentry->mLength;
|
||||
newentry->mNext = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void lbuf_extend(struct lbufhead* buffer, size_t numbytes) {
|
||||
buffer->tail->mLength += numbytes;
|
||||
}
|
||||
|
||||
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, int* ntraversed) {
|
||||
otLinkedBuffer* curr = buffer->head;
|
||||
size_t bytesleft = numbytes;
|
||||
size_t curroffset = buffer->offset;
|
||||
if (curr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
while (bytesleft >= curr->mLength - curroffset) {
|
||||
++*ntraversed;
|
||||
bytesleft -= (curr->mLength - curroffset);
|
||||
buffer->length -= (curr->mLength - curroffset);
|
||||
if (buffer->tail == curr) {
|
||||
buffer->head = NULL;
|
||||
buffer->tail = NULL;
|
||||
buffer->offset = 0;
|
||||
return numbytes - bytesleft;
|
||||
}
|
||||
curr = curr->mNext;
|
||||
curroffset = 0;
|
||||
}
|
||||
/* Handle the last entry. */
|
||||
buffer->head = curr;
|
||||
buffer->offset = curroffset + bytesleft;
|
||||
buffer->length -= bytesleft;
|
||||
return numbytes;
|
||||
}
|
||||
|
||||
int lbuf_getrange(struct lbufhead* buffer, size_t offset, size_t numbytes,
|
||||
otLinkedBuffer** first, size_t* firstoffset,
|
||||
otLinkedBuffer** last, size_t* lastextra) {
|
||||
otLinkedBuffer* curr = buffer->head;
|
||||
size_t offsetleft = offset + buffer->offset;
|
||||
size_t bytesleft = numbytes;
|
||||
if (buffer->length < offset + numbytes) {
|
||||
return 1; // out of range
|
||||
}
|
||||
while (offsetleft > 0 && offsetleft >= curr->mLength) {
|
||||
offsetleft -= curr->mLength;
|
||||
curr = curr->mNext;
|
||||
}
|
||||
*first = curr;
|
||||
*firstoffset = offsetleft;
|
||||
bytesleft += offsetleft;
|
||||
while (bytesleft > 0 && bytesleft > curr->mLength) {
|
||||
bytesleft -= curr->mLength;
|
||||
curr = curr->mNext;
|
||||
}
|
||||
*last = curr;
|
||||
*lastextra = curr->mLength - bytesleft;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t lbuf_used_space(struct lbufhead* buffer) {
|
||||
return buffer->length;
|
||||
}
|
||||
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Sam Kumar <[email protected]>
|
||||
* Copyright (c) 2018, University of California, Berkeley
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LBUF_H_
|
||||
#define LBUF_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct otLinkedBuffer;
|
||||
|
||||
/* LINKED BUFFER */
|
||||
|
||||
struct lbufhead {
|
||||
struct otLinkedBuffer* head;
|
||||
struct otLinkedBuffer* tail;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
/* Initializes a linked buffer. */
|
||||
void lbuf_init(struct lbufhead* buffer);
|
||||
|
||||
/* Returns the contents of the buffer as a linked buffer chain, or NULL if the buffer has
|
||||
no head. */
|
||||
static inline struct otLinkedBuffer* lbuf_head(struct lbufhead* buffer) {
|
||||
return buffer->head;
|
||||
}
|
||||
|
||||
/* Adds the contents of NEWENTRY to the buffer by appending it to the end of
|
||||
the current chain. */
|
||||
void lbuf_append(struct lbufhead* buffer, struct otLinkedBuffer* newentry);
|
||||
|
||||
/* Extends the last entry of the buffer by the specified number of bytes. */
|
||||
void lbuf_extend(struct lbufhead* buffer, size_t numbytes);
|
||||
|
||||
/* Removes the first NUMBYTES bytes from the buffer, and returns the number of
|
||||
bytes removed (which is fewer than NUMBYTES if there were fewer than
|
||||
NUMBYTES bytes in the buffer to begin with). *NTRAVERSED is incremented once
|
||||
for each entry in the buffer that is no longer referenced and can be
|
||||
reclaimed. */
|
||||
size_t lbuf_pop(struct lbufhead* buffer, size_t numbytes, int* ntraversed);
|
||||
|
||||
/* Given a range of indices, specified by an OFFSET from the start and a
|
||||
length NUMBYTES, this function locates the chain of linked buffer entries
|
||||
that reference the corresponding bytes.
|
||||
A pointer to the first entry in the range is stored into FIRST, and the
|
||||
number of bytes in the entry before the start of the range is stored into
|
||||
FIRSTOFFSET. A pointer to the last entry in the range is stored into LAST,
|
||||
and the number of bytes in that entry after the end of the range is stored
|
||||
into LASTEXTRA.
|
||||
Returns 0 on success and 1 on failure. On failure, FIRST, LAST, FIRSTOFFSET,
|
||||
and LASTEXTRA are not set. The only failure condition is when there are not
|
||||
enough bytes in the buffer to do the full traversal. */
|
||||
int lbuf_getrange(struct lbufhead* buffer, size_t offset, size_t numbytes,
|
||||
struct otLinkedBuffer** first, size_t* firstoffset,
|
||||
struct otLinkedBuffer** last, size_t* lastextra);
|
||||
|
||||
/* Returns the total number of bytes stored in the buffer. */
|
||||
size_t lbuf_used_space(struct lbufhead* buffer);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user