Skip to content

feat: systemd socket activation support (LISTEN_FDS auto-detect) #66

Description

@dmaugis

When gemini-web2api is managed by systemd's socket activation (.socket unit), systemd passes an already-bound socket as FD 3. The process must not call bind() or it fails with EADDRINUSE. This patch detects the activation environment and uses socket.fromfd() instead.

+19 lines / -2 lines — zero flags, zero config. If LISTEN_FDS is absent, behaviour is identical.

diff :
diff
diff --git a/gemini_web2api.py b/gemini_web2api.py
index 3cd6f4b..8b49560 100644
--- a/gemini_web2api.py
+++ b/gemini_web2api.py
@@ -32,6 +32,7 @@ import os
import hashlib
import argparse
import base64
+import socket
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn

@@ -865,8 +866,26 @@ def main():
allow_reuse_address = True

 port = CONFIG["port"]
  • server = ThreadedServer((CONFIG["host"], port), GeminiHandler)
  • print(f"gemini-web2api v{version}")
  • listen_fds = os.environ.get("LISTEN_FDS")
  • listen_pid = os.environ.get("LISTEN_PID")
  • if listen_fds and listen_pid and int(listen_pid) == os.getpid() and int(listen_fds) > 0:
  •    fd = 3
    
  •    try:
    
  •        sockinfo = socket.fromfd(fd, socket.AF_INET6, socket.SOCK_STREAM).getsockname()
    
  •        fam = socket.AF_INET6 if len(sockinfo) == 4 else socket.AF_INET
    
  •    except OSError:
    
  •        fam = socket.AF_INET
    
  •    sock = socket.fromfd(fd, fam, socket.SOCK_STREAM)
    
  •    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
  •    server = ThreadedServer((CONFIG["host"], port), GeminiHandler, bind_and_activate=False)
    
  •    server.socket = sock
    
  •    server.server_address = (CONFIG["host"], port)
    
  •    print(f"gemini-web2api v{__version__} (systemd socket activation)")
    
  • else:
  •    server = ThreadedServer((CONFIG["host"], port), GeminiHandler)
    
  •    print(f"gemini-web2api v{__version__}")
    

Labels : enhancement

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions