Struct FtpReceiver

Source
pub struct FtpReceiver { /* private fields */ }
Expand description

“Passive” side of FTP protocol, which mean that receiver expects some data from remote server. As soon as it receives enough data it can “advance” to transmitter state, i.e. fill buffer with commands to be further sent to the remote server.

Implementations§

Source§

impl FtpReceiver

Source

pub fn new() -> Self

Examples found in repository?
examples/ftp-get.rs (line 66)
35fn main() {
36  let url = env::args().nth(1).unwrap();
37  println!("url: {}", url);
38  let ftp_url = Url::parse(&url).unwrap();
39  assert!(ftp_url.scheme() == "ftp");
40
41  let mut username = ftp_url.username();
42  if username == "" { username = "anonymous" };
43
44  let password = match ftp_url.password() {
45    Some(value) => value,
46    None        => "unspecified",
47  };
48
49  assert!(ftp_url.path() != "");
50
51  let host = ftp_url.host().unwrap();
52  let port:u16 = ftp_url.port().or(Some(21)).unwrap();
53  let filename = ftp_url.path_segments().unwrap().last().unwrap();
54  let remote_path = ftp_url.path_segments().unwrap()
55    .take_while(|part| part.to_string() != filename.to_string())
56    .fold(String::new(), |mut acc, part| { acc.push_str("/"); acc.push_str(part); acc } );
57
58  println!("start dowloading {} at {}...", filename, remote_path);
59
60  let mut tx_buff:[u8; 1024] = [0; 1024];
61  let mut tx_count = 0;
62  let mut rx_buff:[u8; 1024] = [0; 1024];
63
64  let host_port = format!("{}:{}", host, port);
65  let mut stream = TcpStream::connect(host_port.as_str()).unwrap();
66  let mut ftp_receiver = FtpReceiver::new();
67
68  let mut transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
69  println!("connected to {}:{}", host, port);
70
71  ftp_receiver = transmitter.send_login(&mut tx_buff, &mut tx_count, username);
72  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
73  println!("login sent...");
74
75  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
76  println!("expecting password...");
77
78  ftp_receiver = transmitter.send_password(&mut tx_buff, &mut tx_count, password);
79  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
80  println!("password sent...");
81
82  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
83  println!("logged in...");
84
85  ftp_receiver = transmitter.send_system_req(&mut tx_buff, &mut tx_count);
86  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
87  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
88  {
89    let (system, subtype) = transmitter.get_system().clone();
90    println!("remote system {} / {}", system, subtype);
91  }
92
93  ftp_receiver = transmitter.send_cwd_req(&mut tx_buff, &mut tx_count, &remote_path);
94  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
95  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
96  println!("cwd to {}", remote_path);
97
98  ftp_receiver = transmitter.send_pwd_req(&mut tx_buff, &mut tx_count);
99  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
100  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
101  println!("changed remote directory is {}", transmitter.get_wd());
102
103  ftp_receiver = transmitter.send_type_req(&mut tx_buff, &mut tx_count, DataMode::Binary);
104  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
105  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
106  println!("switched to binary mode");
107
108  let mut data_stream = {
109    ftp_receiver = transmitter.send_pasv_req(&mut tx_buff, &mut tx_count);
110    let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
111    transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
112    let (addr, port) = transmitter.take_endpoint().clone();
113    println!("confirmed passive connection on {}:{}", addr, port);
114    TcpStream::connect((addr, port)).unwrap()
115  };
116  println!("passive connection opened");
117
118  ftp_receiver = transmitter.send_get_req(&mut tx_buff, &mut tx_count, ftp_url.path());
119
120  let _ = stream.write_all(&tx_buff[0 .. tx_count]).unwrap();
121  transmitter = get_reply(&mut stream, &mut rx_buff, ftp_receiver);
122  println!("starting downloading file {}", filename);
123
124  let mut local_file = File::create(filename).unwrap();
125  let mut eof = false;
126  let mut data_in =  [0; 40960];
127  while !eof {
128    let count = data_stream.read(&mut data_in).unwrap();
129    // println!("got {} bytes", count);
130    eof = count == 0;
131    if !eof { let _ = local_file.write(&data_in[0 .. count]).unwrap(); };
132  }
133  local_file.flush().unwrap();
134  println!("");
135
136  println!("got file {}", filename);
137  let _ = get_reply(&mut stream, &mut rx_buff, transmitter.to_receiver());
138  println!("Success ... ");
139
140}
Source

pub fn try_advance(self, buffer: &[u8]) -> Result<FtpTransmitter, Self>

Try to consume Receiver by parsing buffer and advance into Transmitter. In the case of an error, it returns unmodified Receiver as the error. The actually happened error can be obtained via take_error.

In case of success it remembers the last successful state, probably switches it and returns Transmitter object.

Examples found in repository?
examples/ftp-get.rs (line 21)
13fn get_reply(stream:&mut TcpStream, rx_buff: &mut [u8], receiver: FtpReceiver) -> FtpTransmitter {
14  let mut opt_transmitter = None;
15  let mut opt_receiver = Some(receiver);
16  let mut total_size = 0;
17  while opt_receiver.is_some() {
18    let sz = stream.read(rx_buff).unwrap();
19    total_size = total_size + sz;
20    let ftp_receiver = opt_receiver.take().unwrap();
21    match ftp_receiver.try_advance(&rx_buff[0 .. total_size]) {
22      Ok(transmitter)   => { opt_transmitter = Some(transmitter) }
23      Err(mut receiver) => {
24        match receiver.take_error() {
25          Some(FtpError::NotEnoughData) => { opt_receiver = Some(receiver) }
26          Some(e)  => { panic!(format!("Got unexpected error {}", e )) }
27          _ => {panic!("no advance nor error?")}
28        };
29      }
30    }
31  }
32  opt_transmitter.unwrap()
33}
Source

pub fn take_error(&mut self) -> Option<FtpError>

Returns tha last occurred error, and internally sets up None.

Examples found in repository?
examples/ftp-get.rs (line 24)
13fn get_reply(stream:&mut TcpStream, rx_buff: &mut [u8], receiver: FtpReceiver) -> FtpTransmitter {
14  let mut opt_transmitter = None;
15  let mut opt_receiver = Some(receiver);
16  let mut total_size = 0;
17  while opt_receiver.is_some() {
18    let sz = stream.read(rx_buff).unwrap();
19    total_size = total_size + sz;
20    let ftp_receiver = opt_receiver.take().unwrap();
21    match ftp_receiver.try_advance(&rx_buff[0 .. total_size]) {
22      Ok(transmitter)   => { opt_transmitter = Some(transmitter) }
23      Err(mut receiver) => {
24        match receiver.take_error() {
25          Some(FtpError::NotEnoughData) => { opt_receiver = Some(receiver) }
26          Some(e)  => { panic!(format!("Got unexpected error {}", e )) }
27          _ => {panic!("no advance nor error?")}
28        };
29      }
30    }
31  }
32  opt_transmitter.unwrap()
33}
Source

pub fn to_transmitter(self) -> FtpTransmitter

Sometimes you need to manually advance to Transmitter e.g. in case of Authorization Error, you can re-send other credentials.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.