@@ -70,8 +70,8 @@ use crate::session::{CommonSession, EncryptedState, GlobalRequestResponse, NewKe
7070use crate :: ssh_read:: SshRead ;
7171use crate :: sshbuffer:: { IncomingSshPacket , PacketWriter , SSHBuffer , SshId } ;
7272use crate :: {
73- ChannelId , ChannelOpenFailure , Disconnect , Error , Limits , MethodSet , Sig , auth, map_err , msg ,
74- negotiation,
73+ ChannelId , ChannelOpenFailure , CryptoVec , Disconnect , Error , Limits , MethodSet , Sig , auth,
74+ map_err , msg , negotiation,
7575} ;
7676
7777mod encrypted;
@@ -241,6 +241,13 @@ pub enum Msg {
241241 NoMoreSessions {
242242 want_reply : bool ,
243243 } ,
244+ /// Send a global request with a custom name to the remote
245+ SendGlobalRequest {
246+ name : String ,
247+ data : CryptoVec ,
248+ /// Provide a channel for the reply result to request a reply from the server
249+ reply_channel : Option < oneshot:: Sender < Option < CryptoVec > > > ,
250+ } ,
244251}
245252
246253impl From < ( ChannelId , ChannelMsg ) > for Msg {
@@ -1056,6 +1063,47 @@ impl<H: Handler> Handle<H> {
10561063 . await
10571064 . map_err ( |_| Error :: SendError )
10581065 }
1066+
1067+ /// Send a global request with a custom, non-standard name to the remote peer.
1068+ ///
1069+ /// `data` is the request-specific payload and is appended verbatim after the
1070+ /// request name and the want-reply flag (see RFC 4254 section 4). When
1071+ /// `want_reply` is true this waits for the peer's reply and returns its
1072+ /// response-specific data, which may be empty. When it is false it returns
1073+ /// `Ok(None)` without waiting for a reply.
1074+ pub async fn send_global_request < A : Into < String > > (
1075+ & self ,
1076+ name : A ,
1077+ data : & [ u8 ] ,
1078+ want_reply : bool ,
1079+ ) -> Result < Option < CryptoVec > , Error > {
1080+ let ( reply_channel, reply_recv) = if want_reply {
1081+ let ( send, recv) = oneshot:: channel ( ) ;
1082+ ( Some ( send) , Some ( recv) )
1083+ } else {
1084+ ( None , None )
1085+ } ;
1086+ self . sender
1087+ . send ( Msg :: SendGlobalRequest {
1088+ name : name. into ( ) ,
1089+ data : CryptoVec :: from_slice ( data) ,
1090+ reply_channel,
1091+ } )
1092+ . await
1093+ . map_err ( |_| Error :: SendError ) ?;
1094+
1095+ match reply_recv {
1096+ Some ( reply_recv) => match reply_recv. await {
1097+ Ok ( Some ( data) ) => Ok ( Some ( data) ) ,
1098+ Ok ( None ) => Err ( Error :: RequestDenied ) ,
1099+ Err ( e) => {
1100+ error ! ( "Unable to receive send_global_request result: {e:?}" ) ;
1101+ Err ( Error :: Disconnect )
1102+ }
1103+ } ,
1104+ None => Ok ( None ) ,
1105+ }
1106+ }
10591107}
10601108
10611109impl < H : Handler > Future for Handle < H > {
@@ -1668,6 +1716,13 @@ impl Session {
16681716 Msg :: NoMoreSessions { want_reply } => {
16691717 let _ = self . no_more_sessions ( want_reply) ;
16701718 }
1719+ Msg :: SendGlobalRequest {
1720+ name,
1721+ data,
1722+ reply_channel,
1723+ } => {
1724+ let _ = self . send_global_request ( reply_channel, & name, & data) ;
1725+ }
16711726 Msg :: ServerChannelOpenReply { pending, result } => {
16721727 self . finalize_server_channel_open_reply ( pending, result) ?;
16731728 }
0 commit comments