aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2016-12-10 22:12:08 -0800
committerGarrett D'Amore <garrett@damore.org>2016-12-10 22:12:08 -0800
commite72c61989757d8c0700f8e48ea82a3d99cf327fc (patch)
tree6e03d6a6993d7f85ea62b23ddc0c6491045fbe5f /src
downloadnng-e72c61989757d8c0700f8e48ea82a3d99cf327fc.tar.gz
nng-e72c61989757d8c0700f8e48ea82a3d99cf327fc.tar.bz2
nng-e72c61989757d8c0700f8e48ea82a3d99cf327fc.zip
Initial commit. This is not going to be useful to you for anything.
Diffstat (limited to 'src')
-rw-r--r--src/README.adoc20
-rw-r--r--src/core/message.c249
-rw-r--r--src/core/nng_impl.h64
-rw-r--r--src/core/panic.c86
-rw-r--r--src/core/platform.c33
-rw-r--r--src/core/snprintf.c36
-rw-r--r--src/nng.h426
-rw-r--r--src/platform/platform.h125
-rw-r--r--src/platform/posix/posix_alloc.h45
-rw-r--r--src/platform/posix/posix_debug.h48
-rw-r--r--src/platform/posix/posix_impl.h41
-rw-r--r--src/platform/posix/posix_synch.h143
-rw-r--r--src/platform/posix/posix_vsnprintf.h30
13 files changed, 1346 insertions, 0 deletions
diff --git a/src/README.adoc b/src/README.adoc
new file mode 100644
index 00000000..7560e656
--- /dev/null
+++ b/src/README.adoc
@@ -0,0 +1,20 @@
+nng - nanomsg-NG
+================
+
+This repository represents a work in progress rewrite of the SP protocol
+library called "libnanomsg". The work is being done by Garrett D'Amore,
+and at this juncture he is *not* soliciting assistance.
+
+This is a work in progress, and is *not* for general use or publication.
+When the library is ready for broader consumption, an announcement will
+be posted on the nanomsg mailing list and website.
+
+If you are looking for the current production version of nanomsg, please
+see the https://github.com/nanomsg/nanomsg site.
+
+Note that commit histories here are subject to change in the future --
+once the production reaches a point that we are ready to start using
+issue tracking and so forth, we will compress the existing deltas into
+a single commit. This is probably some number of weeks in the future.
+
+ - Garrett D'Amore (Dec. 9, 2016)
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 <garrett@damore.org>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#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 <garrett@damore.org>
+ *
+ * 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 <garrett@damore.org>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef NNG_HAVE_BACKTRACE
+#include <execinfo.h>
+#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 <garrett@damore.org>
+ *
+ * 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 <garrett@damore.org>
+ *
+ * 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 <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#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);
+}
diff --git a/src/nng.h b/src/nng.h
new file mode 100644
index 00000000..1075b95a
--- /dev/null
+++ b/src/nng.h
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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_H
+#define NNG_H
+
+/*
+ * NNG (nanomsg-ng) is a next generation implementation of the SP protocols.
+ * The APIs have changed, and there is no attempt to provide API compatibility
+ * with legacy libnanomsg. This file defines the library consumer-facing
+ * Public API. Use of definitions or declarations not found in this header file
+ * is specfically unsupported and strongly discouraged.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * NNG_DECL is used on declarations to deal with scope.
+ * For building Windows DLLs, it should be the appropriate
+ * __declspec(). (We recommend *not* building this library
+ * as a DLL, but instead linking it statically for your projects
+ * to minimize questions about link dependencies later.)
+ */
+#ifndef NNG_DECL
+#define NNG_DECL extern
+#endif
+
+/*
+ * Types common to nng.
+ */
+typedef struct nng_socket *nng_socket_t;
+typedef struct nng_endpt *nng_endpt_t;
+typedef struct nn_pipe *nng_pipe_t;
+typedef struct nn_msg *nng_msg_t;
+typedef struct nn_event *nng_event_t;
+typedef struct nng_notify *nng_notify_t;
+typedef struct nng_snapshot *nng_snapshot_t;
+typedef struct nng_stat *nng_stat_t;
+
+/*
+ * nng_socket simply creates a socket of the given class. It returns an
+ * error code on failure, or zero on success. The socket starts in cooked
+ * mode.
+ */
+NNG_DECL int nng_socket_create(nng_socket_t *, int proto);
+
+/*
+ * nng_socket_close closes the socket, terminating all activity and
+ * closing any underlying connections and releasing any associated
+ * resources. Memory associated with the socket is freed, so it is an
+ * error to reference the socket in any way after this is called. Likewise,
+ * it is an error to reference any resources such as end points associated
+ * with the socket.
+ */
+NNG_DECL int nng_socket_close(nng_socket_t);
+
+/*
+ * nng_socket_setopt sets an option for a specific socket.
+ */
+NNG_DECL int nng_socket_setopt(nng_socket_t, int, void *, size_t);
+
+/*
+ * nng_socket_getopt obtains the option for a socket.
+ */
+NNG_DECL int nng_socket_getopt(nng_socket_t, int, void *, size_t *);
+
+/*
+ * nng_notify_register sets a notification callback. The callback will be
+ * called for any of the requested events. The callback can be deregistered
+ * by calling nng_notify_unregister with the same handle. These notification
+ * callbacks are executed on a separate thread, to avoid potential lock
+ * recursion.
+ */
+NNG_DECL nng_notify_t nng_notify_register(nng_socket_t, int,
+ void (*)(nng_socket_t, nng_event_t, void *), void *);
+NNG_DECL int nng_notify_unregister(nng_socket_t, nng_notify_t);
+
+/*
+ * Event types. Sockets can have multiple different kind of events.
+ * Note that these are edge triggered -- therefore the status indicated
+ * may have changed since the notification occurred.
+ *
+ * NNG_EVENT_RECV - A message is ready for receive.
+ * NNG_EVENT_SEND - A message can be sent.
+ * NNG_EVENT_ERROR - An error condition on the socket occurred.
+ * NNG_EVENT_PIPE_ADD - A new pipe (connection) is added to the socket.
+ * The argument is an nn_pipe_t.
+ * NNG_EVENT_PIPE_RM - A pipe (connection) is removed from the socket.
+ * The argument is an nn_pipe_t.
+ * NNG_EVENT_ENDPT_ADD - An endpoint is added to the socket.
+ * The argument is an nn_endpt_t.
+ * NNG_EVENT_ENDPT_RM - An endpoint is removed from the socket.
+ * The argument is an nn_endpt_t.
+ */
+#define NNG_EVENT_BIT(x) (1U << (x))
+#define NNG_EVENT_RECV NNG_EVENT_BIT(0)
+#define NNG_EVENT_SEND NNG_EVENT_BIT(1)
+#define NNG_EVENT_ERROR NNG_EVENT_BIT(2)
+#define NNG_EVENT_PIPE_ADD NNG_EVENT_BIT(3)
+#define NNG_EVENT_PIPE_RM NNG_EVENT_BIT(4)
+#define NNG_EVENT_ENDPT_ADD NNG_EVENT_BIT(5)
+#define NNG_EVENT_ENDPT_RM NNG_EVENT_BIT(6)
+
+/*
+ * The following functions return more detailed information about the event.
+ * Some of the values will not make sense for some event types, in which case
+ * the value returned will be NULL.
+ */
+NNG_DECL int nng_event_type(nng_event_t);
+NNG_DECL nng_socket_t nng_event_socket(nng_event_t);
+NNG_DECL nng_endpt_t nng_event_endpt(nng_event_t);
+NNG_DECL nng_pipe_t nng_event_pipe(nng_event_t);
+NNG_DECL const char *nng_event_reason(nng_event_t);
+
+/*
+ * nng_socket_listen creates a listening endpoint with no special options,
+ * and starts it listening. It is functionally equivalent to the legacy
+ * nn_bind(). The underlying endpoint is returned back to the caller.
+ */
+NNG_DECL int nng_socket_listen(nng_endpt_t *, nng_socket_t, const char *);
+
+/*
+ * nng_socket_dial creates a dialing endpoint, with no special options,
+ * and starts it dialing. Dialers have at most one active connection at a
+ * time. This is similar to the legacy nn_connect(). The underlying endpoint
+ * is returned back to the caller.
+ */
+NNG_DECL int nng_socket_dial(nng_endpt_t *, nng_socket_t, const char *);
+
+/*
+ * nng_socket_endpt creates an endpoint on the socket, but does not
+ * start it either dialing or connecting.
+ */
+NNG_DECL int nng_socket_endpt(nng_endpt_t *, nng_socket_t, const char *);
+
+/*
+ * nng_endpt_dial starts the endpoint dialing. This is only possible if
+ * the endpoint is not already dialing or listening.
+ */
+NNG_DECL int nng_endpt_dial(nng_endpt_t);
+
+/*
+ * nng_endpt_listen starts the endpoint listening. This is only possible if
+ * the endpoint is not already dialing or listening.
+ */
+NNG_DECL int nng_endpt_listen(nng_endpt_t);
+
+/*
+ * nng_endpt_close closes the endpt, shutting down all underlying
+ * connections and releasing all associated resources. It is an error to
+ * refer to the endpoint after this is called.
+ */
+NNG_DECL int nng_endpt_close(nng_endpt_t);
+
+/*
+ * nng_endpt_setopt sets an option for a specific endpoint. Note
+ * endpoint options may not be altered on a running endpoint.
+ */
+NNG_DECL int nng_endpt_setopt(nng_endpt_t, int, void *, size_t);
+
+/*
+ * nng_endpt_getopt obtains the option for an endpoint.
+ */
+NNG_DECL int nng_endpt_getopt(nng_endpt_t, int, void *, size_t *);
+
+/*
+ * nng_strerror returns a human readable string associated with the error
+ * code supplied.
+ */
+NNG_DECL const char *nng_strerror(int);
+
+/*
+ * nng_send sends (or arranges to send) the data on the socket. Note that
+ * this function may (will!) return before any receiver has actually
+ * received the data. The return value will be zero to indicate that the
+ * socket has accepted the entire data for send, or an errno to indicate
+ * failure. The flags may include NNG_FLAG_NONBLOCK.
+ */
+NNG_DECL int nng_send(nng_socket_t, const void *, size_t, int);
+
+/*
+ * nng_recv receives message data into the socket, up to the supplied size.
+ * The actual size of the message data will be written to the value pointed
+ * to by size. The flags may include NNG_FLAG_NONBLOCK and NNG_FLAG_ALLOC.
+ * If NNG_FLAG_ALLOC is supplied then the library will allocate memory for
+ * the caller. In that case the pointer to the allocated will be stored
+ * instead of the data itself. The caller is responsible for freeing the
+ * associated memory with free().
+ */
+NNG_DECL int nng_recv(nng_socket_t, void *, size_t *, int);
+
+/*
+ * nng_sendmsg is like nng_send, but offers up a message structure, which
+ * gives the ability to provide more control over the message, including
+ * providing backtrace information. It also can take a message that was
+ * obtain via nn_recvmsg, allowing for zero copy forwarding.
+ */
+NNG_DECL int nng_sendmsg(nng_socket_t, nng_msg_t, int);
+
+/*
+ * nng_recvmsg is like nng_recv, but is used to obtain a message structure
+ * as well as the data buffer. This can be used to obtain more information
+ * about where the message came from, access raw headers, etc. It also
+ * can be passed off directly to nng_sendmsg.
+ */
+NNG_DECL int nng_recvmsg(nng_socket_t, nng_msg_t *, int);
+
+/*
+ * Message API.
+ */
+NNG_DECL int nng_msg_alloc(nng_msg_t *, size_t);
+NNG_DECL void nng_msg_free(nng_msg_t);
+NNG_DECL const char *nng_msg_data(nng_msg_t);
+NNG_DECL int nng_msg_realloc(nng_msg_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 *);
+
+/*
+ * Pipe API. Generally pipes are only "observable" to applications, but
+ * we do permit an application to close a pipe. This can be useful, for
+ * example during a connection notification, to disconnect a pipe that
+ * is associated with an invalid or untrusted remote peer.
+ */
+NNG_DECL int nng_pipe_getopt(nng_pipe_t, int, void *, size_t *);
+NNG_DECL int nng_pipe_close(nng_pipe_t);
+
+/*
+ * Protocol numbers. These are to be used with nng_socket_create().
+ * These values are used on the wire, so must not be changed. The major
+ * number of the protocol is shifted left by 4 bits, and a subprotocol is
+ * assigned in the lower 4 bits.
+ *
+ * There are gaps in the list, which are obsolete or unsupported protocols.
+ * For now we assume that protocol numbers are never more than 16 bits.
+ */
+#define NNG_PROTO(major, minor) (((major) * 16) + (minor))
+#define NNG_PROTO_PAIR NNG_PROTO(1, 0)
+#define NNG_PROTO_PUB NNG_PROTO(2, 0)
+#define NNG_PROTO_SUB NNG_PROTO(2, 1)
+#define NNG_PROTO_REQ NNG_PROTO(3, 0)
+#define NNG_PROTO_REP NNG_PROTO(3, 1)
+#define NNG_PROTO_PUSH NNG_PROTO(5, 0)
+#define NNG_PROTO_PULL NNG_PROTO(5, 1)
+#define NNG_PROTO_SURVEYOR NNG_PROTO(6, 2)
+#define NNG_PROTO_RESPONDENT NNG_PROTO(6, 3)
+#define NNG_PROTO_BUS NNG_PROTO(7, 0)
+#define NNG_PROTO_STAR NNG_PROTO(100, 0)
+
+/*
+ * Options. We encode option numbers as follows:
+ *
+ * <level> - 0: socket, 1: transport
+ * <type> - zero (socket), or transport (8 bits)
+ * <code> - specific value (16 bits)
+ *
+ */
+#define NNG_OPT_SOCKET(c) (c)
+#define NNG_OPT_TRANSPORT_OPT(t, c) (0x10000 | ((p) << 16) | (c))
+
+#define NNG_OPT_RAW NNG_OPT_SOCKET(0)
+#define NNG_OPT_LINGER NNG_OPT_SOCKET(1)
+#define NNG_OPT_RCVBUF NNG_OPT_SOCKET(2)
+#define NNG_OPT_SNDBUF NNG_OPT_SOCKET(3)
+#define NNG_OPT_RCVTIMEO NNG_OPT_SOCKET(4)
+#define NNG_OPT_SNDTIMEO NNG_OPT_SOCKET(5)
+#define NNG_OPT_RECONN_TIME NNG_OPT_SOCKET(6)
+#define NNG_OPT_RECONN_MAXTIME NNG_OPT_SOCKET(7)
+#define NNG_OPT_RCVMAXSZ NNG_OPT_SOCKET(8)
+#define NNG_OPT_MAXTTL NNG_OPT_SOCKET(9)
+#define NNG_OPT_PROTOCOL NNG_OPT_SOCKET(10)
+#define NNG_OPT_SUBSCRIBE NNG_OPT_SOCKET(11)
+#define NNG_OPT_UNSUBSCRIBE NNG_OPT_SOCKET(12)
+#define NNG_OPT_SURVEYTIME NNG_OPT_SOCKET(13)
+#define NNG_OPT_RESENDTIME NNG_OPT_SOCKET(14)
+#define NNG_OPT_TRANSPORT NNG_OPT_SOCKET(15)
+#define NNG_OPT_LOCALADDR NNG_OPT_SOCKET(16)
+#define NNG_OPT_REMOTEADDR NNG_OPT_SOCKET(17)
+#define NNG_OPT_RECVFD NNG_OPT_SOCKET(18)
+#define NNG_OPT_SENDFD NNG_OPT_SOCKET(19)
+
+/* XXX: TBD: priorities, socket names, ipv4only */
+
+/*
+ * Statistics. These are for informational purposes only, and subject
+ * to change without notice. The API for accessing these is stable,
+ * but the individual statistic names, values, and meanings are all
+ * subject to change.
+ */
+
+/*
+ * nng_snapshot_create creates a statistics snapshot. The snapshot
+ * object must be deallocated expressly by the user, and may persist beyond
+ * the lifetime of any socket object used to update it. Note that the
+ * values of the statistics are initially unset.
+ */
+NNG_DECL int nng_snapshot_create(nng_snapshot_t *);
+
+/*
+ * nng_snapshot_free frees a snapshot object. All statistic objects
+ * contained therein are destroyed as well.
+ */
+NNG_DECL void nng_snapshot_free(nng_snapshot_t);
+
+/*
+ * nng_snapshot_update updates a snapshot of all the statistics
+ * relevant to a particular socket. All prior values are overwritten.
+ * It is acceptable to use the same snapshot object with different
+ * sockets.
+ */
+NNG_DECL int nng_snapshot_update(nng_socket_t, nng_snapshot_t);
+
+/*
+ * nng_snapshot_iterate is used to iterate over the individual statistic
+ * objects inside the snapshot. Note that the statistic object, and the
+ * meta-data for the object (name, type, units) is fixed, and does not
+ * change for the entire life of the snapshot. Only the value
+ * is subject to change, and then only when a snapshot is updated.
+ *
+ * Iteration begins by providing NULL in the value referenced. Successive
+ * calls will update this value, returning NULL when no more statistics
+ * are available in the snapshot.
+ */
+NNG_DECL nng_stat_t nng_snapshot_iterate(nng_snapshot_t, nng_stat_t);
+
+/*
+ * nng_stat_name is used to determine the name of the statistic.
+ * This is a human readable name. Statistic names, as well as the presence
+ * or absence or semantic of any particular statistic are not part of any
+ * stable API, and may be changed without notice in future updates.
+ */
+NNG_DECL const char *nng_stat_name(nng_stat_t);
+
+/*
+ * nng_stat_type is used to determine the type of the statistic.
+ * At present, only NNG_STAT_TYPE_LEVEL and and NNG_STAT_TYPE_COUNTER
+ * are defined. Counters generally increment, and therefore changes in the
+ * value over time are likely more interesting than the actual level. Level
+ * values reflect some absolute state however, and should be presented to the
+ * user as is.
+ */
+NNG_DECL int nng_stat_type(nng_stat_t);
+#define NNG_STAT_LEVEL 0
+#define NNG_STAT_COUNTER 1
+
+/*
+ * nng_stat_unit provides information about the unit for the statistic,
+ * such as NNG_UNIT_BYTES or NNG_UNIT_BYTES. If no specific unit is
+ * applicable, such as a relative priority, then NN_UNIT_NONE is
+ * returned.
+ */
+NNG_DECL int nng_stat_unit(nng_stat_t);
+#define NNG_UNIT_NONE 0
+#define NNG_UNIT_BYTES 1
+#define NNG_UNIT_MESSAGES 2
+#define NNG_UNIT_BOOLEAN 3
+#define NNG_UNIT_MILLIS 4
+#define NNG_UNIT_EVENTS 5
+
+/*
+ * nng_stat_value returns returns the actual value of the statistic.
+ * Statistic values reflect their value at the time that the corresponding
+ * snapshot was updated, and are undefined until an update is performed.
+ */
+NNG_DECL int64_t nng_stat_value(nng_stat_t);
+
+/*
+ * Device functionality. This connects two sockets together in a device,
+ * which means that messages from one side are forwarded to the other.
+ */
+NNG_DECL int nng_device(nng_socket_t, nng_socket_t);
+
+/*
+ * Pollset functionality. TBD. (Note that I'd rather avoid this
+ * altogether, because I believe that the notification mechanism I've
+ * created offers a superior way to handle this. I don't think many
+ * direct consumers of nn_poll existed in the wild, except via nn_device().
+ * I suspect that there not even many nn_device() consumers.)
+ */
+
+/*
+ * Symbol name and visibility. TBD. The only symbols that really should
+ * be directly exported to runtimes IMO are the option symbols. And frankly
+ * they have enough special logic around them that it might be best not to
+ * automate the promotion of them to other APIs. This is an area open
+ * for discussion.
+ */
+
+/*
+ * Error codes. These may happen to align to errnos used on your platform,
+ * but do not count on this.
+ */
+#define NNG_ENOMEM (-2)
+#define NNG_EINVAL (-3)
+#define NNG_EBUSY (-4)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NNG_H */
diff --git a/src/platform/platform.h b/src/platform/platform.h
new file mode 100644
index 00000000..05f55be9
--- /dev/null
+++ b/src/platform/platform.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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 PLATFORM_H
+#define PLATFORM_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+/*
+ * These are the APIs that a platform must implement to support nng.
+ */
+
+/*
+ * nni_abort crashes the system; it should do whatever is appropriate
+ * for abnormal programs on the platform, such as calling abort().
+ */
+void nni_abort(void);
+
+/*
+ * nni_vnsprintf is exactly like its POSIX counterpart.
+ * Some platforms (Windows!) need a special version of this.
+ */
+void nni_vsnprintf(char *, size_t, const char *, va_list);
+
+/*
+ * nni_debug_output is used to emit debug messages. Typically this is used
+ * during core debugging, or to emit panic messages. Message content will
+ * not contain newlines, but the output will add them.
+ */
+void nni_debug_out(const char *);
+
+/*
+ * nni_set_debug_output is used to redirect debug output; for example an
+ * application could replace the default output routine with one that sends
+ * it's output to syslog. If NULL is specified, then a default handler
+ * used instead. The handler should add any newlines to the output as
+ * required. The default handler writes to standard error.
+ */
+void nni_set_debug_out(void (*)(const char *));
+
+/*
+ * nni_alloc allocates memory. In most cases this can just be malloc().
+ * However, you may provide a different allocator, for example it is
+ * possible to use a slab allocator or somesuch. It is permissible for this
+ * to return NULL if memory cannot be allocated.
+ */
+void *nni_alloc(size_t);
+
+/*
+ * nni_free frees memory allocated with nni_alloc. It takes a size because
+ * some allocators do not track size, or can operate more efficiently if
+ * the size is provided with the free call. Examples of this are slab
+ * allocators like this found in Solaris/illumos (see libumem or kmem).
+ * This routine does nothing if supplied with a NULL pointer and zero size.
+ * Most implementations can just call free() here.
+ */
+void nni_free(void *, size_t);
+
+typedef struct nni_mutex *nni_mutex_t;
+typedef struct nni_cond *nni_cond_t;
+
+/*
+ * Mutex handling.
+ */
+int nni_mutex_create(nni_mutex_t *);
+void nni_mutex_destroy(nni_mutex_t);
+void nni_mutex_enter(nni_mutex_t);
+void nni_mutex_exit(nni_mutex_t);
+int nni_mutex_tryenter(nni_mutex_t);
+int nni_cond_create(nni_cond_t *, nni_mutex_t);
+void nni_cond_destroy(nni_cond_t);
+
+/*
+ * nni_cond_broadcast wakes all waiters on the condition. This should be
+ * called with the lock held.
+ */
+int nni_cond_broadcast(nni_cond_t);
+
+/*
+ * nni_cond_signal wakes a signal waiter.
+ */
+int nni_cond_signal(nni_cond_t);
+
+/*
+ * nni_condwait waits for a wake up on the condition variable. The
+ * associated lock is atomically released and reacquired upon wake up.
+ * Callers can be spuriously woken. The return value is 0 on success,
+ * or an error code. (Most implementations should never return an error.)
+ * Most callers will ignore the return value. The associated lock must
+ * be held.
+ */
+int nni_cond_wait(nni_cond_t);
+
+/*
+ * nni_cond_timedwait waits for a wakeup on the condition variable, just
+ * as with nni_condwait, but it will also wake after the given number of
+ * milliseconds has passed. (This is a relative timed wait.) Early
+ * wakeups are permitted, and the caller must take care to double check any
+ * conditions. The return value is 0 on success, or an error code, which
+ * can be NNG_ETIMEDOUT.
+ */
+int nnp_cond_timedwait(nni_cond_t, int);
+
+#endif /* PLATFORM_H */
diff --git a/src/platform/posix/posix_alloc.h b/src/platform/posix/posix_alloc.h
new file mode 100644
index 00000000..8451cc9c
--- /dev/null
+++ b/src/platform/posix/posix_alloc.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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 is more of a direct #include of a .c rather than .h file.
+ * But having it be a .h makes compiler rules work out properly. Do
+ * not include this more than once into your program, or you will
+ * get multiple symbols defined.
+ */
+
+/*
+ * POSIX memory allocation. This is pretty much standard C.
+ */
+
+void *
+nni_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
+void
+nni_free(void *ptr, size_t size)
+{
+ NNI_ARG_UNUSED(size);
+ free(ptr);
+}
diff --git a/src/platform/posix/posix_debug.h b/src/platform/posix/posix_debug.h
new file mode 100644
index 00000000..d25a6c11
--- /dev/null
+++ b/src/platform/posix/posix_debug.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+
+void (*debug_out)(const char *line);
+
+void
+nni_abort(void)
+{
+ abort();
+}
+
+void
+nni_debug_out(const char *message)
+{
+ if (debug_out != NULL) {
+ debug_out(message);
+ } else {
+ (void) fprintf(stderr, "%s\n", message);
+ }
+}
+
+void
+nni_set_debug_out(void (*out)(const char *))
+{
+ debug_out = out;
+}
diff --git a/src/platform/posix/posix_impl.h b/src/platform/posix/posix_impl.h
new file mode 100644
index 00000000..291e3f2e
--- /dev/null
+++ b/src/platform/posix/posix_impl.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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 is more of a direct #include of a .c rather than .h file.
+ * But having it be a .h makes compiler rules work out properly. Do
+ * not include this more than once into your program, or you will
+ * get multiple symbols defined.
+ *
+ * The file itself pulls in POSIX implementations for platform specific
+ * functionality.
+ */
+
+#ifdef PLATFORM_POSIX
+
+#include "platform/posix/posix_debug.h"
+#include "platform/posix/posix_alloc.h"
+#include "platform/posix/posix_synch.h"
+/* #include "platform/posix/posix_thread.h" */
+#include "platform/posix/posix_vsnprintf.h"
+
+#endif
diff --git a/src/platform/posix/posix_synch.h b/src/platform/posix/posix_synch.h
new file mode 100644
index 00000000..4a3a152d
--- /dev/null
+++ b/src/platform/posix/posix_synch.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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 is more of a direct #include of a .c rather than .h file.
+ * But having it be a .h makes compiler rules work out properly. Do
+ * not include this more than once into your program, or you will
+ * get multiple symbols defined.
+ */
+
+/*
+ * POSIX synchronization (mutexes and condition variables).
+ */
+
+#include <pthread.h>
+
+struct nni_mutex {
+ pthread_mutex_t mx;
+};
+
+struct nni_cond {
+ pthread_cond_t cv;
+ pthread_mutex_t *mx;
+};
+
+int
+nni_mutex_create(nni_mutex_t *mp)
+{
+ struct nni_mutex *m;
+ pthread_mutexattr_t attr;
+ int rv;
+
+ if ((m = nni_alloc(sizeof (*m))) == NULL) {
+ return (NNG_ENOMEM);
+ }
+
+ /* We ask for more error checking... */
+ if (pthread_mutexattr_init(&attr) != 0) {
+ nni_free(m, sizeof (*m));
+ return (NNG_ENOMEM);
+ }
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0) {
+ nni_panic("pthread_mutexattr_settype failed");
+ }
+
+ rv = pthread_mutex_init(&m->mx, &attr);
+
+ if (pthread_mutexattr_destroy(&attr) != 0) {
+ nni_panic("pthread_mutexattr_destroy failed");
+ }
+
+ if (rv != 0) {
+ nni_free(m, sizeof (*m));
+ return (NNG_ENOMEM);
+ }
+ *mp = m;
+ return (0);
+}
+
+void
+nni_mutex_destroy(nni_mutex_t m)
+{
+ if (pthread_mutex_destroy(&m->mx) != 0) {
+ nni_panic("pthread_mutex_destroy failed");
+ }
+ /*
+ * If destroy fails for some reason, we can't really do
+ * anything about it. This would actually represent a programming
+ * bug, and the right thing to do here would be to panic.
+ */
+ nni_free(m, sizeof (*m));
+}
+
+void
+nni_mutex_enter(nni_mutex_t m)
+{
+ if (pthread_mutex_lock(&m->mx) != 0) {
+ nni_panic("pthread_mutex_lock failed");
+ }
+}
+
+void
+nni_mutex_exit(nni_mutex_t m)
+{
+ if (pthread_mutex_unlock(&m->mx) != 0) {
+ nni_panic("pthread_mutex_unlock failed");
+ }
+}
+
+int
+nni_mutex_tryenter(nni_mutex_t m)
+{
+ if (pthread_mutex_trylock(&m->mx) != 0) {
+ return (NNG_EBUSY);
+ }
+ return (0);
+}
+
+int
+nni_cond_create(nni_cond_t *cvp, nni_mutex_t mx)
+{
+ struct nni_cond *c;
+ if ((c = nni_alloc(sizeof (*c))) == NULL) {
+ return (NNG_ENOMEM);
+ }
+ c->mx = &mx->mx;
+ if (pthread_cond_init(&c->cv, NULL) != 0) {
+ /* In theory could be EAGAIN, but handle like ENOMEM */
+ nni_free(c, sizeof (*c));
+ return (NNG_ENOMEM);
+ }
+ *cvp = c;
+ return (0);
+}
+
+void
+nni_cond_destroy(nni_cond_t c)
+{
+ if (pthread_cond_destroy(&c->cv) != 0) {
+ nni_panic("pthread_cond_destroy failed");
+ }
+ nni_free(c, sizeof (*c));
+}
diff --git a/src/platform/posix/posix_vsnprintf.h b/src/platform/posix/posix_vsnprintf.h
new file mode 100644
index 00000000..8270d255
--- /dev/null
+++ b/src/platform/posix/posix_vsnprintf.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Garrett D'Amore <garrett@damore.org>
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+void
+nni_vsnprintf(char *dst, size_t sz, const char *fmt, va_list va)
+{
+ (void) vsnprintf(dst, sz, fmt, va);
+}