iosignal 5.3.0 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,19 +2,19 @@ import require$$0$2, { Transform } from 'stream';
2
2
  import net from 'net';
3
3
  import require$$0$3 from 'events';
4
4
  import require$$1$1 from 'https';
5
- import require$$2$2 from 'http';
5
+ import require$$2$1 from 'http';
6
6
  import require$$4 from 'tls';
7
7
  import require$$1 from 'crypto';
8
8
  import require$$7 from 'url';
9
9
  import require$$0 from 'zlib';
10
- import fs, { readFileSync } from 'fs';
11
- import path from 'path';
12
- import require$$2, { networkInterfaces } from 'os';
13
10
  import require$$0$1 from 'buffer';
14
- import require$$2$1 from 'util';
11
+ import require$$2 from 'util';
12
+ import { networkInterfaces } from 'os';
13
+ import fs, { readFileSync } from 'fs';
15
14
  import { memoryUsage } from 'process';
15
+ import path from 'path';
16
16
 
17
- var version$1 = "5.3.0";
17
+ var version$1 = "6.1.1";
18
18
  var pkg = {
19
19
  version: version$1};
20
20
 
@@ -665,6 +665,7 @@ const encoder$2 = new TextEncoder();
665
665
  function getSignalPack(tag, ...args) {
666
666
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
667
667
  let tagEncoded = encoder$2.encode(tag);
668
+ if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN1) throw TypeError('tag UTF-8 byte length exceeds 255')
668
669
  let payload = parsePayload(args);
669
670
 
670
671
  let sigPack;
@@ -772,6 +773,16 @@ const Buffer$1 = $$1.Buffer;
772
773
  const encoder$1 = new TextEncoder();
773
774
  const decoder$4 = new TextDecoder();
774
775
 
