feat: Add option to use unix socket for xml rpc server

This commit is contained in:
2026-08-06 11:42:28 +02:00
parent 835c3a1b61
commit aad540593d
3 changed files with 97 additions and 12 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ watchdog = 1
[XMLRPC] [XMLRPC]
xmlrpc = 1 xmlrpc = 1
aclfile = /etc/revpipyload/aclxmlrpc.conf aclfile = /etc/revpipyload/aclxmlrpc.conf
bindip = 127.0.0.1 bindip = socket
[MQTT] [MQTT]
mqtt = 0 mqtt = 0
+44 -1
View File
@@ -31,6 +31,7 @@ __license__ = "GPLv2"
import gzip import gzip
import os import os
import signal import signal
import socket
import tarfile import tarfile
import zipfile import zipfile
from configparser import ConfigParser from configparser import ConfigParser
@@ -51,7 +52,7 @@ from . import proginit
from .helper import get_revpiled_address, pi_control_reset, refullmatch from .helper import get_revpiled_address, pi_control_reset, refullmatch
from .shared.ipaclmanager import IpAclManager from .shared.ipaclmanager import IpAclManager
from .watchdogs import ResetDriverWatchdog from .watchdogs import ResetDriverWatchdog
from .xrpcserver import SaveXMLRPCServer from .xrpcserver import SaveXMLRPCServer, UnixStreamXMLRPCServer
min_revpimodio = "2.5.0" min_revpimodio = "2.5.0"
@@ -314,6 +315,16 @@ class RevPiPyLoad:
# Bind IP lesen und anpassen # Bind IP lesen und anpassen
self.xmlrpcbindip = \ self.xmlrpcbindip = \
self.globalconfig.get("XMLRPC", "bindip", fallback="127.0.0.1") self.globalconfig.get("XMLRPC", "bindip", fallback="127.0.0.1")
if self.xmlrpcbindip.lower() == "socket":
# Unix Domain Socket mit festem Pfad
self.xmlrpcbindip = "/run/revpipyload/xmlrpc.socket"
self.xmlrpcisunix = True
elif self.xmlrpcbindip.startswith("/"):
# Unix Domain Socket
self.xmlrpcisunix = True
else:
self.xmlrpcisunix = False
if self.xmlrpcbindip == "*": if self.xmlrpcbindip == "*":
self.xmlrpcbindip = "" self.xmlrpcbindip = ""
elif self.xmlrpcbindip == "": elif self.xmlrpcbindip == "":
@@ -388,12 +399,35 @@ class RevPiPyLoad:
self.xsrv = None self.xsrv = None
else: else:
proginit.logger.debug("create xmlrpc server") proginit.logger.debug("create xmlrpc server")
if self.xmlrpcisunix:
# Unix Domain Socket Server
proginit.logger.info(
"starting xmlrpc unix server on {0}".format(self.xmlrpcbindip)
)
# Vorherige Socket-Datei löschen
try:
os.unlink(self.xmlrpcbindip)
except FileNotFoundError:
pass
self.xsrv = UnixStreamXMLRPCServer(
self.xmlrpcbindip,
requestHandler=UnixStreamXMLRPCRequestHandler,
logRequests=False,
allow_none=True,
)
else:
# Standard IP Server
self.xsrv = SaveXMLRPCServer( self.xsrv = SaveXMLRPCServer(
(self.xmlrpcbindip, self.xmlrpcport), (self.xmlrpcbindip, self.xmlrpcport),
logRequests=False, logRequests=False,
allow_none=True, allow_none=True,
ipacl=self.xmlrpcacl ipacl=self.xmlrpcacl
) )
self.xsrv.register_introspection_functions() self.xsrv.register_introspection_functions()
self.xsrv.register_multicall_functions() self.xsrv.register_multicall_functions()
@@ -936,8 +970,17 @@ class RevPiPyLoad:
if self.xsrv is not None: if self.xsrv is not None:
proginit.logger.info("close xmlrpc-server") proginit.logger.info("close xmlrpc-server")
self.xsrv.shutdown()
self.xsrv.server_close() self.xsrv.server_close()
# Unix Socket aufräumen
if hasattr(self.xsrv, "address_family") and \
self.xsrv.address_family == socket.AF_UNIX:
try:
os.unlink(self.xsrv.server_address)
except (FileNotFoundError, AttributeError):
pass
proginit.logger.debug("leave RevPiPyLoad.stop_xmlrpcserver()") proginit.logger.debug("leave RevPiPyLoad.stop_xmlrpcserver()")
def xml_getconfig(self): def xml_getconfig(self):
+42
View File
@@ -4,6 +4,7 @@ __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2023 Sven Sager" __copyright__ = "Copyright (C) 2023 Sven Sager"
__license__ = "GPLv2" __license__ = "GPLv2"
import socket
from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
from . import proginit from . import proginit
@@ -102,3 +103,44 @@ class SaveXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
) )
return False return False
class UnixStreamXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
"""XML-RPC Request-Handler fuer Unix Domain Sockets."""
timeout = 2.0
def setup(self):
"""Initialisiert die Verbindung ohne TCP-spezifische Socket-Optionen."""
self.connection = self.request
if self.timeout is not None:
self.connection.settimeout(self.timeout)
self.rfile = self.connection.makefile("rb", self.rbufsize)
self.wfile = self.connection.makefile("wb", self.wbufsize)
def address_string(self):
"""Liefert einen Namen fuer Logging bei Unix Domain Sockets."""
return "localhost"
class UnixStreamXMLRPCServer(SimpleXMLRPCServer):
"""XML-RPC Server fuer Unix Domain Sockets."""
address_family = socket.AF_UNIX
def _dispatch(self, method, params):
"""Prueft ACL Level fuer angeforderte Methode.
@param method Angeforderte Methode
@param params Argumente fuer Methode
@return Dispatched data
"""
# ACL on a socket is always max level
if method == "xmlmodus":
params = (4,)
return super()._dispatch(method, params)
def register_function(self, acl_level, function, name=None):
"""Override register_function to ignore acl_level for unix sockets."""
return super().register_function(function, name)