pub mod pb { tonic::include_proto!("/grpc.examples.unaryecho"); } use hyper::server::conn::Http; use pb::{EchoRequest, EchoResponse}; use std::sync::Arc; use tokio::net::TcpListener; use tokio_rustls::{ rustls::{Certificate, PrivateKey, ServerConfig}, TlsAcceptor, }; use tonic::{transport::Server, Request, Response, Status}; use tower_http::ServiceBuilderExt; #[tokio::main] async fn main() -> Result<(), Box> { let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]); let certs = { let fd = std::fs::File::open(data_dir.join("tls/server.pem"))?; let mut buf = std::io::BufReader::new(&fd); rustls_pemfile::certs(&mut buf)? .into_iter() .map(Certificate) .collect() }; let key = { let fd = std::fs::File::open(data_dir.join("tls/server.key"))?; let mut buf = std::io::BufReader::new(&fd); rustls_pemfile::pkcs8_private_keys(&mut buf)? .into_iter() .map(PrivateKey) .next() .unwrap() // let key = std::fs::read(data_dir.join("tls/server.key"))?; // PrivateKey(key) }; let mut tls = ServerConfig::builder() .with_safe_defaults() .with_no_client_auth() .with_single_cert(certs, key)?; tls.alpn_protocols = vec![b"h2".to_vec()]; let server = EchoServer::default(); let svc = Server::builder() .add_service(pb::echo_server::EchoServer::new(server)) .into_service(); let mut http = Http::new(); http.http2_only(true); let listener = TcpListener::bind("[::1]:50051").await?; let tls_acceptor = TlsAcceptor::from(Arc::new(tls)); loop { let (conn, addr) = match listener.accept().await { Ok(incoming) => incoming, Err(e) => { eprintln!("Error accepting connection: {}", e); continue; } }; let http = http.clone(); let tls_acceptor = tls_acceptor.clone(); let svc = svc.clone(); tokio::spawn(async move { let mut certificates = Vec::new(); let conn = tls_acceptor .accept_with(conn, |info| { if let Some(certs) = info.peer_certificates() { for cert in certs { certificates.push(cert.clone()); } } }) .await .unwrap(); let svc = tower::ServiceBuilder::new() .add_extension(Arc::new(ConnInfo { addr, certificates })) .service(svc); http.serve_connection(conn, svc).await.unwrap(); }); } } #[derive(Debug)] struct ConnInfo { addr: std::net::SocketAddr, certificates: Vec, } type EchoResult = Result, Status>; #[derive(Default)] pub struct EchoServer; #[tonic::async_trait] impl pb::echo_server::Echo for EchoServer { async fn unary_echo(&self, request: Request) -> EchoResult { let conn_info = request.extensions().get::>().unwrap(); println!( "Got a request from: {:?} with certs: {:?}", conn_info.addr, conn_info.certificates ); let message = request.into_inner().message; Ok(Response::new(EchoResponse { message })) } }