Skip to content

Commit 920de26

Browse files
feat: add proper cleanup on daemon shutdown
- Send goodbye packets for all registered services - Stop browse and hostname resolution operations - Notify clients with SearchStopped events
1 parent 69418d6 commit 920de26

2 files changed

Lines changed: 447 additions & 0 deletions

File tree

src/service_daemon.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,73 @@ impl Zeroconf {
11521152
Ok(())
11531153
}
11541154

1155+
/// Clean up all resources before shutdown.
1156+
///
1157+
/// This method:
1158+
/// 1. Unregisters all registered services (sends goodbye packets)
1159+
/// 2. Stops all active browse operations
1160+
/// 3. Stops all active hostname resolution operations
1161+
/// 4. Clears all retransmissions
1162+
fn cleanup(&mut self) {
1163+
debug!("Starting cleanup for shutdown");
1164+
1165+
// 1. Unregister all services - send goodbye packets
1166+
let service_names: Vec<String> = self.my_services.keys().cloned().collect();
1167+
for fullname in service_names {
1168+
if let Some(info) = self.my_services.get(&fullname) {
1169+
debug!("Unregistering service during shutdown: {}", &fullname);
1170+
1171+
for intf in self.my_intfs.values() {
1172+
if let Some(sock) = self.ipv4_sock.as_ref() {
1173+
self.unregister_service(info, intf, &sock.pktinfo);
1174+
}
1175+
1176+
if let Some(sock) = self.ipv6_sock.as_ref() {
1177+
self.unregister_service(info, intf, &sock.pktinfo);
1178+
}
1179+
}
1180+
}
1181+
}
1182+
self.my_services.clear();
1183+
1184+
// 2. Stop all browse operations
1185+
let browse_types: Vec<String> = self.service_queriers.keys().cloned().collect();
1186+
for ty_domain in browse_types {
1187+
debug!("Stopping browse during shutdown: {}", &ty_domain);
1188+
if let Some(sender) = self.service_queriers.remove(&ty_domain) {
1189+
// Notify the client
1190+
if let Err(e) = sender.send(ServiceEvent::SearchStopped(ty_domain.clone())) {
1191+
debug!("Failed to send SearchStopped during shutdown: {}", e);
1192+
}
1193+
}
1194+
}
1195+
1196+
// 3. Stop all hostname resolution operations
1197+
let hostnames: Vec<String> = self.hostname_resolvers.keys().cloned().collect();
1198+
for hostname in hostnames {
1199+
debug!(
1200+
"Stopping hostname resolution during shutdown: {}",
1201+
&hostname
1202+
);
1203+
if let Some((sender, _timeout)) = self.hostname_resolvers.remove(&hostname) {
1204+
// Notify the client
1205+
if let Err(e) =
1206+
sender.send(HostnameResolutionEvent::SearchStopped(hostname.clone()))
1207+
{
1208+
debug!(
1209+
"Failed to send HostnameResolutionEvent::SearchStopped during shutdown: {}",
1210+
e
1211+
);
1212+
}
1213+
}
1214+
}
1215+
1216+
// 4. Clear all retransmissions
1217+
self.retransmissions.clear();
1218+
1219+
debug!("Cleanup completed");
1220+
}
1221+
11551222
/// The main event loop of the daemon thread
11561223
///
11571224
/// In each round, it will:
@@ -1254,6 +1321,8 @@ impl Zeroconf {
12541321
// process commands from the command channel
12551322
while let Ok(command) = receiver.try_recv() {
12561323
if matches!(command, Command::Exit(_)) {
1324+
debug!("Exit command received, performing cleanup");
1325+
self.cleanup();
12571326
self.status = DaemonStatus::Shutdown;
12581327
return Some(command);
12591328
}

0 commit comments

Comments
 (0)