... |
... |
@@ -220,49 +220,29 @@ const TorProtocolService = { |
220
|
220
|
// Executes a command on the control port.
|
221
|
221
|
// Return a reply object or null if a fatal error occurs.
|
222
|
222
|
async sendCommand(cmd, args) {
|
223
|
|
- let conn, reply;
|
224
|
|
- const maxAttempts = 2;
|
225
|
|
- for (let attempt = 0; !reply && attempt < maxAttempts; attempt++) {
|
226
|
|
- try {
|
227
|
|
- conn = await this._getConnection();
|
228
|
|
- try {
|
229
|
|
- if (conn) {
|
230
|
|
- reply = await conn.sendCommand(cmd + (args ? " " + args : ""));
|
231
|
|
- if (reply) {
|
232
|
|
- // Return for reuse.
|
233
|
|
- this._returnConnection();
|
234
|
|
- } else {
|
235
|
|
- // Connection is bad.
|
236
|
|
- logger.warn(
|
237
|
|
- "sendCommand returned an empty response, taking the connection as broken and closing it."
|
238
|
|
- );
|
239
|
|
- this._closeConnection();
|
240
|
|
- }
|
241
|
|
- }
|
242
|
|
- } catch (e) {
|
243
|
|
- logger.error(`Cannot send the command ${cmd}`, e);
|
244
|
|
- this._closeConnection();
|
245
|
|
- }
|
246
|
|
- } catch (e) {
|
247
|
|
- logger.error("Cannot get a connection to the control port", e);
|
|
223
|
+ const maxTimeout = 1000;
|
|
224
|
+ let leftConnAttempts = 5;
|
|
225
|
+ let timeout = 250;
|
|
226
|
+ let reply;
|
|
227
|
+ while (leftConnAttempts-- > 0) {
|
|
228
|
+ const response = await this._trySend(cmd, args, leftConnAttempts == 0);
|
|
229
|
+ if (response.connected) {
|
|
230
|
+ reply = response.reply;
|
|
231
|
+ break;
|
248
|
232
|
}
|
249
|
|
- }
|
250
|
|
-
|
251
|
|
- // We failed to acquire the controller after multiple attempts.
|
252
|
|
- // Try again after some time.
|
253
|
|
- if (!conn) {
|
254
|
|
- logger.info(
|
255
|
|
- "sendCommand: Acquiring control connection failed",
|
|
233
|
+ // We failed to acquire the controller after multiple attempts.
|
|
234
|
+ // Try again after some time.
|
|
235
|
+ logger.warn(
|
|
236
|
+ "sendCommand: Acquiring control connection failed, trying again later.",
|
256
|
237
|
cmd,
|
257
|
238
|
args
|
258
|
239
|
);
|
259
|
|
- return new Promise(resolve =>
|
260
|
|
- setTimeout(() => {
|
261
|
|
- resolve(this.sendCommand(cmd, args));
|
262
|
|
- }, 250)
|
263
|
|
- );
|
|
240
|
+ await new Promise(resolve => setTimeout(() => resolve(), timeout));
|
|
241
|
+ timeout = Math.min(2 * timeout, maxTimeout);
|
264
|
242
|
}
|
265
|
243
|
|
|
244
|
+ // We sent the command, but we still got an empty response.
|
|
245
|
+ // Something must be busted elsewhere.
|
266
|
246
|
if (!reply) {
|
267
|
247
|
throw new Error(`${cmd} sent an empty response`);
|
268
|
248
|
}
|
... |
... |
@@ -590,6 +570,48 @@ const TorProtocolService = { |
590
|
570
|
}
|
591
|
571
|
},
|
592
|
572
|
|
|
573
|
+ async _trySend(cmd, args, rethrow) {
|
|
574
|
+ let connected = false;
|
|
575
|
+ let reply;
|
|
576
|
+ let leftAttempts = 2;
|
|
577
|
+ while (leftAttempts-- > 0) {
|
|
578
|
+ let conn;
|
|
579
|
+ try {
|
|
580
|
+ conn = await this._getConnection();
|
|
581
|
+ } catch (e) {
|
|
582
|
+ logger.error("Cannot get a connection to the control port", e);
|
|
583
|
+ if (leftAttempts == 0 && rethrow) {
|
|
584
|
+ throw e;
|
|
585
|
+ }
|
|
586
|
+ }
|
|
587
|
+ if (!conn) {
|
|
588
|
+ continue;
|
|
589
|
+ }
|
|
590
|
+ // If we _ever_ got a connection, the caller should not try again
|
|
591
|
+ connected = true;
|
|
592
|
+ try {
|
|
593
|
+ reply = await conn.sendCommand(cmd + (args ? " " + args : ""));
|
|
594
|
+ if (reply) {
|
|
595
|
+ // Return for reuse.
|
|
596
|
+ this._returnConnection();
|
|
597
|
+ } else {
|
|
598
|
+ // Connection is bad.
|
|
599
|
+ logger.warn(
|
|
600
|
+ "sendCommand returned an empty response, taking the connection as broken and closing it."
|
|
601
|
+ );
|
|
602
|
+ this._closeConnection();
|
|
603
|
+ }
|
|
604
|
+ } catch (e) {
|
|
605
|
+ logger.error(`Cannot send the command ${cmd}`, e);
|
|
606
|
+ this._closeConnection();
|
|
607
|
+ if (leftAttempts == 0 && rethrow) {
|
|
608
|
+ throw e;
|
|
609
|
+ }
|
|
610
|
+ }
|
|
611
|
+ }
|
|
612
|
+ return { connected, reply };
|
|
613
|
+ },
|
|
614
|
+
|
593
|
615
|
// Opens an authenticated connection, sets it to this._controlConnection, and
|
594
|
616
|
// return it.
|
595
|
617
|
async _getConnection() {
|