diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h index 9d6129e..56efa1c 100644 --- a/include/ucore/mbuf.h +++ b/include/ucore/mbuf.h @@ -12,8 +12,8 @@ enum UC_MBUF_FLAGS { UC_MBUF_FL_MALLOC = 0x0001, //MBuf and MBuf->bufstart are seperatly malloc'd UC_MBUF_FL_MALLOC_BUF = 0x0001, //MBuf is not malloc'd. MBuf->bufstart is malloc'd - UC_MBUF_FL_MALLOC_INLINE = 0x0002, //MBuf is one big malloc. Can't be resized - UC_MBUF_FL_STATIC = 0x0004, //MBuf and MBuf->bustart is user controlled. Can't be resized + UC_MBUF_FL_MALLOC_INLINE = 0x0002, //MBuf is one big malloc. Can't be extended + UC_MBUF_FL_STATIC = 0x0004, //MBuf and MBuf->bustart is user controlled. Can't be extended }; struct MBuf { @@ -187,6 +187,16 @@ uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size); **/ uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size); +/** Add more tailroom to an mbuf. + * Can only be done with mbufs with either + * UC_MBUF_FL_MALLOC or UC_MBUF_FL_MALLOC_BUF. + * + * @param len additional tailroom to add to mbuf + * @return 0 on success, otherwise failure + * + */ +int uc_mbuf_extend_tailroom(struct MBuf *mbuf, uint32_t len); + /** Get a pointer to the data of the buffer * * @return pointer to the start of the data (head) diff --git a/src/mbuf.c b/src/mbuf.c index 865612a..d77dd7b 100644 --- a/src/mbuf.c +++ b/src/mbuf.c @@ -1,4 +1,5 @@ #include +#include #include #include "ucore/mbuf.h" @@ -119,3 +120,81 @@ struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf) return copy; } +int uc_mbuf_extend_tailroom(struct MBuf *mbuf, uint32_t len) +{ + uint32_t tot_len; + uint32_t headroom_len; + uint32_t data_len; + uint32_t tailroom_len; + uint8_t *new_data; + uint32_t p1_off; + uint32_t p2_off; + uint32_t p3_off; + uint32_t p4_off; + + if ((mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_BUF)) == 0) { + return -1; + } + + headroom_len = uc_mbuf_headroom(mbuf); + data_len = uc_mbuf_len(mbuf); + tailroom_len = uc_mbuf_tailroom(mbuf); + tot_len = headroom_len + + data_len + + tailroom_len; + + if (tot_len + len < tot_len) { + //overflowed + return -2; + } + + tot_len += len; + + //need to re-adjust p1-p4 after the realloc + //This assumes the user controlled p1-p4 really are + //set to point into the data, but we document they have + //to be. + if (mbuf->p1 != NULL) { + p1_off = (uint32_t)(mbuf->p1 - mbuf->bufstart); + } + if (mbuf->p2 != NULL) { + p2_off = (uint32_t)(mbuf->p2 - mbuf->bufstart); + } + if (mbuf->p3 != NULL) { + p3_off = (uint32_t)(mbuf->p3 - mbuf->bufstart); + } + if (mbuf->p4 != NULL) { + p4_off = (uint32_t)(mbuf->p4 - mbuf->bufstart); + } + + assert(tot_len >= mbuf->allocated); + + new_data = realloc(mbuf->bufstart, tot_len); + if (new_data == NULL) { + return -3; + } + + mbuf->allocated = tot_len; + mbuf->bufstart = new_data; + mbuf->head = mbuf->bufstart + headroom_len; + mbuf->tail = mbuf->bufstart + headroom_len + data_len; + + assert(uc_mbuf_len(mbuf) == data_len); + assert(uc_mbuf_tailroom(mbuf) >= tailroom_len); + + if (mbuf->p1 != NULL) { + mbuf->p1 = mbuf->bufstart + p1_off; + } + if (mbuf->p2 != NULL) { + mbuf->p2 = mbuf->bufstart + p2_off; + } + if (mbuf->p3 != NULL) { + mbuf->p3 = mbuf->bufstart + p3_off; + } + if (mbuf->p4 != NULL) { + mbuf->p4 = mbuf->bufstart + p4_off; + } + + return 0; + +} diff --git a/test/test_mbuf.c b/test/test_mbuf.c index badfab2..dcdb4b1 100644 --- a/test/test_mbuf.c +++ b/test/test_mbuf.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -240,6 +241,58 @@ START_TEST (test_mbuf_static) END_TEST +START_TEST (test_mbuf_extend_tailroom) + struct MBuf *mbuf; + uint8_t *data; + void *filler; + int rc; + + mbuf = uc_mbuf_new_hr(5,2); + fail_if(mbuf == NULL); + + data = uc_mbuf_put(mbuf, 5); + fail_if(data == NULL); + memcpy((char*)data, "hello", 5); + mbuf->p1 = mbuf->tail; + + data = uc_mbuf_put(mbuf, 6); + fail_if(data != NULL); + + filler = malloc(5); //just a hope, so realloc also moves.. + rc = uc_mbuf_extend_tailroom(mbuf, 1024); + ck_assert_int_eq(rc, 0); + ck_assert_int_eq(uc_mbuf_tailroom(mbuf), 1024); + ck_assert_int_eq(uc_mbuf_headroom(mbuf), 2); + ck_assert_int_eq(uc_mbuf_len(mbuf), 5); + + //should work now + data = uc_mbuf_put(mbuf, 6); + fail_if(data == NULL); + strcpy((char*)data, "world"); + ck_assert_str_eq((const char*)mbuf->head, "helloworld"); + ck_assert_str_eq((const char*)mbuf->p1, "world"); + + uc_mbuf_free(mbuf); + free(filler); + +END_TEST + +START_TEST (test_mbuf_extend_tailroom_wrong_type) + struct MBuf *mbuf; + uint8_t *data; + int rc; + + mbuf = uc_mbuf_new_inline(10); + fail_if(mbuf == NULL); + + rc = uc_mbuf_extend_tailroom(mbuf, 1024); + ck_assert_int_ne(rc, 0); + + fail_if(data == NULL); + + uc_mbuf_free(mbuf); + +END_TEST Suite *mbuf_suite(void) @@ -258,6 +311,8 @@ Suite *mbuf_suite(void) tcase_add_test(tc, test_mbuf_copy); tcase_add_test(tc, test_mbuf_zero); tcase_add_test(tc, test_mbuf_static); + tcase_add_test(tc, test_mbuf_extend_tailroom); + tcase_add_test(tc, test_mbuf_extend_tailroom_wrong_type); suite_add_tcase(s, tc);