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,162 @@
1
+ // Copyright 2015 Apcera Inc. All rights reserved.
2
+
3
+ #include "../natsp.h"
4
+ #include "../mem.h"
5
+
6
+ bool
7
+ nats_InitOnce(natsInitOnceType *control, natsInitOnceCb cb)
8
+ {
9
+ if (pthread_once(control, cb) != 0)
10
+ return false;
11
+
12
+ return true;
13
+ }
14
+
15
+ struct threadCtx
16
+ {
17
+ natsThreadCb entry;
18
+ void *arg;
19
+ };
20
+
21
+ static void*
22
+ _threadStart(void *arg)
23
+ {
24
+ struct threadCtx *c = (struct threadCtx*) arg;
25
+
26
+ c->entry(c->arg);
27
+
28
+ NATS_FREE(c);
29
+
30
+ return NULL;
31
+ }
32
+
33
+ natsStatus
34
+ natsThread_Create(natsThread **thread, natsThreadCb cb, void *arg)
35
+ {
36
+ struct threadCtx *ctx = NULL;
37
+ natsThread *t = NULL;
38
+ natsStatus s = NATS_OK;
39
+ int err;
40
+
41
+ ctx = (struct threadCtx*) NATS_CALLOC(1, sizeof(*ctx));
42
+ t = (natsThread*) NATS_CALLOC(1, sizeof(natsThread));
43
+
44
+ if ((ctx == NULL) || (t == NULL))
45
+ s = nats_setDefaultError(NATS_NO_MEMORY);
46
+
47
+ if (s == NATS_OK)
48
+ {
49
+ ctx->entry = cb;
50
+ ctx->arg = arg;
51
+
52
+ err = pthread_create(t, NULL, _threadStart, ctx);
53
+ if (err)
54
+ s = nats_setError(NATS_SYS_ERROR,
55
+ "pthread_create error: %d", errno);
56
+ }
57
+
58
+ if (s == NATS_OK)
59
+ {
60
+ *thread = t;
61
+ }
62
+ else
63
+ {
64
+ NATS_FREE(ctx);
65
+ NATS_FREE(t);
66
+ }
67
+
68
+ return s;
69
+ }
70
+
71
+ void
72
+ natsThread_Join(natsThread *t)
73
+ {
74
+ // I think that 'join' should automatically detect if the call is made
75
+ // from the current thread. This simplify the use. That is, you don't
76
+ // need to do:
77
+ // if (!natsThread_IsCurrent(t))
78
+ // natsThread_Join(t)
79
+
80
+ if (!natsThread_IsCurrent(t))
81
+ {
82
+ if (pthread_join(*t, NULL) != 0)
83
+ abort();
84
+ }
85
+ else
86
+ {
87
+ pthread_detach(*t);
88
+ }
89
+ }
90
+
91
+ void
92
+ natsThread_Detach(natsThread *t)
93
+ {
94
+ if (pthread_detach(*t) !=0)
95
+ abort();
96
+ }
97
+
98
+ bool
99
+ natsThread_IsCurrent(natsThread *t)
100
+ {
101
+ if (pthread_equal(pthread_self(), *t) == 0)
102
+ return false;
103
+
104
+ return true;
105
+ }
106
+
107
+ void
108
+ natsThread_Yield(void)
109
+ {
110
+ sched_yield();
111
+ }
112
+
113
+ void
114
+ natsThread_Destroy(natsThread *t)
115
+ {
116
+ if (t == NULL)
117
+ return;
118
+
119
+ NATS_FREE(t);
120
+ }
121
+
122
+ natsStatus
123
+ natsThreadLocal_CreateKey(natsThreadLocal *tl, void (*destructor)(void*))
124
+ {
125
+ int ret;
126
+
127
+ if ((ret = pthread_key_create(tl, destructor)) != 0)
128
+ {
129
+ return nats_setError(NATS_SYS_ERROR,
130
+ "pthread_key_create error: %d", ret);
131
+ }
132
+
133
+ return NATS_OK;
134
+ }
135
+
136
+ void*
137
+ natsThreadLocal_Get(natsThreadLocal tl)
138
+ {
139
+ return pthread_getspecific(tl);
140
+ }
141
+
142
+ natsStatus
143
+ natsThreadLocal_SetEx(natsThreadLocal tl, const void *value, bool setErr)
144
+ {
145
+ int ret;
146
+
147
+ if ((ret = pthread_setspecific(tl, value)) != 0)
148
+ {
149
+ return nats_setError(NATS_SYS_ERROR,
150
+ "pthread_setspecific: %d",
151
+ ret);
152
+ }
153
+
154
+ return NATS_OK;
155
+ }
156
+
157
+ void
158
+ natsThreadLocal_DestroyKey(natsThreadLocal tl)
159
+ {
160
+ pthread_key_delete(tl);
161
+ }
162
+
@@ -0,0 +1,134 @@
1
+ // Copyright 2015 Apcera Inc. All rights reserved.
2
+
3
+ #include "natsp.h"
4
+
5
+ #include <string.h>
6
+
7
+ #include "mem.h"
8
+
9
+ void
10
+ natsUrl_Destroy(natsUrl *url)
11
+ {
12
+ if (url == NULL)
13
+ return;
14
+
15
+ NATS_FREE(url->fullUrl);
16
+ NATS_FREE(url->host);
17
+ NATS_FREE(url->username);
18
+ NATS_FREE(url->password);
19
+ NATS_FREE(url);
20
+ }
21
+
22
+ static natsStatus
23
+ _parseHostAndPort(natsUrl *url, char *host, bool uInfo)
24
+ {
25
+ natsStatus s = NATS_OK;
26
+ char *sport = NULL;
27
+
28
+ sport = strrchr(host, ':');
29
+ if (sport != NULL)
30
+ {
31
+ if (sport[1] != '\0')
32
+ url->port = atoi(sport + 1);
33
+
34
+ *sport = '\0';
35
+ }
36
+
37
+ if (uInfo)
38
+ {
39
+ url->host = NATS_STRDUP(host + 1);
40
+ *host = '\0';
41
+
42
+ if (url->host == NULL)
43
+ s = nats_setDefaultError(NATS_NO_MEMORY);
44
+ }
45
+ else
46
+ {
47
+ url->host = NATS_STRDUP(host);
48
+ if (url->host == NULL)
49
+ s = nats_setDefaultError(NATS_NO_MEMORY);
50
+ }
51
+
52
+ return s;
53
+ }
54
+
55
+ natsStatus
56
+ natsUrl_Create(natsUrl **newUrl, const char *urlStr)
57
+ {
58
+ natsStatus s = NATS_OK;
59
+ bool uInfo = false;
60
+ char *copy = NULL;
61
+ char *ptr = NULL;
62
+ char *host = NULL;
63
+ char *pwd = NULL;
64
+ natsUrl *url = NULL;
65
+
66
+ if ((urlStr == NULL) || (strlen(urlStr) == 0))
67
+ return nats_setDefaultError(NATS_INVALID_ARG);
68
+
69
+ url = (natsUrl*) NATS_CALLOC(1, sizeof(natsUrl));
70
+ if (url == NULL)
71
+ return nats_setDefaultError(NATS_NO_MEMORY);
72
+
73
+ url->fullUrl = NATS_STRDUP(urlStr);
74
+ if (url->fullUrl == NULL)
75
+ return nats_setDefaultError(NATS_NO_MEMORY);
76
+
77
+ if (s == NATS_OK)
78
+ {
79
+ copy = NATS_STRDUP(urlStr);
80
+ if (copy == NULL)
81
+ return nats_setDefaultError(NATS_NO_MEMORY);
82
+ }
83
+
84
+ // This is based on the results of the Go parsing.
85
+ // If '//' is not present, there is no error, but
86
+ // no host, user, password is returned.
87
+ if ((s == NATS_OK)
88
+ && ((ptr = strstr(copy, "//")) != NULL)
89
+ && (*(ptr += 2) != '\0'))
90
+ {
91
+ // If '@' is present, everything after is the host
92
+ // everything before is username/password combo.
93
+
94
+ host = strrchr(ptr, '@');
95
+ if (host != NULL)
96
+ uInfo = true;
97
+ else
98
+ host = ptr;
99
+
100
+ if ((host != NULL) && (host[1] != '\0'))
101
+ {
102
+ s = _parseHostAndPort(url, host, uInfo);
103
+ }
104
+
105
+ if ((s == NATS_OK) && uInfo)
106
+ {
107
+ pwd = strchr(ptr, ':');
108
+ if ((pwd != NULL) && (pwd[1] != '\0'))
109
+ {
110
+ url->password = NATS_STRDUP(pwd + 1);
111
+ *pwd = '\0';
112
+
113
+ if (url->password == NULL)
114
+ return nats_setDefaultError(NATS_NO_MEMORY);
115
+ }
116
+
117
+ if ((s == NATS_OK) && (strlen(ptr) > 0))
118
+ {
119
+ url->username = NATS_STRDUP(ptr);
120
+ if (url->username == NULL)
121
+ return nats_setDefaultError(NATS_NO_MEMORY);
122
+ }
123
+ }
124
+ }
125
+
126
+ NATS_FREE(copy);
127
+
128
+ if (s == NATS_OK)
129
+ *newUrl = url;
130
+ else
131
+ natsUrl_Destroy(url);
132
+
133
+ return NATS_UPDATE_ERR_STACK(s);
134
+ }
@@ -0,0 +1,24 @@
1
+ // Copyright 2015 Apcera Inc. All rights reserved.
2
+
3
+ #ifndef URL_H_
4
+ #define URL_H_
5
+
6
+ #include "status.h"
7
+
8
+ typedef struct __natsUrl
9
+ {
10
+ char *fullUrl;
11
+ char *host;
12
+ int port;
13
+ char *username;
14
+ char *password;
15
+
16
+ } natsUrl;
17
+
18
+ natsStatus
19
+ natsUrl_Create(natsUrl **newUrl, const char *urlStr);
20
+
21
+ void
22
+ natsUrl_Destroy(natsUrl *url);
23
+
24
+ #endif /* SRC_URL_H_ */
@@ -0,0 +1,823 @@
1
+ // Copyright 2015 Apcera Inc. All rights reserved.
2
+
3
+ #include "natsp.h"
4
+
5
+ #include <stdio.h>
6
+ #include <stdarg.h>
7
+ #include <string.h>
8
+
9
+ #include "util.h"
10
+ #include "mem.h"
11
+
12
+ #define ASCII_0 (48)
13
+ #define ASCII_9 (57)
14
+
15
+ // parseInt64 expects decimal positive numbers. We
16
+ // return -1 to signal error
17
+ int64_t
18
+ nats_ParseInt64(const char *d, int dLen)
19
+ {
20
+ int i;
21
+ char dec;
22
+ int64_t n = 0;
23
+
24
+ if (dLen == 0)
25
+ return -1;
26
+
27
+ for (i=0; i<dLen; i++)
28
+ {
29
+ dec = d[i];
30
+ if ((dec < ASCII_0) || (dec > ASCII_9))
31
+ return -1;
32
+
33
+ n = (n * 10) + ((int64_t)dec - ASCII_0);
34
+ }
35
+
36
+ return n;
37
+ }
38
+
39
+ natsStatus
40
+ nats_ParseControl(natsControl *control, const char *line)
41
+ {
42
+ natsStatus s = NATS_OK;
43
+ char *tok = NULL;
44
+ int len = 0;
45
+
46
+ if ((line == NULL) || (line[0] == '\0'))
47
+ return nats_setDefaultError(NATS_PROTOCOL_ERROR);
48
+
49
+ tok = strchr(line, (int) ' ');
50
+ if (tok == NULL)
51
+ {
52
+ control->op = NATS_STRDUP(line);
53
+ if (control->op == NULL)
54
+ return nats_setDefaultError(NATS_NO_MEMORY);
55
+
56
+ return NATS_OK;
57
+ }
58
+
59
+ len = (int) (tok - line);
60
+ control->op = NATS_MALLOC(len + 1);
61
+ if (control->op == NULL)
62
+ {
63
+ s = nats_setDefaultError(NATS_NO_MEMORY);
64
+ }
65
+ else
66
+ {
67
+ memcpy(control->op, line, len);
68
+ control->op[len] = '\0';
69
+ }
70
+
71
+ if (s == NATS_OK)
72
+ {
73
+ // Discard all spaces and the like in between the next token
74
+ while ((tok[0] != '\0')
75
+ && ((tok[0] == ' ')
76
+ || (tok[0] == '\r')
77
+ || (tok[0] == '\n')
78
+ || (tok[0] == '\t')))
79
+ {
80
+ tok++;
81
+ }
82
+ }
83
+
84
+ // If there is a token...
85
+ if (tok[0] != '\0')
86
+ {
87
+ char *tmp;
88
+
89
+ len = (int) strlen(tok);
90
+ tmp = &(tok[len - 1]);
91
+
92
+ // Remove trailing spaces and the like.
93
+ while ((tmp[0] != '\0')
94
+ && ((tmp[0] == ' ')
95
+ || (tmp[0] == '\r')
96
+ || (tmp[0] == '\n')
97
+ || (tmp[0] == '\t')))
98
+ {
99
+ tmp--;
100
+ len--;
101
+ }
102
+
103
+ // We are sure that len is > 0 because of the first while() loop.
104
+
105
+ control->args = NATS_MALLOC(len + 1);
106
+ if (control->args == NULL)
107
+ {
108
+ s = nats_setDefaultError(NATS_NO_MEMORY);
109
+ }
110
+ else
111
+ {
112
+ memcpy(control->args, tok, len);
113
+ control->args[len] = '\0';
114
+ }
115
+ }
116
+
117
+ if (s != NATS_OK)
118
+ {
119
+ NATS_FREE(control->op);
120
+ control->op = NULL;
121
+
122
+ NATS_FREE(control->args);
123
+ control->args = NULL;
124
+ }
125
+
126
+ return NATS_UPDATE_ERR_STACK(s);
127
+ }
128
+
129
+ natsStatus
130
+ nats_CreateStringFromBuffer(char **newStr, natsBuffer *buf)
131
+ {
132
+ char *str = NULL;
133
+ int len = 0;
134
+
135
+ if ((buf == NULL) || ((len = natsBuf_Len(buf)) == 0))
136
+ return NATS_OK;
137
+
138
+ str = NATS_MALLOC(len + 1);
139
+ if (str == NULL)
140
+ return nats_setDefaultError(NATS_NO_MEMORY);
141
+
142
+ memcpy(str, natsBuf_Data(buf), len);
143
+ str[len] = '\0';
144
+
145
+ *newStr = str;
146
+
147
+ return NATS_OK;
148
+ }
149
+
150
+ void
151
+ nats_Sleep(int64_t millisec)
152
+ {
153
+ #ifdef _WIN32
154
+ Sleep((DWORD) millisec);
155
+ #else
156
+ usleep(millisec * 1000);
157
+ #endif
158
+ }
159
+
160
+ const char*
161
+ nats_GetBoolStr(bool value)
162
+ {
163
+ if (value)
164
+ return "true";
165
+
166
+ return "false";
167
+ }
168
+
169
+ void
170
+ nats_NormalizeErr(char *error)
171
+ {
172
+ int start = 0;
173
+ int end = 0;
174
+ int len = (int) strlen(error);
175
+ int i;
176
+
177
+ if (strncmp(error, _ERR_OP_, _ERR_OP_LEN_) == 0)
178
+ start = _ERR_OP_LEN_;
179
+
180
+ for (i=start; i<len; i++)
181
+ {
182
+ if ((error[i] != ' ') && (error[i] != '\''))
183
+ break;
184
+ }
185
+
186
+ start = i;
187
+ if (start == len)
188
+ {
189
+ error[0] = '\0';
190
+ return;
191
+ }
192
+
193
+ for (end=len-1; end>0; end--)
194
+ if ((error[end] != ' ') && (error[end] != '\''))
195
+ break;
196
+
197
+ if (end <= start)
198
+ {
199
+ error[0] = '\0';
200
+ return;
201
+ }
202
+
203
+ len = end - start + 1;
204
+ memmove(error, error + start, len);
205
+ error[len] = '\0';
206
+ }
207
+
208
+ static natsStatus
209
+ _jsonCreateField(nats_JSONField **newField, char *fieldName)
210
+ {
211
+ nats_JSONField *field = NULL;
212
+
213
+ field = (nats_JSONField*) NATS_CALLOC(1, sizeof(nats_JSONField));
214
+ if (field == NULL)
215
+ return nats_setDefaultError(NATS_NO_MEMORY);
216
+
217
+ field->name = fieldName;
218
+ field->typ = TYPE_NOT_SET;
219
+
220
+ *newField = field;
221
+
222
+ return NATS_OK;
223
+ }
224
+
225
+ static void
226
+ _jsonFreeField(nats_JSONField *field)
227
+ {
228
+ if (field->typ == TYPE_ARRAY)
229
+ {
230
+ NATS_FREE(field->value.varr->values);
231
+ NATS_FREE(field->value.varr);
232
+ }
233
+ NATS_FREE(field);
234
+ }
235
+
236
+ static char*
237
+ _jsonTrimSpace(char *ptr)
238
+ {
239
+ while ((*ptr != '\0')
240
+ && ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\r') || (*ptr == '\n')))
241
+ {
242
+ ptr += 1;
243
+ }
244
+ return ptr;
245
+ }
246
+
247
+ static natsStatus
248
+ _jsonGetStr(char **ptr, char **value)
249
+ {
250
+ char *p = *ptr;
251
+
252
+ do
253
+ {
254
+ while ((*p != '\0') && (*p != '"'))
255
+ p += 1;
256
+ }
257
+ while ((*p != '\0') && (*p == '"') && (*(p - 1) == '\\') && (p += 1));
258
+
259
+ if (*p != '\0')
260
+ {
261
+ *value = *ptr;
262
+ *p = '\0';
263
+ *ptr = (char*) (p + 1);
264
+ return NATS_OK;
265
+ }
266
+ return nats_setError(NATS_INVALID_ARG, "%s",
267
+ "error parsing string: unexpected end of JSON input");
268
+ }
269
+
270
+ static natsStatus
271
+ _jsonGetNum(char **ptr, long double *val)
272
+ {
273
+ char *tail = NULL;
274
+ long double lval = 0;
275
+
276
+ errno = 0;
277
+
278
+ lval = strtold(*ptr, &tail);
279
+ if (errno != 0)
280
+ return nats_setError(NATS_INVALID_ARG,
281
+ "error parsing numeric: %d", errno);
282
+
283
+ *ptr = tail;
284
+ *val = lval;
285
+ return NATS_OK;
286
+ }
287
+
288
+ static natsStatus
289
+ _jsonGetBool(char **ptr, bool *val)
290
+ {
291
+ if (strncmp(*ptr, "true", 4) == 0)
292
+ {
293
+ *val = true;
294
+ *ptr += 4;
295
+ return NATS_OK;
296
+ }
297
+ else if (strncmp(*ptr, "false", 5) == 0)
298
+ {
299
+ *val = false;
300
+ *ptr += 5;
301
+ return NATS_OK;
302
+ }
303
+ return nats_setError(NATS_INVALID_ARG,
304
+ "error parsing boolean, got: '%s'", *ptr);
305
+ }
306
+
307
+ static natsStatus
308
+ _jsonGetArray(char **ptr, nats_JSONArray **newArray)
309
+ {
310
+ natsStatus s = NATS_OK;
311
+ char *p = *ptr;
312
+ char *val = NULL;
313
+ bool end = false;
314
+ nats_JSONArray array;
315
+
316
+ // Initialize our stack variable
317
+ memset(&array, 0, sizeof(nats_JSONArray));
318
+
319
+ // We support only string array for now
320
+ array.typ = TYPE_STR;
321
+ array.eltSize = sizeof(char*);
322
+ array.size = 0;
323
+ array.cap = 4;
324
+ array.values = NATS_CALLOC(array.cap, array.eltSize);
325
+
326
+ while ((s == NATS_OK) && (*p != '\0'))
327
+ {
328
+ p = _jsonTrimSpace(p);
329
+
330
+ // We support only array of strings for now
331
+ if (*p != '"')
332
+ {
333
+ s = nats_setError(NATS_NOT_PERMITTED,
334
+ "only string arrays supported, got '%s'", p);
335
+ break;
336
+ }
337
+
338
+ p += 1;
339
+
340
+ s = _jsonGetStr(&p, &val);
341
+ if (s != NATS_OK)
342
+ break;
343
+
344
+ if (array.size + 1 > array.cap)
345
+ {
346
+ char **newValues = NULL;
347
+ int newCap = 2 * array.cap;
348
+
349
+ newValues = (char**) NATS_REALLOC(array.values, newCap * sizeof(char*));
350
+ if (newValues == NULL)
351
+ {
352
+ s = nats_setDefaultError(NATS_NO_MEMORY);
353
+ break;
354
+ }
355
+ array.values = (void**) newValues;
356
+ array.cap = newCap;
357
+ }
358
+ ((char**)array.values)[array.size++] = val;
359
+
360
+ p = _jsonTrimSpace(p);
361
+ if (*p == '\0')
362
+ break;
363
+
364
+ if (*p == ']')
365
+ {
366
+ end = true;
367
+ break;
368
+ }
369
+ else if (*p == ',')
370
+ {
371
+ p += 1;
372
+ }
373
+ else
374
+ {
375
+ s = nats_setError(NATS_ERR, "expected ',' got '%s'", p);
376
+ }
377
+ }
378
+ if ((s == NATS_OK) && !end)
379
+ {
380
+ s = nats_setError(NATS_ERR,
381
+ "unexpected end of array: '%s'",
382
+ (*p != '\0' ? p : "NULL"));
383
+ }
384
+ if (s == NATS_OK)
385
+ {
386
+ *newArray = NATS_MALLOC(sizeof(nats_JSONArray));
387
+ if (*newArray == NULL)
388
+ {
389
+ s = nats_setDefaultError(NATS_NO_MEMORY);
390
+ }
391
+ else
392
+ {
393
+ memcpy(*newArray, &array, sizeof(nats_JSONArray));
394
+ *ptr = (char*) (p + 1);
395
+ }
396
+ }
397
+ if (s != NATS_OK)
398
+ {
399
+ int i;
400
+ for (i=0; i<array.size; i++)
401
+ {
402
+ p = ((char**)array.values)[i];
403
+ *(p + strlen(p)) = '"';
404
+ }
405
+ NATS_FREE(array.values);
406
+ }
407
+
408
+ return NATS_UPDATE_ERR_STACK(s);
409
+ }
410
+
411
+ static char*
412
+ _jsonSkipUnknownType(char *ptr)
413
+ {
414
+ char *p = ptr;
415
+ int skip = 0;
416
+ bool quoteOpen = false;
417
+
418
+ while (*p != '\0')
419
+ {
420
+ if (((*p == ',') || (*p == '}')) && (skip == 0))
421
+ break;
422
+ else if ((*p == '{') || (*p == '['))
423
+ skip++;
424
+ else if ((*p == '}') || (*p == ']'))
425
+ skip--;
426
+ else if ((*p == '"') && (*(p-1) != '\\'))
427
+ {
428
+ if (quoteOpen)
429
+ {
430
+ quoteOpen = false;
431
+ skip--;
432
+ }
433
+ else
434
+ {
435
+ quoteOpen = true;
436
+ skip++;
437
+ }
438
+ }
439
+ p += 1;
440
+ }
441
+ return p;
442
+ }
443
+
444
+ #define JSON_STATE_START (0)
445
+ #define JSON_STATE_NO_FIELD_YET (1)
446
+ #define JSON_STATE_FIELD (2)
447
+ #define JSON_STATE_SEPARATOR (3)
448
+ #define JSON_STATE_VALUE (4)
449
+ #define JSON_STATE_NEXT_FIELD (5)
450
+ #define JSON_STATE_END (6)
451
+
452
+ natsStatus
453
+ nats_JSONParse(nats_JSON **newJSON, const char *jsonStr, int jsonLen)
454
+ {
455
+ natsStatus s = NATS_OK;
456
+ nats_JSON *json = NULL;
457
+ nats_JSONField *field = NULL;
458
+ nats_JSONField *oldField = NULL;
459
+ char *ptr;
460
+ char *fieldName = NULL;
461
+ int state;
462
+ bool gotEnd = false;
463
+
464
+ if (jsonLen < 0)
465
+ {
466
+ if (jsonStr == NULL)
467
+ return nats_setDefaultError(NATS_INVALID_ARG);
468
+
469
+ jsonLen = (int) strlen(jsonStr);
470
+ }
471
+
472
+ json = NATS_CALLOC(1, sizeof(nats_JSON));
473
+ if (json == NULL)
474
+ return nats_setDefaultError(NATS_NO_MEMORY);
475
+
476
+ s = natsStrHash_Create(&(json->fields), 4);
477
+ if (s == NATS_OK)
478
+ {
479
+ json->str = NATS_MALLOC(jsonLen + 1);
480
+ if (json->str == NULL)
481
+ s = nats_setDefaultError(NATS_NO_MEMORY);
482
+
483
+ if (s == NATS_OK)
484
+ {
485
+ memcpy(json->str, jsonStr, jsonLen);
486
+ json->str[jsonLen] = '\0';
487
+ }
488
+ }
489
+ if (s != NATS_OK)
490
+ {
491
+ nats_JSONDestroy(json);
492
+ return NATS_UPDATE_ERR_STACK(s);
493
+ }
494
+
495
+ ptr = json->str;
496
+ state = JSON_STATE_START;
497
+
498
+ while ((s == NATS_OK) && (*ptr != '\0'))
499
+ {
500
+ ptr = _jsonTrimSpace(ptr);
501
+ if (*ptr == '\0')
502
+ break;
503
+ switch (state)
504
+ {
505
+ case JSON_STATE_START:
506
+ {
507
+ // Should be the start of the JSON string
508
+ if (*ptr != '{')
509
+ {
510
+ s = nats_setError(NATS_ERR, "incorrect JSON string: '%s'", ptr);
511
+ break;
512
+ }
513
+ ptr += 1;
514
+ state = JSON_STATE_NO_FIELD_YET;
515
+ break;
516
+ }
517
+ case JSON_STATE_NO_FIELD_YET:
518
+ case JSON_STATE_FIELD:
519
+ {
520
+ // Check for end, which is valid only in state == JSON_STATE_NO_FIELD_YET
521
+ if (*ptr == '}')
522
+ {
523
+ if (state == JSON_STATE_NO_FIELD_YET)
524
+ {
525
+ ptr += 1;
526
+ state = JSON_STATE_END;
527
+ break;
528
+ }
529
+ s = nats_setError(NATS_ERR,
530
+ "expected beginning of field, got: '%s'",
531
+ ptr);
532
+ break;
533
+ }
534
+ // Check for
535
+ // Should be the first quote of a field name
536
+ if (*ptr != '"')
537
+ {
538
+ s = nats_setError(NATS_ERR, "missing quote: '%s'", ptr);
539
+ break;
540
+ }
541
+ ptr += 1;
542
+ s = _jsonGetStr(&ptr, &fieldName);
543
+ if (s != NATS_OK)
544
+ {
545
+ s = nats_setError(NATS_ERR, "invalid field name: '%s'", ptr);
546
+ break;
547
+ }
548
+ s = _jsonCreateField(&field, fieldName);
549
+ if (s != NATS_OK)
550
+ {
551
+ NATS_UPDATE_ERR_STACK(s);
552
+ break;
553
+ }
554
+ s = natsStrHash_Set(json->fields, fieldName, false, (void*) field, (void**)&oldField);
555
+ if (s != NATS_OK)
556
+ {
557
+ NATS_UPDATE_ERR_STACK(s);
558
+ break;
559
+ }
560
+ if (oldField != NULL)
561
+ {
562
+ NATS_FREE(oldField);
563
+ oldField = NULL;
564
+ }
565
+ state = JSON_STATE_SEPARATOR;
566
+ break;
567
+ }
568
+ case JSON_STATE_SEPARATOR:
569
+ {
570
+ // Should be the separation between field name and value.
571
+ if (*ptr != ':')
572
+ {
573
+ s = nats_setError(NATS_ERR, "missing value for field '%s': '%s'", fieldName, ptr);
574
+ break;
575
+ }
576
+ ptr += 1;
577
+ state = JSON_STATE_VALUE;
578
+ break;
579
+ }
580
+ case JSON_STATE_VALUE:
581
+ {
582
+ // Parsing value here. Determine the type based on first character.
583
+ if (*ptr == '"')
584
+ {
585
+ field->typ = TYPE_STR;
586
+ ptr += 1;
587
+ s = _jsonGetStr(&ptr, &field->value.vstr);
588
+ if (s != NATS_OK)
589
+ s = nats_setError(NATS_ERR,
590
+ "invalid string value for field '%s': '%s'",
591
+ fieldName, ptr);
592
+ }
593
+ else if ((*ptr == 't') || (*ptr == 'f'))
594
+ {
595
+ field->typ = TYPE_BOOL;
596
+ s = _jsonGetBool(&ptr, &field->value.vbool);
597
+ if (s != NATS_OK)
598
+ s = nats_setError(NATS_ERR,
599
+ "invalid boolean value for field '%s': '%s'",
600
+ fieldName, ptr);
601
+ }
602
+ else if (((*ptr >= 48) && (*ptr <= 57)) || (*ptr == '-'))
603
+ {
604
+ field->typ = TYPE_NUM;
605
+ s = _jsonGetNum(&ptr, &field->value.vdec);
606
+ if (s != NATS_OK)
607
+ s = nats_setError(NATS_ERR,
608
+ "invalid numeric value for field '%s': '%s'",
609
+ fieldName, ptr);
610
+ }
611
+ else if ((*ptr == '[') || (*ptr == '{'))
612
+ {
613
+ bool doSkip = true;
614
+
615
+ if (*ptr == '[')
616
+ {
617
+ ptr += 1;
618
+ s = _jsonGetArray(&ptr, &field->value.varr);
619
+ if (s == NATS_OK)
620
+ {
621
+ field->typ = TYPE_ARRAY;
622
+ doSkip = false;
623
+ }
624
+ else if (s == NATS_NOT_PERMITTED)
625
+ {
626
+ // This is an array but we don't support the
627
+ // type of elements, so skip.
628
+ s = NATS_OK;
629
+ // Clear error stack
630
+ nats_clearLastError();
631
+ // Need to go back to the '[' character.
632
+ ptr -= 1;
633
+ }
634
+ }
635
+ if ((s == NATS_OK) && doSkip)
636
+ {
637
+ // Don't support, skip until next field.
638
+ ptr = _jsonSkipUnknownType(ptr);
639
+ // Destroy the field that we have created
640
+ natsStrHash_Remove(json->fields, fieldName);
641
+ _jsonFreeField(field);
642
+ field = NULL;
643
+ }
644
+ }
645
+ else
646
+ {
647
+ s = nats_setError(NATS_ERR,
648
+ "looking for value, got: '%s'", ptr);
649
+ }
650
+ if (s == NATS_OK)
651
+ state = JSON_STATE_NEXT_FIELD;
652
+ break;
653
+ }
654
+ case JSON_STATE_NEXT_FIELD:
655
+ {
656
+ // We should have a ',' separator or be at the end of the string
657
+ if ((*ptr != ',') && (*ptr != '}'))
658
+ {
659
+ s = nats_setError(NATS_ERR, "missing separator: '%s' (%s)", ptr, jsonStr);
660
+ break;
661
+ }
662
+ if (*ptr == ',')
663
+ state = JSON_STATE_FIELD;
664
+ else
665
+ state = JSON_STATE_END;
666
+ ptr += 1;
667
+ break;
668
+ }
669
+ case JSON_STATE_END:
670
+ {
671
+ // If we are here it means that there was a character after the '}'
672
+ // so that's considered a failure.
673
+ s = nats_setError(NATS_ERR,
674
+ "invalid characters after end of JSON: '%s'",
675
+ ptr);
676
+ break;
677
+ }
678
+ }
679
+ }
680
+ if (s == NATS_OK)
681
+ {
682
+ if (state != JSON_STATE_END)
683
+ s = nats_setError(NATS_ERR, "%s", "JSON string not properly closed");
684
+ }
685
+ if (s == NATS_OK)
686
+ *newJSON = json;
687
+ else
688
+ nats_JSONDestroy(json);
689
+
690
+ return NATS_UPDATE_ERR_STACK(s);
691
+ }
692
+
693
+ natsStatus
694
+ nats_JSONGetValue(nats_JSON *json, const char *fieldName, int fieldType, void **addr)
695
+ {
696
+ nats_JSONField *field = NULL;
697
+
698
+ field = (nats_JSONField*) natsStrHash_Get(json->fields, (char*) fieldName);
699
+ // If unknown field, just ignore
700
+ if (field == NULL)
701
+ return NATS_OK;
702
+
703
+ // Check parsed type matches what is being asked.
704
+ if ((((fieldType == TYPE_INT) || (fieldType == TYPE_LONG)) && (field->typ != TYPE_NUM))
705
+ || ((field->typ != TYPE_NUM) && (fieldType != field->typ)))
706
+ {
707
+ return nats_setError(NATS_INVALID_ARG,
708
+ "Asked for field '%s' as type %d, but got type %d when parsing",
709
+ field->name, fieldType, field->typ);
710
+ }
711
+ switch (fieldType)
712
+ {
713
+ case TYPE_STR:
714
+ {
715
+ if (field->value.vstr == NULL)
716
+ {
717
+ (*(char**)addr) = NULL;
718
+ }
719
+ else
720
+ {
721
+ char *tmp = NATS_STRDUP(field->value.vstr);
722
+ if (tmp == NULL)
723
+ return nats_setDefaultError(NATS_NO_MEMORY);
724
+ (*(char**)addr) = tmp;
725
+ }
726
+ break;
727
+ }
728
+ case TYPE_BOOL: (*(bool*)addr) = field->value.vbool; break;
729
+ case TYPE_INT: (*(int*)addr) = (int)field->value.vdec; break;
730
+ case TYPE_LONG: (*(int64_t*)addr) = (int64_t) field->value.vdec; break;
731
+ case TYPE_DOUBLE: (*(long double*)addr) = field->value.vdec; break;
732
+ default:
733
+ {
734
+ return nats_setError(NATS_NOT_FOUND,
735
+ "Unknown field type for field '%s': %d",
736
+ field->name, fieldType);
737
+ }
738
+ }
739
+ return NATS_OK;
740
+ }
741
+
742
+ natsStatus
743
+ nats_JSONGetArrayValue(nats_JSON *json, const char *fieldName, int fieldType, void ***array, int *arraySize)
744
+ {
745
+ natsStatus s = NATS_OK;
746
+ nats_JSONField *field = NULL;
747
+ void **values = NULL;
748
+
749
+ field = (nats_JSONField*) natsStrHash_Get(json->fields, (char*) fieldName);
750
+ // If unknown field, just ignore
751
+ if (field == NULL)
752
+ return NATS_OK;
753
+
754
+ // Check parsed type matches what is being asked.
755
+ if (field->typ != TYPE_ARRAY)
756
+ return nats_setError(NATS_INVALID_ARG,
757
+ "Field '%s' is not an array, it has type: %d",
758
+ field->name, field->typ);
759
+ if (fieldType != field->value.varr->typ)
760
+ return nats_setError(NATS_INVALID_ARG,
761
+ "Asked for field '%s' as an array of type: %d, but it is an array of type: %d",
762
+ field->name, fieldType, field->typ);
763
+
764
+ values = NATS_CALLOC(field->value.varr->size, field->value.varr->eltSize);
765
+ if (values == NULL)
766
+ return nats_setDefaultError(NATS_NO_MEMORY);
767
+
768
+ if (fieldType == TYPE_STR)
769
+ {
770
+ int i;
771
+
772
+ for (i=0; i<field->value.varr->size; i++)
773
+ {
774
+ values[i] = NATS_STRDUP((char*)(field->value.varr->values[i]));
775
+ if (values[i] == NULL)
776
+ {
777
+ s = nats_setDefaultError(NATS_NO_MEMORY);
778
+ break;
779
+ }
780
+ }
781
+ if (s != NATS_OK)
782
+ {
783
+ int j;
784
+
785
+ for (j=0; j<i; j++)
786
+ NATS_FREE(values[i]);
787
+
788
+ NATS_FREE(values);
789
+ }
790
+ }
791
+ else
792
+ {
793
+ s = nats_setError(NATS_INVALID_ARG, "%s",
794
+ "Only string arrays are supported");
795
+ }
796
+ if (s == NATS_OK)
797
+ {
798
+ *array = values;
799
+ *arraySize = field->value.varr->size;
800
+ }
801
+
802
+ return NATS_UPDATE_ERR_STACK(s);
803
+ }
804
+
805
+ void
806
+ nats_JSONDestroy(nats_JSON *json)
807
+ {
808
+ natsStrHashIter iter;
809
+ nats_JSONField *field;
810
+
811
+ if (json == NULL)
812
+ return;
813
+
814
+ natsStrHashIter_Init(&iter, json->fields);
815
+ while (natsStrHashIter_Next(&iter, NULL, (void**)&field))
816
+ {
817
+ natsStrHashIter_RemoveCurrent(&iter);
818
+ _jsonFreeField(field);
819
+ }
820
+ natsStrHash_Destroy(json->fields);
821
+ NATS_FREE(json->str);
822
+ NATS_FREE(json);
823
+ }