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