Jellyfin Forum
Help needed for local server discovery (UDP Broadcast response) - Printable Version

+- Jellyfin Forum (https://forum.jellyfin.org)
+-- Forum: Development (https://forum.jellyfin.org/f-development)
+--- Forum: Client Development (https://forum.jellyfin.org/f-client-development)
+--- Thread: Help needed for local server discovery (UDP Broadcast response) (/t-help-needed-for-local-server-discovery-udp-broadcast-response)



Help needed for local server discovery (UDP Broadcast response) - GeoffreyCoulaud - 2023-10-02

Hello!

I've been working for a few days on a Python/GTK/LibAdwaita client for Jellyfin, for fun mainly.
Here is the repo if anyone is curious (very early stage)

I need a little bit of help with local server discovery.
The general networking docs specify that servers can be discovered by broadcasting "Who is JellyfinServer?" on 7359 UDP.
This does work, by analyzing the network with wireshark I can see the expected response.
However, I can't get a response message in python with the socket opened to broadcast.
But if I hardcode the local Jellyfin server address instead of the interface multicast address, then I can get a response fine.

I've read online that multicast could be more appropriate here, but I don't understand which parameters to use for it. (which multicast group, and why?)

Can anyone give me a little bit of advice here?

(UPDATE) I've attached a Wireshark capture of UDP on the Jellyfin server IP.
On it, we can see that the response does arrive to my machine. The destination port changes everytime tho, that is intriguing.

Extract of the Python code (github permalink) :
Code:
def detect_servers_thread_func(self) -> None:
    for name, address_info_list in psutil.net_if_addrs().items():
        for address_info in address_info_list:
            if (
                address_info.family not in (AF_INET, AF_INET6)
                or address_info.broadcast is None
            ):
                continue
            # TODO Run async
            self.detect_servers_on_interface(
                name, address_info.family, address_info.broadcast
            )

def detect_servers_on_interface(
    self,
    interface_name: str,
    address_family: socket.AddressFamily,
    broadcast_address: str,
) -> None:
    MSG_ENCODING = "utf-8"
    RECV_BUFFER_SIZE = 4096
    JELLYFIN_DISCOVER_PORT = 7359
    DISCOVER_SEND_TIMEOUT_SECONDS = 5
    # TODO use 30 seconds when not testing
    DISCOVER_RECV_TIMEOUT_SECONDS = 5

    with socket.socket(
        family=address_family, type=SOCK_DGRAM, proto=IPPROTO_UDP
    ) as sock:
        logging.debug(
            "Discovering servers on %s (%s) %s",
            interface_name,
            address_family,
            broadcast_address,
        )

        # Prepare sockets
        interface_name_buffer = bytearray(interface_name, encoding="utf-8")
        sock.setsockopt(SOL_SOCKET, SO_BINDTODEVICE, interface_name_buffer)
        sock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
        sock.settimeout(DISCOVER_SEND_TIMEOUT_SECONDS)

        # Broadcast discovery message
        msg = bytearray("Who is JellyfinServer?", encoding=MSG_ENCODING)
        try:
            sock.sendto(msg, (broadcast_address, JELLYFIN_DISCOVER_PORT))
        except TimeoutError:
            logging.error("Server discovery broadcast send timed out")
            return

        # Listen for responses
        start = time.time()
        elapsed = 0
        logging.debug("Listening for server responses")
        while elapsed < DISCOVER_RECV_TIMEOUT_SECONDS:
            sock.settimeout(DISCOVER_RECV_TIMEOUT_SECONDS - elapsed)
            try:
                (data, address_info) = sock.recvfrom(RECV_BUFFER_SIZE)
            except TimeoutError:
                logging.info("Server discovery receive timed out")
                break
            msg = data.decode(encoding=MSG_ENCODING)
            # TODO handle response properly
            logging.debug("Response from %s: %s", address_info, msg)
            elapsed = time.time() - start



RE: Help needed for local server discovery (UDP Broadcast response) - GeoffreyCoulaud - 2023-10-03

Update: I tried spinning up a test Jellyfin server with docker on my local machine, and it does get picked up. This makes me think that it may be a network configuration issue? I'd love a hint to what could be misconfigured.