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.
- 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
|
+
}
|