Make reconnect work if Tor is not reachable at start

master
Frank Ploss 9 years ago
parent c85bc9d1d2
commit 751e413cf7

@ -35,7 +35,7 @@ function init(extensionMeta) {
} }
function enable() { function enable() {
torControlClient = new TorControlClient(); torControlClient = new TorControlClient('127.0.0.1', 9051);
torButton = new TorButton(torControlClient); torButton = new TorButton(torControlClient);
Main.panel.addToStatusArea(torButton.Name, torButton); Main.panel.addToStatusArea(torButton.Name, torButton);
torControlClient.openConnection(); torControlClient.openConnection();

@ -23,12 +23,19 @@ const Gio = imports.gi.Gio;
const Lang = imports.lang; const Lang = imports.lang;
const Signals = imports.signals; const Signals = imports.signals;
const TorConnectionError = new Lang.Class({
Name: 'TorConnectionError',
_init: function(message) {
this.message = message;
}
})
const TorProtocolError = new Lang.Class({ const TorProtocolError = new Lang.Class({
Name: 'TorProtocolError', Name: 'TorProtocolError',
Extends: Error,
_init: function(message, statusCode) { _init: function(message, statusCode) {
this.parent(message); this.message = message;
this.statusCode = statusCode; this.statusCode = statusCode;
} }
}); });
@ -36,47 +43,59 @@ const TorProtocolError = new Lang.Class({
const TorControlClient = new Lang.Class({ const TorControlClient = new Lang.Class({
Name: 'TorControlClient', Name: 'TorControlClient',
_init: function() {
_init: function(host, port) {
this._host = host;
this._port = port;
this._fail_reason = null; this._fail_reason = null;
}, },
openConnection: function() { openConnection: function() {
try { try {
this._connect(); this._connect(this._host, this._port);
this._updateProtocolInfo(); this._updateProtocolInfo();
this._ensureProtocolCompatibility(); this._ensureProtocolCompatibility();
this._authenticate(); this._authenticate();
this.emit('changed-connection-state', 'connected'); this.emit('changed-connection-state', 'ready');
} catch (e if (e instanceof Gio.IOErrorEnum || e instanceof TorProtocolError)) { } catch (e if e instanceof TorConnectionError) {
this.emit('changed-connection-state', 'disconnected', e.message); this.closeConnection(e.message);
} catch (e if e instanceof TorProtocolError) {
//this.emit('protocol-error', 'Error while connecting to Tor control port', e.message);
this.closeConnection(e.message);
} }
}, },
closeConnection: function() { closeConnection: function(reason) {
if (this._connection && this._connection.is_connected()) { if (this._connection && this._connection.is_connected()) {
this._outputStream.close(null); this._connection.close(null);
this._inputStream.close(null); this.emit('changed-connection-state', 'closed', reason);
this.emit('changed-connection-state', 'disconnected');
} }
}, },
switchIdentity: function() { switchIdentity: function() {
var reply = this._runCommand('SIGNAL NEWNYM'); var reply = this._runCommand('SIGNAL NEWNYM');
if (reply.statusCode != 250) { if (reply.statusCode == 250) {
this.emit('switched-tor-identity');
} else {
this.emit( this.emit(
'protocol-error', 'protocol-error',
'Could not switch Tor identity: ' + reply.replyLines.join('\n'), 'Could not switch Tor identity: ' + reply.replyLines.join('\n'),
reply.statusCode reply.statusCode
); );
} else {
this.emit('switched-tor-identity');
} }
}, },
_connect: function() { _connect: function(host, port) {
var socketClient = new Gio.SocketClient(); var socketClient = new Gio.SocketClient();
this._connection = socketClient.connect_to_host('127.0.0.1:9051', null, null);
try {
this._connection = socketClient.connect_to_host(host + ':' + port, null, null);
} catch (e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CONNECTION_REFUSED)) {
throw new TorConnectionError(
'Could not connect to Tor control port (Tor is not listening on ' + host + ':' + port + ')');
}
this._inputStream = new Gio.DataInputStream({base_stream: this._connection.get_input_stream()}); this._inputStream = new Gio.DataInputStream({base_stream: this._connection.get_input_stream()});
this._outputStream = new Gio.DataOutputStream({base_stream: this._connection.get_output_stream()}); this._outputStream = new Gio.DataOutputStream({base_stream: this._connection.get_output_stream()});
}, },
@ -156,11 +175,12 @@ const TorControlClient = new Lang.Class({
return { return {
statusCode: statusCode, statusCode: statusCode,
replyLines: replyLines replyLines: replyLines
} };
}, },
_readLine: function() { _readLine: function() {
return this._inputStream.read_line(null, null)[0].toString().trim(); [line, length] = this._inputStream.read_line(null, null);
return line.toString().trim();
}, },
_parseLine: function(line) { _parseLine: function(line) {

@ -55,9 +55,7 @@ const TorButton = new Lang.Class({
this.actor.add_child(this._icon); this.actor.add_child(this._icon);
//var dummyMenu = new PopupMenu.PopupDummyMenu(this.actor); this._showDisconnectedMenu();
//this.setMenu(dummyMenu);
//Main.panel.menuManager.addMenu(dummyMenu);
}, },
_bindEvents: function() { _bindEvents: function() {
@ -66,34 +64,37 @@ const TorButton = new Lang.Class({
this._torControlClient.connect('protocol-error', Lang.bind(this, this._onProtocolError)); this._torControlClient.connect('protocol-error', Lang.bind(this, this._onProtocolError));
}, },
_onChangedConnectionState: function(source, state, message) { _onChangedConnectionState: function(source, state, message, reason) {
if (this._currentState == state)
return;
this._currentState = state;
switch (state) { switch (state) {
case 'connected': case 'ready':
this._icon.icon_name = TorConnectedIcon; this._showConnectedMenu();
this._menu = new TorPopupMenu(this.actor, this._torControlClient);
this.setMenu(this._menu);
Main.panel.menuManager.addMenu(this._menu);
break; break;
case 'disconnected': case 'closed':
this._icon.icon_name = TorDisconnectedIcon; this._showDisconnectedMenu(reason);
this._menu = new TorDisconnectedMenu(this.actor, this._torControlClient);
this.setMenu(this._menu);
Main.panel.menuManager.addMenu(this._menu);
break; break;
} }
}, },
_showConnectedMenu: function() {
this._icon.icon_name = TorConnectedIcon;
this._menu = new TorPopupMenu(this.actor, this._torControlClient);
this.setMenu(this._menu);
Main.panel.menuManager.addMenu(this._menu);
},
_showDisconnectedMenu: function(reason) {
this._icon.icon_name = TorDisconnectedIcon;
this._menu = new TorDisconnectedMenu(this.actor, this._torControlClient, reason);
this.setMenu(this._menu);
Main.panel.menuManager.addMenu(this._menu);
},
_onSwitchedTorIdentity: function() { _onSwitchedTorIdentity: function() {
Main.notify('Switched to a new Tor identity!'); Main.notify('Switched to a new Tor identity!');
}, },
_onProtocolError: function(source, message, statusCode) { _onProtocolError: function(source, message, statusCode) {
Main.notifyError(message); Main.notifyError('Tor: ' + message);
log('Tor control procotol error (status code ' + statusCode + '): ' + reason) log('Tor control procotol error (status code ' + statusCode + '): ' + reason)
} }
}); });

@ -27,8 +27,9 @@ const TorDisconnectedMenu = new Lang.Class({
Name: 'TorDisconnectedMenu', Name: 'TorDisconnectedMenu',
Extends: PopupMenu.PopupMenu, Extends: PopupMenu.PopupMenu,
_init: function(actor, torControlClient) { _init: function(actor, torControlClient, reason) {
this._torControlClient = torControlClient; this._torControlClient = torControlClient;
this._reason = reason;
this.parent(actor, 0.25, St.Side.TOP); this.parent(actor, 0.25, St.Side.TOP);
this._addActions(); this._addActions();
@ -42,7 +43,7 @@ const TorDisconnectedMenu = new Lang.Class({
var errorMessageMenuItem = new PopupMenu.PopupBaseMenuItem({reactive: false}); var errorMessageMenuItem = new PopupMenu.PopupBaseMenuItem({reactive: false});
errorMessageMenuItem.setSensitive(false); errorMessageMenuItem.setSensitive(false);
errorMessageMenuItem.actor.add_actor(new St.Label({ errorMessageMenuItem.actor.add_actor(new St.Label({
text: 'ERROR running' text: 'No connection. Reason: ' + this._reason
})); }));
this.addMenuItem(errorMessageMenuItem); this.addMenuItem(errorMessageMenuItem);

Loading…
Cancel
Save