aboutsummaryrefslogtreecommitdiff
path: root/src/nng_compat.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-02-23 14:48:46 -0800
committerGarrett D'Amore <garrett@damore.org>2018-02-23 14:48:46 -0800
commitc457bddfae64521ea9861f2211e6cb25858559b3 (patch)
tree4c0ef1c7450198ce14ef4fbcdddb5d47e911fb4f /src/nng_compat.c
parentc31c9147320741904b604e2172f99d5ca08eb417 (diff)
downloadnng-c457bddfae64521ea9861f2211e6cb25858559b3.tar.gz
nng-c457bddfae64521ea9861f2211e6cb25858559b3.tar.bz2
nng-c457bddfae64521ea9861f2211e6cb25858559b3.zip
Move compatibility header so that <nanomsg/nn.h> works.
Basically, we have moved the compat stuff into a separate directory. Compatibility layer users will have to update their compile flags, but should be able to avoid changing any *source* files with this change.
Diffstat (limited to 'src/nng_compat.c')
-rw-r--r--src/nng_compat.c728
1 files changed, 0 insertions, 728 deletions
diff --git a/src/nng_compat.c b/src/nng_compat.c
deleted file mode 100644
index 35bacb6f..00000000
--- a/src/nng_compat.c
+++ /dev/null
@@ -1,728 +0,0 @@
-//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-// Copyright 2017 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include "nng_compat.h"
-#include "nng.h"
-#include "protocol/bus0/bus.h"
-#include "protocol/pair0/pair.h"
-#include "protocol/pipeline0/pull.h"
-#include "protocol/pipeline0/push.h"
-#include "protocol/pubsub0/pub.h"
-#include "protocol/pubsub0/sub.h"
-#include "protocol/reqrep0/rep.h"
-#include "protocol/reqrep0/req.h"
-#include "protocol/survey0/respond.h"
-#include "protocol/survey0/survey.h"
-
-#include <stdio.h>
-#include <string.h>
-
-// This file supplies the legacy compatibility API. Applications should
-// avoid using these if at all possible, and instead use the new style APIs.
-
-static const struct {
- int nerr;
- int perr;
-} nn_errnos[] = {
- // clang-format off
- { NNG_EINTR, EINTR },
- { NNG_ENOMEM, ENOMEM },
- { NNG_EINVAL, EINVAL },
- { NNG_EBUSY, EBUSY },
- { NNG_ETIMEDOUT, ETIMEDOUT },
- { NNG_ECONNREFUSED, ECONNREFUSED },
- { NNG_ECLOSED, EBADF },
- { NNG_EAGAIN, EAGAIN },
- { NNG_ENOTSUP, ENOTSUP },
- { NNG_EADDRINUSE, EADDRINUSE },
- { NNG_ESTATE, EFSM },
- { NNG_ENOENT, ENOENT },
- { NNG_EPROTO, EPROTO },
- { NNG_EUNREACHABLE, EHOSTUNREACH },
- { NNG_EADDRINVAL, EADDRNOTAVAIL },
- { NNG_EPERM, EACCES },
- { NNG_EMSGSIZE, EMSGSIZE },
- { NNG_ECONNABORTED, ECONNABORTED },
- { NNG_ECONNRESET, ECONNRESET },
- { NNG_ECANCELED, EBADF },
- { 0, 0 },
- // clang-format on
-};
-
-const char *
-nn_strerror(int err)
-{
- int i;
- static char msgbuf[32];
-
- for (i = 0; nn_errnos[i].perr != 0; i++) {
- if (nn_errnos[i].perr == err) {
- return (nng_strerror(nn_errnos[i].nerr));
- }
- }
- if (err == EIO) {
- return ("Unknown I/O error");
- }
-
- // Arguably we could use strerror() here, but we should only
- // be getting errnos we understand at this point.
- (void) snprintf(msgbuf, sizeof(msgbuf), "Unknown error %d", err);
- return (msgbuf);
-}
-
-static void
-nn_seterror(int err)
-{
- int i;
-
- for (i = 0; nn_errnos[i].nerr != 0; i++) {
- if (nn_errnos[i].nerr == err) {
- errno = nn_errnos[i].perr;
- return;
- }
- }
- // No idea...
- errno = EIO;
-}
-
-int
-nn_errno(void)
-{
- return (errno);
-}
-
-static const struct {
- uint16_t p_id;
- int (*p_open)(nng_socket *);
-} nn_protocols[] = {
-// clang-format off
-#ifdef NNG_HAVE_BUS0
- { NN_BUS, nng_bus0_open },
-#endif
-#ifdef NNG_HAVE_PAIR0
- { NN_PAIR, nng_pair0_open },
-#endif
-#ifdef NNG_HAVE_PUSH0
- { NN_PUSH, nng_push0_open },
-#endif
-#ifdef NNG_HAVE_PULL0
- { NN_PULL, nng_pull0_open },
-#endif
-#ifdef NNG_HAVE_PUB0
- { NN_PUB, nng_pub0_open },
-#endif
-#ifdef NNG_HAVE_SUB0
- { NN_SUB, nng_sub0_open },
-#endif
-#ifdef NNG_HAVE_REQ0
- { NN_REQ, nng_req0_open },
-#endif
-#ifdef NNG_HAVE_REP0
- { NN_REP, nng_rep0_open },
-#endif
-#ifdef NNG_HAVE_SURVEYOR0
- { NN_SURVEYOR, nng_surveyor0_open },
-#endif
-#ifdef NNG_HAVE_RESPONDENT0
- { NN_RESPONDENT, nng_respondent0_open },
-#endif
- { 0, NULL },
- // clang-format on
-};
-
-int
-nn_socket(int domain, int protocol)
-{
- nng_socket sock;
- int rv;
- int i;
-
- if ((domain != AF_SP) && (domain != AF_SP_RAW)) {
- errno = EAFNOSUPPORT;
- return (-1);
- }
-
- for (i = 0; nn_protocols[i].p_id != 0; i++) {
- if (nn_protocols[i].p_id == protocol) {
- break;
- }
- }
- if (nn_protocols[i].p_open == NULL) {
- errno = ENOTSUP;
- return (-1);
- }
-
- if ((rv = nn_protocols[i].p_open(&sock)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
- if (domain == AF_SP_RAW) {
- if ((rv = nng_setopt_int(sock, NNG_OPT_RAW, 1)) != 0) {
- nn_seterror(rv);
- nng_close(sock);
- return (-1);
- }
- }
- return ((int) sock);
-}
-
-int
-nn_close(int s)
-{
- int rv;
-
- if ((rv = nng_close((nng_socket) s)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
- return (0);
-}
-
-int
-nn_bind(int s, const char *addr)
-{
- int rv;
- nng_listener l;
-
- if ((rv = nng_listen((nng_socket) s, addr, &l, 0)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
- return ((int) l);
-}
-
-int
-nn_connect(int s, const char *addr)
-{
- int rv;
- nng_dialer d;
-
- if ((rv = nng_dial((nng_socket) s, addr, &d, NNG_FLAG_NONBLOCK)) !=
- 0) {
- nn_seterror(rv);
- return (-1);
- }
- return ((int) d);
-}
-
-int
-nn_shutdown(int s, int ep)
-{
- int rv;
- (void) s; // Unused
-
- // Socket is wired into the endpoint... so passing a bad endpoint
- // ID can result in affecting the wrong socket. But this requires
- // a buggy application, and because we don't recycle endpoints
- // until wrap, its unlikely to actually come up in practice.
- // Note that listeners and dialers share the same namespace
- // in the core, so we can close either one this way.
-
- if (((rv = nng_dialer_close((nng_dialer) ep)) != 0) &&
- ((rv = nng_listener_close((nng_listener) ep)) != 0)) {
- nn_seterror(rv);
- return (-1);
- }
- return (0);
-}
-
-void *
-nn_allocmsg(size_t size, int type)
-{
- nng_msg *msg;
- int rv;
-
- // Validate type and non-zero size. This also checks for overflow.
- if ((type != 0) || (size < 1) || ((size + sizeof(msg) < size))) {
- nn_seterror(NNG_EINVAL);
- return (NULL);
- }
-
- // So our "messages" from nn are really going to be nng messages
- // but to make this work, we use a bit of headroom in the message
- // to stash the message header.
- if ((rv = nng_msg_alloc(&msg, size + (sizeof(msg)))) != 0) {
- nn_seterror(rv);
- return (NULL);
- }
-
- // This counts on message bodies being aligned sensibly.
- *(nng_msg **) (nng_msg_body(msg)) = msg;
-
- // We are counting on the implementation of nn_msg_trim to not
- // reallocate the message but just to leave the prefix inplace.
- (void) nng_msg_trim(msg, sizeof(msg));
-
- return (nng_msg_body(msg));
-}
-
-int
-nn_freemsg(void *ptr)
-{
- nng_msg *msg;
-
- msg = *(nng_msg **) (((char *) ptr) - sizeof(msg));
- nng_msg_free(msg);
- return (0);
-}
-
-void *
-nn_reallocmsg(void *ptr, size_t len)
-{
- nng_msg *msg;
- int rv;
-
- if ((len + sizeof(msg)) < len) {
- // overflowed!
- nn_seterror(NNG_EINVAL);
- return (NULL);
- }
-
- // This counts on message bodies being aligned sensibly.
- msg = *(nng_msg **) (((char *) ptr) - sizeof(msg));
-
- // We need to realloc the requested len, plus size for our header.
- if ((rv = nng_msg_realloc(msg, len + sizeof(msg))) != 0) {
- // We don't free the old message. Code is free to cope
- // as it sees fit.
- nn_seterror(rv);
- return (NULL);
- }
- // Stash the msg header pointer
- *(nng_msg **) (nng_msg_body(msg)) = msg;
- nng_msg_trim(msg, sizeof(msg));
- return (nng_msg_body(msg));
-}
-
-static int
-nn_flags(int flags)
-{
- switch (flags) {
- case 0:
- return (0);
-
- case NN_DONTWAIT:
- return (NNG_FLAG_NONBLOCK);
-
- default:
- nn_seterror(NNG_EINVAL);
- return (-1);
- }
-}
-
-int
-nn_send(int s, const void *buf, size_t len, int flags)
-{
- struct nn_iovec iov;
- struct nn_msghdr hdr;
-
- iov.iov_base = (void *) buf;
- iov.iov_len = len;
-
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
- hdr.msg_control = NULL;
- hdr.msg_controllen = 0;
-
- return (nn_sendmsg(s, &hdr, flags));
-}
-
-int
-nn_recv(int s, void *buf, size_t len, int flags)
-{
- struct nn_iovec iov;
- struct nn_msghdr hdr;
-
- iov.iov_base = buf;
- iov.iov_len = len;
-
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
- hdr.msg_control = NULL;
- hdr.msg_controllen = 0;
-
- return (nn_recvmsg(s, &hdr, flags));
-}
-
-int
-nn_recvmsg(int s, struct nn_msghdr *mh, int flags)
-{
- int rv;
- nng_msg *msg;
- size_t len;
- int keep = 0;
-
- if ((flags = nn_flags(flags)) == -1) {
- return (-1);
- }
- if (mh == NULL) {
- nn_seterror(NNG_EINVAL);
- return (-1);
- }
- if (mh->msg_iovlen < 0) {
- nn_seterror(NNG_EMSGSIZE);
- return (-1);
- }
-
- if ((rv = nng_recvmsg((nng_socket) s, &msg, flags)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
- if ((mh->msg_iovlen == 1) && (mh->msg_iov[0].iov_len == NN_MSG)) {
- // Receiver wants to have a dynamically allocated message.
- // There can only be one of these.
- if ((rv = nng_msg_insert(msg, &msg, sizeof(msg))) != 0) {
- nng_msg_free(msg);
- nn_seterror(rv);
- return (-1);
- }
- nng_msg_trim(msg, sizeof(msg));
- *(void **) (mh->msg_iov[0].iov_base) = nng_msg_body(msg);
- len = nng_msg_len(msg);
- keep = 1; // Do not discard message!
- } else {
- // copyout to multiple iovecs.
- char * ptr = nng_msg_body(msg);
- int i;
- size_t n;
- len = nng_msg_len(msg);
-
- for (i = 0; i < mh->msg_iovlen; i++) {
- if ((n = mh->msg_iov[i].iov_len) == NN_MSG) {
- // This is forbidden!
- nn_seterror(NNG_EINVAL);
- nng_msg_free(msg);
- return (-1);
- }
- if (n > len) {
- n = len;
- }
- memcpy(mh->msg_iov[i].iov_base, ptr, n);
- len -= n;
- ptr += n;
- }
-
- // If we copied everything, len will be zero, otherwise,
- // it represents the amount of data that we were unable to
- // copyout. The caller is responsible for noticing this,
- // as there is no API to pass this information out.
- len = nng_msg_len(msg);
- }
-
- // If the caller has requested control information (header details),
- // we grab it.
- if (mh->msg_control != NULL) {
- char * cdata;
- size_t clen;
- size_t tlen;
- size_t spsz;
- struct nn_cmsghdr *hdr;
- unsigned char * ptr;
-
- spsz = nng_msg_header_len(msg);
- clen = NN_CMSG_SPACE(sizeof(spsz) + spsz);
-
- if ((tlen = mh->msg_controllen) == NN_MSG) {
- // Ideally we'd use the same msg, but we would need
- // to set up reference counts on the message, so
- // instead we just make a new message.
- nng_msg *nmsg;
-
- rv = nng_msg_alloc(&nmsg, clen + sizeof(nmsg));
- if (rv != 0) {
- nng_msg_free(msg);
- nn_seterror(rv);
- return (-1);
- }
- memcpy(nng_msg_body(nmsg), &nmsg, sizeof(nmsg));
- nng_msg_trim(nmsg, sizeof(nmsg));
- cdata = nng_msg_body(nmsg);
- *(void **) mh->msg_control = cdata;
- tlen = clen;
- } else {
- cdata = mh->msg_control;
- memset(cdata, 0,
- tlen > sizeof(*hdr) ? sizeof(*hdr) : tlen);
- }
-
- if (clen <= tlen) {
- ptr = NN_CMSG_DATA(cdata);
- hdr = (void *) cdata;
- hdr->cmsg_len = clen;
- hdr->cmsg_level = PROTO_SP;
- hdr->cmsg_type = SP_HDR;
-
- memcpy(ptr, &spsz, sizeof(spsz));
- ptr += sizeof(spsz);
- memcpy(ptr, nng_msg_header(msg), spsz);
- }
- }
-
- if (!keep) {
- nng_msg_free(msg);
- }
- return ((int) len);
-}
-
-int
-nn_sendmsg(int s, const struct nn_msghdr *mh, int flags)
-{
- nng_msg *msg = NULL;
- nng_msg *cmsg = NULL;
- char * cdata;
- int keep = 0;
- size_t sz;
- int rv;
-
- if ((flags = nn_flags(flags)) == -1) {
- return (-1);
- }
-
- if (mh == NULL) {
- nn_seterror(NNG_EINVAL);
- return (-1);
- }
-
- if (mh->msg_iovlen < 0) {
- nn_seterror(NNG_EMSGSIZE);
- return (-1);
- }
-
- if ((mh->msg_iovlen == 1) && (mh->msg_iov[0].iov_len == NN_MSG)) {
- char *bufp = *(char **) (mh->msg_iov[0].iov_base);
-
- msg = *(nng_msg **) (bufp - sizeof(msg));
- keep = 1; // keep the message on error
- } else {
- char *ptr;
- int i;
-
- sz = 0;
- // Get the total message size.
- for (i = 0; i < mh->msg_iovlen; i++) {
- sz += mh->msg_iov[i].iov_len;
- }
- if ((rv = nng_msg_alloc(&msg, sz)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
- // Now copy it out.
- ptr = nng_msg_body(msg);
- for (i = 0; i < mh->msg_iovlen; i++) {
- memcpy(ptr, mh->msg_iov[i].iov_base,
- mh->msg_iov[i].iov_len);
- ptr += mh->msg_iov[i].iov_len;
- }
- }
-
- // Now suck up the control data...
- // This POSIX-inspired API is one of the most painful for
- // usability we've ever seen.
- cmsg = NULL;
- if ((cdata = mh->msg_control) != NULL) {
- size_t clen;
- size_t offs;
- size_t spsz;
- struct nn_cmsghdr *chdr;
- unsigned char * data;
-
- if ((clen = mh->msg_controllen) == NN_MSG) {
- // Underlying data is a message. This is awkward,
- // because we have to copy the data, but we should
- // only free this message on success. So we save the
- // message now.
- cdata = *(void **) cdata;
- cmsg = *(nng_msg **) (cdata - sizeof(cmsg));
- clen = nng_msg_len(cmsg);
- } else {
- clen = mh->msg_controllen;
- }
-
- offs = 0;
- while ((offs + sizeof(NN_CMSG_LEN(0))) < clen) {
- chdr = (void *) (cdata + offs);
- if ((chdr->cmsg_level != PROTO_SP) ||
- (chdr->cmsg_type != SP_HDR)) {
- offs += chdr->cmsg_len;
- }
-
- // SP header in theory. Starts with size, then
- // any backtrace details.
- if (chdr->cmsg_len < sizeof(size_t)) {
- offs += chdr->cmsg_len;
- continue;
- }
- data = NN_CMSG_DATA(chdr);
- memcpy(&spsz, data, sizeof(spsz));
- if ((spsz + sizeof(spsz)) > chdr->cmsg_len) {
- // Truncated header? Ignore it.
- offs += chdr->cmsg_len;
- continue;
- }
- data += sizeof(spsz);
- rv = nng_msg_header_append(msg, data, spsz);
- if (rv != 0) {
- if (!keep) {
- nng_msg_free(msg);
- }
- nn_seterror(rv);
- return (-1);
- }
-
- break;
- }
- }
-
- sz = nng_msg_len(msg);
- if ((rv = nng_sendmsg((nng_socket) s, msg, flags)) != 0) {
- if (!keep) {
- nng_msg_free(msg);
- }
- nn_seterror(rv);
- return (-1);
- }
-
- if (cmsg != NULL) {
- // We sent successfully, so free up the control message.
- nng_msg_free(cmsg);
- }
- return ((int) sz);
-}
-
-// options which we convert -- most of the array is initialized at run time.
-static const struct {
- int nnlevel;
- int nnopt;
- const char *opt;
-} options[] = {
- { NN_SOL_SOCKET, NN_LINGER, NNG_OPT_LINGER }, // review
- { NN_SOL_SOCKET, NN_SNDBUF, NNG_OPT_SENDBUF },
- { NN_SOL_SOCKET, NN_RCVBUF, NNG_OPT_RECVBUF },
- { NN_SOL_SOCKET, NN_RECONNECT_IVL, NNG_OPT_RECONNMINT },
- { NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX, NNG_OPT_RECONNMAXT },
- { NN_SOL_SOCKET, NN_SNDFD, NNG_OPT_SENDFD },
- { NN_SOL_SOCKET, NN_RCVFD, NNG_OPT_RECVFD },
- { NN_SOL_SOCKET, NN_RCVMAXSIZE, NNG_OPT_RECVMAXSZ },
- { NN_SOL_SOCKET, NN_MAXTTL, NNG_OPT_MAXTTL },
- { NN_SOL_SOCKET, NN_RCVTIMEO, NNG_OPT_RECVTIMEO },
- { NN_SOL_SOCKET, NN_SNDTIMEO, NNG_OPT_SENDTIMEO },
- { NN_SOL_SOCKET, NN_DOMAIN, NNG_OPT_DOMAIN },
- { NN_SOL_SOCKET, NN_SOCKET_NAME, NNG_OPT_SOCKNAME },
- { NN_REQ, NN_REQ_RESEND_IVL, NNG_OPT_REQ_RESENDTIME },
- { NN_SUB, NN_SUB_SUBSCRIBE, NNG_OPT_SUB_SUBSCRIBE },
- { NN_SUB, NN_SUB_UNSUBSCRIBE, NNG_OPT_SUB_UNSUBSCRIBE },
- { NN_SURVEYOR, NN_SURVEYOR_DEADLINE, NNG_OPT_SURVEYOR_SURVEYTIME },
- // XXX: IPV4ONLY, SNDPRIO, RCVPRIO
-};
-
-int
-nn_getsockopt(int s, int nnlevel, int nnopt, void *valp, size_t *szp)
-{
- const char *name = NULL;
- int rv;
-
- for (unsigned i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
- if ((options[i].nnlevel == nnlevel) &&
- (options[i].nnopt == nnopt)) {
- name = options[i].opt;
- break;
- }
- }
-
- if (name == NULL) {
- errno = ENOPROTOOPT;
- return (-1);
- }
-
- if ((rv = nng_getopt((nng_socket) s, name, valp, szp)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
-
- return (0);
-}
-
-int
-nn_setsockopt(int s, int nnlevel, int nnopt, const void *valp, size_t sz)
-{
- const char *name = NULL;
- int rv;
-
- for (unsigned i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
- if ((options[i].nnlevel == nnlevel) &&
- (options[i].nnopt == nnopt)) {
- name = options[i].opt;
- break;
- }
- }
- if (name == NULL) {
- return (ENOPROTOOPT);
- }
-
- if ((rv = nng_setopt((nng_socket) s, name, valp, sz)) != 0) {
- nn_seterror(rv);
- return (-1);
- }
- return (0);
-}
-
-struct nn_cmsghdr *
-nn_cmsg_next(struct nn_msghdr *mh, struct nn_cmsghdr *first)
-{
- size_t clen;
- char * data;
-
- // We only support SP headers, so there can be at most one header.
- if (first != NULL) {
- return (NULL);
- }
- if ((clen = mh->msg_controllen) == NN_MSG) {
- nng_msg *msg;
- data = *((void **) (mh->msg_control));
- msg = *(nng_msg **) (data - sizeof(msg));
- clen = nng_msg_len(msg);
- } else {
- data = mh->msg_control;
- }
-
- if (first == NULL) {
- first = (void *) data;
- } else {
- first = first + first->cmsg_len;
- }
-
- if (((char *) first + sizeof(*first)) > (data + clen)) {
- return (NULL);
- }
- return (first);
-}
-
-int
-nn_device(int s1, int s2)
-{
- int rv;
-
- rv = nng_device((nng_socket) s1, (nng_socket) s2);
- // rv must always be nonzero
- nn_seterror(rv);
- return (-1);
-}
-
-// nn_term is suitable only for shutting down the entire library,
-// and is not thread-safe with other functions.
-void
-nn_term(void)
-{
- // This function is relatively toxic, since it can affect
- // all sockets in the process, including those
- // in use by libraries, etc. Accordingly, do not use this
- // in a library -- only e.g. atexit() and similar.
- nng_closeall();
-}