1 pub mod pb { 2 tonic::include_proto!("/grpc.examples.unaryecho"); 3 } 4 5 use hyper::server::conn::http2::Builder; 6 use hyper_util::{ 7 rt::{TokioExecutor, TokioIo}, 8 service::TowerToHyperService, 9 }; 10 use pb::{EchoRequest, EchoResponse}; 11 use std::sync::Arc; 12 use tokio::net::TcpListener; 13 use tokio_rustls::{ 14 rustls::{pki_types::CertificateDer, ServerConfig}, 15 TlsAcceptor, 16 }; 17 use tonic::{body::boxed, service::Routes, Request, Response, Status}; 18 use tower::ServiceExt; 19 use tower_http::ServiceBuilderExt; 20 21 #[tokio::main] 22 async fn main() -> Result<(), Box<dyn std::error::Error>> { 23 let data_dir = std::path::PathBuf::from_iter([std::env!("CARGO_MANIFEST_DIR"), "data"]); 24 let certs = { 25 let fd = std::fs::File::open(data_dir.join("tls/server.pem"))?; 26 let mut buf = std::io::BufReader::new(&fd); 27 rustls_pemfile::certs(&mut buf).collect::<Result<Vec<_>, _>>()? 28 }; 29 let key = { 30 let fd = std::fs::File::open(data_dir.join("tls/server.key"))?; 31 let mut buf = std::io::BufReader::new(&fd); 32 rustls_pemfile::private_key(&mut buf)?.unwrap() 33 }; 34 35 let mut tls = ServerConfig::builder() 36 .with_no_client_auth() 37 .with_single_cert(certs, key)?; 38 tls.alpn_protocols = vec![b"h2".to_vec()]; 39 40 let server = EchoServer::default(); 41 42 let svc = Routes::new(pb::echo_server::EchoServer::new(server)).prepare(); 43 44 let http = Builder::new(TokioExecutor::new()); 45 46 let listener = TcpListener::bind("[::1]:50051").await?; 47 let tls_acceptor = TlsAcceptor::from(Arc::new(tls)); 48 49 loop { 50 let (conn, addr) = match listener.accept().await { 51 Ok(incoming) => incoming, 52 Err(e) => { 53 eprintln!("Error accepting connection: {}", e); 54 continue; 55 } 56 }; 57 58 let http = http.clone(); 59 let tls_acceptor = tls_acceptor.clone(); 60 let svc = svc.clone(); 61 62 tokio::spawn(async move { 63 let mut certificates = Vec::new(); 64 65 let conn = tls_acceptor 66 .accept_with(conn, |info| { 67 if let Some(certs) = info.peer_certificates() { 68 for cert in certs { 69 certificates.push(cert.clone()); 70 } 71 } 72 }) 73 .await 74 .unwrap(); 75 76 let svc = tower::ServiceBuilder::new() 77 .add_extension(Arc::new(ConnInfo { addr, certificates })) 78 .service(svc); 79 80 http.serve_connection( 81 TokioIo::new(conn), 82 TowerToHyperService::new(svc.map_request(|req: http::Request<_>| req.map(boxed))), 83 ) 84 .await 85 .unwrap(); 86 }); 87 } 88 } 89 90 #[derive(Debug)] 91 struct ConnInfo { 92 addr: std::net::SocketAddr, 93 certificates: Vec<CertificateDer<'static>>, 94 } 95 96 type EchoResult<T> = Result<Response<T>, Status>; 97 98 #[derive(Default)] 99 pub struct EchoServer {} 100 101 #[tonic::async_trait] 102 impl pb::echo_server::Echo for EchoServer { 103 async fn unary_echo(&self, request: Request<EchoRequest>) -> EchoResult<EchoResponse> { 104 let conn_info = request.extensions().get::<Arc<ConnInfo>>().unwrap(); 105 println!( 106 "Got a request from: {:?} with certs: {:?}", 107 conn_info.addr, conn_info.certificates 108 ); 109 110 let message = request.into_inner().message; 111 Ok(Response::new(EchoResponse { message })) 112 } 113 } 114