aboutsummaryrefslogtreecommitdiff
path: root/src/core/defs.h
blob: 432c0be79852ccf2a41b5fe2a7baaa95e9d6ec50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//
// Copyright 2021 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitoar.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.
//

#ifndef CORE_DEFS_H
#define CORE_DEFS_H

#include <stdbool.h>
#include <stdint.h>

#include <nng/nng.h>

// 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)

#ifndef NDEBUG
#define NNI_ASSERT(x) \
	if (!(x))     \
	nni_panic("%s: %d: assert err: %s", __FILE__, __LINE__, #x)
#else
#define NNI_ASSERT(x) ((void) (0))
#endif

// Returns the size of an array in elements. (Convenience.)
#define NNI_NUM_ELEMENTS(x) ((unsigned) (sizeof(x) / sizeof((x)[0])))

// These types are common but have names shared with user space.
// Internal code should use these names when possible.
typedef nng_msg      nni_msg;
typedef nng_sockaddr nni_sockaddr;
typedef nng_iov      nni_iov;
typedef nng_aio      nni_aio;

// These are our own names.
typedef struct nni_socket   nni_sock;
typedef struct nni_ctx      nni_ctx;
typedef struct nni_dialer   nni_dialer;
typedef struct nni_listener nni_listener;
typedef struct nni_pipe     nni_pipe;

typedef struct nni_sp_tran         nni_sp_tran;
typedef struct nni_sp_dialer_ops   nni_sp_dialer_ops;
typedef struct nni_sp_listener_ops nni_sp_listener_ops;
typedef struct nni_sp_pipe_ops     nni_sp_pipe_ops;

typedef struct nni_proto_ctx_ops  nni_proto_ctx_ops;
typedef struct nni_proto_sock_ops nni_proto_sock_ops;
typedef struct nni_proto_pipe_ops nni_proto_pipe_ops;
typedef struct nni_proto          nni_proto;

typedef struct nni_plat_mtx nni_mtx;
typedef struct nni_plat_cv  nni_cv;
typedef struct nni_thr      nni_thr;
typedef void (*nni_thr_func)(void *);

typedef uint64_t nni_time;     // Abs. time (ms).
typedef int32_t  nni_duration; // Rel. time (ms).

typedef void (*nni_cb)(void *);

// Some default timing things.
#define NNI_TIME_NEVER ((nni_time) -1)
#define NNI_TIME_ZERO ((nni_time) 0)
#define NNI_SECOND (1000)

// Structure allocation conveniences.
#define NNI_ALLOC_STRUCT(s) nni_zalloc(sizeof(*s))
#define NNI_FREE_STRUCT(s) nni_free((s), sizeof(*s))
#define NNI_ALLOC_STRUCTS(s, n) nni_zalloc(sizeof(*s) * n)
#define NNI_FREE_STRUCTS(s, n) nni_free(s, sizeof(*s) * n)

#define NNI_PUT16(ptr, u)                                      \
	do {                                                   \
		(ptr)[0] = (uint8_t) (((uint16_t) (u)) >> 8u); \
		(ptr)[1] = (uint8_t) ((uint16_t) (u));         \
	} while (0)

#define NNI_PUT32(ptr, u)                                       \
	do {                                                    \
		(ptr)[0] = (uint8_t) (((uint32_t) (u)) >> 24u); \
		(ptr)[1] = (uint8_t) (((uint32_t) (u)) >> 16u); \
		(ptr)[2] = (uint8_t) (((uint32_t) (u)) >> 8u);  \
		(ptr)[3] = (uint8_t) ((uint32_t) (u));          \
	} while (0)

#define NNI_PUT64(ptr, u)                                       \
	do {                                                    \
		(ptr)[0] = (uint8_t) (((uint64_t) (u)) >> 56u); \
		(ptr)[1] = (uint8_t) (((uint64_t) (u)) >> 48u); \
		(ptr)[2] = (uint8_t) (((uint64_t) (u)) >> 40u); \
		(ptr)[3] = (uint8_t) (((uint64_t) (u)) >> 32u); \
		(ptr)[4] = (uint8_t) (((uint64_t) (u)) >> 24u); \
		(ptr)[5] = (uint8_t) (((uint64_t) (u)) >> 16u); \
		(ptr)[6] = (uint8_t) (((uint64_t) (u)) >> 8u);  \
		(ptr)[7] = (uint8_t) ((uint64_t) (u));          \
	} while (0)

#define NNI_GET16(ptr, v)                                   \
	v = (((uint16_t) (((uint8_t *) (ptr))[0])) << 8u) + \
	    ((uint16_t) ((uint8_t *) (ptr))[1])

#define NNI_GET32(ptr, v)                                  \
	v = (((uint32_t) ((uint8_t *) (ptr))[0]) << 24u) + \
	    (((uint32_t) ((uint8_t *) (ptr))[1]) << 16u) + \
	    (((uint32_t) ((uint8_t *) (ptr))[2]) << 8u) +  \
	    ((uint32_t) ((uint8_t *) (ptr))[3])

#define NNI_GET64(ptr, v)                                  \
	v = (((uint64_t) ((uint8_t *) (ptr))[0]) << 56u) + \
	    (((uint64_t) ((uint8_t *) (ptr))[1]) << 48u) + \
	    (((uint64_t) ((uint8_t *) (ptr))[2]) << 40u) + \
	    (((uint64_t) ((uint8_t *) (ptr))[3]) << 32u) + \
	    (((uint64_t) ((uint8_t *) (ptr))[4]) << 24u) + \
	    (((uint64_t) ((uint8_t *) (ptr))[5]) << 16u) + \
	    (((uint64_t) ((uint8_t *) (ptr))[6]) << 8u) +  \
	    ((uint64_t) ((uint8_t *) (ptr))[7])

// Modern CPUs are all little endian.  Let's stop paying the endian tax.

#define NNI_PUT16LE(ptr, u)                                    \
	do {                                                   \
		(ptr)[1] = (uint8_t) (((uint16_t) (u)) >> 8u); \
		(ptr)[0] = (uint8_t) ((uint16_t) (u));         \
	} while (0)

#define NNI_PUT32LE(ptr, u)                                     \
	do {                                                    \
		(ptr)[3] = (uint8_t) (((uint32_t) (u)) >> 24u); \
		(ptr)[2] = (uint8_t) (((uint32_t) (u)) >> 16u); \
		(ptr)[1] = (uint8_t) (((uint32_t) (u)) >> 8u);  \
		(ptr)[0] = (uint8_t) ((uint32_t) (u));          \
	} while (0)

#define NNI_PUT64LE(ptr, u)                                     \
	do {                                                    \
		(ptr)[7] = (uint8_t) (((uint64_t) (u)) >> 56u); \
		(ptr)[6] = (uint8_t) (((uint64_t) (u)) >> 48u); \
		(ptr)[5] = (uint8_t) (((uint64_t) (u)) >> 40u); \
		(ptr)[4] = (uint8_t) (((uint64_t) (u)) >> 32u); \
		(ptr)[3] = (uint8_t) (((uint64_t) (u)) >> 24u); \
		(ptr)[2] = (uint8_t) (((uint64_t) (u)) >> 16u); \
		(ptr)[1] = (uint8_t) (((uint64_t) (u)) >> 8u);  \
		(ptr)[0] = (uint8_t) ((uint64_t) (u));          \
	} while (0)

#define NNI_GET16LE(ptr, v)                                 \
	v = (((uint16_t) (((uint8_t *) (ptr))[1])) << 8u) + \
	    ((uint16_t) ((uint8_t *) (ptr))[0])

#define NNI_GET32LE(ptr, v)                                  \
	v = (((uint32_t) (((uint8_t *) (ptr))[3])) << 24u) + \
	    (((uint32_t) (((uint8_t *) (ptr))[2])) << 16u) + \
	    (((uint32_t) (((uint8_t *) (ptr))[1])) << 8u) +  \
	    (((uint32_t) ((uint8_t *) (ptr))[0]))

#define NNI_GET64LE(ptr, v)                                  \
	v = (((uint64_t) (((uint8_t *) (ptr))[7])) << 56u) + \
	    (((uint64_t) (((uint8_t *) (ptr))[6])) << 48u) + \
	    (((uint64_t) (((uint8_t *) (ptr))[5])) << 40u) + \
	    (((uint64_t) (((uint8_t *) (ptr))[4])) << 32u) + \
	    (((uint64_t) (((uint8_t *) (ptr))[3])) << 24u) + \
	    (((uint64_t) (((uint8_t *) (ptr))[2])) << 16u) + \
	    (((uint64_t) (((uint8_t *) (ptr))[1])) << 8u) +  \
	    (((uint64_t) ((uint8_t *) (ptr))[0]))

// This increments a pointer a fixed number of byte cells.
#define NNI_INCPTR(ptr, n) ((ptr) = (void *) ((char *) (ptr) + (n)))

// Alignment -- this is used when allocating adjacent objects to ensure
// that each object begins on a natural alignment boundary.
#define NNI_ALIGN_SIZE sizeof(void *)
#define NNI_ALIGN_MASK (NNI_ALIGN_SIZE - 1)
#define NNI_ALIGN_UP(sz) (((sz) + NNI_ALIGN_MASK) & ~NNI_ALIGN_MASK)

// A few assorted other items.
#define NNI_FLAG_IPV4ONLY 1

// Types.  These are used to provide more structured access to options
// (and maybe later statistics).  For now these are internal only.
typedef enum {
	NNI_TYPE_NONE, // DO NOT USE
	NNI_TYPE_BOOL,
	NNI_TYPE_INT32,
	NNI_TYPE_SIZE,
	NNI_TYPE_DURATION,
	NNI_TYPE_STRING,
	NNI_TYPE_SOCKADDR,
} nni_type;

typedef nni_type nni_opt_type;

// NNI_MAX_MAX_TTL is the maximum value that MAX_TTL can be set to -
// i.e. the number of nng_device boundaries that a message can traverse.
// This value drives the size of pre-allocated headers and back-trace
// buffers -- we need 4 bytes for each hop, plus 4 bytes for the request
// identifier.  Thus, it is recommended not to set this value too large.
// (It is possible to scale out to inconceivably large networks with
// only a few hops - we have yet to see more than 4 in practice.)
#ifndef NNI_MAX_MAX_TTL
#define NNI_MAX_MAX_TTL 15
#endif

// NNI_MAX_HEADER_SIZE is our header size.
#define NNI_MAX_HEADER_SIZE ((NNI_MAX_MAX_TTL + 1) * sizeof(uint32_t))

// NNI_EXPIRE_BATCH lets us handle expiration in batches,
// reducing the number of traverses of the expiration list we perform.
#ifndef NNI_EXPIRE_BATCH
#define NNI_EXPIRE_BATCH 100
#endif

#if __GNUC__ > 3
// NNI_GCC_VERSION is used to indicate a GNU version.  It is used
// to trigger certain cases like atomics that might be compiler specific.
#define NNI_GCC_VERSION \
	(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#endif

#if !defined(NNG_BIG_ENDIAN) && !defined(NNG_LITTLE_ENDIAN)
#if defined(__BYTE_ORDER__)
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define NNG_BIG_ENDIAN 1
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define NNG_LITTLE_ENDIAN 1
#else // middle-endian? (aka PDP-11)
#error "Unsupported or unknown endian"
#endif // __BYTE_ORDER__
#else  // defined(__BYTE_ORDER__)
#define NNG_LITTLE_ENDIAN 1
#error "Unknown endian: specify -DNNG_BIG_ENDIAN=1 or -DNNG_LITTLE_ENDIAN=1"
#endif // defined(__BYTE_ORDER)
#endif // defined() endianness

#endif // CORE_DEFS_H