More work on sockets attempt to get socket command to standard daemon.sock to a running instance. Also, fixed a long standing misspelling in daemon, was deamon, so if your scripts that self-voice or whatever with fenrir no longer work, this is why, please update scripts to the new, correct, daemon.sock.
This commit is contained in:
@@ -485,7 +485,7 @@ class FenrirManager:
|
||||
os.unlink(pid_socket_file)
|
||||
|
||||
# Clean up main socket only if it is stale (not active)
|
||||
main_socket_file = "/tmp/fenrirscreenreader-deamon.sock"
|
||||
main_socket_file = "/tmp/fenrirscreenreader-daemon.sock"
|
||||
if os.path.exists(main_socket_file):
|
||||
try:
|
||||
test_sock = socket.socket(
|
||||
|
||||
@@ -8,6 +8,7 @@ import os
|
||||
import os.path
|
||||
import select
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
|
||||
from fenrirscreenreader.core import debug
|
||||
@@ -16,7 +17,7 @@ from fenrirscreenreader.core.eventData import FenrirEventType
|
||||
from fenrirscreenreader.core.remoteDriver import RemoteDriver as remoteDriver
|
||||
|
||||
|
||||
MAIN_SOCKET_FILE = "/tmp/fenrirscreenreader-deamon.sock"
|
||||
MAIN_SOCKET_FILE = "/tmp/fenrirscreenreader-daemon.sock"
|
||||
|
||||
|
||||
class driver(remoteDriver):
|
||||
@@ -132,6 +133,131 @@ class driver(remoteDriver):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _socket_file_for_socket(self, fenrir_sock):
|
||||
for bound_sock, socket_file in self.bound_sockets:
|
||||
if bound_sock == fenrir_sock:
|
||||
return socket_file
|
||||
return ""
|
||||
|
||||
def _get_peer_pid(self, client_sock):
|
||||
so_peercred = getattr(socket, "SO_PEERCRED", 17)
|
||||
try:
|
||||
creds = client_sock.getsockopt(
|
||||
socket.SOL_SOCKET, so_peercred, struct.calcsize("3i")
|
||||
)
|
||||
pid, _uid, _gid = struct.unpack("3i", creds)
|
||||
return pid
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
def _get_parent_pid(self, pid):
|
||||
try:
|
||||
with open(f"/proc/{pid}/stat", "r", encoding="utf-8") as proc_file:
|
||||
stat_text = proc_file.read()
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
end_command = stat_text.rfind(")")
|
||||
if end_command == -1:
|
||||
return 0
|
||||
stat_fields = stat_text[end_command + 2 :].split()
|
||||
if len(stat_fields) < 2:
|
||||
return 0
|
||||
try:
|
||||
return int(stat_fields[1])
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
def _find_ancestor_private_socket(self, pid):
|
||||
seen_pids = set()
|
||||
while pid > 1 and pid not in seen_pids:
|
||||
seen_pids.add(pid)
|
||||
socket_file = f"/tmp/fenrirscreenreader-{pid}.sock"
|
||||
if self._is_registered_private_socket(socket_file):
|
||||
return socket_file
|
||||
pid = self._get_parent_pid(pid)
|
||||
return ""
|
||||
|
||||
def _is_registered_private_socket(self, socket_file):
|
||||
for instance in remoteInstanceRegistry.list_instances():
|
||||
if socket_file in instance.get("socket_files", []):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _get_registered_private_sockets(self):
|
||||
socket_files = []
|
||||
for instance in remoteInstanceRegistry.list_instances():
|
||||
for socket_file in instance.get("socket_files", []):
|
||||
if socket_file == MAIN_SOCKET_FILE:
|
||||
continue
|
||||
if socket_file in socket_files:
|
||||
continue
|
||||
socket_files.append(socket_file)
|
||||
return socket_files
|
||||
|
||||
def _find_available_private_socket(self, preferred_socket=""):
|
||||
socket_files = self._get_registered_private_sockets()
|
||||
if preferred_socket and preferred_socket in socket_files:
|
||||
socket_files.remove(preferred_socket)
|
||||
socket_files.insert(0, preferred_socket)
|
||||
|
||||
for socket_file in socket_files:
|
||||
if self._is_own_socket_file(socket_file):
|
||||
return socket_file
|
||||
if self._is_socket_active(socket_file):
|
||||
return socket_file
|
||||
return ""
|
||||
|
||||
def _is_own_socket_file(self, socket_file):
|
||||
return any(
|
||||
socket_file == bound_socket_file
|
||||
for _bound_sock, bound_socket_file in self.bound_sockets
|
||||
)
|
||||
|
||||
def _has_own_private_socket(self):
|
||||
return any(
|
||||
bound_socket_file != MAIN_SOCKET_FILE
|
||||
for _bound_sock, bound_socket_file in self.bound_sockets
|
||||
)
|
||||
|
||||
def _forward_remote_to_socket(self, data, socket_file):
|
||||
forward_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
try:
|
||||
forward_sock.settimeout(0.2)
|
||||
forward_sock.connect(socket_file)
|
||||
forward_sock.sendall((data + "\n").encode("utf-8"))
|
||||
return True
|
||||
except OSError as e:
|
||||
self.env["runtime"]["DebugManager"].write_debug_out(
|
||||
"unixDriver watch_dog: Error forwarding remote data to "
|
||||
+ socket_file
|
||||
+ ": "
|
||||
+ str(e),
|
||||
debug.DebugLevel.ERROR,
|
||||
)
|
||||
return False
|
||||
finally:
|
||||
forward_sock.close()
|
||||
|
||||
def _route_main_socket_command(self, data, client_sock, socket_file):
|
||||
if socket_file != MAIN_SOCKET_FILE:
|
||||
return False
|
||||
if not self._has_own_private_socket():
|
||||
return False
|
||||
|
||||
peer_pid = self._get_peer_pid(client_sock)
|
||||
ancestor_socket = ""
|
||||
if peer_pid > 1:
|
||||
ancestor_socket = self._find_ancestor_private_socket(peer_pid)
|
||||
target_socket = self._find_available_private_socket(ancestor_socket)
|
||||
if not target_socket:
|
||||
return False
|
||||
|
||||
if self._is_own_socket_file(target_socket):
|
||||
return False
|
||||
|
||||
return self._forward_remote_to_socket(data, target_socket)
|
||||
|
||||
def _cleanup(self):
|
||||
for fenrir_sock in self.fenrirSocks:
|
||||
try:
|
||||
@@ -152,7 +278,7 @@ class driver(remoteDriver):
|
||||
self.bound_sockets = []
|
||||
remoteInstanceRegistry.remove_instance()
|
||||
|
||||
def _handle_client(self, client_sock, event_queue):
|
||||
def _handle_client(self, client_sock, event_queue, socket_file=""):
|
||||
try:
|
||||
rawdata = client_sock.recv(8129)
|
||||
except Exception as e:
|
||||
@@ -173,6 +299,9 @@ class driver(remoteDriver):
|
||||
client_sock.sendall((response["message"] + "\n").encode("utf-8"))
|
||||
return
|
||||
|
||||
if self._route_main_socket_command(data, client_sock, socket_file):
|
||||
return
|
||||
|
||||
event_queue.put(
|
||||
{
|
||||
"Type": FenrirEventType.remote_incomming,
|
||||
@@ -188,7 +317,7 @@ class driver(remoteDriver):
|
||||
|
||||
def watch_dog(self, active, event_queue):
|
||||
# echo "command say this is a test" | socat -
|
||||
# UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
# UNIX-CLIENT:/tmp/fenrirscreenreader-daemon.sock
|
||||
for socket_file, optional in self._get_socket_candidates():
|
||||
fenrir_sock = self._bind_socket(socket_file, optional)
|
||||
if fenrir_sock is None:
|
||||
@@ -215,10 +344,11 @@ class driver(remoteDriver):
|
||||
continue
|
||||
for fenrir_sock in r:
|
||||
client_sock, client_addr = fenrir_sock.accept()
|
||||
socket_file = self._socket_file_for_socket(fenrir_sock)
|
||||
# Ensure client socket is always closed to prevent resource
|
||||
# leaks
|
||||
try:
|
||||
self._handle_client(client_sock, event_queue)
|
||||
self._handle_client(client_sock, event_queue, socket_file)
|
||||
finally:
|
||||
# Always close client socket, even if data processing fails
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user