@openziti/ziti-sdk-nodejs 0.7.0 → 0.9.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.
- package/.github/workflows/build.yml +4 -11
- package/binding.gyp +5 -3
- package/lib/close.js +29 -0
- package/lib/express-listener.js +253 -0
- package/lib/express.js +58 -0
- package/lib/index.js +1 -1
- package/lib/init.js +39 -0
- package/lib/listen.js +30 -0
- package/lib/write.js +48 -0
- package/lib/ziti-socket.js +119 -0
- package/lib/ziti.js +14 -4
- package/package.json +1 -1
- package/src/Ziti_https_request.c +1 -1
- package/src/Ziti_https_request_data.c +2 -2
- package/src/Ziti_https_request_end.c +1 -1
- package/src/stack_traces.c +1 -1
- package/src/utils.c +1 -1
- package/src/utils.h +1 -1
- package/src/ziti-add-on.c +8 -4
- package/src/ziti-nodejs.h +16 -1
- package/src/ziti_close.c +1 -1
- package/src/ziti_dial.c +4 -5
- package/src/ziti_enroll.c +2 -2
- package/src/ziti_hello.c +1 -1
- package/src/ziti_init.c +4 -25
- package/src/ziti_listen.c +764 -0
- package/src/ziti_service_available.c +1 -1
- package/src/ziti_shutdown.c +1 -1
- package/src/ziti_websocket_connect.c +1 -1
- package/src/ziti_websocket_write.c +1 -1
- package/src/ziti_write.c +9 -1
- package/tests/https-test.js +11 -9
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright Netfoundry, Inc.
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#include "ziti-nodejs.h"
|
|
18
|
+
#include <string.h>
|
|
19
|
+
|
|
20
|
+
// An item that will be generated here and passed into the JavaScript on_listen_client callback
|
|
21
|
+
typedef struct OnClientItem {
|
|
22
|
+
|
|
23
|
+
int status;
|
|
24
|
+
ziti_connection client;
|
|
25
|
+
int64_t js_arb_data;
|
|
26
|
+
char *caller_id;
|
|
27
|
+
uint8_t *app_data;
|
|
28
|
+
size_t app_data_sz;
|
|
29
|
+
|
|
30
|
+
} OnClientItem;
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* This function is responsible for calling the JavaScript 'on_listen_client_data' callback function
|
|
35
|
+
* that was specified when the ziti_listen(...) was called from JavaScript.
|
|
36
|
+
*/
|
|
37
|
+
static void CallJs_on_listen_client_data(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
38
|
+
napi_status status;
|
|
39
|
+
|
|
40
|
+
// This parameter is not used.
|
|
41
|
+
(void) context;
|
|
42
|
+
|
|
43
|
+
// Retrieve the OnClientItem created by the worker thread.
|
|
44
|
+
OnClientItem* item = (OnClientItem*)data;
|
|
45
|
+
ZITI_NODEJS_LOG(INFO, "CallJs_on_listen_client_data: client: %p, app_data: %p, len: %zu", item->client, item->app_data, item->app_data_sz);
|
|
46
|
+
|
|
47
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
48
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
49
|
+
// When env is NULL, we simply skip over the call into Javascript
|
|
50
|
+
if (env != NULL) {
|
|
51
|
+
|
|
52
|
+
// const obj = {}
|
|
53
|
+
napi_value undefined, js_client_item, js_client, js_buffer, js_arb_data;
|
|
54
|
+
void* result_data;
|
|
55
|
+
|
|
56
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
57
|
+
// value of the JavaScript function call.
|
|
58
|
+
status = napi_get_undefined(env, &undefined);
|
|
59
|
+
if (status != napi_ok) {
|
|
60
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
int rc = napi_create_object(env, &js_client_item);
|
|
64
|
+
if (rc != napi_ok) {
|
|
65
|
+
napi_throw_error(env, "EINVAL", "failure to create object");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// js_client_item.js_arb_data = js_arb_data
|
|
69
|
+
if (item->js_arb_data) {
|
|
70
|
+
rc = napi_create_int64(env, item->js_arb_data, &js_arb_data);
|
|
71
|
+
if (rc != napi_ok) {
|
|
72
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.js_arb_data");
|
|
73
|
+
}
|
|
74
|
+
rc = napi_set_named_property(env, js_client_item, "js_arb_data", js_arb_data);
|
|
75
|
+
if (rc != napi_ok) {
|
|
76
|
+
napi_throw_error(env, "EINVAL", "failure to set named property status");
|
|
77
|
+
}
|
|
78
|
+
ZITI_NODEJS_LOG(DEBUG, "js_arb_data: %lld", item->js_arb_data);
|
|
79
|
+
} else {
|
|
80
|
+
rc = napi_set_named_property(env, js_client_item, "js_arb_data", undefined);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// js_client_item.client = client
|
|
84
|
+
napi_create_int64(env, (int64_t)item->client, &js_client);
|
|
85
|
+
if (rc != napi_ok) {
|
|
86
|
+
napi_throw_error(env, "EINVAL", "failure to create js_client_item.client");
|
|
87
|
+
}
|
|
88
|
+
rc = napi_set_named_property(env, js_client_item, "client", js_client);
|
|
89
|
+
if (rc != napi_ok) {
|
|
90
|
+
napi_throw_error(env, "EINVAL", "failure to set named property client");
|
|
91
|
+
}
|
|
92
|
+
ZITI_NODEJS_LOG(DEBUG, "client: %p", item->client);
|
|
93
|
+
|
|
94
|
+
// js_client_item.app_data = app_data
|
|
95
|
+
if (NULL != item->app_data) {
|
|
96
|
+
rc = napi_create_buffer_copy(env, item->app_data_sz, (const void*)item->app_data, (void**)&result_data, &js_buffer);
|
|
97
|
+
if (rc != napi_ok) {
|
|
98
|
+
napi_throw_error(env, "EINVAL", "failure to create js_client_item.app_data");
|
|
99
|
+
}
|
|
100
|
+
rc = napi_set_named_property(env, js_client_item, "app_data", js_buffer);
|
|
101
|
+
if (rc != napi_ok) {
|
|
102
|
+
napi_throw_error(env, "EINVAL", "failure to set named property app_data");
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
rc = napi_set_named_property(env, js_client_item, "app_data", undefined);
|
|
106
|
+
}
|
|
107
|
+
ZITI_NODEJS_LOG(DEBUG, "app_data: %p", item->app_data);
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
ZITI_NODEJS_LOG(INFO, "calling JS on_listen_client_data callback...");
|
|
111
|
+
|
|
112
|
+
// Call the JavaScript function and pass it the data
|
|
113
|
+
status = napi_call_function(
|
|
114
|
+
env,
|
|
115
|
+
undefined,
|
|
116
|
+
js_cb,
|
|
117
|
+
1,
|
|
118
|
+
&js_client_item,
|
|
119
|
+
NULL
|
|
120
|
+
);
|
|
121
|
+
if (status != napi_ok) {
|
|
122
|
+
napi_throw_error(env, NULL, "Unable to napi_call_function");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static ssize_t on_listen_client_data(ziti_connection client, const uint8_t *data, ssize_t len) {
|
|
130
|
+
|
|
131
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client_data: client: %p, data: %p, len: %zu", client, data, len);
|
|
132
|
+
|
|
133
|
+
ListenAddonData* addon_data = (ListenAddonData*) ziti_conn_data(client);
|
|
134
|
+
|
|
135
|
+
OnClientItem* item = memset(malloc(sizeof(*item)), 0, sizeof(*item));
|
|
136
|
+
item->client = client;
|
|
137
|
+
item->js_arb_data = addon_data->js_arb_data;
|
|
138
|
+
|
|
139
|
+
if ((NULL != data) && ((len > 0))) {
|
|
140
|
+
item->app_data = calloc(1, len + 1);
|
|
141
|
+
memcpy((void*)item->app_data, data, len);
|
|
142
|
+
item->app_data_sz = len;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (len > 0) {
|
|
146
|
+
/* NOP */
|
|
147
|
+
}
|
|
148
|
+
else if (len == ZITI_EOF) {
|
|
149
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client_data: client disconnected");
|
|
150
|
+
ziti_close_write(client);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
ZITI_NODEJS_LOG(ERROR, "on_listen_client_data: error: %zd(%s)", len, ziti_errorstr(len));
|
|
154
|
+
ziti_close(client, NULL);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Initiate the call into the JavaScript callback.
|
|
158
|
+
// The call into JavaScript will not have happened
|
|
159
|
+
// when this function returns, but it will be queued.
|
|
160
|
+
napi_status nstatus = napi_call_threadsafe_function(
|
|
161
|
+
addon_data->tsfn_on_listen_client_data,
|
|
162
|
+
item, // Send the status we received over to the JS callback
|
|
163
|
+
napi_tsfn_blocking);
|
|
164
|
+
if (nstatus != napi_ok) {
|
|
165
|
+
ZITI_NODEJS_LOG(ERROR, "Unable to napi_call_threadsafe_function");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return len;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* This function is responsible for calling the JavaScript 'on_listen_client_connect' callback function
|
|
174
|
+
* that was specified when the ziti_listen(...) was called from JavaScript.
|
|
175
|
+
*/
|
|
176
|
+
static void CallJs_on_listen_client_connect(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
177
|
+
napi_status status;
|
|
178
|
+
|
|
179
|
+
// This parameter is not used.
|
|
180
|
+
(void) context;
|
|
181
|
+
|
|
182
|
+
// Retrieve the OnClientItem created by the worker thread.
|
|
183
|
+
OnClientItem* item = (OnClientItem*)data;
|
|
184
|
+
ZITI_NODEJS_LOG(INFO, "CallJs_on_listen_client_connect: client: %p, status: %d", item->client, item->status);
|
|
185
|
+
|
|
186
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
187
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
188
|
+
// When env is NULL, we simply skip over the call into Javascript
|
|
189
|
+
if (env != NULL) {
|
|
190
|
+
|
|
191
|
+
// const obj = {}
|
|
192
|
+
napi_value undefined, js_client_item, js_client, js_clt_ctx, js_status, js_arb_data;
|
|
193
|
+
|
|
194
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
195
|
+
// value of the JavaScript function call.
|
|
196
|
+
status = napi_get_undefined(env, &undefined);
|
|
197
|
+
if (status != napi_ok) {
|
|
198
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
int rc = napi_create_object(env, &js_client_item);
|
|
202
|
+
if (rc != napi_ok) {
|
|
203
|
+
napi_throw_error(env, "EINVAL", "failure to create object");
|
|
204
|
+
}
|
|
205
|
+
rc = napi_create_object(env, &js_clt_ctx);
|
|
206
|
+
if (rc != napi_ok) {
|
|
207
|
+
napi_throw_error(env, "EINVAL", "failure to create object");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// js_client_item.status = status
|
|
211
|
+
rc = napi_create_int32(env, item->status, &js_status);
|
|
212
|
+
if (rc != napi_ok) {
|
|
213
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.status");
|
|
214
|
+
}
|
|
215
|
+
rc = napi_set_named_property(env, js_client_item, "status", js_status);
|
|
216
|
+
if (rc != napi_ok) {
|
|
217
|
+
napi_throw_error(env, "EINVAL", "failure to set named property status");
|
|
218
|
+
}
|
|
219
|
+
ZITI_NODEJS_LOG(DEBUG, "status: %d", item->status);
|
|
220
|
+
|
|
221
|
+
// js_client_item.js_arb_data = js_arb_data
|
|
222
|
+
if (item->js_arb_data) {
|
|
223
|
+
rc = napi_create_int64(env, item->js_arb_data, &js_arb_data);
|
|
224
|
+
if (rc != napi_ok) {
|
|
225
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.js_arb_data");
|
|
226
|
+
}
|
|
227
|
+
rc = napi_set_named_property(env, js_client_item, "js_arb_data", js_arb_data);
|
|
228
|
+
if (rc != napi_ok) {
|
|
229
|
+
napi_throw_error(env, "EINVAL", "failure to set named property status");
|
|
230
|
+
}
|
|
231
|
+
ZITI_NODEJS_LOG(DEBUG, "js_arb_data: %lld", item->js_arb_data);
|
|
232
|
+
} else {
|
|
233
|
+
rc = napi_set_named_property(env, js_client_item, "js_arb_data", undefined);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// js_client_item.client = client
|
|
237
|
+
napi_create_int64(env, (int64_t)item->client, &js_client);
|
|
238
|
+
if (rc != napi_ok) {
|
|
239
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.client");
|
|
240
|
+
}
|
|
241
|
+
rc = napi_set_named_property(env, js_client_item, "client", js_client);
|
|
242
|
+
if (rc != napi_ok) {
|
|
243
|
+
napi_throw_error(env, "EINVAL", "failure to set named property req");
|
|
244
|
+
}
|
|
245
|
+
ZITI_NODEJS_LOG(DEBUG, "client: %p", item->client);
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
ZITI_NODEJS_LOG(INFO, "calling JS on_listen_client_connect callback...");
|
|
249
|
+
|
|
250
|
+
// Call the JavaScript function and pass it the data
|
|
251
|
+
status = napi_call_function(
|
|
252
|
+
env,
|
|
253
|
+
undefined,
|
|
254
|
+
js_cb,
|
|
255
|
+
1,
|
|
256
|
+
&js_client_item,
|
|
257
|
+
NULL
|
|
258
|
+
);
|
|
259
|
+
if (status != napi_ok) {
|
|
260
|
+
napi_throw_error(env, NULL, "Unable to napi_call_function");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static void on_listen_client_connect(ziti_connection client, int status) {
|
|
267
|
+
|
|
268
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client_connect: client: %p, status: %d", client, status);
|
|
269
|
+
|
|
270
|
+
ListenAddonData* addon_data = (ListenAddonData*) ziti_conn_data(client);
|
|
271
|
+
|
|
272
|
+
OnClientItem* item = memset(malloc(sizeof(*item)), 0, sizeof(*item));
|
|
273
|
+
item->status = status;
|
|
274
|
+
item->client = client;
|
|
275
|
+
item->js_arb_data = addon_data->js_arb_data;
|
|
276
|
+
|
|
277
|
+
// Initiate the call into the JavaScript callback.
|
|
278
|
+
// The call into JavaScript will not have happened
|
|
279
|
+
// when this function returns, but it will be queued.
|
|
280
|
+
napi_status nstatus = napi_call_threadsafe_function(
|
|
281
|
+
addon_data->tsfn_on_listen_client_connect,
|
|
282
|
+
item, // Send the status we received over to the JS callback
|
|
283
|
+
napi_tsfn_blocking);
|
|
284
|
+
if (nstatus != napi_ok) {
|
|
285
|
+
ZITI_NODEJS_LOG(ERROR, "Unable to napi_call_threadsafe_function");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* This function is responsible for calling the JavaScript 'on_listen' callback function
|
|
292
|
+
* that was specified when the ziti_listen(...) was called from JavaScript.
|
|
293
|
+
*/
|
|
294
|
+
static void CallJs_on_listen(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
295
|
+
napi_status status;
|
|
296
|
+
|
|
297
|
+
// This parameter is not used.
|
|
298
|
+
(void) context;
|
|
299
|
+
|
|
300
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
301
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
302
|
+
// When env is NULL, we simply skip over the call into Javascript
|
|
303
|
+
if (env != NULL) {
|
|
304
|
+
napi_value undefined, js_rc;
|
|
305
|
+
|
|
306
|
+
ZITI_NODEJS_LOG(INFO, "CallJs_on_listen: data: %lld", (int64_t)data);
|
|
307
|
+
|
|
308
|
+
// Retrieve the rc created by the worker thread.
|
|
309
|
+
int64_t rc = (int64_t)data;
|
|
310
|
+
status = napi_create_int64(env, (int64_t)rc, &js_rc);
|
|
311
|
+
if (status != napi_ok) {
|
|
312
|
+
napi_throw_error(env, NULL, "Failed to napi_create_int64");
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
316
|
+
// value of the JavaScript function call.
|
|
317
|
+
status = napi_get_undefined(env, &undefined);
|
|
318
|
+
if (status != napi_ok) {
|
|
319
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
ZITI_NODEJS_LOG(INFO, "calling JS on_listen callback...");
|
|
323
|
+
|
|
324
|
+
// Call the JavaScript function and pass it the rc
|
|
325
|
+
status = napi_call_function(
|
|
326
|
+
env,
|
|
327
|
+
undefined,
|
|
328
|
+
js_cb,
|
|
329
|
+
1,
|
|
330
|
+
&js_rc,
|
|
331
|
+
NULL
|
|
332
|
+
);
|
|
333
|
+
ZITI_NODEJS_LOG(INFO, "returned from JS on_listen callback...");
|
|
334
|
+
if (status != napi_ok) {
|
|
335
|
+
napi_throw_error(env, NULL, "Failed to napi_call_function");
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* This function is responsible for calling the JavaScript 'data' callback function
|
|
343
|
+
* that was specified when the ziti_dial(...) was called from JavaScript.
|
|
344
|
+
*/
|
|
345
|
+
static void CallJs_on_listen_client(napi_env env, napi_value js_cb, void* context, void* data) {
|
|
346
|
+
napi_status status;
|
|
347
|
+
|
|
348
|
+
// This parameter is not used.
|
|
349
|
+
(void) context;
|
|
350
|
+
|
|
351
|
+
// Retrieve the OnClientItem created by the worker thread.
|
|
352
|
+
OnClientItem* item = (OnClientItem*)data;
|
|
353
|
+
ZITI_NODEJS_LOG(INFO, "CallJs_on_listen_client: client: %p, status: %d, caller_id: %p, app_data: %p, app_data_sz: %zu", item->client, item->status, item->caller_id, item->app_data, item->app_data_sz);
|
|
354
|
+
|
|
355
|
+
// env and js_cb may both be NULL if Node.js is in its cleanup phase, and
|
|
356
|
+
// items are left over from earlier thread-safe calls from the worker thread.
|
|
357
|
+
// When env is NULL, we simply skip over the call into Javascript and free the
|
|
358
|
+
// items.
|
|
359
|
+
if (env != NULL) {
|
|
360
|
+
|
|
361
|
+
napi_value undefined;
|
|
362
|
+
|
|
363
|
+
// const obj = {}
|
|
364
|
+
napi_value js_client_item, js_client, js_clt_ctx, js_status, js_arb_data, js_caller_id, js_buffer;
|
|
365
|
+
void* result_data;
|
|
366
|
+
|
|
367
|
+
// Retrieve the JavaScript `undefined` value so we can use it as the `this`
|
|
368
|
+
// value of the JavaScript function call.
|
|
369
|
+
status = napi_get_undefined(env, &undefined);
|
|
370
|
+
if (status != napi_ok) {
|
|
371
|
+
napi_throw_error(env, NULL, "Unable to napi_get_undefined (3)");
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
int rc = napi_create_object(env, &js_client_item);
|
|
375
|
+
if (rc != napi_ok) {
|
|
376
|
+
napi_throw_error(env, "EINVAL", "failure to create object");
|
|
377
|
+
}
|
|
378
|
+
rc = napi_create_object(env, &js_clt_ctx);
|
|
379
|
+
if (rc != napi_ok) {
|
|
380
|
+
napi_throw_error(env, "EINVAL", "failure to create object");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// js_client_item.status = status
|
|
384
|
+
rc = napi_create_int32(env, item->status, &js_status);
|
|
385
|
+
if (rc != napi_ok) {
|
|
386
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.status");
|
|
387
|
+
}
|
|
388
|
+
rc = napi_set_named_property(env, js_client_item, "status", js_status);
|
|
389
|
+
if (rc != napi_ok) {
|
|
390
|
+
napi_throw_error(env, "EINVAL", "failure to set named property status");
|
|
391
|
+
}
|
|
392
|
+
ZITI_NODEJS_LOG(DEBUG, "status: %d", item->status);
|
|
393
|
+
|
|
394
|
+
// js_client_item.js_arb_data = js_arb_data
|
|
395
|
+
if (item->js_arb_data) {
|
|
396
|
+
rc = napi_create_int64(env, item->js_arb_data, &js_arb_data);
|
|
397
|
+
if (rc != napi_ok) {
|
|
398
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.js_arb_data");
|
|
399
|
+
}
|
|
400
|
+
rc = napi_set_named_property(env, js_client_item, "js_arb_data", js_arb_data);
|
|
401
|
+
if (rc != napi_ok) {
|
|
402
|
+
napi_throw_error(env, "EINVAL", "failure to set named property status");
|
|
403
|
+
}
|
|
404
|
+
ZITI_NODEJS_LOG(DEBUG, "js_arb_data: %lld", item->js_arb_data);
|
|
405
|
+
} else {
|
|
406
|
+
rc = napi_set_named_property(env, js_client_item, "js_arb_data", undefined);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// js_client_item.client = client
|
|
410
|
+
napi_create_int64(env, (int64_t)item->client, &js_client);
|
|
411
|
+
if (rc != napi_ok) {
|
|
412
|
+
napi_throw_error(env, "EINVAL", "failure to create obj.client");
|
|
413
|
+
}
|
|
414
|
+
rc = napi_set_named_property(env, js_client_item, "client", js_client);
|
|
415
|
+
if (rc != napi_ok) {
|
|
416
|
+
napi_throw_error(env, "EINVAL", "failure to set named property req");
|
|
417
|
+
}
|
|
418
|
+
ZITI_NODEJS_LOG(DEBUG, "client: %p", item->client);
|
|
419
|
+
|
|
420
|
+
// js_clt_ctx.caller_id = caller_id
|
|
421
|
+
if (NULL != item->caller_id) {
|
|
422
|
+
rc = napi_create_string_utf8(env, (const char*)item->caller_id, strlen(item->caller_id), &js_caller_id);
|
|
423
|
+
if (rc != napi_ok) {
|
|
424
|
+
napi_throw_error(env, "EINVAL", "failure to create js_clt_ctx.caller_id");
|
|
425
|
+
}
|
|
426
|
+
rc = napi_set_named_property(env, js_clt_ctx, "caller_id", js_caller_id);
|
|
427
|
+
if (rc != napi_ok) {
|
|
428
|
+
napi_throw_error(env, "EINVAL", "failure to set named property caller_id");
|
|
429
|
+
}
|
|
430
|
+
ZITI_NODEJS_LOG(DEBUG, "caller_id: %s", item->caller_id);
|
|
431
|
+
} else {
|
|
432
|
+
rc = napi_set_named_property(env, js_clt_ctx, "caller_id", undefined);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// js_clt_ctx.app_data = app_data
|
|
436
|
+
if (NULL != item->app_data) {
|
|
437
|
+
rc = napi_create_buffer_copy(env, item->app_data_sz, (const void*)item->app_data, (void**)&result_data, &js_buffer);
|
|
438
|
+
if (rc != napi_ok) {
|
|
439
|
+
napi_throw_error(env, "EINVAL", "failure to create js_clt_ctx.app_data");
|
|
440
|
+
}
|
|
441
|
+
rc = napi_set_named_property(env, js_clt_ctx, "app_data", js_buffer);
|
|
442
|
+
if (rc != napi_ok) {
|
|
443
|
+
napi_throw_error(env, "EINVAL", "failure to set named property app_data");
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
446
|
+
rc = napi_set_named_property(env, js_clt_ctx, "app_data", undefined);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// js_client_item.clt_ctx = js_clt_ctx
|
|
450
|
+
rc = napi_set_named_property(env, js_client_item, "clt_ctx", js_clt_ctx);
|
|
451
|
+
if (rc != napi_ok) {
|
|
452
|
+
napi_throw_error(env, "EINVAL", "failure to set named property js_clt_ctx");
|
|
453
|
+
}
|
|
454
|
+
ZITI_NODEJS_LOG(DEBUG, "js_clt_ctx added");
|
|
455
|
+
|
|
456
|
+
// Call the JavaScript function and pass it the data
|
|
457
|
+
status = napi_call_function(
|
|
458
|
+
env,
|
|
459
|
+
undefined,
|
|
460
|
+
js_cb,
|
|
461
|
+
1,
|
|
462
|
+
&js_client_item,
|
|
463
|
+
NULL
|
|
464
|
+
);
|
|
465
|
+
if (status != napi_ok) {
|
|
466
|
+
napi_throw_error(env, NULL, "Unable to napi_call_function");
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
*
|
|
475
|
+
*/
|
|
476
|
+
void on_listen_client(ziti_connection serv, ziti_connection client, int status, ziti_client_ctx *clt_ctx) {
|
|
477
|
+
|
|
478
|
+
ZITI_NODEJS_LOG(INFO, "on_listen_client: client: %p, status: %d, clt_ctx: %p", client, status, clt_ctx);
|
|
479
|
+
|
|
480
|
+
napi_status nstatus;
|
|
481
|
+
|
|
482
|
+
ListenAddonData* addon_data = (ListenAddonData*) ziti_conn_data(serv);
|
|
483
|
+
|
|
484
|
+
if (status == ZITI_OK) {
|
|
485
|
+
|
|
486
|
+
ziti_conn_set_data(client, addon_data);
|
|
487
|
+
|
|
488
|
+
const char *source_identity = clt_ctx->caller_id;
|
|
489
|
+
if (source_identity != NULL) {
|
|
490
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client: incoming connection from '%s'", source_identity );
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client: incoming connection from unidentified client" );
|
|
494
|
+
}
|
|
495
|
+
if (clt_ctx->app_data != NULL) {
|
|
496
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client: got app data '%.*s'!", (int) clt_ctx->app_data_sz, clt_ctx->app_data );
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
ziti_accept(client, on_listen_client_connect, on_listen_client_data);
|
|
500
|
+
|
|
501
|
+
} else {
|
|
502
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen_client: failed to accept client: %s(%d)\n", ziti_errorstr(status), status );
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
OnClientItem* item = memset(malloc(sizeof(*item)), 0, sizeof(*item));
|
|
506
|
+
item->status = status;
|
|
507
|
+
item->js_arb_data = addon_data->js_arb_data;
|
|
508
|
+
item->client = client;
|
|
509
|
+
item->caller_id = strdup(clt_ctx->caller_id);
|
|
510
|
+
if (NULL != clt_ctx->app_data) {
|
|
511
|
+
item->app_data_sz = clt_ctx->app_data_sz;
|
|
512
|
+
item->app_data = calloc(1, clt_ctx->app_data_sz + 1);
|
|
513
|
+
memcpy((void*)item->app_data, clt_ctx->app_data, clt_ctx->app_data_sz);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Initiate the call into the JavaScript callback.
|
|
517
|
+
// The call into JavaScript will not have happened
|
|
518
|
+
// when this function returns, but it will be queued.
|
|
519
|
+
nstatus = napi_call_threadsafe_function(
|
|
520
|
+
addon_data->tsfn_on_listen_client,
|
|
521
|
+
item, // Send the client ctx we received over to the JS callback
|
|
522
|
+
napi_tsfn_blocking);
|
|
523
|
+
if (nstatus != napi_ok) {
|
|
524
|
+
ZITI_NODEJS_LOG(ERROR, "Unable to napi_call_threadsafe_function");
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
*
|
|
532
|
+
*/
|
|
533
|
+
void on_listen(ziti_connection serv, int status) {
|
|
534
|
+
napi_status nstatus;
|
|
535
|
+
|
|
536
|
+
ListenAddonData* addon_data = (ListenAddonData*) ziti_conn_data(serv);
|
|
537
|
+
|
|
538
|
+
if (status == ZITI_OK) {
|
|
539
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen: successfully bound to service[%s]", addon_data->service_name );
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
ZITI_NODEJS_LOG(DEBUG, "on_listen: failed to bind to service[%s]\n", addon_data->service_name );
|
|
543
|
+
ziti_close(serv, NULL);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Initiate the call into the JavaScript callback.
|
|
547
|
+
// The call into JavaScript will not have happened
|
|
548
|
+
// when this function returns, but it will be queued.
|
|
549
|
+
nstatus = napi_call_threadsafe_function(
|
|
550
|
+
addon_data->tsfn_on_listen,
|
|
551
|
+
(void*)(int64_t)status, // Send the status over to the JS callback
|
|
552
|
+
napi_tsfn_blocking);
|
|
553
|
+
if (nstatus != napi_ok) {
|
|
554
|
+
ZITI_NODEJS_LOG(ERROR, "Unable to napi_call_threadsafe_function");
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
*
|
|
561
|
+
*/
|
|
562
|
+
napi_value _ziti_listen(napi_env env, const napi_callback_info info) {
|
|
563
|
+
|
|
564
|
+
napi_status status;
|
|
565
|
+
size_t argc = 6;
|
|
566
|
+
napi_value args[6];
|
|
567
|
+
status = napi_get_cb_info(env, info, &argc, args, NULL, NULL);
|
|
568
|
+
if (status != napi_ok) {
|
|
569
|
+
napi_throw_error(env, NULL, "Failed to parse arguments");
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (argc < 6) {
|
|
573
|
+
napi_throw_error(env, "EINVAL", "Too few arguments");
|
|
574
|
+
return NULL;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Obtain service name
|
|
578
|
+
size_t result;
|
|
579
|
+
char ServiceName[256]; //TODO: make this smarter
|
|
580
|
+
status = napi_get_value_string_utf8(env, args[0], ServiceName, 256, &result);
|
|
581
|
+
if (status != napi_ok) {
|
|
582
|
+
napi_throw_error(env, NULL, "Failed to get Service Name");
|
|
583
|
+
}
|
|
584
|
+
ZITI_NODEJS_LOG(DEBUG, "ServiceName: %s", ServiceName);
|
|
585
|
+
|
|
586
|
+
ListenAddonData* addon_data = memset(malloc(sizeof(*addon_data)), 0, sizeof(*addon_data));
|
|
587
|
+
|
|
588
|
+
// Obtain (optional) arbitrary-data value
|
|
589
|
+
int64_t js_arb_data;
|
|
590
|
+
status = napi_get_value_int64(env, args[1], &js_arb_data);
|
|
591
|
+
if (status != napi_ok) {
|
|
592
|
+
napi_throw_error(env, NULL, "Failed to get js_arb_data");
|
|
593
|
+
}
|
|
594
|
+
addon_data->js_arb_data = js_arb_data;
|
|
595
|
+
ZITI_NODEJS_LOG(DEBUG, "js_arb_data: %lld", js_arb_data);
|
|
596
|
+
|
|
597
|
+
// Obtain ptr to JS 'on_listen' callback function
|
|
598
|
+
napi_value js_on_listen = args[2];
|
|
599
|
+
napi_value work_name_listen;
|
|
600
|
+
|
|
601
|
+
// Create a string to describe this asynchronous operation.
|
|
602
|
+
status = napi_create_string_utf8(
|
|
603
|
+
env,
|
|
604
|
+
"N-API on_listen",
|
|
605
|
+
NAPI_AUTO_LENGTH,
|
|
606
|
+
&work_name_listen);
|
|
607
|
+
if (status != napi_ok) {
|
|
608
|
+
napi_throw_error(env, NULL, "Unable to napi_create_string_utf8");
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
612
|
+
// which we can call from a worker thread.
|
|
613
|
+
status = napi_create_threadsafe_function(
|
|
614
|
+
env,
|
|
615
|
+
js_on_listen,
|
|
616
|
+
NULL,
|
|
617
|
+
work_name_listen,
|
|
618
|
+
0,
|
|
619
|
+
1,
|
|
620
|
+
NULL,
|
|
621
|
+
NULL,
|
|
622
|
+
NULL,
|
|
623
|
+
CallJs_on_listen,
|
|
624
|
+
&(addon_data->tsfn_on_listen));
|
|
625
|
+
if (status != napi_ok) {
|
|
626
|
+
napi_throw_error(env, NULL, "Unable to napi_create_threadsafe_function");
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Obtain ptr to JS 'on_listen_client' callback function
|
|
630
|
+
napi_value js_on_listen_client = args[3];
|
|
631
|
+
napi_value work_name_client;
|
|
632
|
+
|
|
633
|
+
// Create a string to describe this asynchronous operation.
|
|
634
|
+
status = napi_create_string_utf8(
|
|
635
|
+
env,
|
|
636
|
+
"N-API on_listen_client",
|
|
637
|
+
NAPI_AUTO_LENGTH,
|
|
638
|
+
&work_name_client);
|
|
639
|
+
if (status != napi_ok) {
|
|
640
|
+
napi_throw_error(env, NULL, "Unable to napi_create_string_utf8");
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
644
|
+
// which we can call from a worker thread.
|
|
645
|
+
status = napi_create_threadsafe_function(
|
|
646
|
+
env,
|
|
647
|
+
js_on_listen_client,
|
|
648
|
+
NULL,
|
|
649
|
+
work_name_client,
|
|
650
|
+
0,
|
|
651
|
+
1,
|
|
652
|
+
NULL,
|
|
653
|
+
NULL,
|
|
654
|
+
NULL,
|
|
655
|
+
CallJs_on_listen_client,
|
|
656
|
+
&(addon_data->tsfn_on_listen_client));
|
|
657
|
+
if (status != napi_ok) {
|
|
658
|
+
napi_throw_error(env, NULL, "Unable to napi_create_threadsafe_function");
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Obtain ptr to JS 'on_listen_client_connect' callback function
|
|
662
|
+
napi_value js_on_listen_client_connect = args[4];
|
|
663
|
+
|
|
664
|
+
// Create a string to describe this asynchronous operation.
|
|
665
|
+
status = napi_create_string_utf8(
|
|
666
|
+
env,
|
|
667
|
+
"N-API on_listen_client_connect",
|
|
668
|
+
NAPI_AUTO_LENGTH,
|
|
669
|
+
&work_name_client);
|
|
670
|
+
if (status != napi_ok) {
|
|
671
|
+
napi_throw_error(env, NULL, "Unable to napi_create_string_utf8");
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
675
|
+
// which we can call from a worker thread.
|
|
676
|
+
status = napi_create_threadsafe_function(
|
|
677
|
+
env,
|
|
678
|
+
js_on_listen_client_connect,
|
|
679
|
+
NULL,
|
|
680
|
+
work_name_client,
|
|
681
|
+
0,
|
|
682
|
+
1,
|
|
683
|
+
NULL,
|
|
684
|
+
NULL,
|
|
685
|
+
NULL,
|
|
686
|
+
CallJs_on_listen_client_connect,
|
|
687
|
+
&(addon_data->tsfn_on_listen_client_connect));
|
|
688
|
+
if (status != napi_ok) {
|
|
689
|
+
napi_throw_error(env, NULL, "Unable to napi_create_threadsafe_function");
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Obtain ptr to JS 'on_listen_client_data' callback function
|
|
693
|
+
napi_value js_on_listen_client_data = args[5];
|
|
694
|
+
|
|
695
|
+
// Create a string to describe this asynchronous operation.
|
|
696
|
+
status = napi_create_string_utf8(
|
|
697
|
+
env,
|
|
698
|
+
"N-API on_listen_client_data",
|
|
699
|
+
NAPI_AUTO_LENGTH,
|
|
700
|
+
&work_name_client);
|
|
701
|
+
if (status != napi_ok) {
|
|
702
|
+
napi_throw_error(env, NULL, "Unable to napi_create_string_utf8");
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Convert the callback retrieved from JavaScript into a thread-safe function (tsfn)
|
|
706
|
+
// which we can call from a worker thread.
|
|
707
|
+
status = napi_create_threadsafe_function(
|
|
708
|
+
env,
|
|
709
|
+
js_on_listen_client_data,
|
|
710
|
+
NULL,
|
|
711
|
+
work_name_client,
|
|
712
|
+
0,
|
|
713
|
+
1,
|
|
714
|
+
NULL,
|
|
715
|
+
NULL,
|
|
716
|
+
NULL,
|
|
717
|
+
CallJs_on_listen_client_data,
|
|
718
|
+
&(addon_data->tsfn_on_listen_client_data));
|
|
719
|
+
if (status != napi_ok) {
|
|
720
|
+
napi_throw_error(env, NULL, "Unable to napi_create_threadsafe_function");
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Init a Ziti connection object, and attach our add-on data to it so we can
|
|
724
|
+
// pass context around between our callbacks, as propagate it all the way out
|
|
725
|
+
// to the JavaScript callbacks
|
|
726
|
+
addon_data->service_name = strdup(ServiceName);
|
|
727
|
+
int rc = ziti_conn_init(ztx, &addon_data->server, addon_data);
|
|
728
|
+
if (rc != ZITI_OK) {
|
|
729
|
+
napi_throw_error(env, NULL, "failure in 'ziti_conn_init");
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Start listening
|
|
733
|
+
ZITI_NODEJS_LOG(DEBUG, "calling ziti_listen_with_options: %p, addon_data: %p", ztx, addon_data);
|
|
734
|
+
ziti_listen_opts listen_opts = {
|
|
735
|
+
.bind_using_edge_identity = false,
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
ziti_listen_with_options(addon_data->server, ServiceName, &listen_opts, on_listen, on_listen_client);
|
|
739
|
+
// ziti_listen_with_options(addon_data->server, ServiceName, NULL, on_listen, on_listen_client);
|
|
740
|
+
|
|
741
|
+
return NULL;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
*
|
|
748
|
+
*/
|
|
749
|
+
void expose_ziti_listen(napi_env env, napi_value exports) {
|
|
750
|
+
napi_status status;
|
|
751
|
+
napi_value fn;
|
|
752
|
+
|
|
753
|
+
status = napi_create_function(env, NULL, 0, _ziti_listen, NULL, &fn);
|
|
754
|
+
if (status != napi_ok) {
|
|
755
|
+
napi_throw_error(env, NULL, "Unable to wrap native function '_ziti_listen");
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
status = napi_set_named_property(env, exports, "ziti_listen", fn);
|
|
759
|
+
if (status != napi_ok) {
|
|
760
|
+
napi_throw_error(env, NULL, "Unable to populate exports for 'ziti_listen");
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
}
|
|
764
|
+
|