From 72ddacfe51e535b7d0e49b01bd05d85c616bad45 Mon Sep 17 00:00:00 2001 From: Mathis Cavalli Date: Mon, 9 Feb 2026 14:45:27 +0100 Subject: [PATCH 1/3] Allow connecting to chromecast over IPv6 --- pychromecast/__init__.py | 2 ++ pychromecast/socket_client.py | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pychromecast/__init__.py b/pychromecast/__init__.py index ff46f0e9e..5766c3ab3 100644 --- a/pychromecast/__init__.py +++ b/pychromecast/__init__.py @@ -11,6 +11,7 @@ import threading from typing import TYPE_CHECKING, Literal, cast, overload from uuid import UUID +import socket import zeroconf @@ -336,6 +337,7 @@ def __init__( retry_wait=retry_wait, services=cast_info.services, zconf=zconf, + ip_family=socket.AF_INET6 if ':' in cast_info.host else socket.AF_INET, ) receiver_controller = self.socket_client.receiver_controller diff --git a/pychromecast/socket_client.py b/pychromecast/socket_client.py index 881b826b9..bdcc94a23 100644 --- a/pychromecast/socket_client.py +++ b/pychromecast/socket_client.py @@ -173,6 +173,7 @@ def __init__( retry_wait: float | None, services: set[HostServiceInfo | MDNSServiceInfo], zconf: zeroconf.Zeroconf | None, + ip_family: socket.AddressFamily = socket.AF_INET, ) -> None: super().__init__() @@ -192,6 +193,7 @@ def __init__( self.host = "unknown" self.port = 8009 + self.ip_family = ip_family self.source_id = "sender-0" self.stop = threading.Event() @@ -291,7 +293,7 @@ def mdns_backoff( self.socket = None self.remote_selector_key = None - self.socket = new_socket() + self.socket = new_socket(self.ip_family) self.remote_selector_key = self.selector.register( self.socket, selectors.EVENT_READ ) @@ -1085,14 +1087,14 @@ def receive_message(self, message: CastMessage, data: dict) -> bool: return False -def new_socket() -> socket.socket: +def new_socket(family: socket.AddressFamily) -> socket.socket: """ Create a new socket with OS-specific parameters Try to set SO_REUSEPORT for BSD-flavored systems if it's an option. Catches errors if not. """ - new_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + new_sock = socket.socket(family, socket.SOCK_STREAM) new_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: From e0a01aa81db4cf262a9646e6cb903fb5bb7a5356 Mon Sep 17 00:00:00 2001 From: Mathis Cavalli Date: Wed, 4 Mar 2026 14:29:32 +0100 Subject: [PATCH 2/3] use socket.create_connection() --- pychromecast/__init__.py | 2 -- pychromecast/socket_client.py | 24 +++++++++--------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/pychromecast/__init__.py b/pychromecast/__init__.py index 5766c3ab3..ff46f0e9e 100644 --- a/pychromecast/__init__.py +++ b/pychromecast/__init__.py @@ -11,7 +11,6 @@ import threading from typing import TYPE_CHECKING, Literal, cast, overload from uuid import UUID -import socket import zeroconf @@ -337,7 +336,6 @@ def __init__( retry_wait=retry_wait, services=cast_info.services, zconf=zconf, - ip_family=socket.AF_INET6 if ':' in cast_info.host else socket.AF_INET, ) receiver_controller = self.socket_client.receiver_controller diff --git a/pychromecast/socket_client.py b/pychromecast/socket_client.py index bdcc94a23..9fb91c879 100644 --- a/pychromecast/socket_client.py +++ b/pychromecast/socket_client.py @@ -173,7 +173,6 @@ def __init__( retry_wait: float | None, services: set[HostServiceInfo | MDNSServiceInfo], zconf: zeroconf.Zeroconf | None, - ip_family: socket.AddressFamily = socket.AF_INET, ) -> None: super().__init__() @@ -193,7 +192,6 @@ def __init__( self.host = "unknown" self.port = 8009 - self.ip_family = ip_family self.source_id = "sender-0" self.stop = threading.Event() @@ -293,11 +291,6 @@ def mdns_backoff( self.socket = None self.remote_selector_key = None - self.socket = new_socket(self.ip_family) - self.remote_selector_key = self.selector.register( - self.socket, selectors.EVENT_READ - ) - self.socket.settimeout(self.timeout) self._report_connection_status( ConnectionStatus( CONNECTION_STATUS_CONNECTING, @@ -357,7 +350,11 @@ def mdns_backoff( self.host, self.port, ) - self.socket.connect((self.host, self.port)) + self.socket = socket.create_connection((self.host, self.port), self.timeout) + configure_socket(self.socket) + self.remote_selector_key = self.selector.register( + self.socket, selectors.EVENT_READ + ) context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) context.check_hostname = False context.verify_mode = ssl.CERT_NONE @@ -1087,15 +1084,14 @@ def receive_message(self, message: CastMessage, data: dict) -> bool: return False -def new_socket(family: socket.AddressFamily) -> socket.socket: +def configure_socket(_socket: socket.socket) -> None: """ - Create a new socket with OS-specific parameters + Configure a socket with OS-specific parameters Try to set SO_REUSEPORT for BSD-flavored systems if it's an option. Catches errors if not. """ - new_sock = socket.socket(family, socket.SOCK_STREAM) - new_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + _socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: # noinspection PyUnresolvedReferences @@ -1104,10 +1100,8 @@ def new_socket(family: socket.AddressFamily) -> socket.socket: pass else: try: - new_sock.setsockopt(socket.SOL_SOCKET, reuseport, 1) + _socket.setsockopt(socket.SOL_SOCKET, reuseport, 1) except (OSError, socket.error) as err: # OSError on python 3, socket.error on python 2 if err.errno != errno.ENOPROTOOPT: raise - - return new_sock From 76616b03d5b85d8441a5f8ecc4c1ca2c5191c944 Mon Sep 17 00:00:00 2001 From: Mathis Cavalli Date: Wed, 4 Mar 2026 14:35:48 +0100 Subject: [PATCH 3/3] Fix format --- pychromecast/socket_client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pychromecast/socket_client.py b/pychromecast/socket_client.py index 9fb91c879..92a71d929 100644 --- a/pychromecast/socket_client.py +++ b/pychromecast/socket_client.py @@ -350,7 +350,9 @@ def mdns_backoff( self.host, self.port, ) - self.socket = socket.create_connection((self.host, self.port), self.timeout) + self.socket = socket.create_connection( + (self.host, self.port), self.timeout + ) configure_socket(self.socket) self.remote_selector_key = self.selector.register( self.socket, selectors.EVENT_READ