@@ -8,7 +8,7 @@ use std::{
88
99use clap:: Parser ;
1010use secrecy:: SecretString ;
11- use shuthost_common:: UnwrapToStringExt as _;
11+ use shuthost_common:: { create_signed_message , UnwrapToStringExt as _} ;
1212
1313use crate :: {
1414 commands:: execute_shutdown,
@@ -50,6 +50,9 @@ pub(crate) fn start_host_agent(mut config: ServiceOptions) {
5050 TcpListener :: bind ( & addr) . unwrap_or_else ( |_| panic ! ( "Failed to bind port {addr}" ) ) ;
5151 println ! ( "Listening on {addr}" ) ;
5252
53+ // Send UDP broadcast with signed announcement message
54+ broadcast_startup ( & config, port) ;
55+
5356 for stream in listener. incoming ( ) {
5457 match stream {
5558 Ok ( stream) => {
@@ -72,6 +75,21 @@ pub(crate) fn start_host_agent(mut config: ServiceOptions) {
7275 }
7376}
7477
78+ fn broadcast_startup ( config : & ServiceOptions , port : u16 ) {
79+ let signed_message = create_signed_message ( "TBD needs some stable reference to the host, probably needs config update" , config. shared_secret . as_ref ( ) . unwrap ( ) ) ;
80+ match create_broadcast_socket ( 0 ) {
81+ Ok ( socket) => {
82+ let broadcast_addr = format ! ( "255.255.255.255:{}" , port) ;
83+ if let Err ( e) = socket. send_to ( signed_message. as_bytes ( ) , & broadcast_addr) {
84+ eprintln ! ( "Failed to send startup broadcast: {e}" ) ;
85+ } else {
86+ println ! ( "Sent startup broadcast to {broadcast_addr}" ) ;
87+ }
88+ }
89+ Err ( e) => eprintln ! ( "Failed to create broadcast socket: {e}" ) ,
90+ }
91+ }
92+
7593/// Handles a client connection: reads data, invokes handler, writes response, and triggers shutdown if needed.
7694/// Returns the action to take after handling the request.
7795fn handle_client ( mut stream : TcpStream , config : & ServiceOptions ) -> Action {
@@ -112,3 +130,15 @@ pub(crate) fn get_default_shutdown_command() -> String {
112130 #[ cfg( target_os = "windows" ) ]
113131 return "shutdown /s /t 0" . to_string ( ) ;
114132}
133+
134+ /// Creates a UDP socket configured for broadcasting on the specified port.
135+ ///
136+ /// Binds to the given port on all interfaces and enables broadcasting.
137+ /// Returns the socket if successful, or an error message if binding or setting broadcast fails.
138+ pub ( crate ) fn create_broadcast_socket ( port : u16 ) -> Result < std:: net:: UdpSocket , String > {
139+ let socket = std:: net:: UdpSocket :: bind ( format ! ( "0.0.0.0:{port}" ) )
140+ . map_err ( |e| format ! ( "Failed to bind socket on port {port}: {e}" ) ) ?;
141+ socket. set_broadcast ( true )
142+ . map_err ( |e| format ! ( "Failed to set broadcast on socket: {e}" ) ) ?;
143+ Ok ( socket)
144+ }
0 commit comments