Fix SSDP multicast on macOS Sequoia+
Corrige les problèmes de multicast SSDP sur macOS Sequoia+ en ajustant les interfaces multicast et en utilisant Terminal.app pour l'exécution des binaires en debug et release. - Dans le Makefile : modifie les cibles 'run' et 'run-release' pour lancer l'application via Terminal.app, nécessaire pour le multicast sur macOS Sequoia+ - Dans pmoupnp/src/ssdp/client.rs : améliore la gestion des interfaces multicast en rejoignant le groupe sur toutes les interfaces non loopback et en configurant explicitement l'interface de sortie - Dans pmoupnp/src/ssdp/server.rs : corrige la configuration multicast du serveur en maintenant l'interface de sortie correcte et en désactivant le multicast loopback
This commit is contained in:
14
Makefile
14
Makefile
@@ -161,15 +161,17 @@ watch:
|
|||||||
ci: fmt-check clippy test doc-build webapp
|
ci: fmt-check clippy test doc-build webapp
|
||||||
@echo "$(GREEN)✓ Toutes les vérifications CI passées$(NC)"
|
@echo "$(GREEN)✓ Toutes les vérifications CI passées$(NC)"
|
||||||
|
|
||||||
## run: Lance le binaire en mode debug
|
## run: Compile en debug et lance via Terminal.app (requis pour le multicast sur macOS Sequoia+)
|
||||||
run: debug
|
run: debug
|
||||||
@echo "$(YELLOW)→ Lancement de l'application...$(NC)"
|
@echo "$(YELLOW)→ Lancement de l'application via Terminal.app...$(NC)"
|
||||||
./target/debug/$(BINARY_NAME)
|
@echo "$(BLUE) (Terminal.app est nécessaire pour le multicast sur macOS Sequoia+)$(NC)"
|
||||||
|
@osascript -e 'tell application "Terminal" to do script "cd \"$(CURDIR)\" && ./target/debug/$(BINARY_NAME) 2>&1 | tee pmomusic.log; exit"'
|
||||||
|
|
||||||
## run-release: Lance le binaire en mode release
|
## run-release: Compile en release et lance via Terminal.app (requis pour le multicast sur macOS Sequoia+)
|
||||||
run-release: release
|
run-release: release
|
||||||
@echo "$(YELLOW)→ Lancement de l'application (release)...$(NC)"
|
@echo "$(YELLOW)→ Lancement de l'application (release) via Terminal.app...$(NC)"
|
||||||
./$(RUST_TARGET)/$(BINARY_NAME)
|
@echo "$(BLUE) (Terminal.app est nécessaire pour le multicast sur macOS Sequoia+)$(NC)"
|
||||||
|
@osascript -e 'tell application "Terminal" to do script "cd \"$(CURDIR)\" && ./$(RUST_TARGET)/$(BINARY_NAME) 2>&1 | tee pmomusic.log; exit"'
|
||||||
|
|
||||||
## size: Affiche la taille du binaire
|
## size: Affiche la taille du binaire
|
||||||
size:
|
size:
|
||||||
|
|||||||
@@ -75,27 +75,42 @@ impl SsdpClient {
|
|||||||
let bind_addr: SocketAddr = "0.0.0.0:0".parse().unwrap();
|
let bind_addr: SocketAddr = "0.0.0.0:0".parse().unwrap();
|
||||||
socket2.bind(&bind_addr.into())?;
|
socket2.bind(&bind_addr.into())?;
|
||||||
|
|
||||||
// Le client SSDP n'a pas besoin de join_multicast_v4 :
|
let socket: UdpSocket = socket2.into();
|
||||||
// il envoie des M-SEARCH et reçoit des réponses unicast.
|
socket.set_read_timeout(Some(Duration::from_secs(1)))?;
|
||||||
// Le join est seulement utile pour recevoir les NOTIFY multicast,
|
socket.set_multicast_loop_v4(true)?; // utile en dev local
|
||||||
// ce dont le SsdpServer s'occupe.
|
|
||||||
//
|
let multicast_addr = SSDP_MULTICAST_ADDR.parse().unwrap();
|
||||||
// On configure uniquement l'interface de sortie multicast sur
|
for iface in get_if_addrs::get_if_addrs()? {
|
||||||
// l'IP principale pour que send_to vers 239.255.255.250 fonctionne.
|
if let std::net::IpAddr::V4(ipv4) = iface.ip() {
|
||||||
// Sur macOS, join_multicast_v4 sur des interfaces bridge/VM écrase
|
if !ipv4.is_loopback() {
|
||||||
// IP_MULTICAST_IF et provoque EHOSTUNREACH (errno 65).
|
match socket.join_multicast_v4(&multicast_addr, &ipv4) {
|
||||||
|
Ok(()) => {
|
||||||
|
debug!("SSDP: joined {} on {}", SSDP_MULTICAST_ADDR, ipv4);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
warn!(
|
||||||
|
"SSDP: failed to join {} on {}: {}",
|
||||||
|
SSDP_MULTICAST_ADDR, ipv4, e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sur macOS, chaque join_multicast_v4 écrase IP_MULTICAST_IF.
|
||||||
|
// On remet explicitement l'interface de sortie sur l'IP principale
|
||||||
|
// pour que send_to vers 239.255.255.250 utilise la bonne interface.
|
||||||
let local_ip: std::net::Ipv4Addr = pmoutils::guess_local_ip()
|
let local_ip: std::net::Ipv4Addr = pmoutils::guess_local_ip()
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap_or("127.0.0.1".parse().unwrap());
|
.unwrap_or("0.0.0.0".parse().unwrap());
|
||||||
|
let socket2 = Socket::from(socket);
|
||||||
socket2.set_multicast_if_v4(&local_ip)?;
|
socket2.set_multicast_if_v4(&local_ip)?;
|
||||||
debug!(
|
debug!(
|
||||||
"SSDP client: multicast outgoing interface set to {}",
|
"SSDP client: multicast outgoing interface set to {}",
|
||||||
local_ip
|
local_ip
|
||||||
);
|
);
|
||||||
|
|
||||||
let socket: UdpSocket = socket2.into();
|
let socket: UdpSocket = socket2.into();
|
||||||
socket.set_read_timeout(Some(Duration::from_secs(1)))?;
|
|
||||||
socket.set_multicast_loop_v4(true)?; // utile en dev local
|
|
||||||
|
|
||||||
info!("✅ SSDP client ready on {}", addr);
|
info!("✅ SSDP client ready on {}", addr);
|
||||||
|
|
||||||
|
|||||||
@@ -74,30 +74,33 @@ impl SsdpServer {
|
|||||||
let bind_addr: SocketAddr = format!("0.0.0.0:{}", SSDP_PORT).parse().unwrap();
|
let bind_addr: SocketAddr = format!("0.0.0.0:{}", SSDP_PORT).parse().unwrap();
|
||||||
socket2.bind(&bind_addr.into())?;
|
socket2.bind(&bind_addr.into())?;
|
||||||
|
|
||||||
// Configurer l'interface de sortie multicast sur l'IP principale.
|
|
||||||
// Sur macOS, sans cela le kernel peut router les paquets multicast
|
|
||||||
// via une interface bridge/VM qui n'a pas de route, causant
|
|
||||||
// EHOSTUNREACH (errno 65).
|
|
||||||
let local_ip: std::net::Ipv4Addr = pmoutils::guess_local_ip()
|
|
||||||
.parse()
|
|
||||||
.unwrap_or("127.0.0.1".parse().unwrap());
|
|
||||||
socket2.set_multicast_if_v4(&local_ip)?;
|
|
||||||
debug!(
|
|
||||||
"SSDP server: multicast outgoing interface set to {}",
|
|
||||||
local_ip
|
|
||||||
);
|
|
||||||
|
|
||||||
// Convertir en UdpSocket standard
|
// Convertir en UdpSocket standard
|
||||||
let socket: UdpSocket = socket2.into();
|
let mut socket: UdpSocket = socket2.into();
|
||||||
|
|
||||||
// Rejoindre le groupe multicast via INADDR_ANY (l'OS choisit l'interface)
|
// Rejoindre le groupe multicast
|
||||||
socket.join_multicast_v4(
|
socket.join_multicast_v4(
|
||||||
&SSDP_MULTICAST_ADDR.parse().unwrap(),
|
&SSDP_MULTICAST_ADDR.parse().unwrap(),
|
||||||
&"0.0.0.0".parse().unwrap(),
|
&"0.0.0.0".parse().unwrap(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// Sur macOS, join_multicast_v4 peut positionner IP_MULTICAST_IF
|
||||||
|
// sur une interface bridge/VM. On remet explicitement l'interface
|
||||||
|
// de sortie sur l'IP principale.
|
||||||
|
let local_ip: std::net::Ipv4Addr = pmoutils::guess_local_ip()
|
||||||
|
.parse()
|
||||||
|
.unwrap_or("0.0.0.0".parse().unwrap());
|
||||||
|
{
|
||||||
|
let socket2 = Socket::from(socket);
|
||||||
|
socket2.set_multicast_if_v4(&local_ip)?;
|
||||||
|
debug!(
|
||||||
|
"SSDP server: multicast outgoing interface set to {}",
|
||||||
|
local_ip
|
||||||
|
);
|
||||||
|
socket = socket2.into();
|
||||||
|
}
|
||||||
|
|
||||||
socket.set_read_timeout(Some(Duration::from_secs(1)))?;
|
socket.set_read_timeout(Some(Duration::from_secs(1)))?;
|
||||||
socket.set_multicast_loop_v4(true)?; // utile en dev local
|
socket.set_multicast_loop_v4(false)?;
|
||||||
|
|
||||||
let socket = Arc::new(socket);
|
let socket = Arc::new(socket);
|
||||||
self.socket = Some(socket.clone());
|
self.socket = Some(socket.clone());
|
||||||
|
|||||||
Reference in New Issue
Block a user