ffi-nats-core 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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
+