X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcbuffer.h;h=dc9d405cdb51ea3b0714179ab9261c2b1e16fed6;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=d98877bf812cf5220cabfe33ebc93bb6af41325b;hpb=0d868f8c94519610b54ca5bbff995e595b91d28f;p=silc.git diff --git a/lib/silcutil/silcbuffer.h b/lib/silcutil/silcbuffer.h index d98877bf..dc9d405c 100644 --- a/lib/silcutil/silcbuffer.h +++ b/lib/silcutil/silcbuffer.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1998 - 2007 Pekka Riikonen + Copyright (C) 1998 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -135,6 +135,21 @@ typedef struct SilcBufferObject { #define silc_buffer_data(x) (x)->data /***/ +/****f* silcutil/SilcBufferAPI/silc_buffer_tail + * + * NAME + * + * unsigned char *silc_buffer_tail(SilcBuffer sb) + * + * DESCRIPTION + * + * Returns pointer to the tail area of the buffer. + * + * SOURCE + */ +#define silc_buffer_tail(x) (x)->tail +/***/ + /****f* silcutil/SilcBufferAPI/silc_buffer_datalen * * NAME @@ -238,7 +253,8 @@ SilcUInt32 silc_buffer_taillen(SilcBuffer x) * * DESCRIPTION * - * Allocates new SilcBuffer and returns it. Returns NULL on error. + * Allocates new SilcBuffer and returns it. Returns NULL if system is + * out of memory. * ***/ @@ -276,7 +292,8 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len) * * DESCRIPTION * - * Allocates new SilcBuffer and returns it. + * Allocates new SilcBuffer and returns it. Returns NULL if system is + * out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -503,7 +520,8 @@ void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len) * * Pulls current data area towards end. The length of the currently * valid data area is also decremented. Returns pointer to the data - * area before pulling. Returns NULL on error. + * area before pulling. Returns NULL if the pull would lead to buffer + * overflow or would go beyond the valid data area. * * EXAMPLE * @@ -530,8 +548,10 @@ unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len) #ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_len(sb)); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely(len > silc_buffer_len(sb))) + if (silc_unlikely(len > silc_buffer_len(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } sb->data += len; return old_data; @@ -548,7 +568,8 @@ unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len) * * Pushes current data area towards beginning. Length of the currently * valid data area is also incremented. Returns a pointer to the - * data area before pushing. Returns NULL on error. + * data area before pushing. Returns NULL if the push would lead to + * go beyond the buffer boundaries or current data area. * * EXAMPLE * @@ -575,8 +596,10 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len) #ifdef SILC_DIST_INPLACE SILC_ASSERT((sb->data - len) >= sb->head); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely((sb->data - len) < sb->head)) + if (silc_unlikely((sb->data - len) < sb->head)) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } sb->data -= len; return old_data; @@ -593,7 +616,7 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len) * * Pulls current tail section towards end. Length of the current valid * data area is also incremented. Returns a pointer to the data area - * before pulling. Returns NULL on error. + * before pulling. Returns NULL if the pull would lead to buffer overflow. * * EXAMPLE * @@ -620,8 +643,10 @@ unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len) #ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_taillen(sb)); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely(len > silc_buffer_taillen(sb))) + if (silc_unlikely(len > silc_buffer_taillen(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } sb->tail += len; return old_tail; @@ -638,7 +663,8 @@ unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len) * * Pushes current tail section towards beginning. Length of the current * valid data area is also decremented. Returns a pointer to the - * tail section before pushing. Returns NULL on error. + * tail section before pushing. Returns NULL if the push would lead to + * go beyond buffer boundaries or current tail area. * * EXAMPLE * @@ -665,8 +691,10 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len) #ifdef SILC_DIST_INPLACE SILC_ASSERT((sb->tail - len) >= sb->data); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely((sb->tail - len) < sb->data)) + if (silc_unlikely((sb->tail - len) < sb->data)) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } sb->tail -= len; return old_tail; @@ -684,7 +712,8 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len) * DESCRIPTION * * Puts data at the head of the buffer. Returns pointer to the copied - * data area. Returns NULL on error. + * data area. Returns NULL if the data is longer that the current head + * area. * * EXAMPLE * @@ -706,8 +735,18 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, #ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_headlen(sb)); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely(len > silc_buffer_headlen(sb))) + if (silc_unlikely(len > silc_buffer_headlen(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } + + if (sb->head > data) { + if (sb->head - data <= len) + return (unsigned char *)memmove(sb->head, data, len); + } else { + if (data - sb->head <= len) + return (unsigned char *)memmove(sb->head, data, len); + } return (unsigned char *)memcpy(sb->head, data, len); } @@ -724,7 +763,8 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, * DESCRIPTION * * Puts data at the start of the valid data area. Returns a pointer - * to the copied data area. Returns NULL on error. + * to the copied data area. Returns NULL if the data is longer than the + * current data area. * * EXAMPLE * @@ -746,8 +786,18 @@ unsigned char *silc_buffer_put(SilcBuffer sb, #ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_len(sb)); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely(len > silc_buffer_len(sb))) + if (silc_unlikely(len > silc_buffer_len(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } + + if (sb->data > data) { + if (sb->data - data <= len) + return (unsigned char *)memmove(sb->data, data, len); + } else { + if (data - sb->data <= len) + return (unsigned char *)memmove(sb->data, data, len); + } return (unsigned char *)memcpy(sb->data, data, len); } @@ -764,7 +814,8 @@ unsigned char *silc_buffer_put(SilcBuffer sb, * DESCRIPTION * * Puts data at the tail of the buffer. Returns pointer to the copied - * data area. Returns NULL on error. + * data area. Returns NULL if the data is longer than the current tail + * area. * * EXAMPLE * @@ -786,8 +837,18 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, #ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_taillen(sb)); #endif /* SILC_DIST_INPLACE */ - if (silc_unlikely(len > silc_buffer_taillen(sb))) + if (silc_unlikely(len > silc_buffer_taillen(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; + } + + if (sb->tail > data) { + if (sb->tail - data <= len) + return (unsigned char *)memmove(sb->tail, data, len); + } else { + if (data - sb->tail <= len) + return (unsigned char *)memmove(sb->tail, data, len); + } return (unsigned char *)memcpy(sb->tail, data, len); } @@ -803,7 +864,7 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, * * Allocates `len' bytes size buffer and moves the tail area automatically * `len' bytes so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. Returns NULL on error. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * ***/ @@ -828,7 +889,7 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len) * * Allocates `len' bytes size buffer and moves the tail area automatically * `len' bytes so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -943,7 +1004,7 @@ void silc_buffer_end(SilcBuffer sb) * * Generates copy of a SilcBuffer. This copies everything inside the * currently valid data area, nothing more. Use silc_buffer_clone to - * copy entire buffer. Returns NULL on error. + * copy entire buffer. Returns NULL if system is out of memory. * ***/ @@ -971,7 +1032,7 @@ SilcBuffer silc_buffer_copy(SilcBuffer sb) * * Generates copy of a SilcBuffer. This copies everything inside the * currently valid data area, nothing more. Use silc_buffer_clone to - * copy entire buffer. + * copy entire buffer. Returns NULL if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -1005,7 +1066,7 @@ SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb) * * Clones SilcBuffer. This generates new SilcBuffer and copies * everything from the source buffer. The result is exact clone of - * the original buffer. Returns NULL on error. + * the original buffer. Returns NULL if system is out of memory. * ***/ @@ -1035,7 +1096,7 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb) * * Clones SilcBuffer. This generates new SilcBuffer and copies * everything from the source buffer. The result is exact clone of - * the original buffer. + * the original buffer. Returns NULL if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -1070,9 +1131,14 @@ SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb) * DESCRIPTION * * Reallocates buffer. Old data is saved into the new buffer. The buffer - * is exact clone of the old one except that there is now more space + * is exact clone of the old one except that there is now more/less space * at the end of buffer. This always returns the same `sb' unless `sb' - * was NULL. Returns NULL on error. + * was NULL. Returns NULL if system is out of memory. + * + * If the `newsize' is shorter than the current buffer size, the data + * and tail area of the buffer must be set to correct position before + * calling this function so that buffer overflow would not occur when + * the buffer size is reduced. * ***/ @@ -1085,7 +1151,7 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) if (!sb) return silc_buffer_alloc(newsize); - if (silc_unlikely(newsize <= silc_buffer_truelen(sb))) + if (silc_unlikely(newsize == silc_buffer_truelen(sb))) return sb; hlen = silc_buffer_headlen(sb); @@ -1112,8 +1178,14 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) * DESCRIPTION * * Reallocates buffer. Old data is saved into the new buffer. The buffer - * is exact clone of the old one except that there is now more space - * at the end of buffer. + * is exact clone of the old one except that there is now more/less space + * at the end of buffer. Returns NULL if system is out of memory. This + * always returns `sb' unless `sb' was NULL. + * + * If the `newsize' is shorter than the current buffer size, the data + * and tail area of the buffer must be set to correct position before + * calling this function so that buffer overflow would not occur when + * the buffer size is reduced. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -1136,21 +1208,15 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, if (!sb) return silc_buffer_salloc(stack, newsize); - if (newsize <= silc_buffer_truelen(sb)) + if (newsize == silc_buffer_truelen(sb)) return sb; hlen = silc_buffer_headlen(sb); dlen = silc_buffer_len(sb); h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb), sb->head, newsize); - if (!h) { - /* Do slow and stack wasting realloc. The old sb->head is lost and - is freed eventually. */ - h = (unsigned char *)silc_smalloc(stack, newsize); - if (silc_unlikely(!h)) - return NULL; - memcpy(h, sb->head, silc_buffer_truelen(sb)); - } + if (!h) + return NULL; sb->head = h; sb->data = sb->head + hlen; @@ -1171,7 +1237,7 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, * * Same as silc_buffer_realloc but moves moves the tail area * automatically so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. Returns NULL on error. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * ***/ @@ -1197,7 +1263,7 @@ SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize) * * Same as silc_buffer_srealloc but moves moves the tail area * automatically so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -1233,7 +1299,7 @@ SilcBuffer silc_buffer_srealloc_size(SilcStack stack, * is at least the size of `size'. If there is more space than `size' * in the data area this does not do anything. If there is enough * space in the tail area this merely moves the tail area to reveal - * the extra space. Returns FALSE on error. + * the extra space. Returns FALSE if system is out of memory. * ***/ @@ -1267,7 +1333,7 @@ SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size) * is at least the size of `size'. If there is more space than `size' * in the data area this does not do anything. If there is enough * space in the tail area this merely moves the tail area to reveal - * the extra space. Returns FALSE on error. + * the extra space. Returns FALSE if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -1292,6 +1358,106 @@ SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size) return TRUE; } +/****f* silcutil/SilcBufferAPI/silc_buffer_append + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size); + * + * DESCRIPTION + * + * Appends the current data area by the amount of `size'. The tail area + * of the buffer remains intact and contains the same data than the old + * tail area (the data is copied to the new tail area). After appending + * there is now `size' bytes more free area in the data area. Returns + * FALSE if system is out of memory. + * + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); + * + ***/ + +static inline +SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size) +{ + if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size))) + return FALSE; + + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); + + /* Copy old tail area to new tail area */ + silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb)); + + return TRUE; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_append + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, + * SilcUInt32 size) + * + * DESCRIPTION + * + * Appends the current data area by the amount of `size'. The tail area + * of the buffer remains intact and contains the same data than the old + * tail area (the data is copied to the new tail area). After appending + * there is now `size' bytes more free area in the data area. Returns + * FALSE if system is out of memory. + * + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. + * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); + * + ***/ + +static inline +SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size) +{ + if (silc_unlikely(!silc_buffer_srealloc(stack, sb, + silc_buffer_truelen(sb) + size))) + return FALSE; + + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); + + /* Copy old tail area to new tail area */ + silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb)); + + return TRUE; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_strchr * * SYNOPSIS @@ -1345,4 +1511,74 @@ unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first) return NULL; } +/****f* silcutil/SilcBufferAPI/silc_buffer_equal + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2) + * + * DESCRIPTION + * + * Compares if the data area of the buffer `sb1' and `sb2' are identical. + * Returns TRUE if they match and FALSE if they differ. + * + ***/ + +static inline +SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2) +{ + if (silc_buffer_len(sb1) != silc_buffer_len(sb2)) + return FALSE; + return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_memcmp + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_memcmp(SilcBuffer buffer, + * const unsigned char *data, + * SilcUInt32 data_len) + * + * DESCRIPTION + * + * Compares the data area of the buffer with the `data'. Returns TRUE + * if the data area is identical to `data' or FALSE if they differ. + * + ***/ + +static inline +SilcBool silc_buffer_memcmp(SilcBuffer buffer, const unsigned char *data, + SilcUInt32 data_len) +{ + if (silc_buffer_len(buffer) != data_len) + return FALSE; + return memcmp(buffer->data, data, data_len) == 0; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_printf + * + * SYNOPSIS + * + * static inline + * void silc_buffer_printf(SilcBuffer sb, SilcBool newline); + * + * DESCRIPTION + * + * Prints the current data area of `sb' into stdout. If `newline' is + * TRUE prints '\n' after the data in the buffer. + * + ***/ + +static inline +void silc_buffer_printf(SilcBuffer sb, SilcBool newline) +{ + silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb)); + if (newline) + printf("\n"); + fflush(stdout); +} + #endif /* SILCBUFFER_H */