sticnarf / tokio-socks

Asynchronous SOCKS proxy support for Rust.
MIT License
68 stars 30 forks source link

Too strict lifetimes #7

Closed apatrushev closed 4 years ago

apatrushev commented 4 years ago

I am trying to implement very simple connection algo (stripped down example):

use futures::future::Future;

use futures::future::IntoFuture;
use std::net::SocketAddr;

fn main() {
    let proxy = std::env::args().nth(1).unwrap();
    let proxy = proxy.parse::<SocketAddr>().unwrap();
    let destination = std::env::args().nth(2).unwrap();
    let socks = tokio_socks::tcp::Socks5Stream::connect(proxy, &destination[..])
        .into_future()
        .map(|_| ())
        .map_err(|_| ());
    tokio::run(socks);
}

Unfortunately it is not possible that way. I even tried to play with lifetimes and realised that tokio-socks requires (it is only hypothesis, I am not very experienced in lifetimes) static lifetime for addresses:

use futures::future::{Future, IntoFuture};
use std::{
    error::Error,
    io::{Error as IoError, ErrorKind},
    net::SocketAddr,
};

type ConnectFuture = Box<dyn Future<Item = tokio::net::TcpStream, Error = IoError> + Send>;

fn connect<'a>(address: &'a String) -> Result<ConnectFuture, Box<dyn Error>> {
    let parts: Vec<_> = address.split("#").collect();
    let (proxy, destination) = (parts[0], parts[1]);
    let proxy = proxy.parse::<SocketAddr>()?;
    Ok(Box::new(
        tokio_socks::tcp::Socks5Stream::connect(proxy, destination)
            .into_future()
            .flatten()
            .map(|tcp| {
                println!("Connected to proxy");
                tcp.into_inner()
            })
            .map_err(|_| IoError::new(ErrorKind::Other, "socks problem")),
    ))
}

fn main() {
    let address = std::env::args().nth(1).unwrap();
    tokio::run(connect(&address).unwrap().map(|_| ()).map_err(|_| ()));
}

rust claims that lifetime of address should be static.

Finally I decided to fork (https://github.com/apatrushev/tokio-socks) and remove all lifetime parameters which fixes the issue. AFAIKS the lifetimes can save only few memory copy which is not so important. Is it possible to fix static requirements? Should I made a PR with lifetimes removal?

sticnarf commented 4 years ago

@apatrushev Sorry, my fault. Now I've uploaded a new version to solve the problem. You can simply pass in an owned String and get a SocksStream which has 'static lifetime.

apatrushev commented 4 years ago

Unfortunately it does not help to find a solution for the code in second example. tokio-socks still claims about lifetimes:

use futures::future::{Future, IntoFuture};
use std::{
    error::Error,
    io::{Error as IoError, ErrorKind},
    net::SocketAddr,
};

type ConnectFuture = Box<dyn Future<Item = tokio::net::TcpStream, Error = IoError> + Send>;

fn connect(address: &String) -> Result<ConnectFuture, Box<dyn Error>> {
    let parts: Vec<_> = address.split("#").collect();
    let (proxy, destination) = (parts[0], parts[1]);
    let proxy = proxy.parse::<SocketAddr>()?;
    Ok(Box::new(
        tokio_socks::tcp::Socks5Stream::connect(proxy, destination)
            .into_future()
            .flatten()
            .map(|tcp| {
                println!("Connected to proxy");
                tcp.into_inner()
            })
            .map_err(|_| IoError::new(ErrorKind::Other, "socks problem")),
    ))
}

fn main() {
    let address = std::env::args().nth(1).unwrap();
    tokio::run(connect(&address).unwrap().map(|_| ()).map_err(|_| ()));
}

Error:

   Compiling tokio-socks v0.1.3 ([...]/tokio-socks)
error[E0621]: explicit lifetime required in the type of `address`
  --> examples/lifetime.rs:14:5
   |
10 |   fn connect(address: &String) -> Result<ConnectFuture, Box<dyn Error>> {
   |                       ------- help: add explicit lifetime `'static` to the type of `address`: `&'static std::string::String`
...
14 | /     Ok(Box::new(
15 | |         tokio_socks::tcp::Socks5Stream::connect(proxy, destination)
16 | |             .into_future()
17 | |             .flatten()
...  |
22 | |             .map_err(|_| IoError::new(ErrorKind::Other, "socks problem")),
23 | |     ))
   | |______^ lifetime `'static` required

error: aborting due to previous error

For more information about this error, try `rustc --explain E0621`.
error: Could not compile `tokio-socks`.

To learn more, run the command again with --verbose.
sticnarf commented 4 years ago

@apatrushev clone your destination please

apatrushev commented 4 years ago

@apatrushev clone your destination please

Thank you for the quick reply. I tried almost all imaginable variants of clone/copy/slice/etc. Nothing helps.

UPD: I found the solution (&destination[..]).to_string(), not the simple one, but I will try to understand whats going on myself. Thank you for your help!

sticnarf commented 4 years ago

@apatrushev clone your destination please

~Thank you for the quick reply. I tried almost all imaginable variants of clone/copy/slice/etc. Nothing helps.~

UPD: I found the solution (&destination[..]).to_string(), not the simple one, but I will try to understand whats going on myself. Thank you for your help!

A simpler solution is: (notice the to_owned)

tokio_socks::tcp::Socks5Stream::connect(proxy, destination.to_owned())