From e72c61989757d8c0700f8e48ea82a3d99cf327fc Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Sat, 10 Dec 2016 22:12:08 -0800 Subject: Initial commit. This is not going to be useful to you for anything. --- src/core/message.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 src/core/message.c (limited to 'src/core/message.c') diff --git a/src/core/message.c b/src/core/message.c new file mode 100644 index 00000000..20ca6b80 --- /dev/null +++ b/src/core/message.c @@ -0,0 +1,249 @@ +/* + * Copyright 2016 Garrett D'Amore + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include + +#include "../nng.h" + +#include "nng_impl.h" + +/* + * Message API. + */ + +/* Message chunk, internal to the message implementation. */ +typedef struct { + size_t ch_cap; /* allocated size */ + size_t ch_len; /* length in use */ + char *ch_buf; /* underlying buffer */ + char *ch_ptr; /* pointer to actual data */ +} chunk_t; + +/* Underlying message chunk. */ +struct nng_msg { + chunk_t m_header; + chunk_t m_body; + int64_t m_expire; /* Unix usec */ + nng_pipe_t m_pipe; /* Pipe message was received on */ +}; + +/* + * chunk_grow increases the underlying space for a chunk. It ensures + * that the desired amount of trailing space (including the length) + * and headroom (excluding the length) are available. It also copies + * any extant referenced data. Note that the capacity will increase, + * but not the length. To increase the length of the referenced data, + * use either chunk_append or chunk_prepend. + * + * Note that having some headroom is useful when data must be prepended + * to a message - it avoids having to perform extra data copies, so we + * encourage initial allocations to start with sufficient room. + */ +static int +chunk_grow(chunk_t *ch, size_t newsz, size_t headwanted) +{ + size_t headroom = 0; + char *newbuf; + + /* + * We assume that if the pointer is a valid pointer, and inside + * the backing store, then the entire data length fits. In this + * case we perform a logical realloc, except we don't copy any + * unreferenced data. We do preserve the headroom of the previous + * use, since that may be there for a reason. + * + * The test below also covers the case where the pointers are both + * NULL, or the capacity is zero. + */ + + if ((ch->ch_ptr >= ch->ch_buf) && + (ch->ch_ptr < (ch->ch_buf + ch->ch_cap))) { + + headroom = (size_t)(ch->ch_ptr - ch->ch_buf); + if (((newsz + headwanted) < ch->ch_cap) && + (headwanted <= headroom)) { + /* We have enough space at the ends already. */ + return (0); + } + if (headwanted < headroom) { + /* We never shrink... headroom either. */ + headwanted = headroom; + } + if ((newbuf = nni_alloc(newsz + headwanted)) == NULL) { + return (NNG_ENOMEM); + } + /* Copy all the data, but not header or trailer. */ + memcpy(newbuf + headwanted, ch->ch_buf + headroom, ch->ch_len); + nni_free(ch->ch_buf, ch->ch_cap); + ch->ch_buf = newbuf; + ch->ch_ptr = newbuf + headwanted; + ch->ch_cap = newsz + headwanted; + return (0); + } + + /* + * We either don't have a data pointer yet, or it doesn't reference + * the backing store. In this case, we just check against the + * allocated capacity and grow, or don't grow. + */ + if (newsz > ch->ch_cap) { + /* Enough space at end, so just use it. */ + if (ch->ch_ptr == NULL) { + ch->ch_ptr = ch->ch_buf; + } + return (0); + + } else if ((newbuf = nni_alloc(newsz)) == NULL) { + return (NNG_ENOMEM); + } + + nni_free(ch->ch_buf, ch->ch_cap); + ch->ch_buf = newbuf; + ch->ch_cap = newsz; + if (ch->ch_ptr == NULL) { + ch->ch_ptr = ch->ch_buf; + } + return (0); +} + +static void +chunk_free(chunk_t *ch) +{ + if ((ch->ch_cap != 0) && (ch->ch_buf != NULL)) { + nni_free(ch->ch_buf, ch->ch_cap); + } + ch->ch_ptr = NULL; + ch->ch_buf = NULL; + ch->ch_len = 0; + ch->ch_cap = 0; +} + +/* chunk_trunc truncates the number of bytes from the end of the chunk. */ +static int +chunk_trunc(chunk_t *ch, size_t len) +{ + if (ch->ch_len < len) { + return (NNG_EINVAL); + } + ch->ch_len -= len; + return (0); +} + +/* chunk_trim removes the number of bytes from the beginning of the chunk. */ +static int +chunk_trim(chunk_t *ch, size_t len) +{ + if (ch->ch_len < len) { + return (NNG_EINVAL); + } + ch->ch_ptr += len; + ch->ch_len -= len; + return (0); +} + +/* + * chunk_append appends the data to the chunk, growing the size as necessary. + * If the data pointer is NULL, then the chunk data region is allocated, but + * uninitialized. + */ +static int +chunk_append(chunk_t *ch, const char *data, size_t len) +{ + int rv; + if (len == 0) { + return (0); + } + if ((rv = chunk_grow(ch, len + ch->ch_len, 0)) != 0) { + return (rv); + } + if (ch->ch_ptr == NULL) { + ch->ch_ptr = ch->ch_buf; + } + if (data != NULL) { + memcpy(ch->ch_ptr + ch->ch_len, data, len); + } + ch->ch_len += len; + return (0); +} + +/* + * chunk_prepend prepends data to the chunk, as efficiently as possible. + * If the data pointer is NULL, then no data is actually copied, but the + * data region will have "grown" in the beginning, with uninitialized data. + */ +static int +chunk_prepend(chunk_t *ch, const char *data, size_t len) +{ + int rv; + char *newbuf; + size_t headroom = 0; + + if (ch->ch_ptr == NULL) { + ch->ch_ptr = ch->ch_buf; + } + + if ((ch->ch_ptr >= ch->ch_buf) && + (ch->ch_ptr < (ch->ch_buf + ch->ch_cap)) && + (len <= (size_t)(ch->ch_ptr - ch->ch_buf))) { + /* There is already enough room at the beginning. */ + ch->ch_ptr -= len; + + } else if ((ch->ch_len + len) <= ch->ch_cap) { + /* We had enough capacity, just shuffle data down. */ + memmove(ch->ch_ptr + len, ch->ch_ptr, ch->ch_len); + + } else if ((rv = chunk_grow(ch, 0, len)) == 0) { + /* We grew the chunk, so adjust. */ + ch->ch_ptr -= len; + + } else { + /* Couldn't grow the chunk either. Error. */ + return (rv); + } + + ch->ch_len += len; + if (data) { + memcpy(ch->ch_ptr, data, len); + } + + return (0); +} + +#if 0 +NNG_DECL int nng_msg_alloc(nng_msg_t *, size_t); +NNG_DECL void nng_msg_free(nng_msg_t); +NNG_DECL int nng_msg_realloc(nng_mst_t, size_t); +NNG_DECL void *nng_msg_header(nng_msg_t, size_t *); +NNG_DECL void *nng_msg_body(nng_msg_t, size_t *); +NNG_DECL int nng_msg_port(nng_msg_t, nng_pipe_t *); + +NNG_DECL int nng_msg_append(nng_msg_t, const char *, size_t); +NNG_DECL int nng_msg_prepend(nng_msg_t, const char *, size_t); +NNG_DECL int nng_msg_trim(nng_msg_t, size_t); +NNG_DECL int nng_msg_trunc(nng_msg_t, size_t); + +NNG_DECL int nng_msg_append_header(nng_msg_t, const char *, size_t); +NNG_DECL int nng_msg_prepend_header(nng_msg_t, const char *, size_t); +NNG_DECL int nng_msg_trim_header(nng_msg_t, size_t); +NNG_DECL int nng_msg_trunc_header(nng_msg_t, size_t); +#endif -- cgit v1.2.3-70-g09d2