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:
Storm Dragon
2026-05-20 20:11:21 -04:00
parent 8467bd74c3
commit 4caef89f6b
10 changed files with 461 additions and 96 deletions
+1 -1
View File
@@ -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: