appium-ios-tuntap 0.4.3 → 0.4.4
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/CHANGELOG.md +6 -0
- package/README.md +3 -3
- package/lib/tunnel/constants.d.ts +2 -0
- package/lib/tunnel/constants.js +2 -0
- package/lib/tunnel/manager.d.ts +4 -0
- package/lib/tunnel/manager.js +30 -4
- package/package.json +3 -4
- package/prebuilds/darwin-arm64/appium-ios-tuntap.node +0 -0
- package/prebuilds/darwin-x64/appium-ios-tuntap.node +0 -0
- package/prebuilds/linux-arm64/appium-ios-tuntap.node +0 -0
- package/prebuilds/linux-x64/appium-ios-tuntap.node +0 -0
- package/prebuilds/win32-arm64/appium-ios-tuntap.node +0 -0
- package/prebuilds/win32-x64/appium-ios-tuntap.node +0 -0
- package/src/native/tun_backend_darwin.cc +3 -0
- package/src/native/tun_backend_linux.cc +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [0.4.4](https://github.com/appium/appium-ios-tuntap/compare/v0.4.3...v0.4.4) (2026-06-12)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* Update tunnel backpressure handling ([#50](https://github.com/appium/appium-ios-tuntap/issues/50)) ([28b8bce](https://github.com/appium/appium-ios-tuntap/commit/28b8bce8edcf2a0446a653bbec759e6b4a199827))
|
|
6
|
+
|
|
1
7
|
## [0.4.3](https://github.com/appium/appium-ios-tuntap/compare/v0.4.2...v0.4.3) (2026-06-10)
|
|
2
8
|
|
|
3
9
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -272,13 +272,13 @@ Most tests for this module require **root privileges** (sudo) to create and mana
|
|
|
272
272
|
From the project root, run:
|
|
273
273
|
|
|
274
274
|
```sh
|
|
275
|
-
sudo
|
|
275
|
+
sudo npm run test:unit
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
-
Or, to run all tests
|
|
278
|
+
Or, to run all tests:
|
|
279
279
|
|
|
280
280
|
```sh
|
|
281
|
-
sudo
|
|
281
|
+
sudo npm test
|
|
282
282
|
```
|
|
283
283
|
|
|
284
284
|
If you are **not** running as root, you will see a message that tests are skipped.
|
|
@@ -16,3 +16,5 @@ export declare const IPV6_HEADER_SIZE = 40;
|
|
|
16
16
|
export declare const IPV6_VERSION = 6;
|
|
17
17
|
export declare const IPPROTO_TCP = 6;
|
|
18
18
|
export declare const IPPROTO_UDP = 17;
|
|
19
|
+
/** Pause device ingress when the reassembly buffer exceeds this size. */
|
|
20
|
+
export declare const MAX_DEVICE_INGRESS_BUFFER: number;
|
package/lib/tunnel/constants.js
CHANGED
|
@@ -16,3 +16,5 @@ export const IPV6_HEADER_SIZE = 40;
|
|
|
16
16
|
export const IPV6_VERSION = 6;
|
|
17
17
|
export const IPPROTO_TCP = 6;
|
|
18
18
|
export const IPPROTO_UDP = 17;
|
|
19
|
+
/** Pause device ingress when the reassembly buffer exceeds this size. */
|
|
20
|
+
export const MAX_DEVICE_INGRESS_BUFFER = 8 * 1024 * 1024;
|
package/lib/tunnel/manager.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare class TunnelManager extends EventEmitter<TunnelManagerEvents> {
|
|
|
15
15
|
private deviceConn;
|
|
16
16
|
private cleanupPromise;
|
|
17
17
|
private tunReadPausedForBackpressure;
|
|
18
|
+
private deviceIngressPausedForTun;
|
|
18
19
|
/**
|
|
19
20
|
* Register a listener for parsed tunnel packets (in addition to the `data` event).
|
|
20
21
|
*
|
|
@@ -59,6 +60,9 @@ export declare class TunnelManager extends EventEmitter<TunnelManagerEvents> {
|
|
|
59
60
|
private hasPacketTap;
|
|
60
61
|
private processBuffer;
|
|
61
62
|
private writeDeviceFrameToTun;
|
|
63
|
+
private shouldResumeDeviceIngress;
|
|
64
|
+
private pauseDeviceIngress;
|
|
65
|
+
private resumeDeviceIngress;
|
|
62
66
|
private tapL4Packet;
|
|
63
67
|
private dispatchPacketData;
|
|
64
68
|
private startTunReadLoop;
|
package/lib/tunnel/manager.js
CHANGED
|
@@ -2,7 +2,7 @@ import { log } from '../logger.js';
|
|
|
2
2
|
import { TunTap } from '../TunTap.js';
|
|
3
3
|
import { EventEmitter } from 'node:events';
|
|
4
4
|
import { Buffer } from 'node:buffer';
|
|
5
|
-
import { CD_TUNNEL_HANDSHAKE_TIMEOUT_MS, CD_TUNNEL_HEADER_SIZE, CD_TUNNEL_MAGIC, CD_TUNNEL_MAGIC_SIZE, CD_TUNNEL_MTU, DEFAULT_TUN_POLL_QUEUE_DEPTH, FAST_TUN_POLL_QUEUE_DEPTH, IPV6_HEADER_SIZE, LARGE_TUN_POLL_BUFFER, MAX_TUN_POLL_BUFFER, IPV6_VERSION, IPPROTO_TCP, IPPROTO_UDP, } from './constants.js';
|
|
5
|
+
import { CD_TUNNEL_HANDSHAKE_TIMEOUT_MS, CD_TUNNEL_HEADER_SIZE, CD_TUNNEL_MAGIC, CD_TUNNEL_MAGIC_SIZE, CD_TUNNEL_MTU, DEFAULT_TUN_POLL_QUEUE_DEPTH, FAST_TUN_POLL_QUEUE_DEPTH, IPV6_HEADER_SIZE, LARGE_TUN_POLL_BUFFER, MAX_DEVICE_INGRESS_BUFFER, MAX_TUN_POLL_BUFFER, IPV6_VERSION, IPPROTO_TCP, IPPROTO_UDP, } from './constants.js';
|
|
6
6
|
import { appendBuffer } from './buffer-utils.js';
|
|
7
7
|
/**
|
|
8
8
|
* Bridges a CoreDevice tunnel `Socket` and a {@link TunTap} interface: IPv6 framing, TUN I/O, and packet fan-out.
|
|
@@ -17,6 +17,7 @@ export class TunnelManager extends EventEmitter {
|
|
|
17
17
|
deviceConn = null;
|
|
18
18
|
cleanupPromise = null;
|
|
19
19
|
tunReadPausedForBackpressure = false;
|
|
20
|
+
deviceIngressPausedForTun = false;
|
|
20
21
|
/**
|
|
21
22
|
* Register a listener for parsed tunnel packets (in addition to the `data` event).
|
|
22
23
|
*
|
|
@@ -136,7 +137,9 @@ export class TunnelManager extends EventEmitter {
|
|
|
136
137
|
}
|
|
137
138
|
try {
|
|
138
139
|
this.buffer = appendBuffer(this.buffer, data);
|
|
139
|
-
|
|
140
|
+
if (this.buffer.length > MAX_DEVICE_INGRESS_BUFFER) {
|
|
141
|
+
this.pauseDeviceIngress();
|
|
142
|
+
}
|
|
140
143
|
this.processBuffer();
|
|
141
144
|
}
|
|
142
145
|
catch (err) {
|
|
@@ -208,17 +211,40 @@ export class TunnelManager extends EventEmitter {
|
|
|
208
211
|
this.buffer = this.buffer.subarray(offset);
|
|
209
212
|
}
|
|
210
213
|
}
|
|
214
|
+
if (this.deviceIngressPausedForTun && this.shouldResumeDeviceIngress()) {
|
|
215
|
+
this.resumeDeviceIngress();
|
|
216
|
+
}
|
|
211
217
|
}
|
|
212
218
|
writeDeviceFrameToTun(tun, packet, nextHeader) {
|
|
213
219
|
tun.write(packet);
|
|
214
220
|
if (!this.hasPacketTap()) {
|
|
215
221
|
return;
|
|
216
222
|
}
|
|
217
|
-
const bytesWritten = packet.length;
|
|
218
223
|
const { src, dst } = ipv6Endpoints(packet);
|
|
219
|
-
log.debug(`Device → TUN: ${
|
|
224
|
+
log.debug(`Device → TUN: ${packet.length} bytes, IPv6 src=${src}, dst=${dst}`);
|
|
220
225
|
this.tapL4Packet(packet, nextHeader, src, dst);
|
|
221
226
|
}
|
|
227
|
+
shouldResumeDeviceIngress() {
|
|
228
|
+
if (this.buffer.length === 0) {
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
// All complete frames were written; waiting on more socket bytes to finish the tail frame.
|
|
232
|
+
return nextIpv6Frame(this.buffer, 0).kind === 'incomplete';
|
|
233
|
+
}
|
|
234
|
+
pauseDeviceIngress() {
|
|
235
|
+
if (this.deviceIngressPausedForTun || !this.deviceConn || this.deviceConn.destroyed) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
this.deviceIngressPausedForTun = true;
|
|
239
|
+
this.deviceConn.pause();
|
|
240
|
+
}
|
|
241
|
+
resumeDeviceIngress() {
|
|
242
|
+
if (!this.deviceIngressPausedForTun || !this.deviceConn || this.deviceConn.destroyed) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.deviceIngressPausedForTun = false;
|
|
246
|
+
this.deviceConn.resume();
|
|
247
|
+
}
|
|
222
248
|
tapL4Packet(packet, nextHeader, src, dst) {
|
|
223
249
|
let packetData = null;
|
|
224
250
|
if (nextHeader === IPPROTO_UDP) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-ios-tuntap",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Native TUN/TAP interface module for Node.js",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"refresh:wintun": "node scripts/fetch-wintun.mjs",
|
|
19
19
|
"prepare": "npm run build",
|
|
20
20
|
"test": "npm run test:integration && npm run test:unit",
|
|
21
|
-
"test:unit": "
|
|
22
|
-
"test:integration": "
|
|
21
|
+
"test:unit": "node --test --test-force-exit --test-timeout=120000 \"test/unit/**/*.spec.mjs\"",
|
|
22
|
+
"test:integration": "node --test --test-force-exit --test-timeout=120000 \"test/integration/**/*.spec.mjs\""
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"src/tuntap.cc",
|
|
@@ -61,7 +61,6 @@
|
|
|
61
61
|
"@types/node": "^25.0.1",
|
|
62
62
|
"commander": "^14.0.3",
|
|
63
63
|
"conventional-changelog-conventionalcommits": "^9.0.0",
|
|
64
|
-
"mocha": "^11.7.5",
|
|
65
64
|
"prebuildify": "^6.0.1",
|
|
66
65
|
"prettier": "^3.0.0",
|
|
67
66
|
"semantic-release": "^25.0.2"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -134,6 +134,9 @@ public:
|
|
|
134
134
|
|
|
135
135
|
ssize_t bytes_written = write(fd_.get(), write_frame_.data(), write_frame_.size());
|
|
136
136
|
if (bytes_written < 0) {
|
|
137
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
137
140
|
error = std::string("Write error: ") + strerror(errno);
|
|
138
141
|
return -1;
|
|
139
142
|
}
|
|
@@ -104,6 +104,9 @@ public:
|
|
|
104
104
|
}
|
|
105
105
|
ssize_t bytes_written = write(fd_.get(), data, length);
|
|
106
106
|
if (bytes_written < 0) {
|
|
107
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
107
110
|
error = std::string("Write error: ") + strerror(errno);
|
|
108
111
|
return -1;
|
|
109
112
|
}
|