Coverage for qutebrowser/misc/ipc.py : 89%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org> # # This file is part of qutebrowser. # # qutebrowser is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # qutebrowser is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
# The ipc server instance
"""Get a socketname to use for Windows."""
"""Get a socketname to use.""" if utils.is_windows: # pragma: no cover return _get_socketname_windows(basedir)
"""Base class for IPC exceptions."""
"""Exception raised when there was an error with a QLocalSocket.
Args: code: The error code. message: The error message. action: The action which was taken when the error happened. """
"""Constructor.
Args: action: The action which was taken when the error happened. socket: The QLocalSocket which has the error set. """
self.action, self.message, self.code)
"""Exception raised when there was a problem with listening to IPC.
Args: code: The error code. message: The error message. """
"""Constructor.
Args: local_server: The QLocalServer which has the error set. """
self.message, self.code)
"""Emitted when the server address is already in use."""
"""IPC server to which clients connect to.
Attributes: ignored: Whether requests are ignored (in exception hook). _timer: A timer to handle timeouts. _server: A QLocalServer to accept new connections. _socket: The QLocalSocket we're currently connected to. _socketname: The socketname to use. _atime_timer: Timer to update the atime of the socket regularly.
Signals: got_args: Emitted when there was an IPC connection and arguments were passed. got_args: Emitted with the raw data an IPC connection got. got_invalid_data: Emitted when there was invalid incoming data. """
"""Start the IPC server and listen to commands.
Args: socketname: The socketname to use. parent: The parent to be used. """
if utils.is_windows: # pragma: no cover self._atime_timer = None else:
if utils.is_windows: # pragma: no cover # If we use setSocketOptions on Unix with Qt < 5.4, we get a # NameError while listening... log.ipc.debug("Calling setSocketOptions") self._server.setSocketOptions(QLocalServer.UserAccessOption) else: # pragma: no cover log.ipc.debug("Not calling setSocketOptions")
"""Remove an existing server.""" self._socketname))
"""Start listening on self._socketname.""" else: if not utils.is_windows: # pragma: no cover # If we use setSocketOptions on Unix with Qt < 5.4, we get a # NameError while listening. # (see b135569d5c6e68c735ea83f42e4baf51f7972281) # # Also, we don't get an AddressInUseError with Qt 5.5: # https://bugreports.qt.io/browse/QTBUG-48635 # # This means we only use setSocketOption on Windows... try: os.chmod(self._server.fullServerName(), 0o700) except FileNotFoundError: # https://github.com/qutebrowser/qutebrowser/issues/1530 # The server doesn't actually exist even if ok was reported as # True, so report this as an error. raise ListenError(self._server)
def on_error(self, err): """Raise SocketError on fatal errors.""" # Sometimes this gets called from stale sockets. id(self._socket), self._socket.error(), self._socket.errorString()))
def handle_connection(self): """Handle a new connection to the server.""" "still handling another one (0x{:x}).".format( id(self._socket))) QLocalSocket.PeerClosedError]:
def on_disconnected(self): """Clean up socket when the client disconnected.""" id(self._socket))) # Maybe another connection is waiting.
"""Handle invalid data we got from a QLocalSocket.""" log.ipc.error("Ignoring invalid IPC data from socket 0x{:x}.".format( id(self._socket))) self.got_invalid_data.emit() self._socket.error.connect(self.on_error) self._socket.disconnectFromServer()
"""Handle data (as bytes) we got from on_ready_ready_read.""" except UnicodeDecodeError: log.ipc.error("invalid utf-8: {!r}".format(binascii.hexlify(data))) self._handle_invalid_data() return
except ValueError: log.ipc.error("invalid json: {}".format(decoded.strip())) self._handle_invalid_data() return
log.ipc.error("Missing {}: {}".format(name, decoded.strip())) self._handle_invalid_data() return
except (KeyError, ValueError): log.ipc.error("invalid version: {}".format(decoded.strip())) self._handle_invalid_data() return
log.ipc.error("incompatible version: expected {}, got {}".format( PROTOCOL_VERSION, protocol_version)) self._handle_invalid_data() return
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-April/037375.html target_arg = ''
def on_ready_read(self): """Read json data from the client.""" if self._socket is None: # pragma: no cover # This happens when doing a connection while another one is already # active for some reason. if self._old_socket is None: log.ipc.warning("In on_ready_read with None socket and " "old_socket!") return log.ipc.debug("In on_ready_read with None socket!") socket = self._old_socket else: id(socket), data))
def on_timeout(self): """Cancel the current connection if it was idle for too long.""" if self._socket is None: # pragma: no cover log.ipc.debug("on_timeout got called with None socket!") return log.ipc.error("IPC connection timed out " "(socket 0x{:x}).".format(id(self._socket))) self._socket.disconnectFromServer() if self._socket is not None: # pragma: no cover # on_socket_disconnected sets it to None self._socket.waitForDisconnected(CONNECT_TIMEOUT) if self._socket is not None: # pragma: no cover # on_socket_disconnected sets it to None self._socket.abort()
def update_atime(self): """Update the atime of the socket file all few hours.
From the XDG basedir spec:
To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file. """
"""Shut down the IPC server cleanly.""" id(self._socket)))
"""Try to send a commandline to a running instance.
Blocks for CONNECT_TIMEOUT ms.
Args: socketname: The name which should be used for the socket. command: The command to send to the running instance. target_arg: --target command line argument socket: The socket to read data from, or None.
Return: True if connecting was successful, False if no connection was made. """
'version': qutebrowser.__version__, 'protocol_version': PROTOCOL_VERSION} except OSError: pass else: else: else: QLocalSocket.ServerNotFoundError]: else: socket.error()))
"""Display a message box with an IPC error.""" exc, args, "Error while connecting to running instance!", post_text="Maybe another instance is running but frozen?")
"""Send the args to a running instance or start a new IPCServer.
Args: args: The argparse namespace.
Return: The IPCServer instance if no running instance was detected. None if an instance was running and received our request. """ global server args.target) return None # This could be a race condition... args.target) else: |