Skip to main content

Crate btp

Crate btp 

Source
Expand description

src/lib.rs

§Welcome

Btp is stands for ‘Blog Transfer Protocol’ which developed while developing this project. The protocol has a basic structure, a ‘header’ which consists of 10 bytes, and the rest of the message, which can be reach 4GiB.

This protocol handles a basic transmission task between server and client. To add this project to repository

cargo add btp

or with TLS,

cargo add btp --features tls

After you added the library to project, It will be accessible under the crate name btp.

§Examples

Let me teach the structure with examples here;


§NO TLS

Example below is not using any safe transmission with TLS encryption, but bare and crystal clear transmission without any security feature, this type of communication may cause some

type Error = Box<dyn std::error::Error + Send + Sync>;
use btp::server::BtpListener;
use btp::message::BtpPackage;
use btp::socket::{BtpConfig, BtpSocket};
use tokio::net::TcpListener;
// Add the items from libraries.

#[tokio::main]
async fn main() -> Result<(), Error> {
    // Create a listener from a tcp listener for port 0.
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let server_addr = listener.local_addr()?;
    let btp_conf = BtpConfig::from_addr(server_addr);

    // Spawn another async thread to handle incoming btp connection.
    let server_task = tokio::spawn(async move {
        // Assign that listener to a BtpListener.
        let btp_listener = BtpListener::from(listener, btp_conf).await;
        // Wait for someone to connect it.
        let mut server_socket = btp_listener.accept().await?;

        // When connection established, wait for the incoming message.
        // And save it safely.
        let msg = server_socket.read().await?;

        // Validate it.
        assert_eq!(msg.unwrap().body1, "Hello, BTP!");

        // Response back with the confirmation message.
        let response = BtpPackage::from_str("ACK");
        server_socket.write(response).await?;
        Ok::<_, Error>(())
    });

    // Create a config for client and connect to btp port you've listened.
    let client_conf = BtpConfig::from_addr(server_addr);
    let mut client_socket = BtpSocket::connect_without_okie_dokie(client_conf).await?;

    // Prepare the request and send it.
    let request = BtpPackage::from_str("Hello, BTP!");
    client_socket.write(request).await?;

    // Wait for the response and handle it safely, then verify it.
    let response = client_socket.read().await?;
    assert_eq!(response.unwrap().body1, "ACK");

    // Wait for server to finish jobs.
    server_task.await??;
    Ok(())
}

§With TLS

type Error = Box<dyn std::error::Error + Send + Sync>;
use btp::message::BtpPackage;
use btp::server::BtpListenerTls;
use btp::socket::{BtpConfig, BtpSocket};
use rustls::ServerConfig;
use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
use std::sync::Arc;
use tokio::net::TcpListener;
use tokio_rustls::TlsConnector;

fn make_test_tls_config() -> (Arc<ServerConfig>, Vec<u8>) {
    let certified = rcgen::generate_simple_self_signed(vec!["127.0.0.1".into()]).unwrap();

    let cert_der = certified.cert.der().to_vec();

    let server_cert = rustls::pki_types::CertificateDer::from(certified.cert.der().clone());

    let key_der = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
        certified.signing_key.serialize_der(),
    ));

    let config = ServerConfig::builder()
        .with_no_client_auth()
        .with_single_cert(vec![server_cert], key_der)
        .unwrap();

    (Arc::new(config), cert_der)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    // Created a listener, then a TLS configurator and cert_der for conf.
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let server_addr = listener.local_addr()?;
    let btp_conf = BtpConfig::from_addr(server_addr);
    let (tls_conf, cert_der) = make_test_tls_config();

    // Create a root certification store for client with cert_der you've created.
    let mut root_store = rustls::RootCertStore::empty();
    root_store.add(cert_der.into()).unwrap();

    // Create the TLS config for client with that root store.
    let client_config = rustls::ClientConfig::builder()
        .with_root_certificates(root_store)
        .with_no_client_auth();

    let server_task = tokio::spawn(async move {
        // Create a thread to assign listener to BtpListenerTls.
        let btp_listener = BtpListenerTls::from(listener, btp_conf, tls_conf).await;

        // Wait for the client to connect.
        let mut server_socket = btp_listener.accept().await?;

        // Wait for the message after client connects.
        let msg = server_socket.read().await?;

        // Validate it.
        assert_eq!(msg.unwrap().body1, "Hello, TLS BTP!");

        // Response to client back.
        let response = BtpPackage::from_str("TLS ACK");
        server_socket.write(response).await?;

        Ok::<_, Error>(())
    });

    // Create the tls_connector for client, then connect to server.
    let connector = TlsConnector::from(Arc::new(client_config));
    let client_conf = BtpConfig::from_addr(server_addr);

    // Wait for connecting to server.
    let mut client_socket = BtpSocket::connect_tls(connector, client_conf).await?;

    // Send message.
    let request = BtpPackage::from_str("Hello, TLS BTP!");
    client_socket.write(request).await?;

    // Take the response back, handle it correctly and verify.
    let response = client_socket.read().await?;
    assert_eq!(response.unwrap().body1, "TLS ACK");

    // Wait for server to complete its jobs.
    server_task.await??;

    Ok(())
}

Modules§

client
For client connections.
message
For parsing messages and files and it headers safely, without any issue.
server
For server connections, brings BtpListener.
socket
For transmitting messages and files safely.

Constants§

VERSION
Actual current version of the protocol. Used in BtpConfig