diff options
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/defs.h | 82 | ||||
| -rw-r--r-- | src/core/platform.h | 8 | ||||
| -rw-r--r-- | src/nng.c | 19 | ||||
| -rw-r--r-- | src/nng.h | 86 | ||||
| -rw-r--r-- | src/platform/posix/posix_debug.c | 79 | ||||
| -rw-r--r-- | src/platform/posix/posix_impl.h | 29 |
7 files changed, 240 insertions, 64 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78070cc1..58564291 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,6 +62,7 @@ set (NNG_SOURCES platform/posix/posix_alloc.c platform/posix/posix_clock.c platform/posix/posix_debug.c + platform/posix/posix_net.c platform/posix/posix_thread.c protocol/pair/pair.c diff --git a/src/core/defs.h b/src/core/defs.h index 395335d6..be7f71f7 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -22,6 +22,7 @@ typedef struct nng_socket nni_sock; typedef struct nng_endpoint nni_ep; typedef struct nng_pipe nni_pipe; typedef struct nng_msg nni_msg; +typedef struct nng_sockaddr nni_sockaddr; // These are our own names. typedef struct nni_tran nni_tran; @@ -31,10 +32,17 @@ typedef struct nni_tran_pipe nni_tran_pipe; typedef struct nni_proto_pipe nni_proto_pipe; typedef struct nni_proto nni_proto; + typedef int nni_signal; // Turnstile/wakeup channel. typedef uint64_t nni_time; // Absolute time (usec). typedef int64_t nni_duration; // Relative time (usec). +// Used by transports for scatter gather I/O. +typedef struct { + void * iov_buf; + size_t iov_len; +} nni_iov; + // Some default timing things. #define NNI_TIME_NEVER ((nni_time) -1) #define NNI_TIME_ZERO ((nni_time) 0) @@ -44,41 +52,45 @@ typedef int64_t nni_duration; // Relative time (usec). #define NNI_ALLOC_STRUCT(s) nni_alloc(sizeof (*s)) #define NNI_FREE_STRUCT(s) nni_free((s), sizeof (*s)) -#define NNI_PUT32(ptr, u) \ - do { \ - ptr[0] = (uint8_t)(((uint32_t)u) >> 24); \ - ptr[1] = (uint8_t)(((uint32_t)u) >> 16); \ - ptr[2] = (uint8_t)(((uint32_t)u) >> 8); \ - ptr[3] = (uint8_t)((uint32_t)u); \ - } while (0) - -#define NNI_PUT64(ptr, u) \ - do { \ - ptr[0] = (uint8_t)(((uint64_t)u) >> 56); \ - ptr[1] = (uint8_t)(((uint64_t)u) >> 48); \ - ptr[2] = (uint8_t)(((uint64_t)u) >> 40); \ - ptr[3] = (uint8_t)(((uint64_t)u) >> 32); \ - ptr[4] = (uint8_t)(((uint64_t)u) >> 24); \ - ptr[5] = (uint8_t)(((uint64_t)u) >> 16); \ - ptr[6] = (uint8_t)(((uint64_t)u) >> 8); \ - ptr[7] = (uint8_t)((uint64_t)u); \ - } while (0) - -#define NNI_GET32(ptr, v) \ - v = (((uint32_t)((uint8_t)ptr[0])) << 24) + \ - (((uint32_t)((uint8_t)ptr[1])) << 16) + \ - (((uint32_t)((uint8_t)ptr[2])) << 8) + \ - (((uint32_t)(uint8_t)ptr[3])) - -#define NNI_GET64(ptr, v) \ - v = (((uint64_t)((uint8_t)ptr[0])) << 56) + \ - (((uint64_t)((uint8_t)ptr[1])) << 48) + \ - (((uint64_t)((uint8_t)ptr[2])) << 40) + \ - (((uint64_t)((uint8_t)ptr[3])) << 32) + \ - (((uint64_t)((uint8_t)ptr[4])) << 24) + \ - (((uint64_t)((uint8_t)ptr[5])) << 16) + \ - (((uint64_t)((uint8_t)ptr[6])) << 8) + \ - (((uint64_t)(uint8_t)ptr[7])) +#define NNI_PUT32(ptr, u) \ + do { \ + ptr[0] = (uint8_t) (((uint32_t) u) >> 24); \ + ptr[1] = (uint8_t) (((uint32_t) u) >> 16); \ + ptr[2] = (uint8_t) (((uint32_t) u) >> 8); \ + ptr[3] = (uint8_t) ((uint32_t) u); \ + } \ + while (0) + +#define NNI_PUT64(ptr, u) \ + do { \ + ptr[0] = (uint8_t) (((uint64_t) u) >> 56); \ + ptr[1] = (uint8_t) (((uint64_t) u) >> 48); \ + ptr[2] = (uint8_t) (((uint64_t) u) >> 40); \ + ptr[3] = (uint8_t) (((uint64_t) u) >> 32); \ + ptr[4] = (uint8_t) (((uint64_t) u) >> 24); \ + ptr[5] = (uint8_t) (((uint64_t) u) >> 16); \ + ptr[6] = (uint8_t) (((uint64_t) u) >> 8); \ + ptr[7] = (uint8_t) ((uint64_t) u); \ + } \ + while (0) + +#define NNI_GET32(ptr, v) \ + v = (((uint32_t) ((uint8_t) ptr[0])) << 24) + \ + (((uint32_t) ((uint8_t) ptr[1])) << 16) + \ + (((uint32_t) ((uint8_t) ptr[2])) << 8) + \ + (((uint32_t) (uint8_t) ptr[3])) + +#define NNI_GET64(ptr, v) \ + v = (((uint64_t) ((uint8_t) ptr[0])) << 56) + \ + (((uint64_t) ((uint8_t) ptr[1])) << 48) + \ + (((uint64_t) ((uint8_t) ptr[2])) << 40) + \ + (((uint64_t) ((uint8_t) ptr[3])) << 32) + \ + (((uint64_t) ((uint8_t) ptr[4])) << 24) + \ + (((uint64_t) ((uint8_t) ptr[5])) << 16) + \ + (((uint64_t) ((uint8_t) ptr[6])) << 8) + \ + (((uint64_t) (uint8_t) ptr[7])) +// A few assorted other items. +#define NNI_FLAG_IPV4ONLY 1 #endif // CORE_DEFS_H diff --git a/src/core/platform.h b/src/core/platform.h index 15ef6843..2134ed97 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -158,6 +158,14 @@ extern void nni_plat_fini(void); // or under a lock protection.) extern uint32_t nni_plat_nextid(void); +// nni_plat_strerror allows the platform to use additional error messages +// for additional error codes. The err code passed in should be the +// equivalent of errno or GetLastError, without the NNG_ESYSERR component. +// The platform should make sure that the returned value will be valid +// after the call returns. (If necessary, thread-local storage can be +// used.) +extern const char *nni_plat_strerror(int); + // Actual platforms we support. This is included up front so that we can // get the specific types that are supplied by the platform. #if defined(PLATFORM_POSIX) @@ -180,9 +180,24 @@ nng_strerror(int num) case NNG_ENOENT: return ("Entry not found"); - default: - return ("Unknown error"); + case NNG_EPROTO: + return ("Protocol error"); + + case NNG_EUNREACHABLE: + return ("Destination unreachable"); + + case NNG_EADDRINVAL: + return ("Address invalid"); + + case NNG_EPERM: + return ("Permission denied"); } + + if (num & NNG_ESYSERR) { + return (nni_plat_strerror(num & ~NNG_ESYSERR)); + } + + return ("Unknown error"); } @@ -355,23 +355,85 @@ NNG_DECL int nng_device(nng_socket *, nng_socket *); // Error codes. These may happen to align to errnos used on your platform, // but do not count on this. -#define NNG_EINTR (-1) -#define NNG_ENOMEM (-2) -#define NNG_EINVAL (-3) -#define NNG_EBUSY (-4) -#define NNG_ETIMEDOUT (-5) -#define NNG_ECONNREFUSED (-6) -#define NNG_ECLOSED (-7) -#define NNG_EAGAIN (-8) -#define NNG_ENOTSUP (-9) -#define NNG_EADDRINUSE (-10) -#define NNG_ESTATE (-11) -#define NNG_ENOENT (-12) +#define NNG_EINTR (1) +#define NNG_ENOMEM (2) +#define NNG_EINVAL (3) +#define NNG_EBUSY (4) +#define NNG_ETIMEDOUT (5) +#define NNG_ECONNREFUSED (6) +#define NNG_ECLOSED (7) +#define NNG_EAGAIN (8) +#define NNG_ENOTSUP (9) +#define NNG_EADDRINUSE (10) +#define NNG_ESTATE (11) +#define NNG_ENOENT (12) +#define NNG_EPROTO (13) +#define NNG_EUNREACHABLE (14) +#define NNG_EADDRINVAL (15) +#define NNG_EPERM (16) + +// NNG_SYSERR is a special code, which allows us to wrap errors from the +// underlyuing operating system. We generally prefer to map errors to one +// of the above, but if we cannot, then we just encode an error this way. +// The bit is large enough to accommodate all known UNIX and Win32 error +// codes. We try hard to match things semantically to one of our standard +// errors. For example, a connection reset or aborted we treat as a +// closed connection, because that's basically what it means. (The remote +// peer closed the connection.) For certain kinds of resource exhaustion +// we treat it the same as memory. But for files, etc. that's OS-specific, +// and we use the generic below. Some of the above error codes we use +// internally, and the application should never see (e.g. NNG_EINTR). +#define NNG_ESYSERR (0x10000000) // Maximum length of a socket address. This includes the terminating NUL. // This limit is built into other implementations, so do not change it. #define NNG_MAXADDRLEN (128) +// Some address details. This is in some ways like a traditional sockets +// sockaddr, but we have our own to cope with our unique families, etc. +// The details of this structure are directly exposed to applications. +// These structures can be obtained via property lookups, etc. +struct nng_sockaddr_path { + uint16_t sa_family; + uint8_t sa_path[NNG_MAXADDRLEN]; +}; +typedef struct nng_sockaddr_path nng_sockaddr_path; +typedef struct nng_sockaddr_path nng_sockaddr_ipc; +typedef struct nng_sockaddr_path nng_sockaddr_inproc; + +struct nng_sockaddr_in6 { + uint16_t sa_family; + uint16_t sa_port; + uint8_t sa_addr[16]; +}; +typedef struct nng_sockaddr_in6 nng_sockaddr_in6; +typedef struct nng_sockaddr_in6 nng_sockaddr_udp6; +typedef struct nng_sockaddr_in6 nng_sockaddr_tcp6; + +struct nng_sockaddr_in { + uint16_t sa_family; + uint16_t sa_port; + uint32_t sa_addr; +}; +typedef struct nng_sockaddr_in nng_sockaddr_in; +typedef struct nng_sockaddr_in nng_sockaddr_udp; +typedef struct nng_sockaddr_in nng_sockaddr_tcp; + +typedef struct nng_sockaddr { + union { + uint16_t s_family; + nng_sockaddr_path s_path; + nng_sockaddr_in6 s_in6; + nng_sockaddr_in s_in; + } s_un; +} nng_sockaddr; + +#define NNG_AF_UNSPEC 0 +#define NNG_AF_INPROC 1 +#define NNG_AF_IPC 2 +#define NNG_AF_INET 3 +#define NNG_AF_INET6 4 + #ifdef __cplusplus } #endif diff --git a/src/platform/posix/posix_debug.c b/src/platform/posix/posix_debug.c index 56b443e9..f1c6f9e7 100644 --- a/src/platform/posix/posix_debug.c +++ b/src/platform/posix/posix_debug.c @@ -11,8 +11,10 @@ #ifdef PLATFORM_POSIX_DEBUG +#include <errno.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> void nni_plat_abort(void) @@ -28,4 +30,81 @@ nni_plat_println(const char *message) } +const char * +nni_plat_strerror(int errnum) +{ + if (errnum > NNG_ESYSERR) { + errnum -= NNG_ESYSERR; + } + return (strerror(errnum)); +} + + +#define NNI_ERR(x, y) { x, y }, + +// There are of course other errors than these, but these are the ones +// that we might reasonably expect and want to handle "cleanly". Most of +// the others should be handled by the system error code. Note that EFAULT +// is very special, because if the error code is *that*, then we should panic +// because an invalid system call has been made. (That would be a sign +// of a serious software bug, in other words.) POSIX says that all these +// error codes should exist, and be distinct positive numbers. (EWOULDBLOCK +// and EAGAIN are permitted to have the same value.) +static struct { + int posix_err; + int nng_err; +} +nni_plat_errnos[] = { + NNI_ERR(EINTR, NNG_EINTR) + NNI_ERR(EINVAL, NNG_EINVAL) + NNI_ERR(ENOMEM, NNG_ENOMEM) + NNI_ERR(EACCES, NNG_EPERM) + NNI_ERR(EADDRINUSE, NNG_EADDRINUSE) + NNI_ERR(EADDRNOTAVAIL, NNG_EADDRINVAL) + NNI_ERR(EAFNOSUPPORT, NNG_ENOTSUP) + NNI_ERR(EAGAIN, NNG_EAGAIN) + NNI_ERR(EBADF, NNG_ECLOSED) + NNI_ERR(EBUSY, NNG_EBUSY) + NNI_ERR(ECONNABORTED, NNG_ECLOSED) + NNI_ERR(ECONNREFUSED, NNG_ECONNREFUSED) + NNI_ERR(ECONNRESET, NNG_ECLOSED) + NNI_ERR(EHOSTUNREACH, NNG_EUNREACHABLE) + NNI_ERR(ENETUNREACH, NNG_EUNREACHABLE) + NNI_ERR(ENAMETOOLONG, NNG_EINVAL) + NNI_ERR(ENOENT, NNG_ENOENT) + NNI_ERR(ENOBUFS, NNG_ENOMEM) + NNI_ERR(ENOPROTOOPT, NNG_ENOTSUP) + NNI_ERR(ENOSYS, NNG_ENOTSUP) + NNI_ERR(ENOTSUP, NNG_ENOTSUP) + NNI_ERR(EPERM, NNG_EPERM) + NNI_ERR(EPIPE, NNG_ECLOSED) + NNI_ERR(EPROTO, NNG_EPROTO) + NNI_ERR(EPROTONOSUPPORT, NNG_ENOTSUP) + NNI_ERR(ETIME, NNG_ETIMEDOUT) + NNI_ERR(ETIMEDOUT, NNG_ETIMEDOUT) + NNI_ERR(EWOULDBLOCK, NNG_EAGAIN) + NNI_ERR(0, 0) // must be last +}; + +int +nni_plat_errno(int errnum) +{ + int i; + + if (errnum == 0) { + return (0); + } + if (errnum == EFAULT) { + nni_panic("System EFAULT encountered!"); + } + for (i = 0; nni_plat_errnos[i].nng_err != 0; i++) { + if (errnum == nni_plat_errnos[i].posix_err) { + return (nni_plat_errnos[i].nng_err); + } + } + // Other system errno. + return (NNG_ESYSERR + errnum); +} + + #endif // PLATFORM_POSIX_DEBUG diff --git a/src/platform/posix/posix_impl.h b/src/platform/posix/posix_impl.h index 5c5c3798..38fe27c9 100644 --- a/src/platform/posix/posix_impl.h +++ b/src/platform/posix/posix_impl.h @@ -12,35 +12,34 @@ // Some dependency notes: // -// PLATFORM_POSIX_THREAD and PLATFORM_POSIX_SYNCH depend on each other, -// and they both depend on PLATFORM_POSIX_CLOCK. Furthermore, note that +// PLATFORM_POSIX_THREAD depends on PLATFORM_POSIX_CLOCK. Furthermore, // when using PLATFORM_POSIX_CLOCK, your condition variable timeouts need -// to use the same base clock values. Normally all three should be used -// together. +// to use the same base clock values. Normally these should be used +// together. Almost everything depends on PLATFORM_POSIX_DEBUG. #ifdef PLATFORM_POSIX #define PLATFORM_POSIX_ALLOC #define PLATFORM_POSIX_DEBUG #define PLATFORM_POSIX_CLOCK +#define PLATFORM_POSIX_NET #define PLATFORM_POSIX_RANDOM -#define PLATFORM_POSIX_SYNCH #define PLATFORM_POSIX_THREAD #include "platform/posix/posix_config.h" #endif -// Define types that this platform uses. -#ifdef PLATFORM_POSIX_SYNCH +#ifdef PLATFORM_POSIX_DEBUG +extern int nni_plat_errno(int); -#include <pthread.h> +#endif -struct nni_mutex { - pthread_mutex_t mx; -}; +#ifdef PLATFORM_POSIX_NET +typedef int nni_plat_tcpsock; +#endif -struct nni_cond { - pthread_cond_t cv; - pthread_mutex_t * mx; -}; +// Define types that this platform uses. +#ifdef PLATFORM_POSIX_THREAD + +#include <pthread.h> // These types are provided for here, to permit them to be directly inlined // elsewhere. |
