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 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/core/nng_impl.h | 64 ++++++++++++++ src/core/panic.c | 86 ++++++++++++++++++ src/core/platform.c | 33 +++++++ src/core/snprintf.c | 36 ++++++++ 5 files changed, 468 insertions(+) create mode 100644 src/core/message.c create mode 100644 src/core/nng_impl.h create mode 100644 src/core/panic.c create mode 100644 src/core/platform.c create mode 100644 src/core/snprintf.c (limited to 'src/core') 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 diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h new file mode 100644 index 00000000..a25b87a4 --- /dev/null +++ b/src/core/nng_impl.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef NNG_IMPL_H +#define NNG_IMPL_H + +#include "nng.h" +#include "platform/platform.h" + +/* + * Internal implementation things for NNG, common definitions, etc. + * + * Hopefully it should be clear by the name that this file and its contents + * are *NOT* for use outside of this library. + * + * Symbols that are private to the library begin with the nni_ prefix, whereas + * those starting with nng_ are intended for external consumption. + */ + +/* + * C compilers may get unhappy when named arguments are not used. While + * there are things like __attribute__((unused)) which are arguably + * superior, support for such are not universal. + */ +#define NNI_ARG_UNUSED(x) ((void)x); + +/* + * We have our own snprintf, because some platforms lack this, while + * others need special handling. Ours just calls the vsnprintf version + * from the platform. + */ +extern void nni_snprintf(char *, size_t, const char *, ...); + +/* + * nni_panic is used to terminate the process with prejudice, and + * should only be called in the face of a critical programming error, + * or other situation where it would be unsafe to attempt to continue. + * As this crashes the program, it should never be used when factors outside + * the program can cause it, such as receiving protocol errors, or running + * out of memory. Its better in those cases to return an error to the + * program and let the caller handle the error situation. + */ +extern void nni_panic(const char *, ...); + +#endif /* NNG_IMPL_H */ diff --git a/src/core/panic.c b/src/core/panic.c new file mode 100644 index 00000000..47556f70 --- /dev/null +++ b/src/core/panic.c @@ -0,0 +1,86 @@ +/* + * 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 + +#ifdef NNG_HAVE_BACKTRACE +#include +#endif + +#include "nng.h" + +#include "nng_impl.h" + +/* + * Panic handling. + */ + +static void +show_backtrace(void) +{ +#if NNG_HAVE_BACKTRACE + void *frames[50]; + int nframes; + char *lines; + int i; + + nframes = backtrace(frames, sizeof (frames) / sizeof (frames[0])); + if (nframes > 1) { + lines = backtrace_symbols(frames, nframes -1); + if (lines == NULL) { + return; + } + for (i = 0; i < nframes; i++) { + nni_debug_out(lines[i]); + } + } +#endif +} + +/* + * nni_panic shows a panic message, a possible stack bracktrace, then aborts + * the process/program. This should only be called when a condition arises + * that should not be possible, e.g. a programming assertion failure. It should + * not be called in situations such as ENOMEM, as nni_panic is fairly rude + * to any application it may be called from within. + */ +void +nni_panic(const char *fmt, ...) +{ + char buf[128]; + char fbuf[128]; + va_list va; + + va_start(va, fmt); + (void) nni_snprintf(fbuf, sizeof (buf), "panic: %s", fmt); + (void) nni_vsnprintf(buf, sizeof (buf), fbuf, va); + va_end(va); + + nni_debug_out(buf); + nni_debug_out("This message is indicative of a BUG."); + nni_debug_out("Report this at http://github.com/nanomsg/nanomsg"); + + show_backtrace(); + nni_abort(); +} diff --git a/src/core/platform.c b/src/core/platform.c new file mode 100644 index 00000000..d96ebe70 --- /dev/null +++ b/src/core/platform.c @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * This file pulls in the correct platform implementation. + */ + +#include "core/nng_impl.h" + +#if defined(PLATFORM_POSIX) +#include "platform/posix/posix_impl.h" +#else +#error "unknown platform" +#endif diff --git a/src/core/snprintf.c b/src/core/snprintf.c new file mode 100644 index 00000000..3ca73e00 --- /dev/null +++ b/src/core/snprintf.c @@ -0,0 +1,36 @@ +/* + * 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 + +#include "nng_impl.h" + +void +nni_snprintf(char *dst, size_t sz, const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + nni_vsnprintf(dst, sz, fmt, va); + va_end(va); +} -- cgit v1.2.3-70-g09d2