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,87 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#ifndef PARSER_H_
|
4
|
+
#define PARSER_H_
|
5
|
+
|
6
|
+
#include <stdint.h>
|
7
|
+
|
8
|
+
//#include "natsp.h"
|
9
|
+
#include "status.h"
|
10
|
+
#include "buf.h"
|
11
|
+
|
12
|
+
typedef enum
|
13
|
+
{
|
14
|
+
OP_START = 0,
|
15
|
+
OP_PLUS,
|
16
|
+
OP_PLUS_O,
|
17
|
+
OP_PLUS_OK,
|
18
|
+
OP_MINUS,
|
19
|
+
OP_MINUS_E,
|
20
|
+
OP_MINUS_ER,
|
21
|
+
OP_MINUS_ERR,
|
22
|
+
OP_MINUS_ERR_SPC,
|
23
|
+
MINUS_ERR_ARG,
|
24
|
+
OP_M,
|
25
|
+
OP_MS,
|
26
|
+
OP_MSG,
|
27
|
+
OP_MSG_SPC,
|
28
|
+
MSG_ARG,
|
29
|
+
MSG_PAYLOAD,
|
30
|
+
MSG_END,
|
31
|
+
OP_P,
|
32
|
+
OP_PI,
|
33
|
+
OP_PIN,
|
34
|
+
OP_PING,
|
35
|
+
OP_PO,
|
36
|
+
OP_PON,
|
37
|
+
OP_PONG,
|
38
|
+
OP_I,
|
39
|
+
OP_IN,
|
40
|
+
OP_INF,
|
41
|
+
OP_INFO,
|
42
|
+
OP_INFO_SPC,
|
43
|
+
INFO_ARG
|
44
|
+
|
45
|
+
} natsOp;
|
46
|
+
|
47
|
+
typedef struct __natsMsgArg
|
48
|
+
{
|
49
|
+
natsBuffer subjectRec;
|
50
|
+
natsBuffer *subject;
|
51
|
+
natsBuffer replyRec;
|
52
|
+
natsBuffer *reply;
|
53
|
+
int64_t sid;
|
54
|
+
int size;
|
55
|
+
|
56
|
+
} natsMsgArg;
|
57
|
+
|
58
|
+
#define MAX_CONTROL_LINE_SIZE (1024)
|
59
|
+
|
60
|
+
typedef struct __natsParser
|
61
|
+
{
|
62
|
+
natsOp state;
|
63
|
+
int afterSpace;
|
64
|
+
int drop;
|
65
|
+
natsMsgArg ma;
|
66
|
+
natsBuffer argBufRec;
|
67
|
+
natsBuffer *argBuf;
|
68
|
+
natsBuffer msgBufRec;
|
69
|
+
natsBuffer *msgBuf;
|
70
|
+
char scratch[MAX_CONTROL_LINE_SIZE];
|
71
|
+
|
72
|
+
} natsParser;
|
73
|
+
|
74
|
+
// This is defined in natsp.h, natsp.h includes us. Alternatively, we can move
|
75
|
+
// all the parser defines in natsp.h
|
76
|
+
struct __natsConnection;
|
77
|
+
|
78
|
+
natsStatus
|
79
|
+
natsParser_Create(natsParser **newParser);
|
80
|
+
|
81
|
+
natsStatus
|
82
|
+
natsParser_Parse(struct __natsConnection *nc, char *buf, int bufLen);
|
83
|
+
|
84
|
+
void
|
85
|
+
natsParser_Destroy(natsParser *parser);
|
86
|
+
|
87
|
+
#endif /* PARSER_H_ */
|
@@ -0,0 +1,293 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
#include "conn.h"
|
8
|
+
#include "sub.h"
|
9
|
+
#include "msg.h"
|
10
|
+
#include "nuid.h"
|
11
|
+
|
12
|
+
static const char *digits = "0123456789";
|
13
|
+
|
14
|
+
#define _publish(n, s, r, d, l) _publishEx((n), (s), (r), (d), (l), false)
|
15
|
+
|
16
|
+
// _publish is the internal function to publish messages to a nats server.
|
17
|
+
// Sends a protocol data message by queueing into the bufio writer
|
18
|
+
// and kicking the flusher thread. These writes should be protected.
|
19
|
+
static natsStatus
|
20
|
+
_publishEx(natsConnection *nc, const char *subj,
|
21
|
+
const char *reply, const void *data, int dataLen,
|
22
|
+
bool directFlush)
|
23
|
+
{
|
24
|
+
natsStatus s = NATS_OK;
|
25
|
+
int msgHdSize = 0;
|
26
|
+
char b[12];
|
27
|
+
int bSize = sizeof(b);
|
28
|
+
int i = bSize;
|
29
|
+
int subjLen = 0;
|
30
|
+
int replyLen = 0;
|
31
|
+
int sizeSize = 0;
|
32
|
+
|
33
|
+
if (nc == NULL)
|
34
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
35
|
+
|
36
|
+
if ((subj == NULL)
|
37
|
+
|| ((subjLen = (int) strlen(subj)) == 0))
|
38
|
+
{
|
39
|
+
return nats_setDefaultError(NATS_INVALID_SUBJECT);
|
40
|
+
}
|
41
|
+
|
42
|
+
replyLen = ((reply != NULL) ? (int) strlen(reply) : 0);
|
43
|
+
|
44
|
+
natsConn_Lock(nc);
|
45
|
+
|
46
|
+
// Pro-actively reject dataLen over the threshold set by server.
|
47
|
+
if ((int64_t) dataLen > nc->info.maxPayload)
|
48
|
+
{
|
49
|
+
natsConn_Unlock(nc);
|
50
|
+
|
51
|
+
return nats_setError(NATS_MAX_PAYLOAD,
|
52
|
+
"Payload %d greater than maximum allowed: %" PRId64,
|
53
|
+
dataLen, nc->info.maxPayload);
|
54
|
+
|
55
|
+
}
|
56
|
+
|
57
|
+
if ((s == NATS_OK) && natsConn_isClosed(nc))
|
58
|
+
{
|
59
|
+
s = nats_setDefaultError(NATS_CONNECTION_CLOSED);
|
60
|
+
}
|
61
|
+
|
62
|
+
// Check if we are reconnecting, and if so check if
|
63
|
+
// we have exceeded our reconnect outbound buffer limits.
|
64
|
+
if ((s == NATS_OK) && natsConn_isReconnecting(nc))
|
65
|
+
{
|
66
|
+
// Flush to underlying buffer.
|
67
|
+
natsConn_bufferFlush(nc);
|
68
|
+
|
69
|
+
// Check if we are over
|
70
|
+
if (natsBuf_Len(nc->pending) >= nc->opts->reconnectBufSize)
|
71
|
+
{
|
72
|
+
natsConn_Unlock(nc);
|
73
|
+
return NATS_INSUFFICIENT_BUFFER;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
if (s == NATS_OK)
|
78
|
+
{
|
79
|
+
if (dataLen > 0)
|
80
|
+
{
|
81
|
+
int l;
|
82
|
+
|
83
|
+
for (l = dataLen; l > 0; l /= 10)
|
84
|
+
{
|
85
|
+
i -= 1;
|
86
|
+
b[i] = digits[l%10];
|
87
|
+
}
|
88
|
+
}
|
89
|
+
else
|
90
|
+
{
|
91
|
+
i -= 1;
|
92
|
+
b[i] = digits[0];
|
93
|
+
}
|
94
|
+
|
95
|
+
sizeSize = (bSize - i);
|
96
|
+
|
97
|
+
msgHdSize = _PUB_P_LEN_
|
98
|
+
+ subjLen + 1
|
99
|
+
+ (replyLen > 0 ? replyLen + 1 : 0)
|
100
|
+
+ sizeSize + _CRLF_LEN_;
|
101
|
+
|
102
|
+
natsBuf_RewindTo(nc->scratch, _PUB_P_LEN_);
|
103
|
+
|
104
|
+
if (natsBuf_Capacity(nc->scratch) < msgHdSize)
|
105
|
+
{
|
106
|
+
// Although natsBuf_Append() would make sure that the buffer
|
107
|
+
// grows, it is better to make sure that the buffer is big
|
108
|
+
// enough for the pre-calculated size. We make it even a bit bigger.
|
109
|
+
s = natsBuf_Expand(nc->scratch, (int) ((float)msgHdSize * 1.1));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
if (s == NATS_OK)
|
114
|
+
s = natsBuf_Append(nc->scratch, subj, subjLen);
|
115
|
+
if (s == NATS_OK)
|
116
|
+
s = natsBuf_Append(nc->scratch, _SPC_, _SPC_LEN_);
|
117
|
+
if ((s == NATS_OK) && (reply != NULL))
|
118
|
+
{
|
119
|
+
s = natsBuf_Append(nc->scratch, reply, replyLen);
|
120
|
+
if (s == NATS_OK)
|
121
|
+
s = natsBuf_Append(nc->scratch, _SPC_, _SPC_LEN_);
|
122
|
+
}
|
123
|
+
if (s == NATS_OK)
|
124
|
+
s = natsBuf_Append(nc->scratch, (b+i), sizeSize);
|
125
|
+
if (s == NATS_OK)
|
126
|
+
s = natsBuf_Append(nc->scratch, _CRLF_, _CRLF_LEN_);
|
127
|
+
|
128
|
+
if (s == NATS_OK)
|
129
|
+
s = natsConn_bufferWrite(nc, natsBuf_Data(nc->scratch), msgHdSize);
|
130
|
+
|
131
|
+
if (s == NATS_OK)
|
132
|
+
s = natsConn_bufferWrite(nc, data, dataLen);
|
133
|
+
|
134
|
+
if (s == NATS_OK)
|
135
|
+
s = natsConn_bufferWrite(nc, _CRLF_, _CRLF_LEN_);
|
136
|
+
|
137
|
+
if (s == NATS_OK)
|
138
|
+
{
|
139
|
+
if (directFlush)
|
140
|
+
s = natsConn_bufferFlush(nc);
|
141
|
+
else
|
142
|
+
natsConn_kickFlusher(nc);
|
143
|
+
}
|
144
|
+
|
145
|
+
if (s == NATS_OK)
|
146
|
+
{
|
147
|
+
nc->stats.outMsgs += 1;
|
148
|
+
nc->stats.outBytes += dataLen;
|
149
|
+
}
|
150
|
+
|
151
|
+
natsConn_Unlock(nc);
|
152
|
+
|
153
|
+
return NATS_UPDATE_ERR_STACK(s);
|
154
|
+
}
|
155
|
+
|
156
|
+
/*
|
157
|
+
* Publishes the data argument to the given subject. The data argument is left
|
158
|
+
* untouched and needs to be correctly interpreted on the receiver.
|
159
|
+
*/
|
160
|
+
natsStatus
|
161
|
+
natsConnection_Publish(natsConnection *nc, const char *subj,
|
162
|
+
const void *data, int dataLen)
|
163
|
+
{
|
164
|
+
natsStatus s = _publish(nc, subj, NULL, data, dataLen);
|
165
|
+
|
166
|
+
return NATS_UPDATE_ERR_STACK(s);
|
167
|
+
}
|
168
|
+
|
169
|
+
/*
|
170
|
+
* Convenient function to publish a string. This call is equivalent to:
|
171
|
+
*
|
172
|
+
* const char* myString = "hello";
|
173
|
+
*
|
174
|
+
* natsPublish(nc, subj, (const void*) myString, (int) strlen(myString));
|
175
|
+
*/
|
176
|
+
natsStatus
|
177
|
+
natsConnection_PublishString(natsConnection *nc, const char *subj,
|
178
|
+
const char *str)
|
179
|
+
{
|
180
|
+
natsStatus s = _publish(nc, subj, NULL, (const void*) str,
|
181
|
+
(str != NULL ? (int) strlen(str) : 0));
|
182
|
+
|
183
|
+
return NATS_UPDATE_ERR_STACK(s);
|
184
|
+
}
|
185
|
+
|
186
|
+
/*
|
187
|
+
* Publishes the natsMsg structure, which includes the subject, an optional
|
188
|
+
* reply and optional data.
|
189
|
+
*/
|
190
|
+
natsStatus
|
191
|
+
natsConnection_PublishMsg(natsConnection *nc, natsMsg *msg)
|
192
|
+
{
|
193
|
+
natsStatus s = _publish(nc, msg->subject, msg->reply,
|
194
|
+
msg->data, msg->dataLen);
|
195
|
+
|
196
|
+
return NATS_UPDATE_ERR_STACK(s);
|
197
|
+
}
|
198
|
+
|
199
|
+
/*
|
200
|
+
* Publishes the data argument to the given subject expecting a response on
|
201
|
+
* the reply subject. Use natsConnection_Request() for automatically waiting for a
|
202
|
+
* response inline.
|
203
|
+
*/
|
204
|
+
natsStatus
|
205
|
+
natsConnection_PublishRequest(natsConnection *nc, const char *subj,
|
206
|
+
const char *reply, const void *data, int dataLen)
|
207
|
+
{
|
208
|
+
natsStatus s;
|
209
|
+
|
210
|
+
if ((reply == NULL) || (strlen(reply) == 0))
|
211
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
212
|
+
|
213
|
+
s = _publish(nc, subj, reply, data, dataLen);
|
214
|
+
|
215
|
+
return NATS_UPDATE_ERR_STACK(s);
|
216
|
+
}
|
217
|
+
|
218
|
+
/*
|
219
|
+
* Convenient function to publish a request as a string. This call is
|
220
|
+
* equivalent to:
|
221
|
+
*
|
222
|
+
* const char* myString = "hello";
|
223
|
+
*
|
224
|
+
* natsPublishRequest(nc, subj, reply, (const void*) myString,
|
225
|
+
* (int) strlen(myString));
|
226
|
+
*/
|
227
|
+
natsStatus
|
228
|
+
natsConnection_PublishRequestString(natsConnection *nc, const char *subj,
|
229
|
+
const char *reply, const char *str)
|
230
|
+
{
|
231
|
+
natsStatus s;
|
232
|
+
|
233
|
+
if ((reply == NULL) || (strlen(reply) == 0))
|
234
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
235
|
+
|
236
|
+
s = _publish(nc, subj, reply, (const void*) str, (int) strlen(str));
|
237
|
+
|
238
|
+
return NATS_UPDATE_ERR_STACK(s);
|
239
|
+
}
|
240
|
+
|
241
|
+
/*
|
242
|
+
* Creates an inbox and performs a natsPublishRequest() call with the reply
|
243
|
+
* set to that inbox. Returns the first reply received.
|
244
|
+
* This is optimized for the case of multiple responses.
|
245
|
+
*/
|
246
|
+
natsStatus
|
247
|
+
natsConnection_Request(natsMsg **replyMsg, natsConnection *nc, const char *subj,
|
248
|
+
const void *data, int dataLen, int64_t timeout)
|
249
|
+
{
|
250
|
+
natsStatus s = NATS_OK;
|
251
|
+
natsSubscription *sub = NULL;
|
252
|
+
char inbox[NATS_INBOX_PRE_LEN + NUID_BUFFER_LEN + 1];
|
253
|
+
|
254
|
+
if (replyMsg == NULL)
|
255
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
256
|
+
|
257
|
+
s = natsInbox_init(inbox, sizeof(inbox));
|
258
|
+
if (s == NATS_OK)
|
259
|
+
s = natsConn_subscribe(&sub, nc, inbox, NULL, 0, NULL, NULL);
|
260
|
+
if (s == NATS_OK)
|
261
|
+
s = natsSubscription_AutoUnsubscribe(sub, 1);
|
262
|
+
if (s == NATS_OK)
|
263
|
+
s = _publishEx(nc, subj, inbox, data, dataLen, true);
|
264
|
+
if (s == NATS_OK)
|
265
|
+
s = natsSubscription_NextMsg(replyMsg, sub, timeout);
|
266
|
+
|
267
|
+
natsSubscription_Destroy(sub);
|
268
|
+
|
269
|
+
return NATS_UPDATE_ERR_STACK(s);
|
270
|
+
}
|
271
|
+
|
272
|
+
/*
|
273
|
+
* Convenient function to send a request as a string. This call is
|
274
|
+
* equivalent to:
|
275
|
+
*
|
276
|
+
* const char* myString = "hello";
|
277
|
+
*
|
278
|
+
* natsConnection_Request(nc, subj, reply, (const void*) myString,
|
279
|
+
* (int) strlen(myString));
|
280
|
+
*/
|
281
|
+
natsStatus
|
282
|
+
natsConnection_RequestString(natsMsg **replyMsg, natsConnection *nc,
|
283
|
+
const char *subj, const char *str,
|
284
|
+
int64_t timeout)
|
285
|
+
{
|
286
|
+
natsStatus s;
|
287
|
+
|
288
|
+
s = natsConnection_Request(replyMsg, nc, subj, (const void*) str,
|
289
|
+
(str == NULL ? 0 : (int) strlen(str)),
|
290
|
+
timeout);
|
291
|
+
|
292
|
+
return NATS_UPDATE_ERR_STACK(s);
|
293
|
+
}
|
@@ -0,0 +1,380 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include "mem.h"
|
6
|
+
#include "url.h"
|
7
|
+
|
8
|
+
static void
|
9
|
+
_freeSrv(natsSrv *srv)
|
10
|
+
{
|
11
|
+
if (srv == NULL)
|
12
|
+
return;
|
13
|
+
|
14
|
+
natsUrl_Destroy(srv->url);
|
15
|
+
NATS_FREE(srv);
|
16
|
+
}
|
17
|
+
|
18
|
+
static natsStatus
|
19
|
+
_createSrv(natsSrv **newSrv, char *url, bool implicit)
|
20
|
+
{
|
21
|
+
natsStatus s = NATS_OK;
|
22
|
+
natsSrv *srv = (natsSrv*) NATS_CALLOC(1, sizeof(natsSrv));
|
23
|
+
|
24
|
+
if (srv == NULL)
|
25
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
26
|
+
|
27
|
+
srv->isImplicit = implicit;
|
28
|
+
|
29
|
+
s = natsUrl_Create(&(srv->url), url);
|
30
|
+
if (s == NATS_OK)
|
31
|
+
*newSrv = srv;
|
32
|
+
else
|
33
|
+
_freeSrv(srv);
|
34
|
+
|
35
|
+
return NATS_UPDATE_ERR_STACK(s);
|
36
|
+
}
|
37
|
+
|
38
|
+
natsSrv*
|
39
|
+
natsSrvPool_GetCurrentServer(natsSrvPool *pool, const natsUrl *url, int *index)
|
40
|
+
{
|
41
|
+
natsSrv *s = NULL;
|
42
|
+
int i;
|
43
|
+
|
44
|
+
for (i = 0; i < pool->size; i++)
|
45
|
+
{
|
46
|
+
s = pool->srvrs[i];
|
47
|
+
if (s->url == url)
|
48
|
+
{
|
49
|
+
if (index != NULL)
|
50
|
+
*index = i;
|
51
|
+
|
52
|
+
return s;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
if (index != NULL)
|
57
|
+
*index = -1;
|
58
|
+
|
59
|
+
return NULL;
|
60
|
+
}
|
61
|
+
|
62
|
+
// Pop the current server and put onto the end of the list. Select head of list as long
|
63
|
+
// as number of reconnect attempts under MaxReconnect.
|
64
|
+
natsSrv*
|
65
|
+
natsSrvPool_GetNextServer(natsSrvPool *pool, natsOptions *opts, const natsUrl *ncUrl)
|
66
|
+
{
|
67
|
+
natsSrv *s = NULL;
|
68
|
+
int i, j;
|
69
|
+
|
70
|
+
s = natsSrvPool_GetCurrentServer(pool, ncUrl, &i);
|
71
|
+
if (i < 0)
|
72
|
+
return NULL;
|
73
|
+
|
74
|
+
// Shift left servers past current to the current's position
|
75
|
+
for (j = i; j < pool->size - 1; j++)
|
76
|
+
pool->srvrs[j] = pool->srvrs[j+1];
|
77
|
+
|
78
|
+
if ((opts->maxReconnect < 0)
|
79
|
+
|| (s->reconnects < opts->maxReconnect))
|
80
|
+
{
|
81
|
+
// Move the current server to the back of the list
|
82
|
+
pool->srvrs[pool->size - 1] = s;
|
83
|
+
}
|
84
|
+
else
|
85
|
+
{
|
86
|
+
// Remove the server from the list
|
87
|
+
_freeSrv(s);
|
88
|
+
pool->size--;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (pool->size <= 0)
|
92
|
+
return NULL;
|
93
|
+
|
94
|
+
return pool->srvrs[0];
|
95
|
+
}
|
96
|
+
|
97
|
+
void
|
98
|
+
natsSrvPool_Destroy(natsSrvPool *pool)
|
99
|
+
{
|
100
|
+
natsSrv *srv;
|
101
|
+
int i;
|
102
|
+
|
103
|
+
if (pool == NULL)
|
104
|
+
return;
|
105
|
+
|
106
|
+
for (i = 0; i < pool->size; i++)
|
107
|
+
{
|
108
|
+
srv = pool->srvrs[i];
|
109
|
+
_freeSrv(srv);
|
110
|
+
}
|
111
|
+
natsStrHash_Destroy(pool->urls);
|
112
|
+
pool->urls = NULL;
|
113
|
+
|
114
|
+
NATS_FREE(pool->srvrs);
|
115
|
+
pool->srvrs = NULL;
|
116
|
+
pool->size = 0;
|
117
|
+
NATS_FREE(pool);
|
118
|
+
}
|
119
|
+
|
120
|
+
static natsStatus
|
121
|
+
_addURLToPool(natsSrvPool *pool, char *sURL, bool implicit)
|
122
|
+
{
|
123
|
+
natsStatus s;
|
124
|
+
natsSrv *srv = NULL;
|
125
|
+
bool addedToMap = false;
|
126
|
+
char bareURL[256];
|
127
|
+
|
128
|
+
s = _createSrv(&srv, sURL, implicit);
|
129
|
+
if (s != NATS_OK)
|
130
|
+
return s;
|
131
|
+
|
132
|
+
// In the map, we need to add an URL that is just host:port
|
133
|
+
snprintf(bareURL, sizeof(bareURL), "%s:%d", srv->url->host, srv->url->port);
|
134
|
+
s = natsStrHash_Set(pool->urls, bareURL, true, (void*)1, NULL);
|
135
|
+
if (s == NATS_OK)
|
136
|
+
{
|
137
|
+
addedToMap = true;
|
138
|
+
if (pool->size + 1 > pool->cap)
|
139
|
+
{
|
140
|
+
natsSrv **newArray = NULL;
|
141
|
+
int newCap = 2 * pool->cap;
|
142
|
+
|
143
|
+
newArray = (natsSrv**) NATS_REALLOC(pool->srvrs, newCap * sizeof(char*));
|
144
|
+
if (newArray == NULL)
|
145
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
146
|
+
|
147
|
+
if (s == NATS_OK)
|
148
|
+
{
|
149
|
+
pool->cap = newCap;
|
150
|
+
pool->srvrs = newArray;
|
151
|
+
}
|
152
|
+
}
|
153
|
+
if (s == NATS_OK)
|
154
|
+
pool->srvrs[pool->size++] = srv;
|
155
|
+
}
|
156
|
+
if (s != NATS_OK)
|
157
|
+
{
|
158
|
+
if (addedToMap)
|
159
|
+
natsStrHash_Remove(pool->urls, sURL);
|
160
|
+
|
161
|
+
_freeSrv(srv);
|
162
|
+
}
|
163
|
+
|
164
|
+
return NATS_UPDATE_ERR_STACK(s);
|
165
|
+
}
|
166
|
+
|
167
|
+
static void
|
168
|
+
_shufflePool(natsSrvPool *pool)
|
169
|
+
{
|
170
|
+
int i, j;
|
171
|
+
natsSrv *tmp;
|
172
|
+
|
173
|
+
if (pool->size <= 1)
|
174
|
+
return;
|
175
|
+
|
176
|
+
srand((unsigned int) nats_NowInNanoSeconds());
|
177
|
+
|
178
|
+
for (i = 0; i < pool->size; i++)
|
179
|
+
{
|
180
|
+
j = rand() % (i + 1);
|
181
|
+
tmp = pool->srvrs[i];
|
182
|
+
pool->srvrs[i] = pool->srvrs[j];
|
183
|
+
pool->srvrs[j] = tmp;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
natsStatus
|
188
|
+
natsSrvPool_addNewURLs(natsSrvPool *pool, char **urls, int urlCount, bool doShuffle)
|
189
|
+
{
|
190
|
+
natsStatus s = NATS_OK;
|
191
|
+
char url[256];
|
192
|
+
int i;
|
193
|
+
char *sport;
|
194
|
+
int portPos;
|
195
|
+
bool found;
|
196
|
+
bool isLH;
|
197
|
+
|
198
|
+
// If we can shuffle, we shuffle the given array, not the entire pool
|
199
|
+
if (urlCount > 0 && doShuffle)
|
200
|
+
{
|
201
|
+
int j;
|
202
|
+
char *tmp;
|
203
|
+
|
204
|
+
for (i = 0; i < urlCount; i++)
|
205
|
+
{
|
206
|
+
j = rand() % (i + 1);
|
207
|
+
tmp = urls[i];
|
208
|
+
urls[i] = urls[j];
|
209
|
+
urls[j] = tmp;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
for (i=0; (s == NATS_OK) && (i<urlCount); i++)
|
214
|
+
{
|
215
|
+
isLH = false;
|
216
|
+
found = false;
|
217
|
+
|
218
|
+
// Consider localhost:<port>, 127.0.0.1:<port> and [::1]:<port>
|
219
|
+
// all the same.
|
220
|
+
sport = strrchr(urls[i], ':');
|
221
|
+
portPos = (int) (sport - urls[i]);
|
222
|
+
if (((nats_strcasestr(urls[i], "localhost") == urls[i]) && (portPos == 9))
|
223
|
+
|| (strncmp(urls[i], "127.0.0.1", portPos) == 0)
|
224
|
+
|| (strncmp(urls[i], "[::1]", portPos) == 0))
|
225
|
+
{
|
226
|
+
isLH = ((urls[i][0] == 'l') || (urls[i][0] == 'L'));
|
227
|
+
|
228
|
+
snprintf(url, sizeof(url), "localhost%s", sport);
|
229
|
+
found = (natsStrHash_Get(pool->urls, url) != NULL);
|
230
|
+
if (!found)
|
231
|
+
{
|
232
|
+
snprintf(url, sizeof(url), "127.0.0.1%s", sport);
|
233
|
+
found = (natsStrHash_Get(pool->urls, url) != NULL);
|
234
|
+
}
|
235
|
+
if (!found)
|
236
|
+
{
|
237
|
+
snprintf(url, sizeof(url), "[::1]%s", sport);
|
238
|
+
found = (natsStrHash_Get(pool->urls, url) != NULL);
|
239
|
+
}
|
240
|
+
}
|
241
|
+
else
|
242
|
+
{
|
243
|
+
found = (natsStrHash_Get(pool->urls, urls[i]) != NULL);
|
244
|
+
}
|
245
|
+
|
246
|
+
if (!found)
|
247
|
+
{
|
248
|
+
// Make sure that localhost URL is always stored in lower case.
|
249
|
+
if (isLH)
|
250
|
+
snprintf(url, sizeof(url), "nats://localhost%s", sport);
|
251
|
+
else
|
252
|
+
snprintf(url, sizeof(url), "nats://%s", urls[i]);
|
253
|
+
s = _addURLToPool(pool, url, true);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
return NATS_UPDATE_ERR_STACK(s);
|
258
|
+
}
|
259
|
+
|
260
|
+
// Create the server pool using the options given.
|
261
|
+
// We will place a Url option first, followed by any
|
262
|
+
// Server Options. We will randomize the server pool unlesss
|
263
|
+
// the NoRandomize flag is set.
|
264
|
+
natsStatus
|
265
|
+
natsSrvPool_Create(natsSrvPool **newPool, natsOptions *opts)
|
266
|
+
{
|
267
|
+
natsStatus s = NATS_OK;
|
268
|
+
natsSrvPool *pool = NULL;
|
269
|
+
int poolSize;
|
270
|
+
int i;
|
271
|
+
|
272
|
+
poolSize = (opts->url != NULL ? 1 : 0);
|
273
|
+
poolSize += opts->serversCount;
|
274
|
+
|
275
|
+
// If the pool is going to be empty, we will add the default URL.
|
276
|
+
if (poolSize == 0)
|
277
|
+
poolSize = 1;
|
278
|
+
|
279
|
+
pool = (natsSrvPool*) NATS_CALLOC(1, sizeof(natsSrvPool));
|
280
|
+
if (pool == NULL)
|
281
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
282
|
+
|
283
|
+
pool->srvrs = (natsSrv**) NATS_CALLOC(poolSize, sizeof(natsSrv*));
|
284
|
+
if (pool->srvrs == NULL)
|
285
|
+
{
|
286
|
+
NATS_FREE(pool);
|
287
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
288
|
+
}
|
289
|
+
// Set the current capacity. The array of urls may have to grow in
|
290
|
+
// the future.
|
291
|
+
pool->cap = poolSize;
|
292
|
+
|
293
|
+
// Map that helps find out if an URL is already known.
|
294
|
+
s = natsStrHash_Create(&(pool->urls), poolSize);
|
295
|
+
|
296
|
+
// Add URLs from Options' Servers
|
297
|
+
for (i=0; (s == NATS_OK) && (i < opts->serversCount); i++)
|
298
|
+
s = _addURLToPool(pool, opts->servers[i], false);
|
299
|
+
|
300
|
+
if (s == NATS_OK)
|
301
|
+
{
|
302
|
+
// Randomize if allowed to
|
303
|
+
if (!(opts->noRandomize))
|
304
|
+
_shufflePool(pool);
|
305
|
+
}
|
306
|
+
|
307
|
+
// Normally, if this one is set, Options.Servers should not be,
|
308
|
+
// but we always allowed that, so continue to do so.
|
309
|
+
if ((s == NATS_OK) && (opts->url != NULL))
|
310
|
+
{
|
311
|
+
// Add to the end of the array
|
312
|
+
s = _addURLToPool(pool, opts->url, false);
|
313
|
+
if ((s == NATS_OK) && (pool->size > 1))
|
314
|
+
{
|
315
|
+
// Then swap it with first to guarantee that Options.Url is tried first.
|
316
|
+
natsSrv *opstUrl = pool->srvrs[pool->size-1];
|
317
|
+
|
318
|
+
pool->srvrs[pool->size-1] = pool->srvrs[0];
|
319
|
+
pool->srvrs[0] = opstUrl;
|
320
|
+
}
|
321
|
+
}
|
322
|
+
else if ((s == NATS_OK) && (pool->size == 0))
|
323
|
+
{
|
324
|
+
// Place default URL if pool is empty.
|
325
|
+
s = _addURLToPool(pool, (char*) NATS_DEFAULT_URL, false);
|
326
|
+
}
|
327
|
+
|
328
|
+
if (s == NATS_OK)
|
329
|
+
*newPool = pool;
|
330
|
+
else
|
331
|
+
natsSrvPool_Destroy(pool);
|
332
|
+
|
333
|
+
return NATS_UPDATE_ERR_STACK(s);
|
334
|
+
}
|
335
|
+
|
336
|
+
natsStatus
|
337
|
+
natsSrvPool_GetServers(natsSrvPool *pool, bool implicitOnly, char ***servers, int *count)
|
338
|
+
{
|
339
|
+
natsStatus s = NATS_OK;
|
340
|
+
char **srvrs = NULL;
|
341
|
+
natsSrv *srv;
|
342
|
+
natsUrl *url;
|
343
|
+
int i;
|
344
|
+
int discovered = 0;
|
345
|
+
|
346
|
+
if (pool->size == 0)
|
347
|
+
{
|
348
|
+
*servers = NULL;
|
349
|
+
*count = 0;
|
350
|
+
return NATS_OK;
|
351
|
+
}
|
352
|
+
|
353
|
+
srvrs = (char **) NATS_CALLOC(pool->size, sizeof(char*));
|
354
|
+
if (srvrs == NULL)
|
355
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
356
|
+
|
357
|
+
for (i=0; ((s == NATS_OK) && (i<pool->size)); i++)
|
358
|
+
{
|
359
|
+
srv = pool->srvrs[i];
|
360
|
+
if (implicitOnly && !srv->isImplicit)
|
361
|
+
continue;
|
362
|
+
url = srv->url;
|
363
|
+
if (nats_asprintf(&(srvrs[discovered]), "nats://%s:%d", url->host, url->port) == -1)
|
364
|
+
s = nats_setDefaultError(NATS_NO_MEMORY);
|
365
|
+
else
|
366
|
+
discovered++;
|
367
|
+
}
|
368
|
+
if (s == NATS_OK)
|
369
|
+
{
|
370
|
+
*servers = srvrs;
|
371
|
+
*count = discovered;
|
372
|
+
}
|
373
|
+
else
|
374
|
+
{
|
375
|
+
for (i=0; i<discovered; i++)
|
376
|
+
NATS_FREE(srvrs[i]);
|
377
|
+
NATS_FREE(srvrs);
|
378
|
+
}
|
379
|
+
return NATS_UPDATE_ERR_STACK(s);
|
380
|
+
}
|