xbintsc 0.2.9 → 0.3.3
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/README.md +17 -2
- package/README.zh-CN.md +16 -2
- package/bin/xbintsc.js +49 -10
- package/dist/src/ast/expressions.d.ts +2 -0
- package/dist/src/binder/binder.d.ts +24 -98
- package/dist/src/binder/binder.js +13 -559
- package/dist/src/binder/binder.js.map +1 -1
- package/dist/src/binder/declarations.d.ts +16 -0
- package/dist/src/binder/declarations.js +168 -0
- package/dist/src/binder/declarations.js.map +1 -0
- package/dist/src/binder/helpers.d.ts +11 -0
- package/dist/src/binder/helpers.js +46 -0
- package/dist/src/binder/helpers.js.map +1 -0
- package/dist/src/binder/references.d.ts +21 -0
- package/dist/src/binder/references.js +349 -0
- package/dist/src/binder/references.js.map +1 -0
- package/dist/src/binder/types.d.ts +114 -0
- package/dist/src/binder/types.js +27 -0
- package/dist/src/binder/types.js.map +1 -0
- package/dist/src/cli/main.d.ts +1 -0
- package/dist/src/cli/main.js +40 -0
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.d.ts +13 -0
- package/dist/src/codegen/generator/calls/access.js +115 -0
- package/dist/src/codegen/generator/calls/access.js.map +1 -0
- package/dist/src/codegen/generator/calls/closures.d.ts +11 -0
- package/dist/src/codegen/generator/calls/closures.js +50 -0
- package/dist/src/codegen/generator/calls/closures.js.map +1 -0
- package/dist/src/codegen/generator/calls/invocation.d.ts +18 -0
- package/dist/src/codegen/generator/calls/invocation.js +242 -0
- package/dist/src/codegen/generator/calls/invocation.js.map +1 -0
- package/dist/src/codegen/generator/calls/literals.d.ts +10 -0
- package/dist/src/codegen/generator/calls/literals.js +69 -0
- package/dist/src/codegen/generator/calls/literals.js.map +1 -0
- package/dist/src/codegen/generator/calls/super.d.ts +10 -0
- package/dist/src/codegen/generator/calls/super.js +47 -0
- package/dist/src/codegen/generator/calls/super.js.map +1 -0
- package/dist/src/codegen/generator/calls.d.ts +15 -24
- package/dist/src/codegen/generator/calls.js +15 -482
- package/dist/src/codegen/generator/calls.js.map +1 -1
- package/dist/src/codegen/generator/context.d.ts +1 -1
- package/dist/src/codegen/generator/context.js +2 -2
- package/dist/src/codegen/generator/context.js.map +1 -1
- package/dist/src/codegen/generator/expressions/assignment.d.ts +13 -0
- package/dist/src/codegen/generator/expressions/assignment.js +203 -0
- package/dist/src/codegen/generator/expressions/assignment.js.map +1 -0
- package/dist/src/codegen/generator/expressions/operators.d.ts +14 -0
- package/dist/src/codegen/generator/expressions/operators.js +163 -0
- package/dist/src/codegen/generator/expressions/operators.js.map +1 -0
- package/dist/src/codegen/generator/expressions/primary.d.ts +17 -0
- package/dist/src/codegen/generator/expressions/primary.js +260 -0
- package/dist/src/codegen/generator/expressions/primary.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +11 -21
- package/dist/src/codegen/generator/expressions.js +11 -494
- package/dist/src/codegen/generator/expressions.js.map +1 -1
- package/dist/src/codegen/generator/module.js +16 -4
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/statements/control-flow.d.ts +14 -0
- package/dist/src/codegen/generator/statements/control-flow.js +199 -0
- package/dist/src/codegen/generator/statements/control-flow.js.map +1 -0
- package/dist/src/codegen/generator/statements/dispatch.d.ts +12 -0
- package/dist/src/codegen/generator/statements/dispatch.js +100 -0
- package/dist/src/codegen/generator/statements/dispatch.js.map +1 -0
- package/dist/src/codegen/generator/statements/loops.d.ts +13 -0
- package/dist/src/codegen/generator/statements/loops.js +152 -0
- package/dist/src/codegen/generator/statements/loops.js.map +1 -0
- package/dist/src/codegen/generator/statements/variables.d.ts +13 -0
- package/dist/src/codegen/generator/statements/variables.js +146 -0
- package/dist/src/codegen/generator/statements/variables.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +13 -21
- package/dist/src/codegen/generator/statements.js +13 -568
- package/dist/src/codegen/generator/statements.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +7 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/codegen/values.d.ts +17 -17
- package/dist/src/codegen/values.js +21 -57
- package/dist/src/codegen/values.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +1 -0
- package/dist/src/diagnostics/diagnostic.js +1 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/diagnostics/source.d.ts +1 -1
- package/dist/src/diagnostics/source.js +7 -12
- package/dist/src/diagnostics/source.js.map +1 -1
- package/dist/src/driver/compiler.d.ts +4 -0
- package/dist/src/driver/compiler.js +51 -16
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/index.d.ts +5 -2
- package/dist/src/driver/index.js +5 -2
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/paths.d.ts +20 -0
- package/dist/src/driver/paths.js +49 -0
- package/dist/src/driver/paths.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +18 -0
- package/dist/src/driver/runtime-lib.js +31 -0
- package/dist/src/driver/runtime-lib.js.map +1 -0
- package/dist/src/driver/toolchain-download.d.ts +50 -0
- package/dist/src/driver/toolchain-download.js +76 -0
- package/dist/src/driver/toolchain-download.js.map +1 -0
- package/dist/src/driver/toolchain-provider.d.ts +33 -0
- package/dist/src/driver/toolchain-provider.js +71 -0
- package/dist/src/driver/toolchain-provider.js.map +1 -0
- package/dist/src/driver/toolchain.d.ts +9 -4
- package/dist/src/driver/toolchain.js +6 -10
- package/dist/src/driver/toolchain.js.map +1 -1
- package/dist/src/extensions/node/child_process/index.d.ts +4 -2
- package/dist/src/extensions/node/child_process/index.js +4 -2
- package/dist/src/extensions/node/child_process/index.js.map +1 -1
- package/dist/src/extensions/node/events/index.d.ts +10 -0
- package/dist/src/extensions/node/events/index.js +22 -0
- package/dist/src/extensions/node/events/index.js.map +1 -0
- package/dist/src/extensions/node/index.js +6 -0
- package/dist/src/extensions/node/index.js.map +1 -1
- package/dist/src/extensions/node/querystring/index.d.ts +10 -0
- package/dist/src/extensions/node/querystring/index.js +25 -0
- package/dist/src/extensions/node/querystring/index.js.map +1 -0
- package/dist/src/extensions/node/util/index.d.ts +11 -0
- package/dist/src/extensions/node/util/index.js +41 -0
- package/dist/src/extensions/node/util/index.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +6 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.d.ts +9 -0
- package/dist/src/lexer/scanner/identifiers.js +33 -0
- package/dist/src/lexer/scanner/identifiers.js.map +1 -0
- package/dist/src/lexer/scanner/numbers.d.ts +10 -0
- package/dist/src/lexer/scanner/numbers.js +89 -0
- package/dist/src/lexer/scanner/numbers.js.map +1 -0
- package/dist/src/lexer/scanner/punctuation.d.ts +9 -0
- package/dist/src/lexer/scanner/punctuation.js +151 -0
- package/dist/src/lexer/scanner/punctuation.js.map +1 -0
- package/dist/src/lexer/scanner/regex.d.ts +11 -0
- package/dist/src/lexer/scanner/regex.js +69 -0
- package/dist/src/lexer/scanner/regex.js.map +1 -0
- package/dist/src/lexer/scanner/strings.d.ts +13 -0
- package/dist/src/lexer/scanner/strings.js +118 -0
- package/dist/src/lexer/scanner/strings.js.map +1 -0
- package/dist/src/lexer/scanner.d.ts +20 -27
- package/dist/src/lexer/scanner.js +11 -415
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/declarations/classes.d.ts +14 -0
- package/dist/src/parser/declarations/classes.js +191 -0
- package/dist/src/parser/declarations/classes.js.map +1 -0
- package/dist/src/parser/declarations/functions.d.ts +17 -0
- package/dist/src/parser/declarations/functions.js +241 -0
- package/dist/src/parser/declarations/functions.js.map +1 -0
- package/dist/src/parser/declarations/type-members.d.ts +16 -0
- package/dist/src/parser/declarations/type-members.js +156 -0
- package/dist/src/parser/declarations/type-members.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +13 -24
- package/dist/src/parser/declarations.js +13 -571
- package/dist/src/parser/declarations.js.map +1 -1
- package/dist/src/parser/helpers.js +13 -4
- package/dist/src/parser/helpers.js.map +1 -1
- package/dist/src/parser/literals.js +10 -1
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/codegen/llvm.test.js +24 -0
- package/dist/tests/codegen/llvm.test.js.map +1 -1
- package/dist/tests/driver/compiler.test.js +3 -0
- package/dist/tests/driver/compiler.test.js.map +1 -1
- package/dist/tests/driver/paths.test.d.ts +1 -0
- package/dist/tests/driver/paths.test.js +26 -0
- package/dist/tests/driver/paths.test.js.map +1 -0
- package/dist/tests/driver/toolchain-download.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-download.test.js +38 -0
- package/dist/tests/driver/toolchain-download.test.js.map +1 -0
- package/dist/tests/driver/toolchain-provider.test.d.ts +1 -0
- package/dist/tests/driver/toolchain-provider.test.js +37 -0
- package/dist/tests/driver/toolchain-provider.test.js.map +1 -0
- package/dist/tests/e2e/compile-node.test.d.ts +7 -0
- package/dist/tests/e2e/compile-node.test.js +123 -0
- package/dist/tests/e2e/compile-node.test.js.map +1 -0
- package/dist/tests/e2e/compile.test.d.ts +4 -1
- package/dist/tests/e2e/compile.test.js +78 -130
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/e2e/harness.d.ts +36 -0
- package/dist/tests/e2e/harness.js +64 -0
- package/dist/tests/e2e/harness.js.map +1 -0
- package/dist/tests/e2e/node-modules.test.js +60 -0
- package/dist/tests/e2e/node-modules.test.js.map +1 -1
- package/dist/tests/extensions/registry.test.js +4 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/package.json +5 -3
- package/runtime/ext_node/buffer/buffer.c +12 -552
- package/runtime/ext_node/buffer/parts/byte-access.inc +35 -0
- package/runtime/ext_node/buffer/parts/construction.inc +60 -0
- package/runtime/ext_node/buffer/parts/integer-io.inc +119 -0
- package/runtime/ext_node/buffer/parts/methods.inc +135 -0
- package/runtime/ext_node/buffer/parts/prototype.inc +54 -0
- package/runtime/ext_node/buffer/parts/search.inc +86 -0
- package/runtime/ext_node/buffer/parts/static-api.inc +58 -0
- package/runtime/ext_node/child_process/child_process.c +37 -3
- package/runtime/ext_node/events/events.c +285 -0
- package/runtime/ext_node/http/http.c +11 -736
- package/runtime/ext_node/http/parts/client.inc +290 -0
- package/runtime/ext_node/http/parts/helpers.inc +45 -0
- package/runtime/ext_node/http/parts/prototypes.inc +57 -0
- package/runtime/ext_node/http/parts/response.inc +149 -0
- package/runtime/ext_node/http/parts/server.inc +133 -0
- package/runtime/ext_node/http/parts/string-builder.inc +58 -0
- package/runtime/ext_node/net/net.c +12 -504
- package/runtime/ext_node/net/parts/construction.inc +22 -0
- package/runtime/ext_node/net/parts/platform.inc +60 -0
- package/runtime/ext_node/net/parts/prototypes.inc +35 -0
- package/runtime/ext_node/net/parts/read-loop.inc +58 -0
- package/runtime/ext_node/net/parts/server.inc +131 -0
- package/runtime/ext_node/net/parts/socket-methods.inc +100 -0
- package/runtime/ext_node/net/parts/static-api.inc +93 -0
- package/runtime/ext_node/querystring/querystring.c +251 -0
- package/runtime/ext_node/util/util.c +456 -0
- package/runtime/rt.h +8 -2
- package/runtime/rt_internal.h +34 -0
- package/runtime/xt_bigint/arithmetic.inc +135 -0
- package/runtime/xt_bigint/bits.inc +98 -0
- package/runtime/xt_bigint/bitwise.inc +103 -0
- package/runtime/xt_bigint/compare.inc +30 -0
- package/runtime/xt_bigint/conversions.inc +51 -0
- package/runtime/xt_bigint/division.inc +85 -0
- package/runtime/xt_bigint/format.inc +145 -0
- package/runtime/xt_bigint/helpers.inc +92 -0
- package/runtime/xt_bigint/magnitude.inc +88 -0
- package/runtime/xt_bigint/public.inc +59 -0
- package/runtime/xt_bigint/small-arithmetic.inc +58 -0
- package/runtime/xt_bigint.c +42 -0
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_io.c +7 -0
- package/runtime/xt_stdlib/arrays.inc +161 -0
- package/runtime/xt_stdlib/dispatch.inc +116 -0
- package/runtime/xt_stdlib/helpers.inc +23 -0
- package/runtime/xt_stdlib/math.inc +72 -0
- package/runtime/xt_stdlib/strings.inc +178 -0
- package/runtime/xt_stdlib.c +10 -549
- package/runtime/xt_stdlib2/array-statics.inc +37 -0
- package/runtime/xt_stdlib2/arrays.inc +189 -0
- package/runtime/xt_stdlib2/container.inc +23 -0
- package/runtime/xt_stdlib2/date.inc +72 -0
- package/runtime/xt_stdlib2/error.inc +22 -0
- package/runtime/xt_stdlib2/helpers.inc +43 -0
- package/runtime/xt_stdlib2/json.inc +213 -0
- package/runtime/xt_stdlib2/map.inc +95 -0
- package/runtime/xt_stdlib2/number-string-statics.inc +73 -0
- package/runtime/xt_stdlib2/numbers.inc +38 -0
- package/runtime/xt_stdlib2/objects.inc +41 -0
- package/runtime/xt_stdlib2/regexp-match.inc +204 -0
- package/runtime/xt_stdlib2/regexp.inc +20 -0
- package/runtime/xt_stdlib2/set.inc +105 -0
- package/runtime/xt_stdlib2/strings.inc +94 -0
- package/runtime/xt_stdlib2.c +19 -1278
- package/runtime/xt_values.c +155 -12
- package/scripts/build-runtime.ts +109 -0
- package/scripts/fetch-toolchain.ts +101 -0
- package/scripts/package-release.ts +192 -0
- package/src/ast/expressions.ts +2 -0
- package/src/binder/binder.ts +40 -725
- package/src/binder/declarations.ts +203 -0
- package/src/binder/helpers.ts +47 -0
- package/src/binder/references.ts +410 -0
- package/src/binder/types.ts +134 -0
- package/src/cli/main.ts +43 -0
- package/src/codegen/generator/calls/access.ts +139 -0
- package/src/codegen/generator/calls/closures.ts +60 -0
- package/src/codegen/generator/calls/invocation.ts +282 -0
- package/src/codegen/generator/calls/literals.ts +77 -0
- package/src/codegen/generator/calls/super.ts +61 -0
- package/src/codegen/generator/calls.ts +30 -552
- package/src/codegen/generator/context.ts +2 -2
- package/src/codegen/generator/expressions/assignment.ts +226 -0
- package/src/codegen/generator/expressions/operators.ts +182 -0
- package/src/codegen/generator/expressions/primary.ts +304 -0
- package/src/codegen/generator/expressions.ts +22 -553
- package/src/codegen/generator/module.ts +14 -4
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/statements/control-flow.ts +225 -0
- package/src/codegen/generator/statements/dispatch.ts +122 -0
- package/src/codegen/generator/statements/loops.ts +173 -0
- package/src/codegen/generator/statements/variables.ts +152 -0
- package/src/codegen/generator/statements.ts +26 -612
- package/src/codegen/generator/tables.ts +7 -0
- package/src/codegen/values.ts +22 -57
- package/src/diagnostics/diagnostic.ts +1 -0
- package/src/diagnostics/source.ts +7 -12
- package/src/driver/compiler.ts +61 -18
- package/src/driver/index.ts +17 -2
- package/src/driver/paths.ts +54 -0
- package/src/driver/runtime-lib.ts +32 -0
- package/src/driver/toolchain-download.ts +108 -0
- package/src/driver/toolchain-provider.ts +91 -0
- package/src/driver/toolchain.ts +29 -11
- package/src/extensions/node/child_process/index.ts +4 -2
- package/src/extensions/node/events/index.ts +27 -0
- package/src/extensions/node/index.ts +6 -0
- package/src/extensions/node/querystring/index.ts +29 -0
- package/src/extensions/node/util/index.ts +48 -0
- package/src/extensions/registry.ts +6 -0
- package/src/index.ts +1 -0
- package/src/lexer/scanner/identifiers.ts +37 -0
- package/src/lexer/scanner/numbers.ts +84 -0
- package/src/lexer/scanner/punctuation.ts +132 -0
- package/src/lexer/scanner/regex.ts +79 -0
- package/src/lexer/scanner/strings.ts +128 -0
- package/src/lexer/scanner.ts +35 -401
- package/src/parser/declarations/classes.ts +215 -0
- package/src/parser/declarations/functions.ts +254 -0
- package/src/parser/declarations/type-members.ts +181 -0
- package/src/parser/declarations.ts +32 -609
- package/src/parser/helpers.ts +13 -6
- package/src/parser/literals.ts +10 -1
- package/scripts/build-runtime.mjs +0 -55
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* -- tiny string builder -------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
typedef struct {
|
|
4
|
+
char *data;
|
|
5
|
+
size_t length;
|
|
6
|
+
size_t capacity;
|
|
7
|
+
} xt_http_buffer;
|
|
8
|
+
|
|
9
|
+
static void xt_http_buffer_init(xt_http_buffer *buffer) {
|
|
10
|
+
buffer->capacity = 256;
|
|
11
|
+
buffer->length = 0;
|
|
12
|
+
buffer->data = (char *)malloc(buffer->capacity);
|
|
13
|
+
buffer->data[0] = '\0';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static void xt_http_buffer_append(xt_http_buffer *buffer, const char *data, size_t length) {
|
|
17
|
+
if (buffer->length + length + 1 > buffer->capacity) {
|
|
18
|
+
while (buffer->length + length + 1 > buffer->capacity) buffer->capacity *= 2;
|
|
19
|
+
buffer->data = (char *)realloc(buffer->data, buffer->capacity);
|
|
20
|
+
}
|
|
21
|
+
memcpy(buffer->data + buffer->length, data, length);
|
|
22
|
+
buffer->length += length;
|
|
23
|
+
buffer->data[buffer->length] = '\0';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static void xt_http_buffer_free(xt_http_buffer *buffer) { free(buffer->data); }
|
|
27
|
+
|
|
28
|
+
/* Parse `name: value` header lines into an object with lower-cased keys. */
|
|
29
|
+
static xt_value xt_http_parse_headers(const char *headers, size_t length) {
|
|
30
|
+
xt_value object = xt_object_new();
|
|
31
|
+
size_t i = 0;
|
|
32
|
+
while (i < length) {
|
|
33
|
+
size_t lineEnd = i;
|
|
34
|
+
while (lineEnd < length && headers[lineEnd] != '\n') lineEnd++;
|
|
35
|
+
size_t lineLength = lineEnd - i;
|
|
36
|
+
while (lineLength > 0 && (headers[i + lineLength - 1] == '\r' || headers[i + lineLength - 1] == ' ')) lineLength--;
|
|
37
|
+
const char *colon = memchr(headers + i, ':', lineLength);
|
|
38
|
+
if (colon) {
|
|
39
|
+
size_t nameLength = (size_t)(colon - (headers + i));
|
|
40
|
+
const char *value = colon + 1;
|
|
41
|
+
size_t valueLength = lineLength - nameLength - 1;
|
|
42
|
+
while (valueLength > 0 && *value == ' ') {
|
|
43
|
+
value++;
|
|
44
|
+
valueLength--;
|
|
45
|
+
}
|
|
46
|
+
char *name = (char *)malloc(nameLength + 1);
|
|
47
|
+
for (size_t j = 0; j < nameLength; j++) {
|
|
48
|
+
char c = headers[i + j];
|
|
49
|
+
name[j] = (c >= 'A' && c <= 'Z') ? (char)(c + 32) : c;
|
|
50
|
+
}
|
|
51
|
+
name[nameLength] = '\0';
|
|
52
|
+
xt_object_set(object, xt_string_from_cstr(name), xt_string_new(value, valueLength));
|
|
53
|
+
free(name);
|
|
54
|
+
}
|
|
55
|
+
i = lineEnd + 1;
|
|
56
|
+
}
|
|
57
|
+
return object;
|
|
58
|
+
}
|
|
@@ -46,508 +46,16 @@ unsigned char *xt_node_buffer_bytes(xt_value value, size_t *outLength);
|
|
|
46
46
|
static xt_value xt_net_socket_proto(void);
|
|
47
47
|
static xt_value xt_net_server_proto(void);
|
|
48
48
|
|
|
49
|
-
/*
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
ioctlsocket(fd, FIONBIO, &mode);
|
|
55
|
-
#else
|
|
56
|
-
int flags = fcntl(fd, F_GETFL, 0);
|
|
57
|
-
if (flags >= 0) fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
58
|
-
#endif
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
static xt_value *xt_net_box(xt_value value) {
|
|
62
|
-
xt_value *handle = (xt_value *)malloc(sizeof(xt_value));
|
|
63
|
-
*handle = value;
|
|
64
|
-
return handle;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
static int xt_net_fd(xt_value object) {
|
|
68
|
-
return (int)xt_to_number(xt_object_get_cstr(object, "__fd"));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
static unsigned char *xt_net_bytes(xt_value data, size_t *outLength) {
|
|
72
|
-
if (xt_node_is_buffer(data)) return xt_node_buffer_bytes(data, outLength);
|
|
73
|
-
xt_value text = xt_to_string(data);
|
|
74
|
-
const char *string = xt_string_data(text);
|
|
75
|
-
size_t length = string ? (size_t)xt_string_length(xt_as_string(text)) : 0;
|
|
76
|
-
unsigned char *bytes = (unsigned char *)malloc(length + 1);
|
|
77
|
-
if (length > 0 && string) memcpy(bytes, string, length);
|
|
78
|
-
bytes[length] = '\0';
|
|
79
|
-
*outLength = length;
|
|
80
|
-
return bytes;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
static int xt_net_send_all(int fd, const unsigned char *data, size_t length) {
|
|
84
|
-
size_t sent = 0;
|
|
85
|
-
while (sent < length) {
|
|
86
|
-
#if defined(_WIN32)
|
|
87
|
-
int written = send(fd, (const char *)data + sent, (int)(length - sent), 0);
|
|
88
|
-
#else
|
|
89
|
-
ssize_t written = send(fd, data + sent, length - sent, 0);
|
|
90
|
-
#endif
|
|
91
|
-
if (written > 0) {
|
|
92
|
-
sent += (size_t)written;
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
if (written < 0 && xt_net_would_block()) {
|
|
96
|
-
fd_set writeSet;
|
|
97
|
-
FD_ZERO(&writeSet);
|
|
98
|
-
FD_SET(fd, &writeSet);
|
|
99
|
-
struct timeval timeout;
|
|
100
|
-
timeout.tv_sec = 2;
|
|
101
|
-
timeout.tv_usec = 0;
|
|
102
|
-
if (select(fd + 1, NULL, &writeSet, NULL, &timeout) <= 0) return -1;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
return -1;
|
|
106
|
-
}
|
|
107
|
-
return 0;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/* -- socket read loop ----------------------------------------------------- */
|
|
111
|
-
|
|
112
|
-
static void xt_net_socket_read(void *userdata, int events) {
|
|
113
|
-
(void)events;
|
|
114
|
-
xt_value socket = *(xt_value *)userdata;
|
|
115
|
-
int fd = xt_net_fd(socket);
|
|
116
|
-
if (fd < 0) return;
|
|
117
|
-
|
|
118
|
-
unsigned char buffer[65536];
|
|
119
|
-
#if defined(_WIN32)
|
|
120
|
-
int count = recv(fd, (char *)buffer, (int)sizeof(buffer), 0);
|
|
121
|
-
#else
|
|
122
|
-
ssize_t count = recv(fd, buffer, sizeof(buffer), 0);
|
|
123
|
-
#endif
|
|
124
|
-
if (count > 0) {
|
|
125
|
-
const char *encoding = xt_node_encoding(xt_object_get_cstr(socket, "__encoding"));
|
|
126
|
-
xt_value chunk = xt_node_encode(buffer, (size_t)count, encoding);
|
|
127
|
-
xt_node_emit1(socket, "data", chunk);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (count == 0) {
|
|
131
|
-
xt_loop_remove(fd);
|
|
132
|
-
xt_close_socket(fd);
|
|
133
|
-
xt_node_set(socket, "__fd", xt_number(-1));
|
|
134
|
-
xt_node_set(socket, "__closed", xt_bool(1));
|
|
135
|
-
xt_node_emit0(socket, "end");
|
|
136
|
-
xt_node_emit0(socket, "close");
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (xt_net_would_block()) return;
|
|
140
|
-
xt_loop_remove(fd);
|
|
141
|
-
xt_close_socket(fd);
|
|
142
|
-
xt_node_set(socket, "__fd", xt_number(-1));
|
|
143
|
-
xt_node_set(socket, "__closed", xt_bool(1));
|
|
144
|
-
xt_value error = xt_string_from_cstr("ECONNRESET");
|
|
145
|
-
xt_node_emit1(socket, "error", error);
|
|
146
|
-
xt_node_emit0(socket, "close");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
static xt_value xt_net_socket_from_fd(int fd, const struct sockaddr *peer, xt_socklen_t peerLength) {
|
|
150
|
-
xt_value socket = xt_object_new_with_proto(xt_net_socket_proto());
|
|
151
|
-
xt_node_set(socket, "__fd", xt_number((double)fd));
|
|
152
|
-
xt_node_set(socket, "__connected", xt_bool(1));
|
|
153
|
-
xt_node_set(socket, "__readable", xt_array_new(0, NULL));
|
|
154
|
-
|
|
155
|
-
char host[NI_MAXHOST];
|
|
156
|
-
char service[NI_MAXSERV];
|
|
157
|
-
if (peer && getnameinfo(peer, peerLength, host, sizeof(host), service, sizeof(service),
|
|
158
|
-
NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
|
|
159
|
-
xt_node_set(socket, "remoteAddress", xt_string_from_cstr(host));
|
|
160
|
-
xt_node_set(socket, "remotePort", xt_number((double)atoi(service)));
|
|
161
|
-
xt_node_set(socket, "remoteFamily", xt_string_from_cstr(strchr(host, ':') ? "IPv6" : "IPv4"));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
xt_net_set_nonblocking(fd);
|
|
165
|
-
xt_loop_add(fd, XT_IO_READ, xt_net_socket_read, xt_net_box(socket));
|
|
166
|
-
return socket;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/* -- socket methods ------------------------------------------------------- */
|
|
170
|
-
|
|
171
|
-
static xt_value xt_net_socket_write(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
172
|
-
(void)env;
|
|
173
|
-
int fd = xt_net_fd(thisValue);
|
|
174
|
-
if (fd < 0) {
|
|
175
|
-
xt_value callback = xt_arg(argc, argv, argc > 1 ? 2 : 1);
|
|
176
|
-
xt_value error = xt_string_from_cstr("ERR_SOCKET_CLOSED");
|
|
177
|
-
if (XT_IS_FUNCTION(callback)) xt_call_with_this(callback, xt_undefined(), 1, &error);
|
|
178
|
-
return xt_bool(0);
|
|
179
|
-
}
|
|
180
|
-
size_t length = 0;
|
|
181
|
-
unsigned char *bytes = xt_net_bytes(xt_arg(argc, argv, 0), &length);
|
|
182
|
-
xt_net_send_all(fd, bytes, length);
|
|
183
|
-
free(bytes);
|
|
184
|
-
xt_value callback = XT_IS_FUNCTION(xt_arg(argc, argv, 1)) ? xt_arg(argc, argv, 1) : xt_arg(argc, argv, 2);
|
|
185
|
-
if (XT_IS_FUNCTION(callback)) xt_call_with_this(callback, xt_undefined(), 0, NULL);
|
|
186
|
-
return xt_bool(1);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
static xt_value xt_net_socket_end(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
190
|
-
(void)env;
|
|
191
|
-
int fd = xt_net_fd(thisValue);
|
|
192
|
-
if (fd < 0) return thisValue;
|
|
193
|
-
if (argc > 0 && !xt_truthy(xt_is_nullish(argv[0]))) {
|
|
194
|
-
xt_value writeFn = xt_object_get_cstr(thisValue, "write");
|
|
195
|
-
if (XT_IS_FUNCTION(writeFn)) xt_call_with_this(writeFn, thisValue, 1, &argv[0]);
|
|
196
|
-
}
|
|
197
|
-
#if defined(_WIN32)
|
|
198
|
-
shutdown(fd, SD_SEND);
|
|
199
|
-
#else
|
|
200
|
-
shutdown(fd, SHUT_WR);
|
|
201
|
-
#endif
|
|
202
|
-
return thisValue;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
static xt_value xt_net_socket_destroy(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
206
|
-
(void)env;
|
|
207
|
-
(void)argc;
|
|
208
|
-
(void)argv;
|
|
209
|
-
int fd = xt_net_fd(thisValue);
|
|
210
|
-
if (fd >= 0) {
|
|
211
|
-
xt_loop_remove(fd);
|
|
212
|
-
xt_close_socket(fd);
|
|
213
|
-
}
|
|
214
|
-
xt_node_set(thisValue, "__fd", xt_number(-1));
|
|
215
|
-
if (!xt_truthy(xt_object_get_cstr(thisValue, "__closed"))) {
|
|
216
|
-
xt_node_set(thisValue, "__closed", xt_bool(1));
|
|
217
|
-
xt_node_emit0(thisValue, "close");
|
|
218
|
-
}
|
|
219
|
-
return thisValue;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
static xt_value xt_net_socket_set_encoding(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
223
|
-
(void)env;
|
|
224
|
-
xt_node_set(thisValue, "__encoding", xt_arg(argc, argv, 0));
|
|
225
|
-
return thisValue;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
static xt_value xt_net_socket_pause(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
229
|
-
(void)env;
|
|
230
|
-
(void)argc;
|
|
231
|
-
(void)argv;
|
|
232
|
-
return thisValue;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
static xt_value xt_net_socket_resume(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
236
|
-
(void)env;
|
|
237
|
-
(void)argc;
|
|
238
|
-
(void)argv;
|
|
239
|
-
return thisValue;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
static xt_value xt_net_socket_noop(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
243
|
-
(void)env;
|
|
244
|
-
(void)argc;
|
|
245
|
-
(void)argv;
|
|
246
|
-
return thisValue;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
static xt_value xt_net_socket_address(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
250
|
-
(void)env;
|
|
251
|
-
(void)argc;
|
|
252
|
-
(void)argv;
|
|
253
|
-
int fd = xt_net_fd(thisValue);
|
|
254
|
-
if (fd < 0) return xt_null();
|
|
255
|
-
struct sockaddr_storage storage;
|
|
256
|
-
xt_socklen_t length = sizeof(storage);
|
|
257
|
-
if (getsockname(fd, (struct sockaddr *)&storage, &length) != 0) return xt_null();
|
|
258
|
-
char host[NI_MAXHOST];
|
|
259
|
-
char service[NI_MAXSERV];
|
|
260
|
-
if (getnameinfo((struct sockaddr *)&storage, length, host, sizeof(host), service, sizeof(service),
|
|
261
|
-
NI_NUMERICHOST | NI_NUMERICSERV) != 0)
|
|
262
|
-
return xt_null();
|
|
263
|
-
xt_value object = xt_object_new();
|
|
264
|
-
xt_node_set(object, "address", xt_string_from_cstr(host));
|
|
265
|
-
xt_node_set(object, "port", xt_number((double)atoi(service)));
|
|
266
|
-
xt_node_set(object, "family", xt_string_from_cstr(strchr(host, ':') ? "IPv6" : "IPv4"));
|
|
267
|
-
return object;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/* -- server --------------------------------------------------------------- */
|
|
271
|
-
|
|
272
|
-
static void xt_net_server_accept(void *userdata, int events) {
|
|
273
|
-
(void)events;
|
|
274
|
-
xt_value server = *(xt_value *)userdata;
|
|
275
|
-
int listenFd = xt_net_fd(server);
|
|
276
|
-
if (listenFd < 0) return;
|
|
277
|
-
for (;;) {
|
|
278
|
-
struct sockaddr_storage storage;
|
|
279
|
-
xt_socklen_t length = sizeof(storage);
|
|
280
|
-
int fd = accept(listenFd, (struct sockaddr *)&storage, &length);
|
|
281
|
-
if (fd < 0) break;
|
|
282
|
-
xt_value socket = xt_net_socket_from_fd(fd, (struct sockaddr *)&storage, length);
|
|
283
|
-
xt_node_emit1(server, "connection", socket);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/* Parse the many listen() signatures into a port + host. */
|
|
288
|
-
static void xt_net_parse_listen(int32_t argc, xt_value *argv, int *port, const char **host, xt_value *callback) {
|
|
289
|
-
*port = 0;
|
|
290
|
-
*host = "0.0.0.0";
|
|
291
|
-
*callback = XT_UNDEFINED;
|
|
292
|
-
int index = 0;
|
|
293
|
-
if (argc > 0 && XT_IS_OBJECT(argv[0])) {
|
|
294
|
-
xt_value portValue = xt_object_get_cstr(argv[0], "port");
|
|
295
|
-
if (!xt_truthy(xt_is_nullish(portValue))) *port = (int)xt_to_number(portValue);
|
|
296
|
-
xt_value hostValue = xt_object_get_cstr(argv[0], "host");
|
|
297
|
-
if (XT_IS_STRING(hostValue)) *host = xt_string_data(hostValue);
|
|
298
|
-
index = 1;
|
|
299
|
-
} else if (argc > 0 && XT_IS_NUMBER(argv[0])) {
|
|
300
|
-
*port = (int)xt_to_number(argv[0]);
|
|
301
|
-
index = 1;
|
|
302
|
-
if (argc > 1 && XT_IS_STRING(argv[1])) {
|
|
303
|
-
*host = xt_string_data(argv[1]);
|
|
304
|
-
index = 2;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
for (int32_t i = index; i < argc; i++) {
|
|
308
|
-
if (XT_IS_FUNCTION(argv[i])) *callback = argv[i];
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
static xt_value xt_net_server_listen(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
313
|
-
(void)env;
|
|
314
|
-
int port = 0;
|
|
315
|
-
const char *host = "0.0.0.0";
|
|
316
|
-
xt_value callback = XT_UNDEFINED;
|
|
317
|
-
xt_net_parse_listen(argc, argv, &port, &host, &callback);
|
|
318
|
-
|
|
319
|
-
char service[16];
|
|
320
|
-
snprintf(service, sizeof(service), "%d", port);
|
|
321
|
-
struct addrinfo hints;
|
|
322
|
-
memset(&hints, 0, sizeof(hints));
|
|
323
|
-
hints.ai_family = AF_UNSPEC;
|
|
324
|
-
hints.ai_socktype = SOCK_STREAM;
|
|
325
|
-
hints.ai_flags = AI_PASSIVE;
|
|
326
|
-
struct addrinfo *result = NULL;
|
|
327
|
-
if (getaddrinfo(host, service, &hints, &result) != 0) {
|
|
328
|
-
if (XT_IS_FUNCTION(callback)) {
|
|
329
|
-
xt_value error = xt_string_from_cstr("EADDRNOTAVAIL");
|
|
330
|
-
xt_call_with_this(callback, xt_undefined(), 1, &error);
|
|
331
|
-
}
|
|
332
|
-
return thisValue;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
int listenFd = -1;
|
|
336
|
-
for (struct addrinfo *info = result; info; info = info->ai_next) {
|
|
337
|
-
int fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
|
|
338
|
-
if (fd < 0) continue;
|
|
339
|
-
int yes = 1;
|
|
340
|
-
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes));
|
|
341
|
-
if (bind(fd, info->ai_addr, info->ai_addrlen) == 0 && listen(fd, 511) == 0) {
|
|
342
|
-
listenFd = fd;
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
xt_close_socket(fd);
|
|
346
|
-
}
|
|
347
|
-
freeaddrinfo(result);
|
|
348
|
-
|
|
349
|
-
if (listenFd < 0) {
|
|
350
|
-
if (XT_IS_FUNCTION(callback)) {
|
|
351
|
-
xt_value error = xt_string_from_cstr("EADDRINUSE");
|
|
352
|
-
xt_call_with_this(callback, xt_undefined(), 1, &error);
|
|
353
|
-
}
|
|
354
|
-
return thisValue;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
xt_net_set_nonblocking(listenFd);
|
|
358
|
-
xt_node_set(thisValue, "__fd", xt_number((double)listenFd));
|
|
359
|
-
xt_node_set(thisValue, "__listening", xt_bool(1));
|
|
360
|
-
xt_loop_add(listenFd, XT_IO_READ, xt_net_server_accept, xt_net_box(thisValue));
|
|
361
|
-
|
|
362
|
-
xt_node_emit0(thisValue, "listening");
|
|
363
|
-
if (XT_IS_FUNCTION(callback)) xt_call_with_this(callback, xt_undefined(), 0, NULL);
|
|
364
|
-
return thisValue;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
static xt_value xt_net_server_close(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
368
|
-
(void)env;
|
|
369
|
-
int fd = xt_net_fd(thisValue);
|
|
370
|
-
if (fd >= 0) {
|
|
371
|
-
xt_loop_remove(fd);
|
|
372
|
-
xt_close_socket(fd);
|
|
373
|
-
}
|
|
374
|
-
xt_node_set(thisValue, "__fd", xt_number(-1));
|
|
375
|
-
xt_node_set(thisValue, "__listening", xt_bool(0));
|
|
376
|
-
xt_value callback = XT_IS_FUNCTION(xt_arg(argc, argv, 0)) ? xt_arg(argc, argv, 0) : XT_UNDEFINED;
|
|
377
|
-
xt_node_emit0(thisValue, "close");
|
|
378
|
-
if (XT_IS_FUNCTION(callback)) xt_call_with_this(callback, xt_undefined(), 0, NULL);
|
|
379
|
-
return thisValue;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
static xt_value xt_net_server_address(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
383
|
-
return xt_net_socket_address(thisValue, env, argc, argv);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
static xt_value xt_net_server_get_connections(xt_value thisValue, xt_value env, int32_t argc, xt_value *argv) {
|
|
387
|
-
(void)thisValue;
|
|
388
|
-
(void)env;
|
|
389
|
-
(void)argc;
|
|
390
|
-
(void)argv;
|
|
391
|
-
xt_value callback = xt_arg(argc, argv, 0);
|
|
392
|
-
if (XT_IS_FUNCTION(callback)) {
|
|
393
|
-
xt_value count = xt_number(0);
|
|
394
|
-
xt_value args[2];
|
|
395
|
-
args[0] = xt_null();
|
|
396
|
-
args[1] = count;
|
|
397
|
-
xt_call_with_this(callback, xt_undefined(), 2, args);
|
|
398
|
-
}
|
|
399
|
-
return xt_undefined();
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/* -- construction --------------------------------------------------------- */
|
|
403
|
-
|
|
404
|
-
xt_value xt_net_socket_ctor(int32_t argc, xt_value *argv) {
|
|
405
|
-
(void)argc;
|
|
406
|
-
(void)argv;
|
|
407
|
-
xt_value socket = xt_object_new_with_proto(xt_net_socket_proto());
|
|
408
|
-
xt_node_set(socket, "__fd", xt_number(-1));
|
|
409
|
-
xt_node_set(socket, "__readable", xt_array_new(0, NULL));
|
|
410
|
-
return socket;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
xt_value xt_net_server_ctor(int32_t argc, xt_value *argv) {
|
|
414
|
-
xt_value server = xt_object_new_with_proto(xt_net_server_proto());
|
|
415
|
-
xt_node_set(server, "__fd", xt_number(-1));
|
|
416
|
-
for (int32_t i = 0; i < argc; i++) {
|
|
417
|
-
if (XT_IS_FUNCTION(argv[i])) {
|
|
418
|
-
xt_array_push(xt_node_listeners(server, "connection", 1), argv[i]);
|
|
419
|
-
break;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
return server;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/* -- connect / static API ------------------------------------------------- */
|
|
426
|
-
|
|
427
|
-
static int xt_net_connect_fd(const char *host, int port) {
|
|
428
|
-
char service[16];
|
|
429
|
-
snprintf(service, sizeof(service), "%d", port);
|
|
430
|
-
struct addrinfo hints;
|
|
431
|
-
memset(&hints, 0, sizeof(hints));
|
|
432
|
-
hints.ai_family = AF_UNSPEC;
|
|
433
|
-
hints.ai_socktype = SOCK_STREAM;
|
|
434
|
-
struct addrinfo *result = NULL;
|
|
435
|
-
if (getaddrinfo(host, service, &hints, &result) != 0) return -1;
|
|
436
|
-
int fd = -1;
|
|
437
|
-
for (struct addrinfo *info = result; info; info = info->ai_next) {
|
|
438
|
-
int candidate = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
|
|
439
|
-
if (candidate < 0) continue;
|
|
440
|
-
if (connect(candidate, info->ai_addr, info->ai_addrlen) == 0) {
|
|
441
|
-
fd = candidate;
|
|
442
|
-
break;
|
|
443
|
-
}
|
|
444
|
-
xt_close_socket(candidate);
|
|
445
|
-
}
|
|
446
|
-
freeaddrinfo(result);
|
|
447
|
-
return fd;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
xt_value xt_node_net_connect(int32_t argc, xt_value *argv) {
|
|
451
|
-
int port = 0;
|
|
452
|
-
const char *host = "127.0.0.1";
|
|
453
|
-
xt_value callback = XT_UNDEFINED;
|
|
454
|
-
int index = 0;
|
|
455
|
-
if (argc > 0 && XT_IS_OBJECT(argv[0])) {
|
|
456
|
-
xt_value portValue = xt_object_get_cstr(argv[0], "port");
|
|
457
|
-
if (!xt_truthy(xt_is_nullish(portValue))) port = (int)xt_to_number(portValue);
|
|
458
|
-
xt_value hostValue = xt_object_get_cstr(argv[0], "host");
|
|
459
|
-
if (XT_IS_STRING(hostValue)) host = xt_string_data(hostValue);
|
|
460
|
-
index = 1;
|
|
461
|
-
} else if (argc > 0 && XT_IS_NUMBER(argv[0])) {
|
|
462
|
-
port = (int)xt_to_number(argv[0]);
|
|
463
|
-
index = 1;
|
|
464
|
-
if (argc > 1 && XT_IS_STRING(argv[1])) {
|
|
465
|
-
host = xt_string_data(argv[1]);
|
|
466
|
-
index = 2;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
for (int32_t i = index; i < argc; i++) {
|
|
470
|
-
if (XT_IS_FUNCTION(argv[i])) callback = argv[i];
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
int fd = xt_net_connect_fd(host, port);
|
|
474
|
-
if (fd < 0) {
|
|
475
|
-
xt_value socket = xt_net_socket_ctor(0, NULL);
|
|
476
|
-
xt_value error = xt_string_from_cstr("ECONNREFUSED");
|
|
477
|
-
if (XT_IS_FUNCTION(callback)) xt_call_with_this(callback, xt_undefined(), 1, &error);
|
|
478
|
-
else xt_node_emit1(socket, "error", error);
|
|
479
|
-
return socket;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
struct sockaddr_storage storage;
|
|
483
|
-
xt_socklen_t length = sizeof(storage);
|
|
484
|
-
getpeername(fd, (struct sockaddr *)&storage, &length);
|
|
485
|
-
xt_value socket = xt_net_socket_from_fd(fd, (struct sockaddr *)&storage, length);
|
|
486
|
-
xt_node_set(socket, "__connecting", xt_bool(0));
|
|
487
|
-
xt_node_emit0(socket, "connect");
|
|
488
|
-
xt_node_emit0(socket, "ready");
|
|
489
|
-
if (XT_IS_FUNCTION(callback)) xt_call_with_this(callback, xt_undefined(), 0, NULL);
|
|
490
|
-
return socket;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
xt_value xt_net_static(xt_value name, int32_t argc, xt_value *argv) {
|
|
494
|
-
const char *fn = xt_string_data(name);
|
|
495
|
-
if (!fn) return xt_undefined();
|
|
496
|
-
if (strcmp(fn, "createServer") == 0) {
|
|
497
|
-
xt_value server = xt_net_server_ctor(0, NULL);
|
|
498
|
-
for (int32_t i = 0; i < argc; i++) {
|
|
499
|
-
if (XT_IS_FUNCTION(argv[i])) {
|
|
500
|
-
xt_array_push(xt_node_listeners(server, "connection", 1), argv[i]);
|
|
501
|
-
break;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
return server;
|
|
505
|
-
}
|
|
506
|
-
if (strcmp(fn, "connect") == 0 || strcmp(fn, "createConnection") == 0) return xt_node_net_connect(argc, argv);
|
|
507
|
-
if (strcmp(fn, "isIP") == 0 || strcmp(fn, "isIPv4") == 0 || strcmp(fn, "isIPv6") == 0) {
|
|
508
|
-
const char *input = xt_string_data(xt_to_string(xt_arg(argc, argv, 0)));
|
|
509
|
-
if (!input) return xt_number(0);
|
|
510
|
-
if (strcmp(fn, "isIPv4") == 0) return xt_bool(strchr(input, '.') && !strchr(input, ':'));
|
|
511
|
-
if (strcmp(fn, "isIPv6") == 0) return xt_bool(strchr(input, ':') != NULL);
|
|
512
|
-
if (strchr(input, ':')) return xt_number(6);
|
|
513
|
-
if (strchr(input, '.')) return xt_number(4);
|
|
514
|
-
return xt_number(0);
|
|
515
|
-
}
|
|
516
|
-
return xt_undefined();
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
/* -- prototypes ----------------------------------------------------------- */
|
|
520
|
-
|
|
521
|
-
static xt_value xt_net_socket_proto(void) {
|
|
522
|
-
static xt_value proto = 0;
|
|
523
|
-
if (proto) return proto;
|
|
524
|
-
proto = xt_object_new();
|
|
525
|
-
xt_node_install_emitter(proto);
|
|
526
|
-
xt_node_define_method(proto, "write", (void *)xt_net_socket_write);
|
|
527
|
-
xt_node_define_method(proto, "end", (void *)xt_net_socket_end);
|
|
528
|
-
xt_node_define_method(proto, "destroy", (void *)xt_net_socket_destroy);
|
|
529
|
-
xt_node_define_method(proto, "setEncoding", (void *)xt_net_socket_set_encoding);
|
|
530
|
-
xt_node_define_method(proto, "pause", (void *)xt_net_socket_pause);
|
|
531
|
-
xt_node_define_method(proto, "resume", (void *)xt_net_socket_resume);
|
|
532
|
-
xt_node_define_method(proto, "setNoDelay", (void *)xt_net_socket_noop);
|
|
533
|
-
xt_node_define_method(proto, "setKeepAlive", (void *)xt_net_socket_noop);
|
|
534
|
-
xt_node_define_method(proto, "setTimeout", (void *)xt_net_socket_noop);
|
|
535
|
-
xt_node_define_method(proto, "ref", (void *)xt_net_socket_noop);
|
|
536
|
-
xt_node_define_method(proto, "unref", (void *)xt_net_socket_noop);
|
|
537
|
-
xt_node_define_method(proto, "address", (void *)xt_net_socket_address);
|
|
538
|
-
return proto;
|
|
539
|
-
}
|
|
49
|
+
/*
|
|
50
|
+
* The implementation is grouped by functional area under `net/parts/` and
|
|
51
|
+
* `#include`d here as a single translation unit so the section helpers stay
|
|
52
|
+
* `static` while each file stays focused on one area.
|
|
53
|
+
*/
|
|
540
54
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
xt_node_define_method(proto, "address", (void *)xt_net_server_address);
|
|
549
|
-
xt_node_define_method(proto, "getConnections", (void *)xt_net_server_get_connections);
|
|
550
|
-
xt_node_define_method(proto, "ref", (void *)xt_net_socket_noop);
|
|
551
|
-
xt_node_define_method(proto, "unref", (void *)xt_net_socket_noop);
|
|
552
|
-
return proto;
|
|
553
|
-
}
|
|
55
|
+
#include "parts/platform.inc"
|
|
56
|
+
#include "parts/read-loop.inc"
|
|
57
|
+
#include "parts/socket-methods.inc"
|
|
58
|
+
#include "parts/server.inc"
|
|
59
|
+
#include "parts/construction.inc"
|
|
60
|
+
#include "parts/static-api.inc"
|
|
61
|
+
#include "parts/prototypes.inc"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* -- construction --------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
xt_value xt_net_socket_ctor(int32_t argc, xt_value *argv) {
|
|
4
|
+
(void)argc;
|
|
5
|
+
(void)argv;
|
|
6
|
+
xt_value socket = xt_object_new_with_proto(xt_net_socket_proto());
|
|
7
|
+
xt_node_set(socket, "__fd", xt_number(-1));
|
|
8
|
+
xt_node_set(socket, "__readable", xt_array_new(0, NULL));
|
|
9
|
+
return socket;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
xt_value xt_net_server_ctor(int32_t argc, xt_value *argv) {
|
|
13
|
+
xt_value server = xt_object_new_with_proto(xt_net_server_proto());
|
|
14
|
+
xt_node_set(server, "__fd", xt_number(-1));
|
|
15
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
16
|
+
if (XT_IS_FUNCTION(argv[i])) {
|
|
17
|
+
xt_array_push(xt_node_listeners(server, "connection", 1), argv[i]);
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return server;
|
|
22
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* -- platform helpers ----------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
static void xt_net_set_nonblocking(int fd) {
|
|
4
|
+
#if defined(_WIN32)
|
|
5
|
+
u_long mode = 1;
|
|
6
|
+
ioctlsocket(fd, FIONBIO, &mode);
|
|
7
|
+
#else
|
|
8
|
+
int flags = fcntl(fd, F_GETFL, 0);
|
|
9
|
+
if (flags >= 0) fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
10
|
+
#endif
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static xt_value *xt_net_box(xt_value value) {
|
|
14
|
+
xt_value *handle = (xt_value *)malloc(sizeof(xt_value));
|
|
15
|
+
*handle = value;
|
|
16
|
+
return handle;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static int xt_net_fd(xt_value object) {
|
|
20
|
+
return (int)xt_to_number(xt_object_get_cstr(object, "__fd"));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static unsigned char *xt_net_bytes(xt_value data, size_t *outLength) {
|
|
24
|
+
if (xt_node_is_buffer(data)) return xt_node_buffer_bytes(data, outLength);
|
|
25
|
+
xt_value text = xt_to_string(data);
|
|
26
|
+
const char *string = xt_string_data(text);
|
|
27
|
+
size_t length = string ? (size_t)xt_string_length(xt_as_string(text)) : 0;
|
|
28
|
+
unsigned char *bytes = (unsigned char *)malloc(length + 1);
|
|
29
|
+
if (length > 0 && string) memcpy(bytes, string, length);
|
|
30
|
+
bytes[length] = '\0';
|
|
31
|
+
*outLength = length;
|
|
32
|
+
return bytes;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static int xt_net_send_all(int fd, const unsigned char *data, size_t length) {
|
|
36
|
+
size_t sent = 0;
|
|
37
|
+
while (sent < length) {
|
|
38
|
+
#if defined(_WIN32)
|
|
39
|
+
int written = send(fd, (const char *)data + sent, (int)(length - sent), 0);
|
|
40
|
+
#else
|
|
41
|
+
ssize_t written = send(fd, data + sent, length - sent, 0);
|
|
42
|
+
#endif
|
|
43
|
+
if (written > 0) {
|
|
44
|
+
sent += (size_t)written;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (written < 0 && xt_net_would_block()) {
|
|
48
|
+
fd_set writeSet;
|
|
49
|
+
FD_ZERO(&writeSet);
|
|
50
|
+
FD_SET(fd, &writeSet);
|
|
51
|
+
struct timeval timeout;
|
|
52
|
+
timeout.tv_sec = 2;
|
|
53
|
+
timeout.tv_usec = 0;
|
|
54
|
+
if (select(fd + 1, NULL, &writeSet, NULL, &timeout) <= 0) return -1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
return -1;
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* -- prototypes ----------------------------------------------------------- */
|
|
2
|
+
|
|
3
|
+
static xt_value xt_net_socket_proto(void) {
|
|
4
|
+
static xt_value proto = 0;
|
|
5
|
+
if (proto) return proto;
|
|
6
|
+
proto = xt_object_new();
|
|
7
|
+
xt_node_install_emitter(proto);
|
|
8
|
+
xt_node_define_method(proto, "write", (void *)xt_net_socket_write);
|
|
9
|
+
xt_node_define_method(proto, "end", (void *)xt_net_socket_end);
|
|
10
|
+
xt_node_define_method(proto, "destroy", (void *)xt_net_socket_destroy);
|
|
11
|
+
xt_node_define_method(proto, "setEncoding", (void *)xt_net_socket_set_encoding);
|
|
12
|
+
xt_node_define_method(proto, "pause", (void *)xt_net_socket_pause);
|
|
13
|
+
xt_node_define_method(proto, "resume", (void *)xt_net_socket_resume);
|
|
14
|
+
xt_node_define_method(proto, "setNoDelay", (void *)xt_net_socket_noop);
|
|
15
|
+
xt_node_define_method(proto, "setKeepAlive", (void *)xt_net_socket_noop);
|
|
16
|
+
xt_node_define_method(proto, "setTimeout", (void *)xt_net_socket_noop);
|
|
17
|
+
xt_node_define_method(proto, "ref", (void *)xt_net_socket_noop);
|
|
18
|
+
xt_node_define_method(proto, "unref", (void *)xt_net_socket_noop);
|
|
19
|
+
xt_node_define_method(proto, "address", (void *)xt_net_socket_address);
|
|
20
|
+
return proto;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static xt_value xt_net_server_proto(void) {
|
|
24
|
+
static xt_value proto = 0;
|
|
25
|
+
if (proto) return proto;
|
|
26
|
+
proto = xt_object_new();
|
|
27
|
+
xt_node_install_emitter(proto);
|
|
28
|
+
xt_node_define_method(proto, "listen", (void *)xt_net_server_listen);
|
|
29
|
+
xt_node_define_method(proto, "close", (void *)xt_net_server_close);
|
|
30
|
+
xt_node_define_method(proto, "address", (void *)xt_net_server_address);
|
|
31
|
+
xt_node_define_method(proto, "getConnections", (void *)xt_net_server_get_connections);
|
|
32
|
+
xt_node_define_method(proto, "ref", (void *)xt_net_socket_noop);
|
|
33
|
+
xt_node_define_method(proto, "unref", (void *)xt_net_socket_noop);
|
|
34
|
+
return proto;
|
|
35
|
+
}
|