0

Update: Related questions helped to understand what the problem is but not to solve it.

I now understand that I can not save the Sftp object with Session in the same struct, and better generate Sftp when needed. New Code is:

use std::io::prelude::*;
use std::io;
use ssh2;
use std::net::TcpStream;
use std::net::ToSocketAddrs;
use std::path::Path;
use ssh2::{Session, Sftp, File};

pub enum SftpClientError {
    Ssh(ssh2::Error),
    Io(io::Error)
}

pub struct SftpClient {
    session: Session,
    stream: TcpStream,
}

impl SftpClient {
    pub fn new<A: ToSocketAddrs>(addr: A) -> SftpClient {
        let mut s = Session::new().unwrap();
        let mut t = TcpStream::connect(addr).unwrap();

        s.handshake(&t).unwrap();

        SftpClient {
            session: s,
            stream: t,
        }
    }

    pub fn get_file(&self, path: &Path) -> Result<(File, Sftp), SftpClientError>  {
        let sftp = self.session.sftp().unwrap();
        let file = match sftp.create(path) {
            Ok(o) => o,
            Err(e) => return Err(SftpClientError::Ssh(e)),
        };

        Ok((file, sftp))
    }
}

Which outputs a slightly different error. The new error is that sftp in the get_file method, does not live long enough. So how can I make it live long enough to return a File and use it on the caller side?

Old Question

The following code tries to create a struct that contains all required data for a SFTP connection in the rust library ssh2. The struct is given as SftpClient and the new function should generate it.

use std::io::prelude::*;
use std::io;
use std::net::TcpStream;
use std::net::ToSocketAddrs;
use ssh2::{Session, Sftp, File};

pub struct SftpClient<'s> {
    session: Session,
    stream: TcpStream,
    connection: Sftp<'s>,
}

impl<'s> SftpClient<'s> {
    pub fn new<A: ToSocketAddrs>(addr: A) -> SftpClient<'s> {
        let mut s = Session::new().unwrap();
        let mut t = TcpStream::connect(addr).unwrap();

        s.handshake(&t).unwrap();

        let sftp = s.sftp().unwrap();
        SftpClient {
            session: s,
            stream: t,
            connection: sftp,
        }
    }
}

When I compile this code rustc complains that s does not live long enough:

src/sftp.rs:20:20: 20:21 error: `s` does not live long enough
src/sftp.rs:20         let sftp = s.sftp().unwrap();
                                  ^
src/sftp.rs:14:61: 26:6 note: reference must be valid for the lifetime 's as defined on the block at 14:60...
src/sftp.rs:14     pub fn new<A: ToSocketAddrs>(addr: A) -> SftpClient<'s> {
src/sftp.rs:15         let mut s = Session::new().unwrap();
src/sftp.rs:16         let mut t = TcpStream::connect(addr).unwrap();
src/sftp.rs:17 
src/sftp.rs:18         s.handshake(&t).unwrap();
src/sftp.rs:19 
               ...
src/sftp.rs:15:45: 26:6 note: ...but borrowed value is only valid for the block suffix following statement 0 at 15:44
src/sftp.rs:15         let mut s = Session::new().unwrap();
src/sftp.rs:16         let mut t = TcpStream::connect(addr).unwrap();
src/sftp.rs:17 
src/sftp.rs:18         s.handshake(&t).unwrap();
src/sftp.rs:19 
src/sftp.rs:20         let sftp = s.sftp().unwrap();

I don't understand why s does not live long enough as it's given to SftpClient just like the Sftp struct. From my understanding they should both live their happy lifes until SftpClient is dropped.

0kp
  • 173
  • 7
  • This is a duplicate of http://stackoverflow.com/q/32209391/155423 if you change the struct names. Does that help? – Shepmaster Aug 30 '15 at 16:05
  • 1
    Or, for more information, I just attempted to create [this canonical question and answer](http://stackoverflow.com/q/32300132/155423). If that seems useful, we can mark this as a duplicate of that. – Shepmaster Aug 30 '15 at 19:07
  • @Shepmaster - The canonical question somewhat helps thanks for writing it up! But as a Rust beginner who faces this exact same problem as here of encapsulating all the necessary pieces to abstract away an SSH "connection to a device", I still struggle to come up with a working solution... – Andrew Y Nov 12 '17 at 21:19
  • @AndrewY if you are a beginner, you can just boil down the duplicate as "this is really hard to get right without causing memory unsafety, therefore it's hard to do in safe Rust". Unfortunately for you in this case, I don't think SO's purpose is to write every Nth variation of a common problem tailored for each unique case. You can look at all the duplicates of that question for more clues, or you could pop into another format (the Rust subreddit, the [user's forum](https://users.rust-lang.org/), IRC, our own SO chat, etc.) and hope someone will walk you through the nuances specific to you. – Shepmaster Nov 12 '17 at 21:26
  • @Shepmaster - thanks, the user forum does seem quite helpful. Particularly, https://users.rust-lang.org/t/solved-first-issue-with-lifetimes/13243/16 seems like a useful idea to play with, so I will go from there. – Andrew Y Nov 12 '17 at 22:03
  • I got it working. I have posted the snippet on the rust forum so someone could critique it. Adding here in case it might be useful to someone. https://users.rust-lang.org/t/ssh2-encapsulating-session-and-channel/13839 – Andrew Y Nov 13 '17 at 00:03

0 Answers0