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