react-native-nitro-net 0.1.5 → 0.3.0
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 +122 -12
- package/android/libs/arm64-v8a/librust_c_net.so +0 -0
- package/android/libs/armeabi-v7a/librust_c_net.so +0 -0
- package/android/libs/x86/librust_c_net.so +0 -0
- package/android/libs/x86_64/librust_c_net.so +0 -0
- package/cpp/HybridHttpParser.hpp +67 -0
- package/cpp/HybridNetDriver.hpp +74 -0
- package/cpp/HybridNetServerDriver.hpp +16 -0
- package/cpp/HybridNetSocketDriver.hpp +176 -0
- package/cpp/NetBindings.hpp +67 -1
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64/RustCNet.framework/RustCNet +0 -0
- package/ios/Frameworks/RustCNet.xcframework/ios-arm64_x86_64-simulator/RustCNet.framework/RustCNet +0 -0
- package/lib/Net.nitro.d.ts +46 -1
- package/lib/Net.nitro.js +3 -1
- package/lib/http.d.ts +203 -0
- package/lib/http.js +1138 -0
- package/lib/https.d.ts +24 -0
- package/lib/https.js +144 -0
- package/lib/index.d.ts +50 -11
- package/lib/index.js +179 -31
- package/lib/tls.d.ts +145 -0
- package/lib/tls.js +521 -0
- package/nitrogen/generated/android/RustCNet+autolinking.cmake +2 -0
- package/nitrogen/generated/android/RustCNetOnLoad.cpp +2 -0
- package/nitrogen/generated/android/c++/JHybridHttpParserSpec.cpp +54 -0
- package/nitrogen/generated/android/c++/JHybridHttpParserSpec.hpp +65 -0
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.cpp +47 -1
- package/nitrogen/generated/android/c++/JHybridNetDriverSpec.hpp +9 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.cpp +8 -0
- package/nitrogen/generated/android/c++/JHybridNetServerDriverSpec.hpp +2 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.cpp +79 -0
- package/nitrogen/generated/android/c++/JHybridNetSocketDriverSpec.hpp +17 -0
- package/nitrogen/generated/android/c++/JNetConfig.hpp +7 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridHttpParserSpec.kt +58 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetDriverSpec.kt +37 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetServerDriverSpec.kt +8 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/HybridNetSocketDriverSpec.kt +68 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/net/NetConfig.kt +6 -3
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Bridge.hpp +118 -41
- package/nitrogen/generated/ios/RustCNet-Swift-Cxx-Umbrella.hpp +5 -0
- package/nitrogen/generated/ios/c++/HybridHttpParserSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridHttpParserSpecSwift.hpp +79 -0
- package/nitrogen/generated/ios/c++/HybridNetDriverSpecSwift.hpp +69 -0
- package/nitrogen/generated/ios/c++/HybridNetServerDriverSpecSwift.hpp +12 -0
- package/nitrogen/generated/ios/c++/HybridNetSocketDriverSpecSwift.hpp +123 -0
- package/nitrogen/generated/ios/swift/HybridHttpParserSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridHttpParserSpec_cxx.swift +131 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec.swift +9 -0
- package/nitrogen/generated/ios/swift/HybridNetDriverSpec_cxx.swift +133 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridNetServerDriverSpec_cxx.swift +36 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec.swift +17 -0
- package/nitrogen/generated/ios/swift/HybridNetSocketDriverSpec_cxx.swift +314 -0
- package/nitrogen/generated/ios/swift/NetConfig.swift +19 -1
- package/nitrogen/generated/shared/c++/HybridHttpParserSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridHttpParserSpec.hpp +63 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.cpp +9 -0
- package/nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp +13 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridNetServerDriverSpec.hpp +2 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.cpp +17 -0
- package/nitrogen/generated/shared/c++/HybridNetSocketDriverSpec.hpp +18 -0
- package/nitrogen/generated/shared/c++/NetConfig.hpp +6 -2
- package/package.json +7 -5
- package/react-native-nitro-net.podspec +1 -3
- package/src/Net.nitro.ts +44 -1
- package/src/http.ts +1304 -0
- package/src/https.ts +127 -0
- package/src/index.ts +167 -27
- package/src/tls.ts +608 -0
package/README.md
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
# react-native-nitro-net
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ultra-high-performance networking to React Native by combining a memory-safe Rust core with the zero-overhead Nitro Modules JSI bridge. Provides Node.js-compatible net, tls, http(s) API.
|
|
4
|
+
|
|
5
|
+
[]()
|
|
6
|
+
[]()
|
|
7
|
+
[]()
|
|
8
|
+
[中文文档](./README_zh.md)
|
|
4
9
|
|
|
5
10
|
## Features
|
|
6
11
|
|
|
7
12
|
* 🚀 **High Performance**: Built on top of Rust's `tokio` asynchronous runtime.
|
|
8
|
-
* 🤝 **Node.js Compatible**: Implements
|
|
13
|
+
* 🤝 **Node.js Compatible**: Implements standard `net`, `tls`, `http`, and `https` APIs.
|
|
14
|
+
* 🛡️ **Modern Security**: TLS implementation powered by **Rustls 0.23** (Ring provider), supporting TLS 1.2 and 1.3.
|
|
15
|
+
* 🔒 **Full Protocol Support**: Support for PEM/PFX certificates, SNI, HTTP Trailers, 100 Continue, Protocol Upgrades (101), and HTTP Tunneling (CONNECT).
|
|
9
16
|
* ⚡ **Nitro Modules**: Uses JSI for zero-overhead communication between JavaScript and Native code.
|
|
10
|
-
* 🛡️ **Robust & Stable**: Advanced fixes for
|
|
17
|
+
* 🛡️ **Robust & Stable**: Advanced fixes for port reuse, deadlocks, and connection pooling hangs.
|
|
11
18
|
* 📱 **Cross-Platform**: Supports both iOS and Android.
|
|
12
19
|
|
|
13
20
|
## Installation
|
|
@@ -30,7 +37,7 @@ cd ios && pod install
|
|
|
30
37
|
|
|
31
38
|
This library uses a high-performance three-layer architecture:
|
|
32
39
|
|
|
33
|
-
1. **JavaScript Layer**: Provides
|
|
40
|
+
1. **JavaScript Layer**: Provides high-level Node.js compatible `net` and `tls` APIs using `readable-stream` and `EventEmitter`.
|
|
34
41
|
2. **C++ Bridge (Nitro)**: Handles the zero-copy orchestration between JS and Rust using Nitro Hybrid Objects and JSI.
|
|
35
42
|
3. **Rust Core**: Implements the actual networking logic using the **Tokio** asynchronous runtime, providing memory safety and high concurrency.
|
|
36
43
|
|
|
@@ -73,15 +80,97 @@ server.listen(0, '127.0.0.1', () => {
|
|
|
73
80
|
});
|
|
74
81
|
```
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
### TLS (Secure Socket)
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { tls } from 'react-native-nitro-net';
|
|
87
|
+
|
|
88
|
+
// Client connection
|
|
89
|
+
const socket = tls.connect({
|
|
90
|
+
host: 'example.com',
|
|
91
|
+
port: 443,
|
|
92
|
+
servername: 'example.com', // SNI
|
|
93
|
+
}, () => {
|
|
94
|
+
console.log('Securely connected!');
|
|
95
|
+
console.log('Protocol:', socket.getProtocol());
|
|
96
|
+
});
|
|
77
97
|
|
|
78
|
-
|
|
98
|
+
// Server with PFX
|
|
99
|
+
const server = tls.createServer({
|
|
100
|
+
pfx: fs.readFileSync('server.pfx'),
|
|
101
|
+
passphrase: 'your-password'
|
|
102
|
+
}, (socket) => {
|
|
103
|
+
socket.write('Secure hello!');
|
|
104
|
+
});
|
|
105
|
+
server.listen(443);
|
|
106
|
+
```
|
|
79
107
|
|
|
80
|
-
* **
|
|
81
|
-
* **
|
|
82
|
-
* **DNS Reliability**: Automatically retries all resolved IP addresses if the first one fails to connect.
|
|
108
|
+
* **Advanced Features**: Supports `keylog` event re-emission for Wireshark, session resumption, and `asyncDispose`.
|
|
109
|
+
* **Performance Tuning**: Configurable `headersTimeout`, `keepAliveTimeout`, and `requestTimeout`.
|
|
83
110
|
* **Resource Management**: Strict protective shutdown logic in Rust to prevent socket and Unix domain socket file leaks.
|
|
84
111
|
|
|
112
|
+
## Usage
|
|
113
|
+
|
|
114
|
+
### HTTP Request
|
|
115
|
+
|
|
116
|
+
Implementation of the standard Node.js `http` API.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { http } from 'react-native-nitro-net';
|
|
120
|
+
|
|
121
|
+
http.get('http://google.com', (res) => {
|
|
122
|
+
console.log(`Status: ${res.statusCode}`);
|
|
123
|
+
res.on('data', (chunk) => console.log(`Body segment: ${chunk.length} bytes`));
|
|
124
|
+
res.on('end', () => console.log('Request complete'));
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### HTTPS with Connection Pooling
|
|
129
|
+
|
|
130
|
+
Uses `https` and the built-in `Agent` for connection reuse.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { https } from 'react-native-nitro-net';
|
|
134
|
+
|
|
135
|
+
const agent = new https.Agent({ keepAlive: true });
|
|
136
|
+
|
|
137
|
+
https.get('https://api.github.com/users/margelo', { agent }, (res) => {
|
|
138
|
+
// ... handle response
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### TCP Client (Socket)
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import net from 'react-native-nitro-net';
|
|
146
|
+
|
|
147
|
+
const client = net.createConnection({ port: 8080, host: '127.0.0.1' }, () => {
|
|
148
|
+
client.write('Hello Server!');
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Server (Dynamic Port Support)
|
|
153
|
+
|
|
154
|
+
The server supports binding to a dynamic port by using `0`.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import net from 'react-native-nitro-net';
|
|
158
|
+
|
|
159
|
+
const server = net.createServer((socket) => {
|
|
160
|
+
socket.write('Echo: ' + socket.read());
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
server.listen(0, '127.0.0.1', () => {
|
|
164
|
+
const address = server.address();
|
|
165
|
+
console.log(`Server listening on dynamic port: ${address?.port}`);
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Compatibility Notes
|
|
170
|
+
|
|
171
|
+
> [!IMPORTANT]
|
|
172
|
+
> **`Server.close()` Behavior**: Unlike Node.js's default behavior where `server.close()` only stops accepting new connections, this implementation **immediately destroys all active connections** when `close()` is called. This ensures clean resource release and is more intuitive for mobile applications.
|
|
173
|
+
|
|
85
174
|
## API Reference
|
|
86
175
|
|
|
87
176
|
### `net.Socket`
|
|
@@ -97,11 +186,25 @@ We have implemented several critical fixes to ensure production-grade stability:
|
|
|
97
186
|
|
|
98
187
|
**Events**: `connect`, `ready`, `data`, `error`, `close`, `timeout`, `lookup`.
|
|
99
188
|
|
|
189
|
+
### `tls.TLSSocket`
|
|
190
|
+
*Extends `net.Socket`*
|
|
191
|
+
|
|
192
|
+
| Property / Method | Description |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `authorized` | `true` if peer certificate is verified. |
|
|
195
|
+
| `getProtocol()` | Returns negotiated TLS version (e.g., "TLSv1.3"). |
|
|
196
|
+
| `getCipher()` | Returns current cipher information. |
|
|
197
|
+
| `getPeerCertificate()`| Returns detailed JSON of the peer certificate. |
|
|
198
|
+
| `getSession()` | Returns the session ticket for resumption. |
|
|
199
|
+
| `encrypted` | Always `true`. |
|
|
200
|
+
|
|
201
|
+
**Events**: `secureConnect`, `session`, `keylog`, `OCSPResponse`.
|
|
202
|
+
|
|
100
203
|
### Global APIs
|
|
101
204
|
|
|
102
205
|
| Method | Description |
|
|
103
206
|
| --- | --- |
|
|
104
|
-
| `initWithConfig(options)` | Optional. Initializes the Rust runtime with custom settings (e.g., `workerThreads`). Must be called before any other operation. |
|
|
207
|
+
| `initWithConfig(options)` | Optional. Initializes the Rust runtime with custom settings (e.g., `workerThreads`, `debug`). Must be called before any other operation. |
|
|
105
208
|
| `setVerbose(bool)` | Toggle detailed logging for JS, C++, and Rust. |
|
|
106
209
|
| `isIP(string)` | Returns `0`, `4`, or `6`. |
|
|
107
210
|
|
|
@@ -110,11 +213,18 @@ We have implemented several critical fixes to ensure production-grade stability:
|
|
|
110
213
|
| Method | Description |
|
|
111
214
|
| --- | --- |
|
|
112
215
|
| `listen(options)` | Start listening. Supports `port: 0` for dynamic allocation. |
|
|
113
|
-
| `close()` | Stops the server
|
|
216
|
+
| `close()` | Stops the server and **destroys all active connections**. |
|
|
114
217
|
| `address()` | Returns the bound address (crucial for dynamic ports). |
|
|
115
218
|
| `getConnections(cb)`| Get count of active connections. |
|
|
219
|
+
| `renegotiate(opt, cb)`| **Shim**: Returns `ERR_TLS_RENEGOTIATION_DISABLED` (Rustls security policy). |
|
|
220
|
+
|
|
221
|
+
**Events**: `listening`, `connection`, `error`, `close`, `connect` (HTTP Tunneling).
|
|
222
|
+
|
|
223
|
+
### `tls.Server`
|
|
224
|
+
*Extends `net.Server`*
|
|
116
225
|
|
|
117
|
-
|
|
226
|
+
Supported methods: `listen`, `close`, `addContext`, `setTicketKeys`, `getTicketKeys`.
|
|
227
|
+
**Events**: `secureConnection`, `keylog`, `newSession`.
|
|
118
228
|
|
|
119
229
|
## Debugging
|
|
120
230
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "../nitrogen/generated/shared/c++/HybridHttpParserSpec.hpp"
|
|
4
|
+
#include "NetBindings.hpp"
|
|
5
|
+
#include <NitroModules/ArrayBuffer.hpp>
|
|
6
|
+
#include <string>
|
|
7
|
+
|
|
8
|
+
namespace margelo {
|
|
9
|
+
namespace nitro {
|
|
10
|
+
namespace net {
|
|
11
|
+
|
|
12
|
+
using namespace margelo::nitro;
|
|
13
|
+
|
|
14
|
+
class HybridHttpParser : public HybridHttpParserSpec {
|
|
15
|
+
public:
|
|
16
|
+
HybridHttpParser(int mode) : HybridObject(TAG) {
|
|
17
|
+
_id = net_http_parser_create(mode);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
~HybridHttpParser() { net_http_parser_destroy(_id); }
|
|
21
|
+
|
|
22
|
+
std::string feed(const std::shared_ptr<ArrayBuffer> &data) override {
|
|
23
|
+
if (!data)
|
|
24
|
+
return "";
|
|
25
|
+
|
|
26
|
+
char buf[4096];
|
|
27
|
+
int res =
|
|
28
|
+
net_http_parser_feed(_id, data->data(), data->size(), buf, sizeof(buf));
|
|
29
|
+
|
|
30
|
+
if (res > 0) {
|
|
31
|
+
// Complete message
|
|
32
|
+
return std::string(buf, res);
|
|
33
|
+
} else if (res == 0) {
|
|
34
|
+
// Partial message
|
|
35
|
+
return "";
|
|
36
|
+
} else if (res < -3) {
|
|
37
|
+
// Buffer too small, required size is -res
|
|
38
|
+
size_t requiredSize = static_cast<size_t>(-res);
|
|
39
|
+
std::string largerBuf(requiredSize, '\0');
|
|
40
|
+
res = net_http_parser_feed(_id, nullptr, 0, &largerBuf[0],
|
|
41
|
+
requiredSize + 1);
|
|
42
|
+
if (res > 0) {
|
|
43
|
+
return std::string(largerBuf.data(), res);
|
|
44
|
+
}
|
|
45
|
+
return "ERROR: Re-parse failed after enlarging buffer";
|
|
46
|
+
} else {
|
|
47
|
+
// Error
|
|
48
|
+
switch (res) {
|
|
49
|
+
case -1:
|
|
50
|
+
return "ERROR: JSON serialization failed";
|
|
51
|
+
case -2:
|
|
52
|
+
return "ERROR: HTTP parse failed";
|
|
53
|
+
case -3:
|
|
54
|
+
return "ERROR: Parser not found";
|
|
55
|
+
default:
|
|
56
|
+
return "ERROR: Unknown error";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private:
|
|
62
|
+
uint32_t _id;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
} // namespace net
|
|
66
|
+
} // namespace nitro
|
|
67
|
+
} // namespace margelo
|
package/cpp/HybridNetDriver.hpp
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include "../nitrogen/generated/shared/c++/HybridHttpParserSpec.hpp"
|
|
3
4
|
#include "../nitrogen/generated/shared/c++/HybridNetDriverSpec.hpp"
|
|
5
|
+
#include "HybridHttpParser.hpp"
|
|
4
6
|
#include "HybridNetServerDriver.hpp"
|
|
5
7
|
#include "HybridNetSocketDriver.hpp"
|
|
6
8
|
#include "NetManager.hpp"
|
|
9
|
+
#include <NitroModules/ArrayBuffer.hpp>
|
|
10
|
+
#include <optional>
|
|
11
|
+
#include <string>
|
|
7
12
|
|
|
8
13
|
namespace margelo {
|
|
9
14
|
namespace nitro {
|
|
10
15
|
namespace net {
|
|
11
16
|
|
|
17
|
+
using namespace margelo::nitro;
|
|
18
|
+
|
|
12
19
|
class HybridNetDriver : public HybridNetDriverSpec {
|
|
13
20
|
public:
|
|
14
21
|
HybridNetDriver() : HybridObject(TAG) {}
|
|
@@ -31,6 +38,73 @@ public:
|
|
|
31
38
|
return std::make_shared<HybridNetServerDriver>();
|
|
32
39
|
}
|
|
33
40
|
|
|
41
|
+
std::shared_ptr<HybridHttpParserSpec> createHttpParser(double mode) override {
|
|
42
|
+
return std::make_shared<HybridHttpParser>(static_cast<int>(mode));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
double
|
|
46
|
+
createSecureContext(const std::string &cert, const std::string &key,
|
|
47
|
+
const std::optional<std::string> &passphrase) override {
|
|
48
|
+
return static_cast<double>(net_create_secure_context(
|
|
49
|
+
cert.c_str(), key.c_str(),
|
|
50
|
+
passphrase.has_value() ? passphrase.value().c_str() : nullptr));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
double createEmptySecureContext() override {
|
|
54
|
+
return static_cast<double>(net_secure_context_create());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void addCACertToSecureContext(double scId, const std::string &ca) override {
|
|
58
|
+
net_secure_context_add_ca(static_cast<uint32_t>(scId), ca.c_str());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
void addContextToSecureContext(
|
|
62
|
+
double scId, const std::string &hostname, const std::string &cert,
|
|
63
|
+
const std::string &key,
|
|
64
|
+
const std::optional<std::string> &passphrase) override {
|
|
65
|
+
net_secure_context_add_context(
|
|
66
|
+
static_cast<uint32_t>(scId), hostname.c_str(), cert.c_str(),
|
|
67
|
+
key.c_str(),
|
|
68
|
+
passphrase.has_value() ? passphrase.value().c_str() : nullptr);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
void
|
|
72
|
+
setPFXToSecureContext(double scId, const std::shared_ptr<ArrayBuffer> &pfx,
|
|
73
|
+
const std::optional<std::string> &passphrase) override {
|
|
74
|
+
if (pfx) {
|
|
75
|
+
net_secure_context_set_pfx(
|
|
76
|
+
static_cast<uint32_t>(scId), pfx->data(), pfx->size(),
|
|
77
|
+
passphrase.has_value() ? passphrase.value().c_str() : nullptr);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void setOCSPResponseToSecureContext(
|
|
82
|
+
double scId, const std::shared_ptr<ArrayBuffer> &ocsp) override {
|
|
83
|
+
if (ocsp) {
|
|
84
|
+
net_secure_context_set_ocsp_response(static_cast<uint32_t>(scId),
|
|
85
|
+
ocsp->data(), ocsp->size());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
std::optional<std::shared_ptr<ArrayBuffer>>
|
|
90
|
+
getTicketKeys(double scId) override {
|
|
91
|
+
uint8_t buf[256];
|
|
92
|
+
size_t len = net_server_get_ticket_keys(static_cast<uint32_t>(scId), buf,
|
|
93
|
+
sizeof(buf));
|
|
94
|
+
if (len > 0) {
|
|
95
|
+
return ArrayBuffer::copy(buf, len);
|
|
96
|
+
}
|
|
97
|
+
return std::nullopt;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
void setTicketKeys(double scId,
|
|
101
|
+
const std::shared_ptr<ArrayBuffer> &keys) override {
|
|
102
|
+
if (keys) {
|
|
103
|
+
net_server_set_ticket_keys(static_cast<uint32_t>(scId), keys->data(),
|
|
104
|
+
keys->size());
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
34
108
|
void initWithConfig(const NetConfig &config) override {
|
|
35
109
|
uint32_t workerThreads = config.workerThreads.value_or(0);
|
|
36
110
|
NetManager::shared().initWithConfig(workerThreads);
|
|
@@ -49,11 +49,27 @@ public:
|
|
|
49
49
|
ipv6Only.value_or(false), reusePort.value_or(false));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
void listenTLS(double port, double secureContextId,
|
|
53
|
+
std::optional<double> backlog, std::optional<bool> ipv6Only,
|
|
54
|
+
std::optional<bool> reusePort) override {
|
|
55
|
+
net_listen_tls(_id, static_cast<int>(port),
|
|
56
|
+
static_cast<int>(backlog.value_or(128)),
|
|
57
|
+
ipv6Only.value_or(false), reusePort.value_or(false),
|
|
58
|
+
static_cast<uint32_t>(secureContextId));
|
|
59
|
+
}
|
|
60
|
+
|
|
52
61
|
void listenUnix(const std::string &path,
|
|
53
62
|
std::optional<double> backlog) override {
|
|
54
63
|
net_listen_unix(_id, path.c_str(), static_cast<int>(backlog.value_or(128)));
|
|
55
64
|
}
|
|
56
65
|
|
|
66
|
+
void listenTLSUnix(const std::string &path, double secureContextId,
|
|
67
|
+
std::optional<double> backlog) override {
|
|
68
|
+
net_listen_tls_unix(_id, path.c_str(),
|
|
69
|
+
static_cast<int>(backlog.value_or(128)),
|
|
70
|
+
static_cast<uint32_t>(secureContextId));
|
|
71
|
+
}
|
|
72
|
+
|
|
57
73
|
void listenHandle(double fd, std::optional<double> backlog) override {
|
|
58
74
|
net_listen_handle(_id, static_cast<int>(fd),
|
|
59
75
|
static_cast<int>(backlog.value_or(128)));
|
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
#include "NetBindings.hpp"
|
|
5
5
|
#include "NetManager.hpp"
|
|
6
6
|
#include <NitroModules/ArrayBuffer.hpp>
|
|
7
|
+
#include <memory>
|
|
8
|
+
#include <optional>
|
|
7
9
|
#include <string>
|
|
10
|
+
#include <vector>
|
|
8
11
|
|
|
9
12
|
namespace margelo {
|
|
10
13
|
namespace nitro {
|
|
11
14
|
namespace net {
|
|
12
15
|
|
|
16
|
+
using namespace margelo::nitro;
|
|
17
|
+
|
|
13
18
|
class HybridNetSocketDriver : public HybridNetSocketDriverSpec {
|
|
14
19
|
public:
|
|
15
20
|
HybridNetSocketDriver() : HybridObject(TAG) {
|
|
@@ -48,6 +53,111 @@ public:
|
|
|
48
53
|
net_connect(_id, host.c_str(), static_cast<int>(port));
|
|
49
54
|
}
|
|
50
55
|
|
|
56
|
+
void connectTLS(const std::string &host, double port,
|
|
57
|
+
const std::optional<std::string> &serverName,
|
|
58
|
+
std::optional<bool> rejectUnauthorized) override {
|
|
59
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : nullptr;
|
|
60
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
61
|
+
net_connect_tls(_id, host.c_str(), static_cast<int>(port), sni,
|
|
62
|
+
static_cast<int>(ru));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
void connectTLSWithContext(const std::string &host, double port,
|
|
66
|
+
const std::optional<std::string> &serverName,
|
|
67
|
+
std::optional<bool> rejectUnauthorized,
|
|
68
|
+
std::optional<double> secureContextId) override {
|
|
69
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : nullptr;
|
|
70
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
71
|
+
if (secureContextId.has_value()) {
|
|
72
|
+
net_connect_tls_with_context(
|
|
73
|
+
_id, host.c_str(), static_cast<int>(port), sni, static_cast<int>(ru),
|
|
74
|
+
static_cast<uint32_t>(secureContextId.value()));
|
|
75
|
+
} else {
|
|
76
|
+
net_connect_tls(_id, host.c_str(), static_cast<int>(port), sni,
|
|
77
|
+
static_cast<int>(ru));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
std::optional<std::string> getAuthorizationError() override {
|
|
82
|
+
char buf[1024];
|
|
83
|
+
size_t len = net_get_authorization_error(_id, buf, sizeof(buf));
|
|
84
|
+
if (len > 0) {
|
|
85
|
+
return std::string(buf);
|
|
86
|
+
}
|
|
87
|
+
return std::nullopt;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
std::optional<std::string> getProtocol() override {
|
|
91
|
+
char buf[128];
|
|
92
|
+
size_t len = net_get_protocol(_id, buf, sizeof(buf));
|
|
93
|
+
if (len > 0) {
|
|
94
|
+
return std::string(buf);
|
|
95
|
+
}
|
|
96
|
+
return std::nullopt;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
std::optional<std::string> getCipher() override {
|
|
100
|
+
char buf[256];
|
|
101
|
+
size_t len = net_get_cipher(_id, buf, sizeof(buf));
|
|
102
|
+
if (len > 0) {
|
|
103
|
+
return std::string(buf);
|
|
104
|
+
}
|
|
105
|
+
return std::nullopt;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
std::optional<std::string> getALPN() override {
|
|
109
|
+
char buf[64];
|
|
110
|
+
size_t len = net_get_alpn(_id, buf, sizeof(buf));
|
|
111
|
+
if (len > 0) {
|
|
112
|
+
return std::string(buf);
|
|
113
|
+
}
|
|
114
|
+
return std::nullopt;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
std::optional<std::string> getPeerCertificateJSON() override {
|
|
118
|
+
char buf[16384];
|
|
119
|
+
size_t len = net_get_peer_certificate_json(_id, buf, sizeof(buf));
|
|
120
|
+
if (len > 0) {
|
|
121
|
+
return std::string(buf, len);
|
|
122
|
+
}
|
|
123
|
+
return std::nullopt;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
std::optional<std::string> getEphemeralKeyInfo() override {
|
|
127
|
+
char buf[512];
|
|
128
|
+
size_t len = net_get_ephemeral_key_info(_id, buf, sizeof(buf));
|
|
129
|
+
if (len > 0) {
|
|
130
|
+
return std::string(buf, len);
|
|
131
|
+
}
|
|
132
|
+
return std::nullopt;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
std::optional<std::string> getSharedSigalgs() override {
|
|
136
|
+
char buf[1024];
|
|
137
|
+
size_t len = net_get_shared_sigalgs(_id, buf, sizeof(buf));
|
|
138
|
+
if (len > 0) {
|
|
139
|
+
return std::string(buf, len);
|
|
140
|
+
}
|
|
141
|
+
return std::nullopt;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
bool isSessionReused() override { return net_is_session_reused(_id); }
|
|
145
|
+
|
|
146
|
+
std::optional<std::shared_ptr<ArrayBuffer>> getSession() override {
|
|
147
|
+
uint8_t buf[2048];
|
|
148
|
+
size_t len = net_get_session(_id, buf, sizeof(buf));
|
|
149
|
+
if (len > 0) {
|
|
150
|
+
return ArrayBuffer::copy(buf, len);
|
|
151
|
+
}
|
|
152
|
+
return std::nullopt;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
void setSession(const std::shared_ptr<ArrayBuffer> &session) override {
|
|
156
|
+
if (session && session->size() > 0) {
|
|
157
|
+
net_set_session(_id, session->data(), session->size());
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
51
161
|
void write(const std::shared_ptr<ArrayBuffer> &data) override {
|
|
52
162
|
if (!data)
|
|
53
163
|
return;
|
|
@@ -70,6 +180,33 @@ public:
|
|
|
70
180
|
}
|
|
71
181
|
}
|
|
72
182
|
|
|
183
|
+
void enableKeylog() override { net_socket_enable_keylog(_id); }
|
|
184
|
+
|
|
185
|
+
void enableTrace() override { net_socket_enable_trace(_id); }
|
|
186
|
+
|
|
187
|
+
std::optional<std::shared_ptr<ArrayBuffer>> exportKeyingMaterial(
|
|
188
|
+
double length, const std::string &label,
|
|
189
|
+
const std::optional<std::shared_ptr<ArrayBuffer>> &context) override {
|
|
190
|
+
size_t len = static_cast<size_t>(length);
|
|
191
|
+
std::vector<uint8_t> output(len);
|
|
192
|
+
|
|
193
|
+
const uint8_t *ctx_data = nullptr;
|
|
194
|
+
size_t ctx_len = 0;
|
|
195
|
+
if (context.has_value() && context.value()) {
|
|
196
|
+
ctx_data = context.value()->data();
|
|
197
|
+
ctx_len = context.value()->size();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
int result = net_socket_export_keying_material(
|
|
201
|
+
_id, len, label.c_str(), ctx_data, ctx_len, output.data(),
|
|
202
|
+
output.size());
|
|
203
|
+
|
|
204
|
+
if (result > 0) {
|
|
205
|
+
return ArrayBuffer::copy(output.data(), static_cast<size_t>(result));
|
|
206
|
+
}
|
|
207
|
+
return std::nullopt;
|
|
208
|
+
}
|
|
209
|
+
|
|
73
210
|
void setNoDelay(bool enable) override { net_set_nodelay(_id, enable); }
|
|
74
211
|
|
|
75
212
|
void setKeepAlive(bool enable, double delay) override {
|
|
@@ -107,6 +244,45 @@ public:
|
|
|
107
244
|
net_connect_unix(_id, path.c_str());
|
|
108
245
|
}
|
|
109
246
|
|
|
247
|
+
void connectUnixTLS(const std::string &path,
|
|
248
|
+
const std::optional<std::string> &serverName,
|
|
249
|
+
std::optional<bool> rejectUnauthorized) override {
|
|
250
|
+
#if !defined(__ANDROID__)
|
|
251
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : "";
|
|
252
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
253
|
+
net_connect_unix_tls(_id, path.c_str(), sni, static_cast<int>(ru));
|
|
254
|
+
#else
|
|
255
|
+
// Unix TLS not supported on Android
|
|
256
|
+
(void)path;
|
|
257
|
+
(void)serverName;
|
|
258
|
+
(void)rejectUnauthorized;
|
|
259
|
+
#endif
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
void
|
|
263
|
+
connectUnixTLSWithContext(const std::string &path,
|
|
264
|
+
const std::optional<std::string> &serverName,
|
|
265
|
+
std::optional<bool> rejectUnauthorized,
|
|
266
|
+
std::optional<double> secureContextId) override {
|
|
267
|
+
#if !defined(__ANDROID__)
|
|
268
|
+
const char *sni = serverName.has_value() ? serverName->c_str() : "";
|
|
269
|
+
bool ru = rejectUnauthorized.value_or(true);
|
|
270
|
+
if (secureContextId.has_value()) {
|
|
271
|
+
net_connect_unix_tls_with_context(
|
|
272
|
+
_id, path.c_str(), sni, static_cast<int>(ru),
|
|
273
|
+
static_cast<uint32_t>(secureContextId.value()));
|
|
274
|
+
} else {
|
|
275
|
+
net_connect_unix_tls(_id, path.c_str(), sni, static_cast<int>(ru));
|
|
276
|
+
}
|
|
277
|
+
#else
|
|
278
|
+
// Unix TLS not supported on Android
|
|
279
|
+
(void)path;
|
|
280
|
+
(void)serverName;
|
|
281
|
+
(void)rejectUnauthorized;
|
|
282
|
+
(void)secureContextId;
|
|
283
|
+
#endif
|
|
284
|
+
}
|
|
285
|
+
|
|
110
286
|
private:
|
|
111
287
|
void onNativeEvent(int type, const uint8_t *data, size_t len) {
|
|
112
288
|
if (!_onEvent)
|