2023-10-02, 08:26 PM
(This post was last modified: 2023-10-02, 09:59 PM by GeoffreyCoulaud. Edited 2 times in total.
Edit Reason: Added wireshark screenshot
)
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) :
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