ffi-nats-core 0.3.0 → 0.3.1

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