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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/ffi-nats-core.gemspec +8 -0
  3. data/lib/ffi/nats/core/version.rb +1 -1
  4. data/vendor/cnats/CMakeLists.txt +137 -0
  5. data/vendor/cnats/adapters/libevent.h +220 -0
  6. data/vendor/cnats/adapters/libuv.h +472 -0
  7. data/vendor/cnats/examples/CMakeLists.txt +56 -0
  8. data/vendor/cnats/examples/asynctimeout.c +83 -0
  9. data/vendor/cnats/examples/examples.h +322 -0
  10. data/vendor/cnats/examples/libevent-pub.c +136 -0
  11. data/vendor/cnats/examples/libevent-sub.c +104 -0
  12. data/vendor/cnats/examples/libuv-pub.c +120 -0
  13. data/vendor/cnats/examples/libuv-sub.c +114 -0
  14. data/vendor/cnats/examples/publisher.c +62 -0
  15. data/vendor/cnats/examples/queuegroup.c +132 -0
  16. data/vendor/cnats/examples/replier.c +149 -0
  17. data/vendor/cnats/examples/requestor.c +75 -0
  18. data/vendor/cnats/examples/subscriber.c +133 -0
  19. data/vendor/cnats/src/CMakeLists.txt +31 -0
  20. data/vendor/cnats/src/asynccb.c +66 -0
  21. data/vendor/cnats/src/asynccb.h +42 -0
  22. data/vendor/cnats/src/buf.c +246 -0
  23. data/vendor/cnats/src/buf.h +116 -0
  24. data/vendor/cnats/src/comsock.c +474 -0
  25. data/vendor/cnats/src/comsock.h +81 -0
  26. data/vendor/cnats/src/conn.c +2725 -0
  27. data/vendor/cnats/src/conn.h +75 -0
  28. data/vendor/cnats/src/err.h +31 -0
  29. data/vendor/cnats/src/gc.h +27 -0
  30. data/vendor/cnats/src/hash.c +725 -0
  31. data/vendor/cnats/src/hash.h +141 -0
  32. data/vendor/cnats/src/include/n-unix.h +56 -0
  33. data/vendor/cnats/src/include/n-win.h +59 -0
  34. data/vendor/cnats/src/mem.h +20 -0
  35. data/vendor/cnats/src/msg.c +155 -0
  36. data/vendor/cnats/src/msg.h +43 -0
  37. data/vendor/cnats/src/nats.c +1734 -0
  38. data/vendor/cnats/src/nats.h +2024 -0
  39. data/vendor/cnats/src/natsp.h +518 -0
  40. data/vendor/cnats/src/natstime.c +79 -0
  41. data/vendor/cnats/src/natstime.h +27 -0
  42. data/vendor/cnats/src/nuid.c +265 -0
  43. data/vendor/cnats/src/nuid.h +21 -0
  44. data/vendor/cnats/src/opts.c +1030 -0
  45. data/vendor/cnats/src/opts.h +19 -0
  46. data/vendor/cnats/src/parser.c +869 -0
  47. data/vendor/cnats/src/parser.h +87 -0
  48. data/vendor/cnats/src/pub.c +293 -0
  49. data/vendor/cnats/src/srvpool.c +380 -0
  50. data/vendor/cnats/src/srvpool.h +71 -0
  51. data/vendor/cnats/src/stats.c +54 -0
  52. data/vendor/cnats/src/stats.h +21 -0
  53. data/vendor/cnats/src/status.c +60 -0
  54. data/vendor/cnats/src/status.h +95 -0
  55. data/vendor/cnats/src/sub.c +956 -0
  56. data/vendor/cnats/src/sub.h +34 -0
  57. data/vendor/cnats/src/timer.c +86 -0
  58. data/vendor/cnats/src/timer.h +57 -0
  59. data/vendor/cnats/src/unix/cond.c +103 -0
  60. data/vendor/cnats/src/unix/mutex.c +107 -0
  61. data/vendor/cnats/src/unix/sock.c +105 -0
  62. data/vendor/cnats/src/unix/thread.c +162 -0
  63. data/vendor/cnats/src/url.c +134 -0
  64. data/vendor/cnats/src/url.h +24 -0
  65. data/vendor/cnats/src/util.c +823 -0
  66. data/vendor/cnats/src/util.h +75 -0
  67. data/vendor/cnats/src/version.h +29 -0
  68. data/vendor/cnats/src/version.h.in +29 -0
  69. data/vendor/cnats/src/win/cond.c +86 -0
  70. data/vendor/cnats/src/win/mutex.c +54 -0
  71. data/vendor/cnats/src/win/sock.c +158 -0
  72. data/vendor/cnats/src/win/strings.c +108 -0
  73. data/vendor/cnats/src/win/thread.c +180 -0
  74. data/vendor/cnats/test/CMakeLists.txt +35 -0
  75. data/vendor/cnats/test/certs/ca.pem +38 -0
  76. data/vendor/cnats/test/certs/client-cert.pem +30 -0
  77. data/vendor/cnats/test/certs/client-key.pem +51 -0
  78. data/vendor/cnats/test/certs/server-cert.pem +31 -0
  79. data/vendor/cnats/test/certs/server-key.pem +51 -0
  80. data/vendor/cnats/test/dylib/CMakeLists.txt +10 -0
  81. data/vendor/cnats/test/dylib/nonats.c +13 -0
  82. data/vendor/cnats/test/list.txt +125 -0
  83. data/vendor/cnats/test/test.c +11655 -0
  84. data/vendor/cnats/test/tls.conf +15 -0
  85. data/vendor/cnats/test/tlsverify.conf +19 -0
  86. 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
+