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