ipc: Update the atime of the socket all 6h.

See #888.
This commit is contained in:
Florian Bruhin 2015-09-10 07:38:11 +02:00
parent 1311e99e7c
commit 58073fd768
2 changed files with 51 additions and 1 deletions

View File

@ -27,7 +27,7 @@ import getpass
import binascii import binascii
import hashlib import hashlib
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, Qt
from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket from PyQt5.QtNetwork import QLocalSocket, QLocalServer, QAbstractSocket
import qutebrowser import qutebrowser
@ -38,6 +38,7 @@ from qutebrowser.utils import (log, usertypes, error, objreg, standarddir,
CONNECT_TIMEOUT = 100 CONNECT_TIMEOUT = 100
WRITE_TIMEOUT = 1000 WRITE_TIMEOUT = 1000
READ_TIMEOUT = 5000 READ_TIMEOUT = 5000
ATIME_INTERVAL = 60 * 60 * 6 * 1000 # 6 hours
PROTOCOL_VERSION = 1 PROTOCOL_VERSION = 1
@ -146,6 +147,7 @@ class IPCServer(QObject):
_socketname: The socketname to use. _socketname: The socketname to use.
_socketopts_ok: Set if using setSocketOptions is working with this _socketopts_ok: Set if using setSocketOptions is working with this
OS/Qt version. OS/Qt version.
_atime_timer: Timer to update the atime of the socket regularily.
Signals: Signals:
got_args: Emitted when there was an IPC connection and arguments were got_args: Emitted when there was an IPC connection and arguments were
@ -168,11 +170,22 @@ class IPCServer(QObject):
super().__init__(parent) super().__init__(parent)
self.ignored = False self.ignored = False
self._socketname = socketname self._socketname = socketname
self._timer = usertypes.Timer(self, 'ipc-timeout') self._timer = usertypes.Timer(self, 'ipc-timeout')
self._timer.setInterval(READ_TIMEOUT) self._timer.setInterval(READ_TIMEOUT)
self._timer.timeout.connect(self.on_timeout) self._timer.timeout.connect(self.on_timeout)
if os.name == 'nt':
self._atime_timer = None
else:
self._atime_timer = usertypes.Timer(self, 'ipc-atime')
self._atime_timer.setInterval(READ_TIMEOUT)
self._atime_timer.timeout.connect(self.update_atime)
self._atime_timer.setTimerType(Qt.VeryCoarseTimer)
self._server = QLocalServer(self) self._server = QLocalServer(self)
self._server.newConnection.connect(self.handle_connection) self._server.newConnection.connect(self.handle_connection)
self._socket = None self._socket = None
self._socketopts_ok = os.name == 'nt' or qtutils.version_check('5.4') self._socketopts_ok = os.name == 'nt' or qtutils.version_check('5.4')
if self._socketopts_ok: # pragma: no cover if self._socketopts_ok: # pragma: no cover
@ -190,6 +203,7 @@ class IPCServer(QObject):
def listen(self): def listen(self):
"""Start listening on self._socketname.""" """Start listening on self._socketname."""
log.ipc.debug("Listening as {}".format(self._socketname)) log.ipc.debug("Listening as {}".format(self._socketname))
self._atime_timer.start()
self._remove_server() self._remove_server()
ok = self._server.listen(self._socketname) ok = self._server.listen(self._socketname)
if not ok: if not ok:
@ -330,12 +344,29 @@ class IPCServer(QObject):
log.ipc.error("IPC connection timed out.") log.ipc.error("IPC connection timed out.")
self._socket.close() self._socket.close()
@pyqtSlot()
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.
"""
path = self._server.fullServerName()
if not path:
log.ipc.error("In update_atime with no server path!")
return
os.utime(path)
def shutdown(self): def shutdown(self):
"""Shut down the IPC server cleanly.""" """Shut down the IPC server cleanly."""
if self._socket is not None: if self._socket is not None:
self._socket.deleteLater() self._socket.deleteLater()
self._socket = None self._socket = None
self._timer.stop() self._timer.stop()
self._atime_timer.stop()
self._server.close() self._server.close()
self._server.deleteLater() self._server.deleteLater()
self._remove_server() self._remove_server()

View File

@ -324,6 +324,25 @@ class TestListen:
assert file_owner_ok or dir_owner_ok assert file_owner_ok or dir_owner_ok
assert file_mode_ok or dir_mode_ok assert file_mode_ok or dir_mode_ok
@pytest.mark.posix
def test_atime_update(self, qtbot, ipc_server):
ipc_server._atime_timer.setInterval(500) # We don't want to wait 6h
ipc_server.listen()
old_atime = os.stat(ipc_server._server.fullServerName()).st_atime_ns
with qtbot.waitSignal(ipc_server._atime_timer.timeout, timeout=2000,
raising=True):
pass
# Make sure the timer is not singleShot
with qtbot.waitSignal(ipc_server._atime_timer.timeout, timeout=2000,
raising=True):
pass
new_atime = os.stat(ipc_server._server.fullServerName()).st_atime_ns
assert old_atime != new_atime
class TestOnError: class TestOnError: