@honeybbq/teamspeak-client 1.0.0-beta.1 → 1.0.0-beta.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 +28 -9
- package/dist/client.d.ts +3 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/handshake.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -17
- package/dist/index.js.map +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.d.ts.map +1 -1
- package/dist/transport/generation-window.d.ts +15 -0
- package/dist/transport/generation-window.d.ts.map +1 -1
- package/dist/transport/handler.d.ts +7 -0
- package/dist/transport/handler.d.ts.map +1 -1
- package/dist/types.d.ts +1 -110
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/client.ts +5 -4
- package/src/handshake/crypt-handshake.ts +2 -2
- package/src/handshake/license.fuzz.test.ts +87 -0
- package/src/handshake.ts +1 -0
- package/src/index.ts +0 -8
- package/src/notifications.ts +1 -1
- package/src/transport/generation-window.ts +32 -1
- package/src/transport/handler.ts +16 -13
- package/src/types.ts +8 -122
package/README.md
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
**A clean-room TeamSpeak client protocol library written in pure TypeScript.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Works with TeamSpeak 3 and TeamSpeak 6 servers. No proprietary SDK, no copied code.
|
|
8
8
|
|
|
9
9
|
[](https://github.com/honeybbq/teamspeak-js/actions/workflows/ci.yml)
|
|
10
10
|
[](https://www.npmjs.com/package/@honeybbq/teamspeak-client)
|
|
11
|
+
[](https://www.npmjs.com/package/@honeybbq/teamspeak-client?activeTab=versions)
|
|
12
|
+
[](https://scorecard.dev/viewer/?uri=github.com/HoneyBBQ/teamspeak-js)
|
|
11
13
|
[](package.json)
|
|
12
14
|
[](LICENSE)
|
|
13
15
|
|
|
@@ -28,20 +30,23 @@ Upgrading from 0.x? See the [migration guide](https://github.com/HoneyBBQ/teamsp
|
|
|
28
30
|
- **Identity management** — Generate, import/export, and upgrade security level of identities
|
|
29
31
|
- **Full command set** — 111 typed functions covering every command the voice protocol answers
|
|
30
32
|
- **Reconnection** — Opt-in retry with backoff, tuned for TeamSpeak's antiflood ban
|
|
31
|
-
- **Server capabilities** — Reports the server version and the uid hash it uses (SHA-1 on TS3, SHA-256 on TS6)
|
|
33
|
+
- **Server capabilities** — Reports the server version and the uid hash it uses (SHA-1 on TS3, SHA-256 on TS6), and the server's name, icon, banner and welcome message
|
|
32
34
|
- **Custom transports** — Supply your own socket, for proxies, tunnels or tests
|
|
33
35
|
- **ESM with types** — Ships ES modules with full TypeScript declarations
|
|
34
36
|
- **Zero native deps** — Pure TypeScript, no native addons required
|
|
35
37
|
|
|
36
38
|
## Installation
|
|
37
39
|
|
|
40
|
+
1.0 is in beta, published under the `beta` tag. A plain `npm install` still
|
|
41
|
+
gets 0.3, so ask for the beta:
|
|
42
|
+
|
|
38
43
|
```bash
|
|
39
|
-
npm install @honeybbq/teamspeak-client
|
|
44
|
+
npm install @honeybbq/teamspeak-client@beta
|
|
40
45
|
# or
|
|
41
|
-
pnpm add @honeybbq/teamspeak-client
|
|
46
|
+
pnpm add @honeybbq/teamspeak-client@beta
|
|
42
47
|
```
|
|
43
48
|
|
|
44
|
-
|
|
49
|
+
Everything in this README is the 1.0 API. You need Node.js 22.12 or newer.
|
|
45
50
|
|
|
46
51
|
## Quick Start
|
|
47
52
|
|
|
@@ -152,7 +157,15 @@ for await (const msg of client.events("textMessage", { signal })) {
|
|
|
152
157
|
```
|
|
153
158
|
|
|
154
159
|
`notification` delivers every notification as it arrived, for the ones the SDK
|
|
155
|
-
does not model.
|
|
160
|
+
does not model. `NotificationName` names them:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { NotificationName } from "@honeybbq/teamspeak-client";
|
|
164
|
+
|
|
165
|
+
client.on("notification", (n) => {
|
|
166
|
+
if (n.name === NotificationName.ChannelEdited) console.log(n.params);
|
|
167
|
+
});
|
|
168
|
+
```
|
|
156
169
|
|
|
157
170
|
### Commands
|
|
158
171
|
|
|
@@ -176,6 +189,7 @@ import {
|
|
|
176
189
|
addServerGroupPermission,
|
|
177
190
|
iterateClientDatabase,
|
|
178
191
|
permissionByName,
|
|
192
|
+
PermissionName,
|
|
179
193
|
asClientID,
|
|
180
194
|
Codec,
|
|
181
195
|
Reason,
|
|
@@ -195,7 +209,7 @@ await sendChannelMessage(client, "hello");
|
|
|
195
209
|
await kickClient(client, someone, Reason.KickChannel, { reasonMessage: "take a break" });
|
|
196
210
|
|
|
197
211
|
await addServerGroupPermission(client, sgid, {
|
|
198
|
-
permission: permissionByName(
|
|
212
|
+
permission: permissionByName(PermissionName.ClientTalkPower),
|
|
199
213
|
value: 50,
|
|
200
214
|
});
|
|
201
215
|
|
|
@@ -215,7 +229,8 @@ and only the fields you set are sent: an unset field leaves the setting alone,
|
|
|
215
229
|
while `""` sends it empty — `editChannel(client, cid, { password: "" })` clears
|
|
216
230
|
a password. A key an options type does not name is never sent. The exceptions
|
|
217
231
|
are `editServer` and `editInstance`, which take the raw `virtualserver_*` and
|
|
218
|
-
`serverinstance_*` properties as `getServerInfo` reports them
|
|
232
|
+
`serverinstance_*` properties as `getServerInfo` reports them; `PropertyName` names
|
|
233
|
+
the keys.
|
|
219
234
|
|
|
220
235
|
Results are camelCase too. Timestamps are `Date`s (`undefined` where the server
|
|
221
236
|
sends 0 for "never"), durations are milliseconds with an `Ms` suffix
|
|
@@ -397,7 +412,11 @@ const client = new Client(identity, "ts.example.com", "Bot", {
|
|
|
397
412
|
|
|
398
413
|
```typescript
|
|
399
414
|
const caps = client.serverCapabilities;
|
|
400
|
-
// {
|
|
415
|
+
// {
|
|
416
|
+
// version: "6.0.0-beta13.1 [Build: 1790080330]", major: 6, family: "ts6",
|
|
417
|
+
// uidAlgorithm: "sha256", name: "TeamSpeak 6 Server", iconID: undefined,
|
|
418
|
+
// hostBannerImageURL: undefined, welcomeMessage: "…"
|
|
419
|
+
// }
|
|
401
420
|
```
|
|
402
421
|
|
|
403
422
|
Read from `initserver` during the handshake, so it costs no extra round trip.
|
package/dist/client.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export declare class Client implements CommandExecutor, AsyncDisposable {
|
|
|
77
77
|
* Send a raw command line and return the rows that answer it: the escape
|
|
78
78
|
* hatch for a command the typed functions do not cover. The line is sent as
|
|
79
79
|
* given, so its values must already be escaped and any channel password
|
|
80
|
-
* already hashed.
|
|
80
|
+
* already hashed. `CommandName` lists the command names.
|
|
81
81
|
*
|
|
82
82
|
* Rejects with a NotConnectedError unless the client is connected: while it
|
|
83
83
|
* is still connecting, the session's keys may not exist yet.
|
|
@@ -85,7 +85,8 @@ export declare class Client implements CommandExecutor, AsyncDisposable {
|
|
|
85
85
|
exec(command: string, options?: CommandOptions): Promise<Record<string, string>[]>;
|
|
86
86
|
/**
|
|
87
87
|
* Send a raw command line without waiting for an answer, for the few
|
|
88
|
-
* commands the server answers with nothing at all.
|
|
88
|
+
* commands the server answers with nothing at all. `CommandName` lists
|
|
89
|
+
* the command names.
|
|
89
90
|
*
|
|
90
91
|
* Commands are paced by a flood throttle; aborting `signal` while this waits
|
|
91
92
|
* for its turn rejects with the signal's reason and sends nothing. Rejects
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/handshake.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,mEAAmE;AACnE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,IAAI,
|
|
1
|
+
{"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../src/handshake.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,mEAAmE;AACnE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,IAAI,CASN;AAED,sEAAsE;AACtE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,IAAI,CAYN;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CA0B9F;AAwBD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAG5D"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export * from "@honeybbq/teamspeak-core";
|
|
9
9
|
export { Client, ClientStatus } from "./client.js";
|
|
10
|
-
export type {
|
|
10
|
+
export type { EventMap, EventMiddleware, Listener, ServerEvent, ServerEventName, Unsubscribe, AddrResolver, ClientOptions, ResolvedAddr, DatagramSocket, SocketFactory, FileTransferSocketFactory, } from "./types.js";
|
|
11
11
|
export { AlreadyConnectedError, FileTransferError, CryptoInitError, InvalidAddressError, InvalidIdentityError, RemovedError, ConnectionTimeoutError, } from "./errors.js";
|
|
12
12
|
export * from "./api/voice.js";
|
|
13
13
|
export { dialFileTransfer, uploadFileData, downloadFileData } from "./transfer.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,0BAA0B,CAAC;AAGzC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEnD,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,0BAA0B,CAAC;AAGzC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEnD,YAAY,EACV,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,WAAW,EACX,eAAe,EACf,WAAW,EACX,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,cAAc,EACd,aAAa,EACb,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnF,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG1E,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGlE,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACxF,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1220,10 +1220,30 @@ var GenerationWindow = class {
|
|
|
1220
1220
|
if (maxOffset < this.#mod) return mappedValue >= this.#mappedBaseOffset && mappedValue < maxOffset;
|
|
1221
1221
|
return mappedValue >= this.#mappedBaseOffset || mappedValue < maxOffset - this.#mod;
|
|
1222
1222
|
}
|
|
1223
|
+
/**
|
|
1224
|
+
* The offset from the window base: negative means stale, `receiveWindow` or
|
|
1225
|
+
* more too far ahead. An id up to `receiveWindow` behind the base across the
|
|
1226
|
+
* last wrap, which reads as a high number, is stale too.
|
|
1227
|
+
*/
|
|
1223
1228
|
mappedToIndex(mappedValue) {
|
|
1224
1229
|
if (this.#isNextGen(mappedValue)) return mappedValue + this.#mod - this.#mappedBaseOffset;
|
|
1225
|
-
|
|
1230
|
+
const index = mappedValue - this.#mappedBaseOffset;
|
|
1231
|
+
return this.#isBehindAcrossWrap(index) ? index - this.#mod : index;
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Whether an id `index` past the base is really up to `receiveWindow` behind
|
|
1235
|
+
* it, in the generation before: the base has wrapped since, so the id reads as
|
|
1236
|
+
* nearly a whole generation ahead. Before the first wrap no id lies behind the
|
|
1237
|
+
* base across it.
|
|
1238
|
+
*/
|
|
1239
|
+
#isBehindAcrossWrap(index) {
|
|
1240
|
+
return this.#generation > 0 && index >= this.#receiveWindow && index >= this.#mod - this.#receiveWindow;
|
|
1226
1241
|
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Whether the id is before the receive window: a packet whose acknowledgement
|
|
1244
|
+
* was lost is sent again after the window has moved past it, also when the
|
|
1245
|
+
* move wrapped the 16-bit id.
|
|
1246
|
+
*/
|
|
1227
1247
|
isOldPacket(mappedValue) {
|
|
1228
1248
|
return this.mappedToIndex(mappedValue) < 0;
|
|
1229
1249
|
}
|
|
@@ -1233,8 +1253,14 @@ var GenerationWindow = class {
|
|
|
1233
1253
|
#isNextGen(mappedValue) {
|
|
1234
1254
|
return this.#mappedBaseOffset > this.#mod - this.#receiveWindow && mappedValue < this.#mappedBaseOffset + this.#receiveWindow - this.#mod;
|
|
1235
1255
|
}
|
|
1256
|
+
/**
|
|
1257
|
+
* The generation the id belongs to: one past the current generation if the id
|
|
1258
|
+
* has already wrapped, one before it if the id is just behind the base across
|
|
1259
|
+
* the last wrap.
|
|
1260
|
+
*/
|
|
1236
1261
|
getGeneration(mappedValue) {
|
|
1237
1262
|
if (this.#isNextGen(mappedValue)) return this.#generation + 1;
|
|
1263
|
+
if (this.#isBehindAcrossWrap(mappedValue - this.#mappedBaseOffset)) return this.#generation - 1;
|
|
1238
1264
|
return this.#generation;
|
|
1239
1265
|
}
|
|
1240
1266
|
reset() {
|
|
@@ -1529,6 +1555,12 @@ var PacketHandler = class {
|
|
|
1529
1555
|
/** The bytes held in both command queues; see MAX_QUEUED_BYTES. */
|
|
1530
1556
|
#queuedBytes = 0;
|
|
1531
1557
|
#ackManager = /* @__PURE__ */ new Map();
|
|
1558
|
+
/**
|
|
1559
|
+
* The last Init1 packet the client sent, resent until the handshake's final
|
|
1560
|
+
* acknowledgement. Init1 packets are not acknowledged one by one: each step
|
|
1561
|
+
* the client sends replaces it, and only `receivedFinalInitAck` clears it.
|
|
1562
|
+
* Receiving an Init1 does not, as the client may have nothing to answer with.
|
|
1563
|
+
*/
|
|
1532
1564
|
#initPacketCheck = null;
|
|
1533
1565
|
/**
|
|
1534
1566
|
* Command packets sent under the dummy key, before crypto init completed:
|
|
@@ -1633,6 +1665,13 @@ var PacketHandler = class {
|
|
|
1633
1665
|
const resendTimer = setInterval(() => this.#checkResends(), RESEND_LOOP_INTERVAL_MS);
|
|
1634
1666
|
this.#stopResend = () => clearInterval(resendTimer);
|
|
1635
1667
|
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Stop resending the last Init1 packet the client sent. Until this is called,
|
|
1670
|
+
* the latest step stays pending whatever the server sends in between: a step
|
|
1671
|
+
* the client does not answer, an unknown one or a second RSA challenge, must
|
|
1672
|
+
* not stop the resending of its own. The server's `initivexpand2` command
|
|
1673
|
+
* acknowledges the last step, not an Init1 reply.
|
|
1674
|
+
*/
|
|
1636
1675
|
receivedFinalInitAck() {
|
|
1637
1676
|
this.#initPacketCheck = null;
|
|
1638
1677
|
}
|
|
@@ -1937,7 +1976,6 @@ var PacketHandler = class {
|
|
|
1937
1976
|
let totalSize = 0;
|
|
1938
1977
|
let currID = nextID;
|
|
1939
1978
|
let startSeen = false;
|
|
1940
|
-
let complete = false;
|
|
1941
1979
|
while (true) {
|
|
1942
1980
|
const frag = queue.get(currID);
|
|
1943
1981
|
if (!frag) return null;
|
|
@@ -1954,17 +1992,10 @@ var PacketHandler = class {
|
|
|
1954
1992
|
const fragmented = (packetFlags(frag) & PacketFlags.Fragmented) !== 0;
|
|
1955
1993
|
if (!startSeen) {
|
|
1956
1994
|
startSeen = true;
|
|
1957
|
-
if (!fragmented)
|
|
1958
|
-
|
|
1959
|
-
break;
|
|
1960
|
-
}
|
|
1961
|
-
} else if (fragmented) {
|
|
1962
|
-
complete = true;
|
|
1963
|
-
break;
|
|
1964
|
-
}
|
|
1995
|
+
if (!fragmented) break;
|
|
1996
|
+
} else if (fragmented) break;
|
|
1965
1997
|
currID = currID + 1 & 65535;
|
|
1966
1998
|
}
|
|
1967
|
-
if (!complete) return null;
|
|
1968
1999
|
const combined = new Uint8Array(totalSize);
|
|
1969
2000
|
let pos = 0;
|
|
1970
2001
|
for (const frag of fragments) {
|
|
@@ -1995,10 +2026,6 @@ var PacketHandler = class {
|
|
|
1995
2026
|
}
|
|
1996
2027
|
#updatePostReceiveState(p) {
|
|
1997
2028
|
const pType = packetType(p);
|
|
1998
|
-
if (pType === PacketType.Init1) {
|
|
1999
|
-
this.#initPacketCheck = null;
|
|
2000
|
-
return;
|
|
2001
|
-
}
|
|
2002
2029
|
if ((pType === PacketType.Ack || pType === PacketType.AckLow) && p.data.length >= 2) {
|
|
2003
2030
|
const ackID = new DataView(p.data.buffer, p.data.byteOffset).getUint16(0, false);
|
|
2004
2031
|
const key = (pType === PacketType.Ack ? PacketType.Command : PacketType.CommandLow) << 16 | ackID;
|
|
@@ -2589,6 +2616,7 @@ function handleHandshakeInitIV(client, params) {
|
|
|
2589
2616
|
const alpha = params["alpha"] ?? "";
|
|
2590
2617
|
const beta = params["beta"] ?? "";
|
|
2591
2618
|
const omega = params["omega"] ?? "";
|
|
2619
|
+
client.handler.receivedFinalInitAck();
|
|
2592
2620
|
client.crypt.initCrypto(alpha, beta, omega);
|
|
2593
2621
|
client.logger.info("crypto initialized (P-256 path), sending clientinit");
|
|
2594
2622
|
sendClientInit(client);
|
|
@@ -3265,7 +3293,7 @@ var Client = class {
|
|
|
3265
3293
|
* Send a raw command line and return the rows that answer it: the escape
|
|
3266
3294
|
* hatch for a command the typed functions do not cover. The line is sent as
|
|
3267
3295
|
* given, so its values must already be escaped and any channel password
|
|
3268
|
-
* already hashed.
|
|
3296
|
+
* already hashed. `CommandName` lists the command names.
|
|
3269
3297
|
*
|
|
3270
3298
|
* Rejects with a NotConnectedError unless the client is connected: while it
|
|
3271
3299
|
* is still connecting, the session's keys may not exist yet.
|
|
@@ -3275,7 +3303,8 @@ var Client = class {
|
|
|
3275
3303
|
}
|
|
3276
3304
|
/**
|
|
3277
3305
|
* Send a raw command line without waiting for an answer, for the few
|
|
3278
|
-
* commands the server answers with nothing at all.
|
|
3306
|
+
* commands the server answers with nothing at all. `CommandName` lists
|
|
3307
|
+
* the command names.
|
|
3279
3308
|
*
|
|
3280
3309
|
* Commands are paced by a flood throttle; aborting `signal` while this waits
|
|
3281
3310
|
* for its turn rejects with the signal's reason and sends nothing. Rejects
|