xref: /tonic/examples/src/tls_rustls/server.rs (revision 7173808a)
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