xref: /webrtc/turn/examples/turn_server_udp.rs (revision 9ea7b2ac)
1 use turn::auth::*;
2 use turn::relay::relay_static::*;
3 use turn::server::{config::*, *};
4 use turn::Error;
5 
6 use clap::{App, AppSettings, Arg};
7 use std::collections::HashMap;
8 use std::net::{IpAddr, SocketAddr};
9 use std::str::FromStr;
10 use std::sync::Arc;
11 use tokio::net::UdpSocket;
12 use tokio::signal;
13 use tokio::time::Duration;
14 use util::vnet::net::*;
15 
16 struct MyAuthHandler {
17     cred_map: HashMap<String, Vec<u8>>,
18 }
19 
20 impl MyAuthHandler {
new(cred_map: HashMap<String, Vec<u8>>) -> Self21     fn new(cred_map: HashMap<String, Vec<u8>>) -> Self {
22         MyAuthHandler { cred_map }
23     }
24 }
25 
26 impl AuthHandler for MyAuthHandler {
auth_handle( &self, username: &str, _realm: &str, _src_addr: SocketAddr, ) -> Result<Vec<u8>, Error>27     fn auth_handle(
28         &self,
29         username: &str,
30         _realm: &str,
31         _src_addr: SocketAddr,
32     ) -> Result<Vec<u8>, Error> {
33         if let Some(pw) = self.cred_map.get(username) {
34             //log::debug!("username={}, password={:?}", username, pw);
35             Ok(pw.to_vec())
36         } else {
37             Err(Error::ErrFakeErr)
38         }
39     }
40 }
41 
42 // RUST_LOG=trace cargo run --color=always --package turn --example turn_server_udp -- --public-ip 0.0.0.0 --users user=pass
43 
44 #[tokio::main]
main() -> Result<(), Error>45 async fn main() -> Result<(), Error> {
46     env_logger::init();
47 
48     let mut app = App::new("TURN Server UDP")
49         .version("0.1.0")
50         .author("Rain Liu <[email protected]>")
51         .about("An example of TURN Server UDP")
52         .setting(AppSettings::DeriveDisplayOrder)
53         .setting(AppSettings::SubcommandsNegateReqs)
54         .arg(
55             Arg::with_name("FULLHELP")
56                 .help("Prints more detailed help information")
57                 .long("fullhelp"),
58         )
59         .arg(
60             Arg::with_name("public-ip")
61                 .required_unless("FULLHELP")
62                 .takes_value(true)
63                 .long("public-ip")
64                 .help("IP Address that TURN can be contacted by."),
65         )
66         .arg(
67             Arg::with_name("users")
68                 .required_unless("FULLHELP")
69                 .takes_value(true)
70                 .long("users")
71                 .help("List of username and password (e.g. \"user=pass,user=pass\")"),
72         )
73         .arg(
74             Arg::with_name("realm")
75                 .default_value("webrtc.rs")
76                 .takes_value(true)
77                 .long("realm")
78                 .help("Realm (defaults to \"webrtc.rs\")"),
79         )
80         .arg(
81             Arg::with_name("port")
82                 .takes_value(true)
83                 .default_value("3478")
84                 .long("port")
85                 .help("Listening port."),
86         );
87 
88     let matches = app.clone().get_matches();
89 
90     if matches.is_present("FULLHELP") {
91         app.print_long_help().unwrap();
92         std::process::exit(0);
93     }
94 
95     let public_ip = matches.value_of("public-ip").unwrap();
96     let port = matches.value_of("port").unwrap();
97     let users = matches.value_of("users").unwrap();
98     let realm = matches.value_of("realm").unwrap();
99 
100     // Cache -users flag for easy lookup later
101     // If passwords are stored they should be saved to your DB hashed using turn.GenerateAuthKey
102     let creds: Vec<&str> = users.split(',').collect();
103     let mut cred_map = HashMap::new();
104     for user in creds {
105         let cred: Vec<&str> = user.splitn(2, '=').collect();
106         let key = generate_auth_key(cred[0], realm, cred[1]);
107         cred_map.insert(cred[0].to_owned(), key);
108     }
109 
110     // Create a UDP listener to pass into pion/turn
111     // turn itself doesn't allocate any UDP sockets, but lets the user pass them in
112     // this allows us to add logging, storage or modify inbound/outbound traffic
113     let conn = Arc::new(UdpSocket::bind(format!("0.0.0.0:{port}")).await?);
114     println!("listening {}...", conn.local_addr()?);
115 
116     let server = Server::new(ServerConfig {
117         conn_configs: vec![ConnConfig {
118             conn,
119             relay_addr_generator: Box::new(RelayAddressGeneratorStatic {
120                 relay_address: IpAddr::from_str(public_ip)?,
121                 address: "0.0.0.0".to_owned(),
122                 net: Arc::new(Net::new(None)),
123             }),
124         }],
125         realm: realm.to_owned(),
126         auth_handler: Arc::new(MyAuthHandler::new(cred_map)),
127         channel_bind_timeout: Duration::from_secs(0),
128         alloc_close_notify: None,
129     })
130     .await?;
131 
132     println!("Waiting for Ctrl-C...");
133     signal::ctrl_c().await.expect("failed to listen for event");
134     println!("\nClosing connection now...");
135     server.close().await?;
136 
137     Ok(())
138 }
139