776
+ // Wire tag lengths use one byte, regardless of JavaScript string length.
777
+ function encodeTag(tag, allowEmpty = true) {
778
+ if (typeof tag !== 'string') throw TypeError('tag should be string.')
779
+ const encoded = encoder$1.encode(tag);
780
+ if ((!allowEmpty && encoded.byteLength === 0) || encoded.byteLength > SIZE_LIMIT.TAG_LEN1) {
781
+ throw TypeError('tag UTF-8 byte length must be ' + (allowEmpty ? '0' : '1') + '~255')
782
+ }
783
+ return encoded
784
+ }
785
+
775
786
  function byteToUrl(buffer) {
776
787
  //ipv4(4bytes) , port(2bytes)
777
788
  if (buffer.byteLength != 6) return
@@ -821,6 +832,7 @@ class IOCore extends EventEmitter {
821
832
  * @type {string}
822
833
  */
823
834
  this.stateName = this.getStateName(); // String type
835
+ this._stateRevision = 0;
824
836
 
825
837
  /**
826
838
  * Transmitted message counter.
@@ -957,14 +969,14 @@ class IOCore extends EventEmitter {
957
969
  * If autoReconnect is false, it also clears the keep-alive timer.
958
970
  */
959
971
  close() {
960
- if (this._closed) return;
961
- this._closed = true;
962
972
  // console.log('####### IOCOre.js close() called')
963
973
  // If auto-reconnect is disabled, we must stop the keep-alive timer.
964
974
  if (this.autoReconnect === false) {
965
975
  clearInterval(this.connectionCheckerIntervalID);
966
976
  this.connectionCheckerIntervalID = null;
967
977
  }
978
+ if (this._closed) return;
979
+ this._closed = true;
968
980
 
969
981
  // socket clean
970
982
  if (this.socket) {
@@ -987,8 +999,11 @@ class IOCore extends EventEmitter {
987
999
  this.socket = null;
988
1000
  }
989
1001
  this.promiseMap.clear();
990
- this.emit('closed');
991
- this.stateChange('closed');
1002
+ this.cid = '';
1003
+ if (this.boho) this.boho.isAuthorized = false;
1004
+ if (this.state !== STATE.STOP && this.stateChange('closed')) {
1005
+ this.emit('closed');
1006
+ }
992
1007
  }
993
1008
 
994
1009
  /**
@@ -1061,6 +1076,7 @@ class IOCore extends EventEmitter {
1061
1076
 
1062
1077
  // The actual connection is created here.
1063
1078
  this.createConnection(this.url);
1079
+ if (this._closed) return; // A connecting listener may have stopped the client.
1064
1080
 
1065
1081
  // Ensure the keep-alive timer is running.
1066
1082
  if (!this.connectionCheckerIntervalID) {
@@ -1085,9 +1101,7 @@ class IOCore extends EventEmitter {
1085
1101
  * Handles the 'close' event of the WebSocket.
1086
1102
  */
1087
1103
  onClose() {
1088
- this.boho.isAuthorized = false;
1089
- this.cid = "";
1090
- this.stateChange('closed');
1104
+ this.close();
1091
1105
  }
1092
1106
 
1093
1107
  /**
@@ -1098,11 +1112,11 @@ class IOCore extends EventEmitter {
1098
1112
  */
1099
1113
  login(id, key) {
1100
1114
  if( this.serverTimeNonce ){
1101
- console.log('iosignal.login serverTimeNonce', this.serverTimeNonce);
1102
1115
  this.auth(id, key);
1103
1116
  this.useAuth = true;
1104
1117
  let auth_pack = this.boho.auth_req(this.serverTimeNonce );
1105
1118
  this.send(auth_pack);
1119
+ this.stateChange('auth_req', 'auth_req');
1106
1120
  }
1107
1121
  return this
1108
1122
  }
@@ -1248,14 +1262,13 @@ class IOCore extends EventEmitter {
1248
1262
  break;
1249
1263
 
1250
1264
  case it.BohoMsg.SERVER_TIME_NONCE: // SERVER_READY
1251
- this.stateChange('server_ready', 'server_ready');
1265
+ buffer.copy(this.serverTimeNonce);
1266
+ if (!this.stateChange('server_ready', 'server_ready')) break;
1252
1267
  if (this.useAuth) {
1253
1268
  this.send(this.boho.auth_req(buffer));
1254
1269
  this.stateChange('auth_req','auth_req');
1255
1270
  // CID_REQ will be called, after auth_res.
1256
1271
  } else {
1257
- // keep server_time_nonce for manual login()
1258
- buffer.copy( this.serverTimeNonce);
1259
1272
  // CID_REQ here, if not using auth.
1260
1273
  this.send(Buffer$1.from([IOMsg.CID_REQ]));
1261
1274
  }
@@ -1306,10 +1319,10 @@ class IOCore extends EventEmitter {
1306
1319
  switch (payloadType) {
1307
1320
 
1308
1321
  case PAYLOAD_TYPE.EMPTY:
1309
- if (tag.indexOf('@') === 0) this.emit('@', tag, null);
1322
+ if (tag.indexOf('@') === 0) this.emit('@', tag);
1310
1323
  else {
1311
- this.emit(tag, tag, null);
1312
- this.emit('message', tag, null);
1324
+ this.emit(tag, tag);
1325
+ this.emit('message', tag);
1313
1326
  }
1314
1327
  break;
1315
1328
 
@@ -1380,14 +1393,16 @@ class IOCore extends EventEmitter {
1380
1393
  break;
1381
1394
 
1382
1395
  case it.BohoMsg.AUTH_FAIL:
1396
+ this.boho.isAuthorized = false;
1383
1397
  this.stateChange('auth_fail', 'auth_fail from server.');
1384
1398
  break;
1385
1399
 
1386
1400
  case it.BohoMsg.AUTH_RES:
1387
1401
  if (this.boho.verify_auth_res(buffer)) {
1388
- this.stateChange('auth_res', 'server sent auth_res');
1402
+ if (!this.stateChange('auth_res', 'server sent auth_res')) break;
1389
1403
  this.send(Buffer$1.from([IOMsg.CID_REQ]));
1390
1404
  } else {
1405
+ this.boho.isAuthorized = false;
1391
1406
  this.stateChange('auth_fail', 'verify_auth_res() invalid server_hmac');
1392
1407
  }
1393
1408
  break;
@@ -1593,6 +1608,7 @@ class IOCore extends EventEmitter {
1593
1608
  */
1594
1609
  signal(tag, ...args) {
1595
1610
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1611
+ if (tag.startsWith('@') && this.cid) encodeTag(this.cid + tag);
1596
1612
  let signalPack = getSignalPack(tag, ...args);
1597
1613
  this.send_enc_mode(signalPack);
1598
1614
  }
@@ -1616,9 +1632,9 @@ class IOCore extends EventEmitter {
1616
1632
  */
1617
1633
  signal_e2e(tag, data, key) {
1618
1634
 
1635
+ const tagEncoded = encodeTag(tag);
1636
+ if (tag.startsWith('@') && this.cid) encodeTag(this.cid + tag);
1619
1637
  if( !this.boho.isAuthorized ) return;
1620
- if (typeof tag !== 'string') throw TypeError('tag should be string.')
1621
- let tagEncoded = encoder$1.encode(tag);
1622
1638
  let dataPack = $$1.B8(data);
1623
1639
 
1624
1640
  //encrypt payload area with key
@@ -1703,39 +1719,37 @@ class IOCore extends EventEmitter {
1703
1719
  * @throws {TypeError} If tag is not a string or exceeds length limit.
1704
1720
  */
1705
1721
  subscribe(tag) {
1706
- if (typeof tag !== 'string') throw TypeError('tag should be string.')
1707
- if (tag.length > SIZE_LIMIT.TAG_LEN1) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN1)
1708
-
1709
- try {
1710
- let tagEncoded = encoder$1.encode(tag);
1711
- this.send_enc_mode(
1712
- Buffer$1.concat([
1713
- $$1.NB('8', IOMsg.SUBSCRIBE),
1714
- $$1.NB('8', tagEncoded.byteLength),
1715
- tagEncoded]));
1716
- } catch (error) { }
1717
-
1722
+ const tagEncoded = encodeTag(tag);
1723
+ this.send_enc_mode(Buffer$1.concat([
1724
+ $$1.NB('8', IOMsg.SUBSCRIBE),
1725
+ $$1.NB('8', tagEncoded.byteLength),
1726
+ tagEncoded]));
1718
1727
  }
1719
1728
 
1720
1729
 
1721
1730
  /**
1722
- * Subscribes stored channels.
1723
- * called client state become 'ready'
1731
+ * Sends subscriptions stored by listen()/link() on each CID-ready transition,
1732
+ * including reconnection. This automates subscription setup for simple clients.
1724
1733
  */
1725
1734
  subscribe_channels() {
1726
- if (this.state !== STATE.READY) return
1727
- if (this.channels.size == 0) return
1728
- let tag = Array.from(this.channels).join(',');
1729
-
1730
- try {
1731
- let tagEncoded = encoder$1.encode(tag);
1732
- this.send_enc_mode(
1733
- Buffer$1.concat([
1734
- $$1.NB('8', IOMsg.SUBSCRIBE),
1735
- $$1.NB('8', tagEncoded.byteLength),
1736
- tagEncoded]));
1737
- } catch (error) { }
1738
-
1735
+ if (this.state !== STATE.READY || this.channels.size === 0) return
1736
+ // Validate the entire list first, then split only at tag boundaries.
1737
+ // Preserve comma-separated entries accepted by existing registration APIs.
1738
+ const tags = Array.from(this.channels).join(',').split(',');
1739
+ const sizes = tags.map(tag => encodeTag(tag).byteLength);
1740
+ const batches = [];
1741
+ let batch = [], bytes = 0;
1742
+ tags.forEach((tag, i) => {
1743
+ if (batch.length && bytes + 1 + sizes[i] > SIZE_LIMIT.TAG_LEN1) {
1744
+ batches.push(batch.join(','));
1745
+ batch = [];
1746
+ bytes = 0;
1747
+ }
1748
+ bytes += (batch.length ? 1 : 0) + sizes[i];
1749
+ batch.push(tag);
1750
+ });
1751
+ if (batch.length) batches.push(batch.join(','));
1752
+ batches.forEach(tag => this.subscribe(tag));
1739
1753
  }
1740
1754
 
1741
1755
  /**
@@ -1744,7 +1758,7 @@ class IOCore extends EventEmitter {
1744
1758
  * @throws {TypeError} If tag is not a string or exceeds length limit.
1745
1759
  */
1746
1760
  unsubscribe(tag = "") {
1747
- if (typeof tag !== 'string') throw TypeError('tag should be string.')
1761
+ const tagEncoded = encodeTag(tag);
1748
1762
 
1749
1763
  if (tag == "") { // blank tag means unsubscribe all
1750
1764
  this.channels.clear();
@@ -1755,8 +1769,6 @@ class IOCore extends EventEmitter {
1755
1769
  });
1756
1770
  }
1757
1771
 
1758
- let tagEncoded = encoder$1.encode(tag);
1759
- if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN1) throw TypeError('please use tag string bytelength below:' + SIZE_LIMIT.TAG_LEN1)
1760
1772
 
1761
1773
  this.send_enc_mode(Buffer$1.concat([
1762
1774
  $$1.NB('8', IOMsg.UNSUBSCRIBE),
@@ -1766,22 +1778,28 @@ class IOCore extends EventEmitter {
1766
1778
 
1767
1779
 
1768
1780
  /**
1769
- * Listens for signals on a specific tag.
1781
+ * Convenience API for simple clients (for example, CLI tools): register a
1782
+ * tag handler once and remember its subscription in channels. Register before
1783
+ * connection readiness; the CID-ready flow subscribes on initial connection
1784
+ * and again after reconnect, without application-level ready/subscribe code.
1785
+ * This does not send a subscription immediately, even if already ready.
1786
+ * For precise subscription/send ordering or dynamic subscriptions, use
1787
+ * on() with subscribe() in a ready handler instead. Direct signals use on('@').
1770
1788
  * @param {string} tag - The tag to listen on.
1771
1789
  * @param {Function} handler - The callback function to handle the signal.
1772
1790
  * @throws {TypeError} If tag is not a string, handler is not a function, or tag length is invalid.
1773
1791
  */
1774
1792
  listen(tag, handler) {
1775
1793
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1776
- if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
1794
+ encodeTag(tag, false);
1777
1795
  if (typeof handler !== 'function') throw TypeError('handler is not a function.')
1778
1796
 
1779
1797
  if (tag.indexOf('@') !== 0) {
1780
1798
  this.channels.add(tag);
1781
1799
  }
1782
1800
  this.on(tag, handler);
1783
- // do not subscribe now.
1784
- // will subscribe when io state is 'ready'. (receive CID_RES from server)
1801
+ // Subscribe from the CID-ready flow, initially and after reconnect.
1802
+ // Keep registration separate from immediate subscription/send ordering.
1785
1803
 
1786
1804
  }
1787
1805
 
@@ -1797,7 +1815,7 @@ class IOCore extends EventEmitter {
1797
1815
  link(to, tag, handler) {
1798
1816
  if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
1799
1817
  if (typeof tag !== 'string') throw TypeError('tag is not a string.')
1800
- if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
1818
+ encodeTag(tag, false);
1801
1819
  if (typeof handler !== 'function') throw TypeError('handler is not a function.')
1802
1820
 
1803
1821
  if (tag.indexOf('@') !== 0) {
@@ -1828,7 +1846,7 @@ class IOCore extends EventEmitter {
1828
1846
  unlink(to, tag) {
1829
1847
  if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
1830
1848
  if (typeof tag !== 'string') throw TypeError('tag is not a string.')
1831
- if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
1849
+ encodeTag(tag, false);
1832
1850
 
1833
1851
  const linkSet = this.linkMap.get(to);
1834
1852
  if (!linkSet || !linkSet.has(tag)) return;
@@ -1921,6 +1939,9 @@ class IOCore extends EventEmitter {
1921
1939
  * 1. 상태가 변경 될 때만 'change' 이벤트 호출된다.
1922
1940
  * 2. emitEventAndMessage 옵션 값이 지정되야 해당 이벤트 이름이 호출된다.
1923
1941
  * 보통 이벤트 이름과 동일하게 적거나 이벤트 상황 안내문을 넣는다.
1942
+ * 3. 두 상태값 갱신 후 change, 개별 이벤트 순서로 호출한다.
1943
+ * 콜백에서 다른 상태로 전이하면 이전 상태의 개별 이벤트는 생략한다.
1944
+ * @returns {boolean} Whether this transition is still current after callbacks.
1924
1945
  */
1925
1946
  stateChange(state, emitEventAndMessage) {
1926
1947
  // STATE constant name <string> upperCase
@@ -1928,16 +1949,19 @@ class IOCore extends EventEmitter {
1928
1949
  // .state <number>
1929
1950
  // console.log('### stateChange reason:', emitEventAndMessage )
1930
1951
  let eventName = state.toLowerCase();
1931
- this.state = STATE[state.toUpperCase()]; // state: number
1932
-
1933
- if (emitEventAndMessage) {
1934
- this.emit(eventName, emitEventAndMessage);
1935
- }
1936
-
1937
- if (this.stateName !== eventName) {
1938
- this.stateName = eventName;
1952
+ const nextState = STATE[state.toUpperCase()];
1953
+ if (typeof nextState !== 'number') throw new TypeError('Unknown state: ' + state);
1954
+ const changed = this.state !== nextState;
1955
+ this.state = nextState;
1956
+ this.stateName = eventName;
1957
+ if (changed) this._stateRevision++;
1958
+ const revision = this._stateRevision;
1959
+ if (changed) {
1939
1960
  this.emit('change', eventName);
1940
1961
  }
1962
+ if (revision !== this._stateRevision) return false;
1963
+ if (emitEventAndMessage) this.emit(eventName, emitEventAndMessage);
1964
+ return revision === this._stateRevision;
1941
1965
  }
1942
1966
 
1943
1967
  }
@@ -2098,6 +2122,7 @@ class IOCongSocket extends IOCore {
2098
2122
  this.congRx = null;
2099
2123
  }
2100
2124
  this.socket.removeAllListeners();
2125
+ this.socket.on('error', () => {});
2101
2126
  if (!this.socket.destroyed) {
2102
2127
  this.socket.destroy(); // destroy() is sufficient for forceful closing
2103
2128
  }
@@ -2122,23 +2147,29 @@ class IOCongSocket extends IOCore {
2122
2147
  if (urlObj.protocol != "cong:") {
2123
2148
  urlObj = new URL('cong://' + url);
2124
2149
  }
2125
- this.socket = net.createConnection(urlObj.port, urlObj.hostname);
2126
- this.stateChange('connecting','connecting');
2150
+ const socket = this.socket = net.createConnection(urlObj.port, urlObj.hostname);
2151
+ this._closed = false;
2127
2152
 
2128
2153
  this.socket.on('connect', () => {
2154
+ if (this.socket !== socket) return;
2129
2155
  this.congRx = new CongRx();
2130
2156
  this.socket.pipe(this.congRx);
2131
- this.congRx.on("data", this.onTCPSocketMessage.bind(this));
2157
+ this.congRx.on('data', data => {
2158
+ if (this.socket === socket) this.onTCPSocketMessage(data);
2159
+ });
2132
2160
  this.emit('open');
2133
2161
  });
2134
2162
 
2135
2163
  this.socket.on('error', e => {
2164
+ if (this.socket !== socket) return;
2136
2165
  this.emit('error', e);
2137
2166
  });
2138
2167
 
2139
2168
  this.socket.on('close', () => {
2169
+ if (this.socket !== socket) return;
2140
2170
  this.emit('close');
2141
2171
  });
2172
+ this.stateChange('connecting','connecting');
2142
2173
 
2143
2174
  }
2144
2175
 
@@ -2193,300 +2224,6 @@ function requireConstants () {
2193
2224
  return constants;
2194
2225
  }
2195
2226
 
2196
- var bufferutil = {exports: {}};
2197
-
2198
- function commonjsRequire(path) {
2199
- throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
2200
- }
2201
-
2202
- var nodeGypBuild$1 = {exports: {}};
2203
-
2204
- var nodeGypBuild;
2205
- var hasRequiredNodeGypBuild$1;
2206
-
2207
- function requireNodeGypBuild$1 () {
2208
- if (hasRequiredNodeGypBuild$1) return nodeGypBuild;
2209
- hasRequiredNodeGypBuild$1 = 1;
2210
- var fs$1 = fs;
2211
- var path$1 = path;
2212
- var os = require$$2;
2213
-
2214
- // Workaround to fix webpack's build warnings: 'the request of a dependency is an expression'
2215
- var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire; // eslint-disable-line
2216
-
2217
- var vars = (process.config && process.config.variables) || {};
2218
- var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
2219
- var abi = process.versions.modules; // TODO: support old node where this is undef
2220
- var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node');
2221
-
2222
- var arch = process.env.npm_config_arch || os.arch();
2223
- var platform = process.env.npm_config_platform || os.platform();
2224
- var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc');
2225
- var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || '';
2226
- var uv = (process.versions.uv || '').split('.')[0];
2227
-
2228
- nodeGypBuild = load;
2229
-
2230
- function load (dir) {
2231
- return runtimeRequire(load.resolve(dir))
2232
- }
2233
-
2234
- load.resolve = load.path = function (dir) {
2235
- dir = path$1.resolve(dir || '.');
2236
-
2237
- try {
2238
- var name = runtimeRequire(path$1.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_');
2239
- if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD'];
2240
- } catch (err) {}
2241
-
2242
- if (!prebuildsOnly) {
2243
- var release = getFirst(path$1.join(dir, 'build/Release'), matchBuild);
2244
- if (release) return release
2245
-
2246
- var debug = getFirst(path$1.join(dir, 'build/Debug'), matchBuild);
2247
- if (debug) return debug
2248
- }
2249
-
2250
- var prebuild = resolve(dir);
2251
- if (prebuild) return prebuild
2252
-
2253
- var nearby = resolve(path$1.dirname(process.execPath));
2254
- if (nearby) return nearby
2255
-
2256
- var target = [
2257
- 'platform=' + platform,
2258
- 'arch=' + arch,
2259
- 'runtime=' + runtime,
2260
- 'abi=' + abi,
2261
- 'uv=' + uv,
2262
- armv ? 'armv=' + armv : '',
2263
- 'libc=' + libc,
2264
- 'node=' + process.versions.node,
2265
- process.versions.electron ? 'electron=' + process.versions.electron : '',
2266
- typeof __webpack_require__ === 'function' ? 'webpack=true' : '' // eslint-disable-line
2267
- ].filter(Boolean).join(' ');
2268
-
2269
- throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n')
2270
-
2271
- function resolve (dir) {
2272
- // Find matching "prebuilds/<platform>-<arch>" directory
2273
- var tuples = readdirSync(path$1.join(dir, 'prebuilds')).map(parseTuple);
2274
- var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
2275
- if (!tuple) return
2276
-
2277
- // Find most specific flavor first
2278
- var prebuilds = path$1.join(dir, 'prebuilds', tuple.name);
2279
- var parsed = readdirSync(prebuilds).map(parseTags);
2280
- var candidates = parsed.filter(matchTags(runtime, abi));
2281
- var winner = candidates.sort(compareTags(runtime))[0];
2282
- if (winner) return path$1.join(prebuilds, winner.file)
2283
- }
2284
- };
2285
-
2286
- function readdirSync (dir) {
2287
- try {
2288
- return fs$1.readdirSync(dir)
2289
- } catch (err) {
2290
- return []
2291
- }
2292
- }
2293
-
2294
- function getFirst (dir, filter) {
2295
- var files = readdirSync(dir).filter(filter);
2296
- return files[0] && path$1.join(dir, files[0])
2297
- }
2298
-
2299
- function matchBuild (name) {
2300
- return /\.node$/.test(name)
2301
- }
2302
-
2303
- function parseTuple (name) {
2304
- // Example: darwin-x64+arm64
2305
- var arr = name.split('-');
2306
- if (arr.length !== 2) return
2307
-
2308
- var platform = arr[0];
2309
- var architectures = arr[1].split('+');
2310
-
2311
- if (!platform) return
2312
- if (!architectures.length) return
2313
- if (!architectures.every(Boolean)) return
2314
-
2315
- return { name, platform, architectures }
2316
- }
2317
-
2318
- function matchTuple (platform, arch) {
2319
- return function (tuple) {
2320
- if (tuple == null) return false
2321
- if (tuple.platform !== platform) return false
2322
- return tuple.architectures.includes(arch)
2323
- }
2324
- }
2325
-
2326
- function compareTuples (a, b) {
2327
- // Prefer single-arch prebuilds over multi-arch
2328
- return a.architectures.length - b.architectures.length
2329
- }
2330
-
2331
- function parseTags (file) {
2332
- var arr = file.split('.');
2333
- var extension = arr.pop();
2334
- var tags = { file: file, specificity: 0 };
2335
-
2336
- if (extension !== 'node') return
2337
-
2338
- for (var i = 0; i < arr.length; i++) {
2339
- var tag = arr[i];
2340
-
2341
- if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
2342
- tags.runtime = tag;
2343
- } else if (tag === 'napi') {
2344
- tags.napi = true;
2345
- } else if (tag.slice(0, 3) === 'abi') {
2346
- tags.abi = tag.slice(3);
2347
- } else if (tag.slice(0, 2) === 'uv') {
2348
- tags.uv = tag.slice(2);
2349
- } else if (tag.slice(0, 4) === 'armv') {
2350
- tags.armv = tag.slice(4);
2351
- } else if (tag === 'glibc' || tag === 'musl') {
2352
- tags.libc = tag;
2353
- } else {
2354
- continue
2355
- }
2356
-
2357
- tags.specificity++;
2358
- }
2359
-
2360
- return tags
2361
- }
2362
-
2363
- function matchTags (runtime, abi) {
2364
- return function (tags) {
2365
- if (tags == null) return false
2366
- if (tags.runtime && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
2367
- if (tags.abi && tags.abi !== abi && !tags.napi) return false
2368
- if (tags.uv && tags.uv !== uv) return false
2369
- if (tags.armv && tags.armv !== armv) return false
2370
- if (tags.libc && tags.libc !== libc) return false
2371
-
2372
- return true
2373
- }
2374
- }
2375
-
2376
- function runtimeAgnostic (tags) {
2377
- return tags.runtime === 'node' && tags.napi
2378
- }
2379
-
2380
- function compareTags (runtime) {
2381
- // Precedence: non-agnostic runtime, abi over napi, then by specificity.
2382
- return function (a, b) {
2383
- if (a.runtime !== b.runtime) {
2384
- return a.runtime === runtime ? -1 : 1
2385
- } else if (a.abi !== b.abi) {
2386
- return a.abi ? -1 : 1
2387
- } else if (a.specificity !== b.specificity) {
2388
- return a.specificity > b.specificity ? -1 : 1
2389
- } else {
2390
- return 0
2391
- }
2392
- }
2393
- }
2394
-
2395
- function isNwjs () {
2396
- return !!(process.versions && process.versions.nw)
2397
- }
2398
-
2399
- function isElectron () {
2400
- if (process.versions && process.versions.electron) return true
2401
- if (process.env.ELECTRON_RUN_AS_NODE) return true
2402
- return typeof window !== 'undefined' && window.process && window.process.type === 'renderer'
2403
- }
2404
-
2405
- function isAlpine (platform) {
2406
- return platform === 'linux' && fs$1.existsSync('/etc/alpine-release')
2407
- }
2408
-
2409
- // Exposed for unit tests
2410
- // TODO: move to lib
2411
- load.parseTags = parseTags;
2412
- load.matchTags = matchTags;
2413
- load.compareTags = compareTags;
2414
- load.parseTuple = parseTuple;
2415
- load.matchTuple = matchTuple;
2416
- load.compareTuples = compareTuples;
2417
- return nodeGypBuild;
2418
- }
2419
-
2420
- var hasRequiredNodeGypBuild;
2421
-
2422
- function requireNodeGypBuild () {
2423
- if (hasRequiredNodeGypBuild) return nodeGypBuild$1.exports;
2424
- hasRequiredNodeGypBuild = 1;
2425
- const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire; // eslint-disable-line
2426
- if (typeof runtimeRequire.addon === 'function') { // if the platform supports native resolving prefer that
2427
- nodeGypBuild$1.exports = runtimeRequire.addon.bind(runtimeRequire);
2428
- } else { // else use the runtime version here
2429
- nodeGypBuild$1.exports = requireNodeGypBuild$1();
2430
- }
2431
- return nodeGypBuild$1.exports;
2432
- }
2433
-
2434
- var fallback$1;
2435
- var hasRequiredFallback$1;
2436
-
2437
- function requireFallback$1 () {
2438
- if (hasRequiredFallback$1) return fallback$1;
2439
- hasRequiredFallback$1 = 1;
2440
-
2441
- /**
2442
- * Masks a buffer using the given mask.
2443
- *
2444
- * @param {Buffer} source The buffer to mask
2445
- * @param {Buffer} mask The mask to use
2446
- * @param {Buffer} output The buffer where to store the result
2447
- * @param {Number} offset The offset at which to start writing
2448
- * @param {Number} length The number of bytes to mask.
2449
- * @public
2450
- */
2451
- const mask = (source, mask, output, offset, length) => {
2452
- for (var i = 0; i < length; i++) {
2453
- output[offset + i] = source[i] ^ mask[i & 3];
2454
- }
2455
- };
2456
-
2457
- /**
2458
- * Unmasks a buffer using the given mask.
2459
- *
2460
- * @param {Buffer} buffer The buffer to unmask
2461
- * @param {Buffer} mask The mask to use
2462
- * @public
2463
- */
2464
- const unmask = (buffer, mask) => {
2465
- // Required until https://github.com/nodejs/node/issues/9006 is resolved.
2466
- const length = buffer.length;
2467
- for (var i = 0; i < length; i++) {
2468
- buffer[i] ^= mask[i & 3];
2469
- }
2470
- };
2471
-
2472
- fallback$1 = { mask, unmask };
2473
- return fallback$1;
2474
- }
2475
-
2476
- var hasRequiredBufferutil;
2477
-
2478
- function requireBufferutil () {
2479
- if (hasRequiredBufferutil) return bufferutil.exports;
2480
- hasRequiredBufferutil = 1;
2481
-
2482
- try {
2483
- bufferutil.exports = requireNodeGypBuild()(__dirname);
2484
- } catch (e) {
2485
- bufferutil.exports = requireFallback$1();
2486
- }
2487
- return bufferutil.exports;
2488
- }
2489
-
2490
2227
  var hasRequiredBufferUtil;
2491
2228
 
2492
2229
  function requireBufferUtil () {
@@ -2607,7 +2344,7 @@ function requireBufferUtil () {
2607
2344
  /* istanbul ignore else */
2608
2345
  if (!process.env.WS_NO_BUFFER_UTIL) {
2609
2346
  try {
2610
- const bufferUtil$1 = requireBufferutil();
2347
+ const bufferUtil$1 = require('bufferutil');
2611
2348
 
2612
2349
  bufferUtil.exports.mask = function (source, mask, output, offset, length) {
2613
2350
  if (length < 48) _mask(source, mask, output, offset, length);
@@ -3228,92 +2965,6 @@ function requirePermessageDeflate () {
3228
2965
 
3229
2966
  var validation = {exports: {}};
3230
2967
 
3231
- var utf8Validate = {exports: {}};
3232
-
3233
- var fallback;
3234
- var hasRequiredFallback;
3235
-
3236
- function requireFallback () {
3237
- if (hasRequiredFallback) return fallback;
3238
- hasRequiredFallback = 1;
3239
-
3240
- /**
3241
- * Checks if a given buffer contains only correct UTF-8.
3242
- * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
3243
- * Markus Kuhn.
3244
- *
3245
- * @param {Buffer} buf The buffer to check
3246
- * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
3247
- * @public
3248
- */
3249
- function isValidUTF8(buf) {
3250
- const len = buf.length;
3251
- let i = 0;
3252
-
3253
- while (i < len) {
3254
- if ((buf[i] & 0x80) === 0x00) { // 0xxxxxxx
3255
- i++;
3256
- } else if ((buf[i] & 0xe0) === 0xc0) { // 110xxxxx 10xxxxxx
3257
- if (
3258
- i + 1 === len ||
3259
- (buf[i + 1] & 0xc0) !== 0x80 ||
3260
- (buf[i] & 0xfe) === 0xc0 // overlong
3261
- ) {
3262
- return false;
3263
- }
3264
-
3265
- i += 2;
3266
- } else if ((buf[i] & 0xf0) === 0xe0) { // 1110xxxx 10xxxxxx 10xxxxxx
3267
- if (
3268
- i + 2 >= len ||
3269
- (buf[i + 1] & 0xc0) !== 0x80 ||
3270
- (buf[i + 2] & 0xc0) !== 0x80 ||
3271
- buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80 || // overlong
3272
- buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0 // surrogate (U+D800 - U+DFFF)
3273
- ) {
3274
- return false;
3275
- }
3276
-
3277
- i += 3;
3278
- } else if ((buf[i] & 0xf8) === 0xf0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3279
- if (
3280
- i + 3 >= len ||
3281
- (buf[i + 1] & 0xc0) !== 0x80 ||
3282
- (buf[i + 2] & 0xc0) !== 0x80 ||
3283
- (buf[i + 3] & 0xc0) !== 0x80 ||
3284
- buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80 || // overlong
3285
- buf[i] === 0xf4 && buf[i + 1] > 0x8f || buf[i] > 0xf4 // > U+10FFFF
3286
- ) {
3287
- return false;
3288
- }
3289
-
3290
- i += 4;
3291
- } else {
3292
- return false;
3293
- }
3294
- }
3295
-
3296
- return true;
3297
- }
3298
-
3299
- fallback = isValidUTF8;
3300
- return fallback;
3301
- }
3302
-
3303
- var hasRequiredUtf8Validate;
3304
-
3305
- function requireUtf8Validate () {
3306
- if (hasRequiredUtf8Validate) return utf8Validate.exports;
3307
- hasRequiredUtf8Validate = 1;
3308
-
3309
- try {
3310
- utf8Validate.exports = requireNodeGypBuild()(__dirname);
3311
- } catch (e) {
3312
- utf8Validate.exports = requireFallback();
3313
- }
3314
- return utf8Validate.exports;
3315
- }
3316
-
3317
2968
  var hasRequiredValidation;
3318
2969
 
3319
2970
  function requireValidation () {
@@ -3461,7 +3112,7 @@ function requireValidation () {
3461
3112
  };
3462
3113
  } /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {
3463
3114
  try {
3464
- const isValidUTF8 = requireUtf8Validate();
3115
+ const isValidUTF8 = require('utf-8-validate');
3465
3116
 
3466
3117
  validation.exports.isValidUTF8 = function (buf) {
3467
3118
  return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
@@ -4237,7 +3888,7 @@ function requireSender () {
4237
3888
  const { randomFillSync } = require$$1;
4238
3889
  const {
4239
3890
  types: { isUint8Array }
4240
- } = require$$2$1;
3891
+ } = require$$2;
4241
3892
 
4242
3893
  const PerMessageDeflate = requirePermessageDeflate();
4243
3894
  const { EMPTY_BUFFER, kWebSocket, NOOP } = requireConstants();
@@ -5361,7 +5012,7 @@ function requireWebsocket () {
5361
5012
 
5362
5013
  const EventEmitter = require$$0$3;
5363
5014
  const https = require$$1$1;
5364
- const http = require$$2$2;
5015
+ const http = require$$2$1;
5365
5016
  const net$1 = net;
5366
5017
  const tls = require$$4;
5367
5018
  const { randomBytes, createHash } = require$$1;
@@ -7030,7 +6681,7 @@ function requireWebsocketServer () {
7030
6681
  hasRequiredWebsocketServer = 1;
7031
6682
 
7032
6683
  const EventEmitter = require$$0$3;
7033
- const http = require$$2$2;
6684
+ const http = require$$2$1;
7034
6685
  const { Duplex } = require$$0$2;
7035
6686
  const { createHash } = require$$1;
7036
6687
 
@@ -7608,6 +7259,8 @@ class IOWS extends IOCore {
7608
7259
  close() {
7609
7260
  if (this.socket) {
7610
7261
  this.socket.removeAllListeners();
7262
+ // Closing a connecting ws can emit an asynchronous error after detachment.
7263
+ this.socket.on('error', () => {});
7611
7264
  if (this.socket.readyState !== WebSocket.CLOSED) {
7612
7265
  this.socket.close();
7613
7266
  }
@@ -7627,21 +7280,27 @@ class IOWS extends IOCore {
7627
7280
 
7628
7281
  createConnection(url) {
7629
7282
  // node WebSocket
7630
- this.socket = new WebSocket(url);
7631
- this.stateChange('connecting','connecting');
7283
+ const socket = this.socket = new WebSocket(url);
7284
+ this._closed = false;
7632
7285
 
7633
7286
  this.socket.onopen = () => {
7634
- this.socket.on('message', this.onWebSocketMessage.bind(this));
7287
+ if (this.socket !== socket) return;
7288
+ socket.on('message', data => {
7289
+ if (this.socket === socket) this.onWebSocketMessage(data);
7290
+ });
7635
7291
  this.emit('open');
7636
7292
  };
7637
7293
 
7638
7294
  this.socket.onerror = (e) => {
7295
+ if (this.socket !== socket) return;
7639
7296
  this.emit('error', e);
7640
7297
  };
7641
7298
 
7642
7299
  this.socket.onclose = () => {
7300
+ if (this.socket !== socket) return;
7643
7301
  this.emit('close');
7644
7302
  };
7303
+ this.stateChange('connecting','connecting');
7645
7304
  }
7646
7305
 
7647
7306
  onWebSocketMessage(data) {
@@ -7760,7 +7419,9 @@ class RemoteCore {
7760
7419
  static ssid = 1;
7761
7420
 
7762
7421
  setState(state) {
7422
+ const previous = this.state;
7763
7423
  this.state = state;
7424
+ if (previous !== state) this.manager.server?.emit('remote:state', this, previous);
7764
7425
  if (serverOption.debug.showAuthInfo) {
7765
7426
  this.stateLog.push( state + ":" + STATE[ state] );
7766
7427
  if( state == STATE.AUTH_RES){
@@ -7829,6 +7490,8 @@ class RemoteCore {
7829
7490
  // CongSocket or WebSocket
7830
7491
  onSocketMessage(message, isBinary = true) {
7831
7492
 
7493
+ if (this._closing || this.state === STATE.CLOSED) return;
7494
+
7832
7495
  this.receiveMonitor(); // rx-data, ping/pong and timeout check
7833
7496
  if (!this.rxQuotaChecker(message)) return
7834
7497
 
@@ -7882,10 +7545,11 @@ class RemoteCore {
7882
7545
  break;
7883
7546
 
7884
7547
  case IOMsg.CID_REQ:
7885
- if (this.state < STATE.SERVER_READY) {
7548
+ if (![STATE.SERVER_READY, STATE.AUTH_RES, STATE.AUTH_FAIL, STATE.CID_RES].includes(this.state)) {
7886
7549
  // Protocol violation: CID_REQ was sent before receiving the SERVER_READY signal.
7887
7550
  console.log('CID_REQ before SERVER_READY');
7888
7551
  this.close();
7552
+ return;
7889
7553
  }
7890
7554
 
7891
7555
  if (!this.cid) {
@@ -8005,9 +7669,12 @@ class RemoteCore {
8005
7669
  // client's auth requst
8006
7670
  case it.BohoMsg.AUTH_REQ:
8007
7671
  if (!this.manager.authManager) return
8008
- if (this.state < STATE.SERVER_READY) {
7672
+ // Do not start overlapping verification on the same connection.
7673
+ if (this.state === STATE.AUTH_REQ) return;
7674
+ if (![STATE.SERVER_READY, STATE.AUTH_RES, STATE.AUTH_FAIL, STATE.CID_RES].includes(this.state)) {
8009
7675
  console.log('protocol error. must called auth_req after server_ready');
8010
7676
  this.close();
7677
+ return;
8011
7678
  }
8012
7679
  this.setState(STATE.AUTH_REQ);
8013
7680
  //async
@@ -8356,6 +8023,7 @@ class Remote extends RemoteCore {
8356
8023
  }
8357
8024
 
8358
8025
  close(terminateNow = false) {
8026
+ this._closing = true;
8359
8027
  this.getTraffic();
8360
8028
  if (this.socketType === 'websocket') {
8361
8029
  if (terminateNow) this.socket.terminate();
@@ -8621,6 +8289,7 @@ class Manager {
8621
8289
  if (socket.isAlive === false) {
8622
8290
  console.log('## timeout. cid:', remo.cid);
8623
8291
  remo.close();
8292
+ return;
8624
8293
  }
8625
8294
 
8626
8295
  socket.txCounter++;
@@ -8660,6 +8329,9 @@ class Manager {
8660
8329
 
8661
8330
  removeRemote(remote) {
8662
8331
 
8332
+ remote._closing = true;
8333
+ remote.setState(STATE.CLOSED);
8334
+
8663
8335
  let remoteInfo = `- IP:${remote.ip} #${remote.ssid} cid:${remote.cid} ${remote?.socket.socketType === 'websocket' ? "WS" : "CS"} `;
8664
8336
  if (this.connectionLogger) this.connectionLogger.log(remoteInfo);
8665
8337
  this.deligateSignal(remote, '@state', 'close');
@@ -8697,7 +8369,7 @@ class Manager {
8697
8369
  }
8698
8370
 
8699
8371
  this.remotes.delete(remote);
8700
- this.cid2remote.delete(remote.cid);
8372
+ if (this.cid2remote.get(remote.cid) === remote) this.cid2remote.delete(remote.cid);
8701
8373
  remote = null;
8702
8374
 
8703
8375
  }
@@ -8727,6 +8399,7 @@ class Manager {
8727
8399
  let tagLen = buffer.readUint8(1);
8728
8400
  let newTagBuf = encoder.encode(newTag);
8729
8401
  let newTagLen = newTagBuf.byteLength;
8402
+ if (newTagLen > SIZE_LIMIT.TAG_LEN1) return null;
8730
8403
  let payloadCunk = buffer.subarray(2 + tagLen);
8731
8404
  let newBuffer = Buffer.concat([Buffer.from([msgType, newTagLen]), newTagBuf, payloadCunk]);
8732
8405
  return newBuffer
@@ -8764,6 +8437,7 @@ class Manager {
8764
8437
  }
8765
8438
 
8766
8439
  sender(tag, remote, message) {
8440
+ if (encoder.encode(tag).byteLength > SIZE_LIMIT.TAG_LEN1) return ['err', 'Tag exceeds 255 UTF-8 bytes']
8767
8441
  if (serverOption.membersOnly && !remote.boho.isAuthorized) {
8768
8442
  // console.log("### server reject client signal reason: [membersOnly]" ,tag, remote.cid )
8769
8443
  remote.send(Buffer.from([IOMsg.AUTH_CLEAR]));
@@ -8780,6 +8454,7 @@ class Manager {
8780
8454
  // modify signalpack with cid_appneded tag.
8781
8455
  tag = remote.cid + tag;
8782
8456
  message = this.getNewSignalTagMessage(message, tag);
8457
+ if (!message) return ['err', 'CID-prefixed tag exceeds 255 UTF-8 bytes']
8783
8458
 
8784
8459
  } else if (cidIndex > 0) {
8785
8460
  // uni-cast.
@@ -8789,6 +8464,7 @@ class Manager {
8789
8464
  let ommitCIdTag = '@' + tag.split('@')[1];
8790
8465
  // console.log('uni-cast tag change from', tag, 'to' , ommitCIdTag )
8791
8466
  message = this.getNewSignalTagMessage(message, ommitCIdTag);
8467
+ if (!message) return ['err', 'Tag exceeds 255 UTF-8 bytes']
8792
8468
  // console.log(`origin tag: ${tag} omitTag: ${this.getSignalTag(message)}`)
8793
8469
  this.cid2remote.get(targetCId).send_enc_mode(message);
8794
8470
  return ['ok', 1]
@@ -9265,6 +8941,8 @@ class BohoAuth {
9265
8941
  }
9266
8942
 
9267
8943
  send_auth_fail(peer, reason) {
8944
+ if (peer._closing || peer.state === STATE.CLOSED) return;
8945
+ peer.boho.isAuthorized = false;
9268
8946
  if (this.authLogger) {
9269
8947
  let peerInfo = `FAIL #${peer.ssid} reason:${reason} `;
9270
8948
  this.authLogger.log(peerInfo);
@@ -9273,7 +8951,9 @@ class BohoAuth {
9273
8951
  peer.setState(STATE.AUTH_FAIL);
9274
8952
  // add some delay time.
9275
8953
  setTimeout(e => {
9276
- peer.send(Buffer.from([it.BohoMsg.AUTH_FAIL]));
8954
+ if (!peer._closing && peer.state === STATE.AUTH_FAIL) {
8955
+ peer.send(Buffer.from([it.BohoMsg.AUTH_FAIL]));
8956
+ }
9277
8957
  }, serverOption.auth.delay_auth_fail);
9278
8958
  }
9279
8959
 
@@ -9296,6 +8976,7 @@ class BohoAuth {
9296
8976
 
9297
8977
  //2. get key of id from DB
9298
8978
  let authInfo = await this.keyProvider.getAuth(id);
8979
+ if (peer._closing || peer.state === STATE.CLOSED) return;
9299
8980
  if (!authInfo) {
9300
8981
  this.send_auth_fail(peer, 'NO ID:' + id);
9301
8982
  return
@@ -9328,33 +9009,31 @@ class BohoAuth {
9328
9009
  //4. get info
9329
9010
 
9330
9011
  //5. check duplicate login.
9331
- if (peer.manager.cid2remote.has(authInfo.cid)) {
9012
+ if (peer.manager.cid2remote.has(authInfo.cid) && peer.manager.cid2remote.get(authInfo.cid) !== peer) {
9332
9013
  let old = peer.manager.cid2remote.get(authInfo.cid);
9333
9014
  console.log('[WARN]DUPLICATE_LOGIN detected.', old.cid);
9334
9015
  old.ping(); // check the connection.
9335
- if (old == peer) {
9336
- console.log('## trying to RELOGIN after login.');
9337
- return
9338
- }
9339
9016
 
9340
9017
  let authClearSignal = $$1.pack(
9341
9018
  $$1.MB('#MsgType', '8', IOMsg.AUTH_CLEAR),
9342
9019
  $$1.MB('#reason', 'duplicate login.')
9343
9020
  );
9344
9021
  if (this.keepOldConnection) { // default true
9022
+ peer.boho.isAuthorized = false;
9345
9023
  // keep old connection. reject new connection by sending auth_fail signal.
9346
9024
  // peer.send(authClearSignal)
9347
9025
  if( peer.socketType == 'websocket'){
9348
9026
  this.send_auth_fail(peer, 'duplicate login');
9349
9027
  }else {
9028
+ peer.setState(STATE.AUTH_FAIL);
9350
9029
  peer.close(); //arduino
9351
9030
  }
9352
9031
  } else {
9353
9032
  // accept new connection. stop the old connection by sending auth_clear signal.
9354
9033
  old.send(authClearSignal);
9355
- peer.close();
9034
+ old.close();
9356
9035
  }
9357
- return
9036
+ if (this.keepOldConnection) return
9358
9037
  }
9359
9038
 
9360
9039
  //6. delete current (or anonymouse)cid if exist.