ffi-nats-core 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ffi-nats-core.gemspec +8 -0
- data/lib/ffi/nats/core/version.rb +1 -1
- data/vendor/cnats/CMakeLists.txt +137 -0
- data/vendor/cnats/adapters/libevent.h +220 -0
- data/vendor/cnats/adapters/libuv.h +472 -0
- data/vendor/cnats/examples/CMakeLists.txt +56 -0
- data/vendor/cnats/examples/asynctimeout.c +83 -0
- data/vendor/cnats/examples/examples.h +322 -0
- data/vendor/cnats/examples/libevent-pub.c +136 -0
- data/vendor/cnats/examples/libevent-sub.c +104 -0
- data/vendor/cnats/examples/libuv-pub.c +120 -0
- data/vendor/cnats/examples/libuv-sub.c +114 -0
- data/vendor/cnats/examples/publisher.c +62 -0
- data/vendor/cnats/examples/queuegroup.c +132 -0
- data/vendor/cnats/examples/replier.c +149 -0
- data/vendor/cnats/examples/requestor.c +75 -0
- data/vendor/cnats/examples/subscriber.c +133 -0
- data/vendor/cnats/src/CMakeLists.txt +31 -0
- data/vendor/cnats/src/asynccb.c +66 -0
- data/vendor/cnats/src/asynccb.h +42 -0
- data/vendor/cnats/src/buf.c +246 -0
- data/vendor/cnats/src/buf.h +116 -0
- data/vendor/cnats/src/comsock.c +474 -0
- data/vendor/cnats/src/comsock.h +81 -0
- data/vendor/cnats/src/conn.c +2725 -0
- data/vendor/cnats/src/conn.h +75 -0
- data/vendor/cnats/src/err.h +31 -0
- data/vendor/cnats/src/gc.h +27 -0
- data/vendor/cnats/src/hash.c +725 -0
- data/vendor/cnats/src/hash.h +141 -0
- data/vendor/cnats/src/include/n-unix.h +56 -0
- data/vendor/cnats/src/include/n-win.h +59 -0
- data/vendor/cnats/src/mem.h +20 -0
- data/vendor/cnats/src/msg.c +155 -0
- data/vendor/cnats/src/msg.h +43 -0
- data/vendor/cnats/src/nats.c +1734 -0
- data/vendor/cnats/src/nats.h +2024 -0
- data/vendor/cnats/src/natsp.h +518 -0
- data/vendor/cnats/src/natstime.c +79 -0
- data/vendor/cnats/src/natstime.h +27 -0
- data/vendor/cnats/src/nuid.c +265 -0
- data/vendor/cnats/src/nuid.h +21 -0
- data/vendor/cnats/src/opts.c +1030 -0
- data/vendor/cnats/src/opts.h +19 -0
- data/vendor/cnats/src/parser.c +869 -0
- data/vendor/cnats/src/parser.h +87 -0
- data/vendor/cnats/src/pub.c +293 -0
- data/vendor/cnats/src/srvpool.c +380 -0
- data/vendor/cnats/src/srvpool.h +71 -0
- data/vendor/cnats/src/stats.c +54 -0
- data/vendor/cnats/src/stats.h +21 -0
- data/vendor/cnats/src/status.c +60 -0
- data/vendor/cnats/src/status.h +95 -0
- data/vendor/cnats/src/sub.c +956 -0
- data/vendor/cnats/src/sub.h +34 -0
- data/vendor/cnats/src/timer.c +86 -0
- data/vendor/cnats/src/timer.h +57 -0
- data/vendor/cnats/src/unix/cond.c +103 -0
- data/vendor/cnats/src/unix/mutex.c +107 -0
- data/vendor/cnats/src/unix/sock.c +105 -0
- data/vendor/cnats/src/unix/thread.c +162 -0
- data/vendor/cnats/src/url.c +134 -0
- data/vendor/cnats/src/url.h +24 -0
- data/vendor/cnats/src/util.c +823 -0
- data/vendor/cnats/src/util.h +75 -0
- data/vendor/cnats/src/version.h +29 -0
- data/vendor/cnats/src/version.h.in +29 -0
- data/vendor/cnats/src/win/cond.c +86 -0
- data/vendor/cnats/src/win/mutex.c +54 -0
- data/vendor/cnats/src/win/sock.c +158 -0
- data/vendor/cnats/src/win/strings.c +108 -0
- data/vendor/cnats/src/win/thread.c +180 -0
- data/vendor/cnats/test/CMakeLists.txt +35 -0
- data/vendor/cnats/test/certs/ca.pem +38 -0
- data/vendor/cnats/test/certs/client-cert.pem +30 -0
- data/vendor/cnats/test/certs/client-key.pem +51 -0
- data/vendor/cnats/test/certs/server-cert.pem +31 -0
- data/vendor/cnats/test/certs/server-key.pem +51 -0
- data/vendor/cnats/test/dylib/CMakeLists.txt +10 -0
- data/vendor/cnats/test/dylib/nonats.c +13 -0
- data/vendor/cnats/test/list.txt +125 -0
- data/vendor/cnats/test/test.c +11655 -0
- data/vendor/cnats/test/tls.conf +15 -0
- data/vendor/cnats/test/tlsverify.conf +19 -0
- metadata +83 -1
@@ -0,0 +1,79 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#ifdef _WIN32
|
6
|
+
#include <sys/timeb.h>
|
7
|
+
#endif
|
8
|
+
#include <time.h>
|
9
|
+
|
10
|
+
int64_t
|
11
|
+
nats_Now(void)
|
12
|
+
{
|
13
|
+
#ifdef _WIN32
|
14
|
+
struct _timeb now;
|
15
|
+
_ftime_s(&now);
|
16
|
+
return (((int64_t)now.time) * 1000 + now.millitm);
|
17
|
+
#elif defined CLOCK_MONOTONIC
|
18
|
+
struct timespec ts;
|
19
|
+
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
|
20
|
+
abort();
|
21
|
+
return ((int64_t)ts.tv_sec) * 1000 + (((int64_t)ts.tv_nsec) / 1000000);
|
22
|
+
#else
|
23
|
+
struct timeval tv;
|
24
|
+
if (gettimeofday(&tv, NULL) != 0)
|
25
|
+
abort();
|
26
|
+
return ((int64_t)tv.tv_sec) * 1000 + (((int64_t)tv.tv_usec) / 1000);
|
27
|
+
#endif
|
28
|
+
}
|
29
|
+
|
30
|
+
int64_t
|
31
|
+
nats_NowInNanoSeconds(void)
|
32
|
+
{
|
33
|
+
#ifdef _WIN32
|
34
|
+
struct _timeb now;
|
35
|
+
_ftime_s(&now);
|
36
|
+
return (((int64_t)now.time) * 1000 + now.millitm) * 1000000L;
|
37
|
+
#elif defined CLOCK_MONOTONIC
|
38
|
+
struct timespec ts;
|
39
|
+
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
|
40
|
+
abort();
|
41
|
+
return ((int64_t)ts.tv_sec) * 1000000000L + ((int64_t)ts.tv_nsec);
|
42
|
+
#else
|
43
|
+
struct timeval tv;
|
44
|
+
if (gettimeofday(&tv, NULL) != 0)
|
45
|
+
abort();
|
46
|
+
return ((int64_t)tv.tv_sec) * 1000000000L + (((int64_t)tv.tv_usec) * 1000);
|
47
|
+
#endif
|
48
|
+
}
|
49
|
+
|
50
|
+
void
|
51
|
+
natsDeadline_Init(natsDeadline *deadline, int64_t timeout)
|
52
|
+
{
|
53
|
+
deadline->active = true;
|
54
|
+
deadline->absoluteTime = nats_Now() + timeout;
|
55
|
+
deadline->timeout.tv_sec = (long) timeout / 1000;
|
56
|
+
deadline->timeout.tv_usec = (timeout % 1000) * 1000;
|
57
|
+
}
|
58
|
+
|
59
|
+
void
|
60
|
+
natsDeadline_Clear(natsDeadline *deadline)
|
61
|
+
{
|
62
|
+
deadline->active = false;
|
63
|
+
}
|
64
|
+
|
65
|
+
struct timeval*
|
66
|
+
natsDeadline_GetTimeout(natsDeadline *deadline)
|
67
|
+
{
|
68
|
+
int64_t timeout;
|
69
|
+
|
70
|
+
if (!(deadline->active))
|
71
|
+
return NULL;
|
72
|
+
|
73
|
+
timeout = deadline->absoluteTime - nats_Now();
|
74
|
+
|
75
|
+
deadline->timeout.tv_sec = (long) (timeout / 1000);
|
76
|
+
deadline->timeout.tv_usec = (timeout % 1000) * 1000;
|
77
|
+
|
78
|
+
return &(deadline->timeout);
|
79
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
|
4
|
+
#ifndef NATSTIME_H_
|
5
|
+
#define NATSTIME_H_
|
6
|
+
|
7
|
+
#include "natsp.h"
|
8
|
+
|
9
|
+
typedef struct __natsDeadline
|
10
|
+
{
|
11
|
+
int64_t absoluteTime;
|
12
|
+
struct timeval timeout;
|
13
|
+
bool active;
|
14
|
+
|
15
|
+
} natsDeadline;
|
16
|
+
|
17
|
+
void
|
18
|
+
natsDeadline_Init(natsDeadline *deadline, int64_t timeout);
|
19
|
+
|
20
|
+
struct timeval*
|
21
|
+
natsDeadline_GetTimeout(natsDeadline *deadline);
|
22
|
+
|
23
|
+
void
|
24
|
+
natsDeadline_Clear(natsDeadline *deadline);
|
25
|
+
|
26
|
+
|
27
|
+
#endif /* NATSTIME_H_ */
|
@@ -0,0 +1,265 @@
|
|
1
|
+
// Copyright 2016 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
// From https://en.wikipedia.org/wiki/Multiply-with-carry
|
6
|
+
|
7
|
+
// CMWC working parts
|
8
|
+
#define CMWC_CYCLE 4096 // as Marsaglia recommends
|
9
|
+
#define CMWC_C_MAX 809430660 // as Marsaglia recommends
|
10
|
+
static uint32_t Q[CMWC_CYCLE];
|
11
|
+
static uint32_t carry = 362436; // must be limited with CMWC_C_MAX (we will reinit it with seed)
|
12
|
+
|
13
|
+
// Make 32 bit random number (some systems use 16 bit RAND_MAX)
|
14
|
+
static uint32_t
|
15
|
+
_rand32(void)
|
16
|
+
{
|
17
|
+
uint32_t result = 0;
|
18
|
+
result = rand();
|
19
|
+
result <<= 16;
|
20
|
+
result |= rand();
|
21
|
+
return result;
|
22
|
+
}
|
23
|
+
|
24
|
+
// Init all engine parts with seed
|
25
|
+
static void
|
26
|
+
_initCMWC(unsigned int seed)
|
27
|
+
{
|
28
|
+
int i;
|
29
|
+
|
30
|
+
for (i = 0; i < CMWC_CYCLE; i++)
|
31
|
+
Q[i] = _rand32();
|
32
|
+
|
33
|
+
do
|
34
|
+
{
|
35
|
+
carry = _rand32();
|
36
|
+
}
|
37
|
+
while (carry >= CMWC_C_MAX);
|
38
|
+
}
|
39
|
+
|
40
|
+
// CMWC engine
|
41
|
+
static uint32_t
|
42
|
+
_randCMWC(void)
|
43
|
+
{
|
44
|
+
static uint32_t i = CMWC_CYCLE - 1;
|
45
|
+
uint64_t t = 0;
|
46
|
+
uint64_t a = 18782; // as Marsaglia recommends
|
47
|
+
uint32_t r = 0xfffffffe; // as Marsaglia recommends
|
48
|
+
uint32_t x = 0;
|
49
|
+
|
50
|
+
i = (i + 1) & (CMWC_CYCLE - 1);
|
51
|
+
t = a * Q[i] + carry;
|
52
|
+
carry = t >> 32;
|
53
|
+
x = (uint32_t) (t + carry);
|
54
|
+
if (x < carry)
|
55
|
+
{
|
56
|
+
x++;
|
57
|
+
carry++;
|
58
|
+
}
|
59
|
+
|
60
|
+
return (Q[i] = r - x);
|
61
|
+
}
|
62
|
+
|
63
|
+
static int64_t
|
64
|
+
_rand64(int64_t maxValue)
|
65
|
+
{
|
66
|
+
int64_t v;
|
67
|
+
|
68
|
+
v = ((int64_t) _randCMWC() << 32);
|
69
|
+
v |= (int64_t) _randCMWC();
|
70
|
+
|
71
|
+
if (v < 0)
|
72
|
+
v = v * -1;
|
73
|
+
|
74
|
+
v = v % maxValue;
|
75
|
+
|
76
|
+
return v;
|
77
|
+
}
|
78
|
+
|
79
|
+
// A unique identifier generator that is high performance, very fast, and entropy pool friendly.
|
80
|
+
//
|
81
|
+
// NUID needs to be very fast to generate and truly unique, all while being entropy pool friendly.
|
82
|
+
// We will use 12 bytes of crypto generated data (entropy draining), and 10 bytes of sequential data
|
83
|
+
// that is started at a pseudo random number and increments with a pseudo-random increment.
|
84
|
+
// Total is 22 bytes of base 36 ascii text :)
|
85
|
+
|
86
|
+
#define NUID_PRE_LEN (12)
|
87
|
+
#define NUID_SEQ_LEN (10)
|
88
|
+
|
89
|
+
static const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
90
|
+
static const int base = 36;
|
91
|
+
static const int64_t maxPre = 4738381338321616896L;
|
92
|
+
static const int64_t maxSeq = 3656158440062976L;
|
93
|
+
static const int64_t minInc = 33L;
|
94
|
+
static const int64_t maxInc = 333L;
|
95
|
+
static const int totalLen= NUID_PRE_LEN + NUID_SEQ_LEN;
|
96
|
+
|
97
|
+
typedef struct natsNUID
|
98
|
+
{
|
99
|
+
char pre[NUID_PRE_LEN];
|
100
|
+
int64_t seq;
|
101
|
+
int64_t inc;
|
102
|
+
|
103
|
+
} natsNUID;
|
104
|
+
|
105
|
+
typedef struct natsLockedNUID
|
106
|
+
{
|
107
|
+
natsMutex *mu;
|
108
|
+
natsNUID nuid;
|
109
|
+
|
110
|
+
} natsLockedNUID;
|
111
|
+
|
112
|
+
// Global NUID
|
113
|
+
static natsLockedNUID globalNUID;
|
114
|
+
|
115
|
+
static natsStatus
|
116
|
+
_nextLong(int64_t *next, bool useCrypto, int64_t maxValue)
|
117
|
+
{
|
118
|
+
natsStatus s = NATS_OK;
|
119
|
+
|
120
|
+
if (maxValue <= 0)
|
121
|
+
return nats_setError(NATS_INVALID_ARG,
|
122
|
+
"Invalid argument for nextLong: %" PRId64 "",
|
123
|
+
maxValue);
|
124
|
+
#if defined(NATS_HAS_TLS)
|
125
|
+
if (useCrypto)
|
126
|
+
{
|
127
|
+
int64_t r = 0;
|
128
|
+
|
129
|
+
RAND_bytes((unsigned char*) &r, sizeof(int64_t));
|
130
|
+
if (r < 0)
|
131
|
+
r = r * -1;
|
132
|
+
|
133
|
+
*next = r;
|
134
|
+
}
|
135
|
+
else
|
136
|
+
#endif
|
137
|
+
*next = _rand64(maxValue);
|
138
|
+
|
139
|
+
return s;
|
140
|
+
}
|
141
|
+
|
142
|
+
// Resets the sequential portion of the NUID.
|
143
|
+
static natsStatus
|
144
|
+
_resetSequential(natsNUID *nuid)
|
145
|
+
{
|
146
|
+
natsStatus s;
|
147
|
+
|
148
|
+
s = _nextLong(&(nuid->seq), false, maxSeq);
|
149
|
+
if (s == NATS_OK)
|
150
|
+
s = _nextLong(&(nuid->inc), false, maxInc - minInc);
|
151
|
+
if (s == NATS_OK)
|
152
|
+
nuid->inc += minInc;
|
153
|
+
|
154
|
+
return NATS_UPDATE_ERR_STACK(s);
|
155
|
+
}
|
156
|
+
|
157
|
+
// Generate a new prefix from crypto rand.
|
158
|
+
// This will drain entropy and will be called automatically when we exhaust the sequential
|
159
|
+
static natsStatus
|
160
|
+
_randomizePrefix(natsNUID *nuid)
|
161
|
+
{
|
162
|
+
natsStatus s;
|
163
|
+
int64_t r = 0;
|
164
|
+
|
165
|
+
s = _nextLong(&r, true, maxPre);
|
166
|
+
if (s == NATS_OK)
|
167
|
+
{
|
168
|
+
int64_t l;
|
169
|
+
int i = NUID_PRE_LEN;
|
170
|
+
for (l = r; i > 0; l /= base)
|
171
|
+
{
|
172
|
+
i--;
|
173
|
+
nuid->pre[i] = digits[(int) (l % base)];
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
return NATS_UPDATE_ERR_STACK(s);
|
178
|
+
}
|
179
|
+
|
180
|
+
void
|
181
|
+
natsNUID_free(void)
|
182
|
+
{
|
183
|
+
natsMutex_Destroy(globalNUID.mu);
|
184
|
+
globalNUID.mu = NULL;
|
185
|
+
}
|
186
|
+
|
187
|
+
// Seed sequential random with math/random and current time and generate crypto prefix.
|
188
|
+
natsStatus
|
189
|
+
natsNUID_init(void)
|
190
|
+
{
|
191
|
+
natsStatus s;
|
192
|
+
unsigned int seed = (unsigned int) nats_NowInNanoSeconds();
|
193
|
+
|
194
|
+
memset(&globalNUID, 0, sizeof(natsNUID));
|
195
|
+
|
196
|
+
srand(seed);
|
197
|
+
_initCMWC(seed);
|
198
|
+
|
199
|
+
s = natsMutex_Create(&(globalNUID.mu));
|
200
|
+
if (s == NATS_OK)
|
201
|
+
s = _resetSequential(&(globalNUID.nuid));
|
202
|
+
if (s == NATS_OK)
|
203
|
+
s = _randomizePrefix(&(globalNUID.nuid));
|
204
|
+
|
205
|
+
if (s != NATS_OK)
|
206
|
+
natsNUID_free();
|
207
|
+
|
208
|
+
return NATS_UPDATE_ERR_STACK(s);
|
209
|
+
}
|
210
|
+
|
211
|
+
// Generate the next NUID string.
|
212
|
+
static natsStatus
|
213
|
+
_nextNUID(natsNUID *nuid, char *buffer, int bufferLen)
|
214
|
+
{
|
215
|
+
natsStatus s = NATS_OK;
|
216
|
+
|
217
|
+
// Check bufferLen is big enough
|
218
|
+
if (bufferLen <= totalLen)
|
219
|
+
return NATS_INSUFFICIENT_BUFFER;
|
220
|
+
|
221
|
+
// Increment and capture.
|
222
|
+
nuid->seq += nuid->inc;
|
223
|
+
if (nuid->seq >= maxSeq)
|
224
|
+
{
|
225
|
+
s = _randomizePrefix(nuid);
|
226
|
+
if (s == NATS_OK)
|
227
|
+
s = _resetSequential(nuid);
|
228
|
+
}
|
229
|
+
|
230
|
+
if (s == NATS_OK)
|
231
|
+
{
|
232
|
+
int64_t l;
|
233
|
+
int i;
|
234
|
+
|
235
|
+
// Copy prefix
|
236
|
+
memcpy(buffer, nuid->pre, NUID_PRE_LEN);
|
237
|
+
|
238
|
+
// copy in the seq in base36.
|
239
|
+
l = nuid->seq;
|
240
|
+
for (i = totalLen; i > NUID_PRE_LEN; l /= base)
|
241
|
+
{
|
242
|
+
i--;
|
243
|
+
buffer[i] = digits[(int) (l % base)];
|
244
|
+
}
|
245
|
+
|
246
|
+
buffer[totalLen] = '\0';
|
247
|
+
}
|
248
|
+
|
249
|
+
return NATS_UPDATE_ERR_STACK(s);
|
250
|
+
}
|
251
|
+
|
252
|
+
// Generate the next NUID string from the global locked NUID instance.
|
253
|
+
natsStatus
|
254
|
+
natsNUID_Next(char *buffer, int bufferLen)
|
255
|
+
{
|
256
|
+
natsStatus s;
|
257
|
+
|
258
|
+
natsMutex_Lock(globalNUID.mu);
|
259
|
+
|
260
|
+
s = _nextNUID(&(globalNUID.nuid), buffer, bufferLen);
|
261
|
+
|
262
|
+
natsMutex_Unlock(globalNUID.mu);
|
263
|
+
|
264
|
+
return NATS_UPDATE_ERR_STACK(s);
|
265
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
// Copyright 2016 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#ifndef NUID_H_
|
4
|
+
#define NUID_H_
|
5
|
+
|
6
|
+
#include "status.h"
|
7
|
+
|
8
|
+
#define NUID_BUFFER_LEN (12 + 10)
|
9
|
+
|
10
|
+
// Seed sequential random with math/random and current time and generate crypto prefix.
|
11
|
+
natsStatus
|
12
|
+
natsNUID_init(void);
|
13
|
+
|
14
|
+
// Generate the next NUID string from the global locked NUID instance.
|
15
|
+
natsStatus
|
16
|
+
natsNUID_Next(char *buffer, int bufferLen);
|
17
|
+
|
18
|
+
void
|
19
|
+
natsNUID_free(void);
|
20
|
+
|
21
|
+
#endif /* NUID_H_ */
|
@@ -0,0 +1,1030 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
#include "mem.h"
|
8
|
+
#include "opts.h"
|
9
|
+
|
10
|
+
#define LOCK_AND_CHECK_OPTIONS(o, c) \
|
11
|
+
if (((o) == NULL) || ((c))) \
|
12
|
+
return nats_setDefaultError(NATS_INVALID_ARG); \
|
13
|
+
natsMutex_Lock((o)->mu);
|
14
|
+
|
15
|
+
#define UNLOCK_OPTS(o) natsMutex_Unlock((o)->mu)
|
16
|
+
|
17
|
+
natsStatus
|
18
|
+
natsOptions_SetURL(natsOptions *opts, const char* url)
|
19
|
+
{
|
20
|
+
natsStatus s = NATS_OK;
|
21
|
+
|
22
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
23
|
+
|
24
|
+
if (opts->url != NULL)
|
25
|
+
{
|
26
|
+
NATS_FREE(opts->url);
|
27
|
+
opts->url = NULL;
|
28
|
+
}
|
29
|
+
|
30
|
+
if (url != NULL)
|
31
|
+
{
|
32
|
+
opts->url = NATS_STRDUP(url);
|
33
|
+
if (opts->url == NULL)
|
34
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
35
|
+
}
|
36
|
+
|
37
|
+
UNLOCK_OPTS(opts);
|
38
|
+
|
39
|
+
return s;
|
40
|
+
}
|
41
|
+
|
42
|
+
static void
|
43
|
+
_freeServers(natsOptions *opts)
|
44
|
+
{
|
45
|
+
int i;
|
46
|
+
|
47
|
+
if ((opts->servers == NULL) || (opts->serversCount == 0))
|
48
|
+
return;
|
49
|
+
|
50
|
+
for (i = 0; i < opts->serversCount; i++)
|
51
|
+
NATS_FREE(opts->servers[i]);
|
52
|
+
|
53
|
+
NATS_FREE(opts->servers);
|
54
|
+
|
55
|
+
opts->servers = NULL;
|
56
|
+
opts->serversCount = 0;
|
57
|
+
}
|
58
|
+
|
59
|
+
natsStatus
|
60
|
+
natsOptions_SetServers(natsOptions *opts, const char** servers, int serversCount)
|
61
|
+
{
|
62
|
+
natsStatus s = NATS_OK;
|
63
|
+
int i;
|
64
|
+
|
65
|
+
LOCK_AND_CHECK_OPTIONS(opts,
|
66
|
+
(((servers != NULL) && (serversCount <= 0))
|
67
|
+
|| ((servers == NULL) && (serversCount != 0))));
|
68
|
+
|
69
|
+
_freeServers(opts);
|
70
|
+
|
71
|
+
if (servers != NULL)
|
72
|
+
{
|
73
|
+
opts->servers = (char**) NATS_CALLOC(serversCount, sizeof(char*));
|
74
|
+
if (opts->servers == NULL)
|
75
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
76
|
+
|
77
|
+
for (i = 0; (s == NATS_OK) && (i < serversCount); i++)
|
78
|
+
{
|
79
|
+
opts->servers[i] = (char*) NATS_STRDUP(servers[i]);
|
80
|
+
if (opts->servers[i] == NULL)
|
81
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
82
|
+
else
|
83
|
+
opts->serversCount++;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
if (s != NATS_OK)
|
88
|
+
_freeServers(opts);
|
89
|
+
|
90
|
+
UNLOCK_OPTS(opts);
|
91
|
+
|
92
|
+
return s;
|
93
|
+
}
|
94
|
+
|
95
|
+
natsStatus
|
96
|
+
natsOptions_SetNoRandomize(natsOptions *opts, bool noRandomize)
|
97
|
+
{
|
98
|
+
natsStatus s = NATS_OK;
|
99
|
+
|
100
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
101
|
+
|
102
|
+
opts->noRandomize = noRandomize;
|
103
|
+
|
104
|
+
UNLOCK_OPTS(opts);
|
105
|
+
|
106
|
+
return s;
|
107
|
+
}
|
108
|
+
|
109
|
+
natsStatus
|
110
|
+
natsOptions_SetTimeout(natsOptions *opts, int64_t timeout)
|
111
|
+
{
|
112
|
+
LOCK_AND_CHECK_OPTIONS(opts, (timeout < 0));
|
113
|
+
|
114
|
+
opts->timeout = timeout;
|
115
|
+
|
116
|
+
UNLOCK_OPTS(opts);
|
117
|
+
|
118
|
+
return NATS_OK;
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
natsStatus
|
123
|
+
natsOptions_SetName(natsOptions *opts, const char *name)
|
124
|
+
{
|
125
|
+
natsStatus s = NATS_OK;
|
126
|
+
|
127
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
128
|
+
|
129
|
+
NATS_FREE(opts->name);
|
130
|
+
opts->name = NULL;
|
131
|
+
if (name != NULL)
|
132
|
+
{
|
133
|
+
opts->name = NATS_STRDUP(name);
|
134
|
+
if (opts->name == NULL)
|
135
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
136
|
+
}
|
137
|
+
|
138
|
+
UNLOCK_OPTS(opts);
|
139
|
+
|
140
|
+
return s;
|
141
|
+
}
|
142
|
+
|
143
|
+
natsStatus
|
144
|
+
natsOptions_SetUserInfo(natsOptions *opts, const char *user, const char *password)
|
145
|
+
{
|
146
|
+
natsStatus s = NATS_OK;
|
147
|
+
|
148
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
149
|
+
|
150
|
+
NATS_FREE(opts->user);
|
151
|
+
opts->user= NULL;
|
152
|
+
NATS_FREE(opts->password);
|
153
|
+
opts->password = NULL;
|
154
|
+
if (user != NULL)
|
155
|
+
{
|
156
|
+
opts->user = NATS_STRDUP(user);
|
157
|
+
if (opts->user== NULL)
|
158
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
159
|
+
}
|
160
|
+
if ((s == NATS_OK) && (password != NULL))
|
161
|
+
{
|
162
|
+
opts->password = NATS_STRDUP(password);
|
163
|
+
if (opts->password == NULL)
|
164
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
165
|
+
}
|
166
|
+
|
167
|
+
UNLOCK_OPTS(opts);
|
168
|
+
|
169
|
+
return s;
|
170
|
+
}
|
171
|
+
|
172
|
+
natsStatus
|
173
|
+
natsOptions_SetToken(natsOptions *opts, const char *token)
|
174
|
+
{
|
175
|
+
natsStatus s = NATS_OK;
|
176
|
+
|
177
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
178
|
+
|
179
|
+
NATS_FREE(opts->token);
|
180
|
+
opts->token= NULL;
|
181
|
+
if (token != NULL)
|
182
|
+
{
|
183
|
+
opts->token = NATS_STRDUP(token);
|
184
|
+
if (opts->token == NULL)
|
185
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
186
|
+
}
|
187
|
+
|
188
|
+
UNLOCK_OPTS(opts);
|
189
|
+
|
190
|
+
return s;
|
191
|
+
}
|
192
|
+
|
193
|
+
static void
|
194
|
+
natsSSLCtx_release(natsSSLCtx *ctx)
|
195
|
+
{
|
196
|
+
int refs;
|
197
|
+
|
198
|
+
if (ctx == NULL)
|
199
|
+
return;
|
200
|
+
|
201
|
+
natsMutex_Lock(ctx->lock);
|
202
|
+
|
203
|
+
refs = --(ctx->refs);
|
204
|
+
|
205
|
+
natsMutex_Unlock(ctx->lock);
|
206
|
+
|
207
|
+
if (refs == 0)
|
208
|
+
{
|
209
|
+
NATS_FREE(ctx->expectedHostname);
|
210
|
+
SSL_CTX_free(ctx->ctx);
|
211
|
+
natsMutex_Destroy(ctx->lock);
|
212
|
+
NATS_FREE(ctx);
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
static natsSSLCtx*
|
217
|
+
natsSSLCtx_retain(natsSSLCtx *ctx)
|
218
|
+
{
|
219
|
+
natsMutex_Lock(ctx->lock);
|
220
|
+
ctx->refs++;
|
221
|
+
natsMutex_Unlock(ctx->lock);
|
222
|
+
|
223
|
+
return ctx;
|
224
|
+
}
|
225
|
+
|
226
|
+
#if defined(NATS_HAS_TLS)
|
227
|
+
// See section RFC 6125 Sections 2.4 and 3.1
|
228
|
+
static bool
|
229
|
+
_hostnameMatches(char *expr, char *string)
|
230
|
+
{
|
231
|
+
int i, j;
|
232
|
+
|
233
|
+
for (i = 0, j = 0; i < (int) strlen(expr); i++)
|
234
|
+
{
|
235
|
+
if (expr[i] == '*')
|
236
|
+
{
|
237
|
+
if (string[j] == '.')
|
238
|
+
return 0;
|
239
|
+
while (string[j] != '.')
|
240
|
+
j++;
|
241
|
+
}
|
242
|
+
else if (expr[i] != string[j])
|
243
|
+
{
|
244
|
+
return false;
|
245
|
+
}
|
246
|
+
else
|
247
|
+
j++;
|
248
|
+
}
|
249
|
+
|
250
|
+
return (j == (int) strlen(string));
|
251
|
+
}
|
252
|
+
|
253
|
+
// Does this hostname match an entry in the subjectAltName extension?
|
254
|
+
// returns: 0 if no, 1 if yes, -1 if no subjectAltName entries were found.
|
255
|
+
static int
|
256
|
+
_hostnameMatchesSubjectAltName(char *hostname, X509 *cert)
|
257
|
+
{
|
258
|
+
bool foundAnyEntry = false;
|
259
|
+
bool foundMatch = false;
|
260
|
+
GENERAL_NAME *namePart = NULL;
|
261
|
+
STACK_OF(GENERAL_NAME) *san;
|
262
|
+
|
263
|
+
san = (STACK_OF(GENERAL_NAME)*) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
|
264
|
+
|
265
|
+
while (sk_GENERAL_NAME_num(san) > 0)
|
266
|
+
{
|
267
|
+
namePart = sk_GENERAL_NAME_pop(san);
|
268
|
+
|
269
|
+
if (namePart->type == GEN_DNS)
|
270
|
+
{
|
271
|
+
foundAnyEntry = true;
|
272
|
+
foundMatch = _hostnameMatches((char*) ASN1_STRING_data(namePart->d.uniformResourceIdentifier),
|
273
|
+
hostname);
|
274
|
+
}
|
275
|
+
|
276
|
+
GENERAL_NAME_free(namePart);
|
277
|
+
|
278
|
+
if (foundMatch)
|
279
|
+
break;
|
280
|
+
}
|
281
|
+
|
282
|
+
GENERAL_NAMES_free(san);
|
283
|
+
|
284
|
+
if (foundMatch)
|
285
|
+
return 1;
|
286
|
+
|
287
|
+
return (foundAnyEntry ? 0 : -1);
|
288
|
+
}
|
289
|
+
|
290
|
+
static bool
|
291
|
+
_hostnameMatchesSubjectCN(char *hostname, X509 *cert)
|
292
|
+
{
|
293
|
+
X509_NAME *name;
|
294
|
+
X509_NAME_ENTRY *name_entry;
|
295
|
+
char *certname;
|
296
|
+
int position;
|
297
|
+
|
298
|
+
name = X509_get_subject_name(cert);
|
299
|
+
position = -1;
|
300
|
+
while (1)
|
301
|
+
{
|
302
|
+
position = X509_NAME_get_index_by_NID(name, NID_commonName, position);
|
303
|
+
if (position == -1)
|
304
|
+
break;
|
305
|
+
name_entry = X509_NAME_get_entry(name, position);
|
306
|
+
certname = (char*) X509_NAME_ENTRY_get_data(name_entry)->data;
|
307
|
+
if (_hostnameMatches(certname, hostname))
|
308
|
+
return true;
|
309
|
+
}
|
310
|
+
|
311
|
+
return false;
|
312
|
+
}
|
313
|
+
|
314
|
+
static int
|
315
|
+
_hostnameMatchesCertificate(char *hostname, X509 *cert)
|
316
|
+
{
|
317
|
+
int san_result = _hostnameMatchesSubjectAltName(hostname, cert);
|
318
|
+
if (san_result > -1)
|
319
|
+
return san_result;
|
320
|
+
|
321
|
+
return _hostnameMatchesSubjectCN(hostname, cert);
|
322
|
+
}
|
323
|
+
|
324
|
+
static int
|
325
|
+
_verifyCb(int preverifyOk, X509_STORE_CTX* ctx)
|
326
|
+
{
|
327
|
+
char buf[256];
|
328
|
+
SSL *ssl = NULL;
|
329
|
+
X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
|
330
|
+
int depth = X509_STORE_CTX_get_error_depth(ctx);
|
331
|
+
int err = X509_STORE_CTX_get_error(ctx);
|
332
|
+
natsConnection *nc = NULL;
|
333
|
+
|
334
|
+
// Retrieve the SSL object, then our connection...
|
335
|
+
ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
|
336
|
+
nc = (natsConnection*) SSL_get_ex_data(ssl, 0);
|
337
|
+
|
338
|
+
// Should we skip serve certificate verification?
|
339
|
+
if (nc->opts->sslCtx->skipVerify)
|
340
|
+
return 1;
|
341
|
+
|
342
|
+
// If the depth is greater than the limit (when not set, the limit is
|
343
|
+
// 100), then report as an error.
|
344
|
+
if (depth > 100)
|
345
|
+
{
|
346
|
+
preverifyOk = 0;
|
347
|
+
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
348
|
+
X509_STORE_CTX_set_error(ctx, err);
|
349
|
+
}
|
350
|
+
|
351
|
+
if (!preverifyOk)
|
352
|
+
{
|
353
|
+
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
|
354
|
+
snprintf(nc->errStr, sizeof(nc->errStr), "%d:%s:depth=%d:%s",
|
355
|
+
err, X509_verify_cert_error_string(err),
|
356
|
+
depth, buf);
|
357
|
+
}
|
358
|
+
|
359
|
+
if (!preverifyOk && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
|
360
|
+
{
|
361
|
+
X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf));
|
362
|
+
snprintf(nc->errStr, sizeof(nc->errStr), "issuer=%s", buf);
|
363
|
+
}
|
364
|
+
|
365
|
+
if (preverifyOk
|
366
|
+
&& (depth == 0) // Verify hostname only for the server certificate.
|
367
|
+
&& (natsSSLCtx_getExpectedHostname(nc->opts->sslCtx) != NULL))
|
368
|
+
{
|
369
|
+
if (!_hostnameMatchesCertificate(
|
370
|
+
natsSSLCtx_getExpectedHostname(nc->opts->sslCtx), cert))
|
371
|
+
{
|
372
|
+
snprintf(nc->errStr, sizeof(nc->errStr),
|
373
|
+
"Did not get expected hostname '%s'",
|
374
|
+
natsSSLCtx_getExpectedHostname(nc->opts->sslCtx));
|
375
|
+
|
376
|
+
preverifyOk = 0;
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
return preverifyOk;
|
381
|
+
}
|
382
|
+
|
383
|
+
static natsStatus
|
384
|
+
_createSSLCtx(natsSSLCtx **newCtx)
|
385
|
+
{
|
386
|
+
natsStatus s = NATS_OK;
|
387
|
+
natsSSLCtx *ctx = NULL;
|
388
|
+
|
389
|
+
ctx = (natsSSLCtx*) NATS_CALLOC(1, sizeof(natsSSLCtx));
|
390
|
+
if (ctx == NULL)
|
391
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
392
|
+
|
393
|
+
if (s == NATS_OK)
|
394
|
+
{
|
395
|
+
ctx->refs = 1;
|
396
|
+
|
397
|
+
s = natsMutex_Create(&(ctx->lock));
|
398
|
+
}
|
399
|
+
if (s == NATS_OK)
|
400
|
+
{
|
401
|
+
#if defined(NATS_USE_TLS_CLIENT_METHOD)
|
402
|
+
ctx->ctx = SSL_CTX_new(TLS_client_method());
|
403
|
+
#else
|
404
|
+
ctx->ctx = SSL_CTX_new(TLSv1_2_client_method());
|
405
|
+
#endif
|
406
|
+
if (ctx->ctx == NULL)
|
407
|
+
s = nats_setError(NATS_SSL_ERROR,
|
408
|
+
"Unable to create SSL context: %s",
|
409
|
+
NATS_SSL_ERR_REASON_STRING);
|
410
|
+
}
|
411
|
+
|
412
|
+
if (s == NATS_OK)
|
413
|
+
{
|
414
|
+
(void) SSL_CTX_set_mode(ctx->ctx, SSL_MODE_AUTO_RETRY);
|
415
|
+
|
416
|
+
SSL_CTX_set_options(ctx->ctx, SSL_OP_NO_SSLv2);
|
417
|
+
SSL_CTX_set_options(ctx->ctx, SSL_OP_NO_SSLv3);
|
418
|
+
|
419
|
+
// Set to SSL_VERIFY_NONE so that we can get more error trace in
|
420
|
+
// the verifyCb that is then used in conn.c's makeTLSConn function.
|
421
|
+
SSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_NONE, _verifyCb);
|
422
|
+
|
423
|
+
*newCtx = ctx;
|
424
|
+
}
|
425
|
+
else if (ctx != NULL)
|
426
|
+
{
|
427
|
+
natsSSLCtx_release(ctx);
|
428
|
+
}
|
429
|
+
|
430
|
+
return NATS_UPDATE_ERR_STACK(s);
|
431
|
+
}
|
432
|
+
|
433
|
+
static natsStatus
|
434
|
+
_getSSLCtx(natsOptions *opts)
|
435
|
+
{
|
436
|
+
natsStatus s;
|
437
|
+
|
438
|
+
s = nats_sslInit();
|
439
|
+
if ((s == NATS_OK) && (opts->sslCtx != NULL))
|
440
|
+
{
|
441
|
+
bool createNew = false;
|
442
|
+
|
443
|
+
natsMutex_Lock(opts->sslCtx->lock);
|
444
|
+
|
445
|
+
// If this context is retained by a cloned natsOptions, we need to
|
446
|
+
// release it and create a new context.
|
447
|
+
if (opts->sslCtx->refs > 1)
|
448
|
+
createNew = true;
|
449
|
+
|
450
|
+
natsMutex_Unlock(opts->sslCtx->lock);
|
451
|
+
|
452
|
+
if (createNew)
|
453
|
+
{
|
454
|
+
natsSSLCtx_release(opts->sslCtx);
|
455
|
+
opts->sslCtx = NULL;
|
456
|
+
}
|
457
|
+
else
|
458
|
+
{
|
459
|
+
// We can use this ssl context.
|
460
|
+
return NATS_OK;
|
461
|
+
}
|
462
|
+
}
|
463
|
+
|
464
|
+
if (s == NATS_OK)
|
465
|
+
s = _createSSLCtx(&(opts->sslCtx));
|
466
|
+
|
467
|
+
return NATS_UPDATE_ERR_STACK(s);
|
468
|
+
}
|
469
|
+
|
470
|
+
natsStatus
|
471
|
+
natsOptions_SetSecure(natsOptions *opts, bool secure)
|
472
|
+
{
|
473
|
+
natsStatus s = NATS_OK;
|
474
|
+
|
475
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
476
|
+
|
477
|
+
if (!secure && (opts->sslCtx != NULL))
|
478
|
+
{
|
479
|
+
natsSSLCtx_release(opts->sslCtx);
|
480
|
+
opts->sslCtx = NULL;
|
481
|
+
}
|
482
|
+
else if (secure && (opts->sslCtx == NULL))
|
483
|
+
{
|
484
|
+
s = _getSSLCtx(opts);
|
485
|
+
}
|
486
|
+
|
487
|
+
if (s == NATS_OK)
|
488
|
+
opts->secure = secure;
|
489
|
+
|
490
|
+
UNLOCK_OPTS(opts);
|
491
|
+
|
492
|
+
return NATS_UPDATE_ERR_STACK(s);
|
493
|
+
}
|
494
|
+
|
495
|
+
natsStatus
|
496
|
+
natsOptions_LoadCATrustedCertificates(natsOptions *opts, const char *fileName)
|
497
|
+
{
|
498
|
+
natsStatus s = NATS_OK;
|
499
|
+
|
500
|
+
LOCK_AND_CHECK_OPTIONS(opts, ((fileName == NULL) || (fileName[0] == '\0')));
|
501
|
+
|
502
|
+
s = _getSSLCtx(opts);
|
503
|
+
if (s == NATS_OK)
|
504
|
+
{
|
505
|
+
nats_sslRegisterThreadForCleanup();
|
506
|
+
|
507
|
+
if (SSL_CTX_load_verify_locations(opts->sslCtx->ctx, fileName, NULL) != 1)
|
508
|
+
{
|
509
|
+
s = nats_setError(NATS_SSL_ERROR,
|
510
|
+
"Error loading trusted certificates '%s': %s",
|
511
|
+
fileName,
|
512
|
+
NATS_SSL_ERR_REASON_STRING);
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
UNLOCK_OPTS(opts);
|
517
|
+
|
518
|
+
return s;
|
519
|
+
}
|
520
|
+
|
521
|
+
natsStatus
|
522
|
+
natsOptions_LoadCertificatesChain(natsOptions *opts,
|
523
|
+
const char *certFileName,
|
524
|
+
const char *keyFileName)
|
525
|
+
{
|
526
|
+
natsStatus s = NATS_OK;
|
527
|
+
|
528
|
+
if ((certFileName == NULL) || (certFileName[0] == '\0')
|
529
|
+
|| (keyFileName == NULL) || (keyFileName[0] == '\0'))
|
530
|
+
{
|
531
|
+
return nats_setError(NATS_INVALID_ARG, "%s",
|
532
|
+
"certificate and key file names can't be NULL nor empty");
|
533
|
+
}
|
534
|
+
|
535
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
536
|
+
|
537
|
+
s = _getSSLCtx(opts);
|
538
|
+
if (s == NATS_OK)
|
539
|
+
{
|
540
|
+
nats_sslRegisterThreadForCleanup();
|
541
|
+
|
542
|
+
if (SSL_CTX_use_certificate_chain_file(opts->sslCtx->ctx, certFileName) != 1)
|
543
|
+
{
|
544
|
+
s = nats_setError(NATS_SSL_ERROR,
|
545
|
+
"Error loading certificate chain '%s': %s",
|
546
|
+
certFileName,
|
547
|
+
NATS_SSL_ERR_REASON_STRING);
|
548
|
+
}
|
549
|
+
}
|
550
|
+
if (s == NATS_OK)
|
551
|
+
{
|
552
|
+
if (SSL_CTX_use_PrivateKey_file(opts->sslCtx->ctx, keyFileName, SSL_FILETYPE_PEM) != 1)
|
553
|
+
{
|
554
|
+
s = nats_setError(NATS_SSL_ERROR,
|
555
|
+
"Error loading private key '%s': %s",
|
556
|
+
keyFileName,
|
557
|
+
NATS_SSL_ERR_REASON_STRING);
|
558
|
+
}
|
559
|
+
}
|
560
|
+
|
561
|
+
UNLOCK_OPTS(opts);
|
562
|
+
|
563
|
+
return s;
|
564
|
+
}
|
565
|
+
|
566
|
+
natsStatus
|
567
|
+
natsOptions_SetCiphers(natsOptions *opts, const char *ciphers)
|
568
|
+
{
|
569
|
+
natsStatus s = NATS_OK;
|
570
|
+
|
571
|
+
LOCK_AND_CHECK_OPTIONS(opts, ((ciphers == NULL) || (ciphers[0] == '\0')));
|
572
|
+
|
573
|
+
s = _getSSLCtx(opts);
|
574
|
+
if (s == NATS_OK)
|
575
|
+
{
|
576
|
+
nats_sslRegisterThreadForCleanup();
|
577
|
+
|
578
|
+
if (SSL_CTX_set_cipher_list(opts->sslCtx->ctx, ciphers) != 1)
|
579
|
+
{
|
580
|
+
s = nats_setError(NATS_SSL_ERROR,
|
581
|
+
"Error setting ciphers '%s': %s",
|
582
|
+
ciphers,
|
583
|
+
NATS_SSL_ERR_REASON_STRING);
|
584
|
+
}
|
585
|
+
}
|
586
|
+
|
587
|
+
UNLOCK_OPTS(opts);
|
588
|
+
|
589
|
+
return s;
|
590
|
+
}
|
591
|
+
|
592
|
+
natsStatus
|
593
|
+
natsOptions_SetExpectedHostname(natsOptions *opts, const char *hostname)
|
594
|
+
{
|
595
|
+
natsStatus s = NATS_OK;
|
596
|
+
|
597
|
+
LOCK_AND_CHECK_OPTIONS(opts, ((hostname == NULL) || (hostname[0] == '\0')));
|
598
|
+
|
599
|
+
s = _getSSLCtx(opts);
|
600
|
+
if (s == NATS_OK)
|
601
|
+
{
|
602
|
+
NATS_FREE(opts->sslCtx->expectedHostname);
|
603
|
+
opts->sslCtx->expectedHostname = NULL;
|
604
|
+
|
605
|
+
if (hostname != NULL)
|
606
|
+
{
|
607
|
+
opts->sslCtx->expectedHostname = NATS_STRDUP(hostname);
|
608
|
+
if (opts->sslCtx->expectedHostname == NULL)
|
609
|
+
{
|
610
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
611
|
+
}
|
612
|
+
}
|
613
|
+
}
|
614
|
+
|
615
|
+
UNLOCK_OPTS(opts);
|
616
|
+
|
617
|
+
return s;
|
618
|
+
}
|
619
|
+
|
620
|
+
natsStatus
|
621
|
+
natsOptions_SkipServerVerification(natsOptions *opts, bool skip)
|
622
|
+
{
|
623
|
+
natsStatus s = NATS_OK;
|
624
|
+
|
625
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
626
|
+
|
627
|
+
s = _getSSLCtx(opts);
|
628
|
+
if (s == NATS_OK)
|
629
|
+
opts->sslCtx->skipVerify = skip;
|
630
|
+
|
631
|
+
UNLOCK_OPTS(opts);
|
632
|
+
|
633
|
+
return s;
|
634
|
+
}
|
635
|
+
|
636
|
+
#else
|
637
|
+
|
638
|
+
natsStatus
|
639
|
+
natsOptions_SetSecure(natsOptions *opts, bool secure)
|
640
|
+
{
|
641
|
+
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
|
642
|
+
}
|
643
|
+
|
644
|
+
natsStatus
|
645
|
+
natsOptions_LoadCATrustedCertificates(natsOptions *opts, const char *fileName)
|
646
|
+
{
|
647
|
+
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
|
648
|
+
}
|
649
|
+
|
650
|
+
natsStatus
|
651
|
+
natsOptions_LoadCertificatesChain(natsOptions *opts,
|
652
|
+
const char *certFileName,
|
653
|
+
const char *keyFileName)
|
654
|
+
{
|
655
|
+
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
|
656
|
+
}
|
657
|
+
|
658
|
+
natsStatus
|
659
|
+
natsOptions_SetCiphers(natsOptions *opts, const char *ciphers)
|
660
|
+
{
|
661
|
+
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
|
662
|
+
}
|
663
|
+
|
664
|
+
natsStatus
|
665
|
+
natsOptions_SetExpectedHostname(natsOptions *opts, const char *hostname)
|
666
|
+
{
|
667
|
+
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
|
668
|
+
}
|
669
|
+
|
670
|
+
natsStatus
|
671
|
+
natsOptions_SkipServerVerification(natsOptions *opts, bool skip)
|
672
|
+
{
|
673
|
+
return nats_setError(NATS_ILLEGAL_STATE, "%s", NO_SSL_ERR);
|
674
|
+
}
|
675
|
+
|
676
|
+
#endif
|
677
|
+
|
678
|
+
natsStatus
|
679
|
+
natsOptions_SetVerbose(natsOptions *opts, bool verbose)
|
680
|
+
{
|
681
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
682
|
+
|
683
|
+
opts->verbose = verbose;
|
684
|
+
|
685
|
+
UNLOCK_OPTS(opts);
|
686
|
+
|
687
|
+
return NATS_OK;
|
688
|
+
}
|
689
|
+
|
690
|
+
natsStatus
|
691
|
+
natsOptions_SetPedantic(natsOptions *opts, bool pedantic)
|
692
|
+
{
|
693
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
694
|
+
|
695
|
+
opts->pedantic = pedantic;
|
696
|
+
|
697
|
+
UNLOCK_OPTS(opts);
|
698
|
+
|
699
|
+
return NATS_OK;
|
700
|
+
}
|
701
|
+
|
702
|
+
natsStatus
|
703
|
+
natsOptions_SetPingInterval(natsOptions *opts, int64_t interval)
|
704
|
+
{
|
705
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
706
|
+
|
707
|
+
opts->pingInterval = interval;
|
708
|
+
|
709
|
+
UNLOCK_OPTS(opts);
|
710
|
+
|
711
|
+
return NATS_OK;
|
712
|
+
}
|
713
|
+
|
714
|
+
natsStatus
|
715
|
+
natsOptions_SetMaxPingsOut(natsOptions *opts, int maxPignsOut)
|
716
|
+
{
|
717
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
718
|
+
|
719
|
+
opts->maxPingsOut = maxPignsOut;
|
720
|
+
|
721
|
+
UNLOCK_OPTS(opts);
|
722
|
+
|
723
|
+
return NATS_OK;
|
724
|
+
}
|
725
|
+
|
726
|
+
|
727
|
+
natsStatus
|
728
|
+
natsOptions_SetAllowReconnect(natsOptions *opts, bool allow)
|
729
|
+
{
|
730
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
731
|
+
|
732
|
+
opts->allowReconnect = allow;
|
733
|
+
|
734
|
+
UNLOCK_OPTS(opts);
|
735
|
+
|
736
|
+
return NATS_OK;
|
737
|
+
}
|
738
|
+
|
739
|
+
natsStatus
|
740
|
+
natsOptions_SetMaxReconnect(natsOptions *opts, int maxReconnect)
|
741
|
+
{
|
742
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
743
|
+
|
744
|
+
opts->maxReconnect = maxReconnect;
|
745
|
+
|
746
|
+
UNLOCK_OPTS(opts);
|
747
|
+
|
748
|
+
return NATS_OK;
|
749
|
+
}
|
750
|
+
|
751
|
+
natsStatus
|
752
|
+
natsOptions_SetReconnectWait(natsOptions *opts, int64_t reconnectWait)
|
753
|
+
{
|
754
|
+
LOCK_AND_CHECK_OPTIONS(opts, (reconnectWait < 0));
|
755
|
+
|
756
|
+
opts->reconnectWait = reconnectWait;
|
757
|
+
|
758
|
+
UNLOCK_OPTS(opts);
|
759
|
+
|
760
|
+
return NATS_OK;
|
761
|
+
}
|
762
|
+
|
763
|
+
natsStatus
|
764
|
+
natsOptions_SetReconnectBufSize(natsOptions *opts, int reconnectBufSize)
|
765
|
+
{
|
766
|
+
LOCK_AND_CHECK_OPTIONS(opts, (reconnectBufSize < 0));
|
767
|
+
|
768
|
+
opts->reconnectBufSize = reconnectBufSize;
|
769
|
+
|
770
|
+
UNLOCK_OPTS(opts);
|
771
|
+
|
772
|
+
return NATS_OK;
|
773
|
+
}
|
774
|
+
|
775
|
+
natsStatus
|
776
|
+
natsOptions_SetMaxPendingMsgs(natsOptions *opts, int maxPending)
|
777
|
+
{
|
778
|
+
LOCK_AND_CHECK_OPTIONS(opts, (maxPending <= 0));
|
779
|
+
|
780
|
+
opts->maxPendingMsgs = maxPending;
|
781
|
+
|
782
|
+
UNLOCK_OPTS(opts);
|
783
|
+
|
784
|
+
return NATS_OK;
|
785
|
+
}
|
786
|
+
|
787
|
+
natsStatus
|
788
|
+
natsOptions_SetErrorHandler(natsOptions *opts, natsErrHandler errHandler,
|
789
|
+
void *closure)
|
790
|
+
{
|
791
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
792
|
+
|
793
|
+
opts->asyncErrCb = errHandler;
|
794
|
+
opts->asyncErrCbClosure = closure;
|
795
|
+
|
796
|
+
UNLOCK_OPTS(opts);
|
797
|
+
|
798
|
+
return NATS_OK;
|
799
|
+
}
|
800
|
+
|
801
|
+
natsStatus
|
802
|
+
natsOptions_SetClosedCB(natsOptions *opts, natsConnectionHandler closedCb,
|
803
|
+
void *closure)
|
804
|
+
{
|
805
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
806
|
+
|
807
|
+
opts->closedCb = closedCb;
|
808
|
+
opts->closedCbClosure = closure;
|
809
|
+
|
810
|
+
UNLOCK_OPTS(opts);
|
811
|
+
|
812
|
+
return NATS_OK;
|
813
|
+
}
|
814
|
+
|
815
|
+
natsStatus
|
816
|
+
natsOptions_SetDisconnectedCB(natsOptions *opts,
|
817
|
+
natsConnectionHandler disconnectedCb,
|
818
|
+
void *closure)
|
819
|
+
{
|
820
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
821
|
+
|
822
|
+
opts->disconnectedCb = disconnectedCb;
|
823
|
+
opts->disconnectedCbClosure = closure;
|
824
|
+
|
825
|
+
UNLOCK_OPTS(opts);
|
826
|
+
|
827
|
+
return NATS_OK;
|
828
|
+
}
|
829
|
+
|
830
|
+
natsStatus
|
831
|
+
natsOptions_SetReconnectedCB(natsOptions *opts,
|
832
|
+
natsConnectionHandler reconnectedCb,
|
833
|
+
void *closure)
|
834
|
+
{
|
835
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
836
|
+
|
837
|
+
opts->reconnectedCb = reconnectedCb;
|
838
|
+
opts->reconnectedCbClosure = closure;
|
839
|
+
|
840
|
+
UNLOCK_OPTS(opts);
|
841
|
+
|
842
|
+
return NATS_OK;
|
843
|
+
}
|
844
|
+
|
845
|
+
natsStatus
|
846
|
+
natsOptions_SetEventLoop(natsOptions *opts,
|
847
|
+
void *loop,
|
848
|
+
natsEvLoop_Attach attachCb,
|
849
|
+
natsEvLoop_ReadAddRemove readCb,
|
850
|
+
natsEvLoop_WriteAddRemove writeCb,
|
851
|
+
natsEvLoop_Detach detachCb)
|
852
|
+
{
|
853
|
+
LOCK_AND_CHECK_OPTIONS(opts, (loop == NULL)
|
854
|
+
|| (attachCb == NULL)
|
855
|
+
|| (readCb == NULL)
|
856
|
+
|| (writeCb == NULL)
|
857
|
+
|| (detachCb == NULL));
|
858
|
+
|
859
|
+
opts->evLoop = loop;
|
860
|
+
opts->evCbs.attach = attachCb;
|
861
|
+
opts->evCbs.read = readCb;
|
862
|
+
opts->evCbs.write = writeCb;
|
863
|
+
opts->evCbs.detach = detachCb;
|
864
|
+
|
865
|
+
UNLOCK_OPTS(opts);
|
866
|
+
|
867
|
+
return NATS_OK;
|
868
|
+
}
|
869
|
+
|
870
|
+
natsStatus
|
871
|
+
natsOptions_UseGlobalMessageDelivery(natsOptions *opts, bool global)
|
872
|
+
{
|
873
|
+
LOCK_AND_CHECK_OPTIONS(opts, 0);
|
874
|
+
|
875
|
+
// Sets if the subscriptions created from the connection will
|
876
|
+
// create their own delivery thread or use the one(s) from
|
877
|
+
// the library.
|
878
|
+
opts->libMsgDelivery = global;
|
879
|
+
|
880
|
+
UNLOCK_OPTS(opts);
|
881
|
+
|
882
|
+
return NATS_OK;
|
883
|
+
}
|
884
|
+
|
885
|
+
natsStatus
|
886
|
+
natsOptions_IPResolutionOrder(natsOptions *opts, int order)
|
887
|
+
{
|
888
|
+
LOCK_AND_CHECK_OPTIONS(opts, ((order != 0)
|
889
|
+
&& (order != 4)
|
890
|
+
&& (order != 6)
|
891
|
+
&& (order != 46)
|
892
|
+
&& (order != 64)));
|
893
|
+
|
894
|
+
opts->orderIP = order;
|
895
|
+
|
896
|
+
UNLOCK_OPTS(opts);
|
897
|
+
|
898
|
+
return NATS_OK;
|
899
|
+
}
|
900
|
+
|
901
|
+
static void
|
902
|
+
_freeOptions(natsOptions *opts)
|
903
|
+
{
|
904
|
+
if (opts == NULL)
|
905
|
+
return;
|
906
|
+
|
907
|
+
NATS_FREE(opts->url);
|
908
|
+
NATS_FREE(opts->name);
|
909
|
+
_freeServers(opts);
|
910
|
+
NATS_FREE(opts->user);
|
911
|
+
NATS_FREE(opts->password);
|
912
|
+
NATS_FREE(opts->token);
|
913
|
+
natsMutex_Destroy(opts->mu);
|
914
|
+
natsSSLCtx_release(opts->sslCtx);
|
915
|
+
NATS_FREE(opts);
|
916
|
+
}
|
917
|
+
|
918
|
+
natsStatus
|
919
|
+
natsOptions_Create(natsOptions **newOpts)
|
920
|
+
{
|
921
|
+
natsStatus s;
|
922
|
+
natsOptions *opts = NULL;
|
923
|
+
|
924
|
+
// Ensure the library is loaded
|
925
|
+
s = nats_Open(-1);
|
926
|
+
if (s != NATS_OK)
|
927
|
+
return s;
|
928
|
+
|
929
|
+
opts = (natsOptions*) NATS_CALLOC(1, sizeof(natsOptions));
|
930
|
+
if (opts == NULL)
|
931
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
932
|
+
|
933
|
+
if (natsMutex_Create(&(opts->mu)) != NATS_OK)
|
934
|
+
{
|
935
|
+
NATS_FREE(opts);
|
936
|
+
return NATS_UPDATE_ERR_STACK(NATS_NO_MEMORY);
|
937
|
+
}
|
938
|
+
|
939
|
+
opts->allowReconnect = true;
|
940
|
+
opts->secure = false;
|
941
|
+
opts->maxReconnect = NATS_OPTS_DEFAULT_MAX_RECONNECT;
|
942
|
+
opts->reconnectWait = NATS_OPTS_DEFAULT_RECONNECT_WAIT;
|
943
|
+
opts->pingInterval = NATS_OPTS_DEFAULT_PING_INTERVAL;
|
944
|
+
opts->maxPingsOut = NATS_OPTS_DEFAULT_MAX_PING_OUT;
|
945
|
+
opts->maxPendingMsgs = NATS_OPTS_DEFAULT_MAX_PENDING_MSGS;
|
946
|
+
opts->timeout = NATS_OPTS_DEFAULT_TIMEOUT;
|
947
|
+
opts->libMsgDelivery = natsLib_isLibHandlingMsgDeliveryByDefault();
|
948
|
+
|
949
|
+
*newOpts = opts;
|
950
|
+
|
951
|
+
return NATS_OK;
|
952
|
+
}
|
953
|
+
|
954
|
+
natsOptions*
|
955
|
+
natsOptions_clone(natsOptions *opts)
|
956
|
+
{
|
957
|
+
natsStatus s = NATS_OK;
|
958
|
+
natsOptions *cloned = NULL;
|
959
|
+
int muSize;
|
960
|
+
|
961
|
+
if ((s = natsOptions_Create(&cloned)) != NATS_OK)
|
962
|
+
{
|
963
|
+
NATS_UPDATE_ERR_STACK(s);
|
964
|
+
return NULL;
|
965
|
+
}
|
966
|
+
|
967
|
+
natsMutex_Lock(opts->mu);
|
968
|
+
|
969
|
+
muSize = sizeof(cloned->mu);
|
970
|
+
|
971
|
+
// Make a blind copy first...
|
972
|
+
memcpy((char*)cloned + muSize, (char*)opts + muSize,
|
973
|
+
sizeof(natsOptions) - muSize);
|
974
|
+
|
975
|
+
// Then remove all pointers, so that if we fail while
|
976
|
+
// strduping them, and free the cloned, we don't free the strings
|
977
|
+
// from the original.
|
978
|
+
cloned->name = NULL;
|
979
|
+
cloned->servers = NULL;
|
980
|
+
cloned->url = NULL;
|
981
|
+
cloned->sslCtx = NULL;
|
982
|
+
cloned->user = NULL;
|
983
|
+
cloned->password= NULL;
|
984
|
+
cloned->token = NULL;
|
985
|
+
|
986
|
+
// Also, set the number of servers count to 0, until we update
|
987
|
+
// it (if necessary) when calling SetServers.
|
988
|
+
cloned->serversCount = 0;
|
989
|
+
|
990
|
+
if (opts->name != NULL)
|
991
|
+
s = natsOptions_SetName(cloned, opts->name);
|
992
|
+
|
993
|
+
if ((s == NATS_OK) && (opts->url != NULL))
|
994
|
+
s = natsOptions_SetURL(cloned, opts->url);
|
995
|
+
|
996
|
+
if ((s == NATS_OK) && (opts->servers != NULL))
|
997
|
+
s = natsOptions_SetServers(cloned,
|
998
|
+
(const char**)opts->servers,
|
999
|
+
opts->serversCount);
|
1000
|
+
|
1001
|
+
if ((s == NATS_OK) && (opts->user != NULL))
|
1002
|
+
s = natsOptions_SetUserInfo(cloned, opts->user, opts->password);
|
1003
|
+
|
1004
|
+
if ((s == NATS_OK) && (opts->token != NULL))
|
1005
|
+
s = natsOptions_SetToken(cloned, opts->token);
|
1006
|
+
|
1007
|
+
if ((s == NATS_OK) && (opts->sslCtx != NULL))
|
1008
|
+
cloned->sslCtx = natsSSLCtx_retain(opts->sslCtx);
|
1009
|
+
|
1010
|
+
if (s != NATS_OK)
|
1011
|
+
{
|
1012
|
+
_freeOptions(cloned);
|
1013
|
+
cloned = NULL;
|
1014
|
+
NATS_UPDATE_ERR_STACK(s);
|
1015
|
+
}
|
1016
|
+
|
1017
|
+
natsMutex_Unlock(opts->mu);
|
1018
|
+
|
1019
|
+
return cloned;
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
void
|
1023
|
+
natsOptions_Destroy(natsOptions *opts)
|
1024
|
+
{
|
1025
|
+
if (opts == NULL)
|
1026
|
+
return;
|
1027
|
+
|
1028
|
+
_freeOptions(opts);
|
1029
|
+
}
|
1030
|
+
|