1 use connect::{ConnectDatagram, Connection, SinkExt, StreamExt};
3 use rustls::ClientConfig;
7 async fn main() -> anyhow::Result<()> {
10 // get ip address and domain from cmd line args
11 let (ip_addr, domain, cafile_path) = parse_args();
13 // construct `rustls` client config
14 let client_config = create_client_config(cafile_path)?;
16 // create a client connection to the server
17 let mut conn = Connection::tls_client(ip_addr, &domain, client_config.into()).await?;
19 // send a message to the server
20 let msg = String::from("Hello world");
21 info!("Sending message: {}", msg);
23 let envelope = ConnectDatagram::with_tag(65535, msg.into_bytes())?;
24 conn.writer().send(envelope).await?;
26 // wait for the server to reply with an ack
27 if let Some(reply) = conn.reader().next().await {
28 let data = reply.data().to_vec();
29 let msg = String::from_utf8(data)?;
31 info!("Received message: {}", msg);
37 fn create_client_config(path: String) -> anyhow::Result<ClientConfig> {
38 let cafile = std::fs::read(path)?;
40 let mut client_pem = std::io::Cursor::new(cafile);
42 let mut client_config = ClientConfig::new();
45 .add_pem_file(&mut client_pem)
46 .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "invalid cert"))?;
51 fn parse_args() -> (String, String, String) {
52 let args: Vec<String> = env::args().collect();
54 let ip_address = match args.get(1) {
57 error!("Need to pass IP address to connect to as first command line argument");
62 let domain = match args.get(2) {
65 error!("Need to pass domain name as second command line argument");
70 let cafile_path = match args.get(3) {
73 error!("Need to pass path to cafile as third command line argument");
79 ip_address.to_string(),
81 cafile_path.to_string(),