aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mumd/src/main.rs12
-rw-r--r--mumd/src/network.rs35
-rw-r--r--mumd/src/state.rs201
-rw-r--r--todo.org5
4 files changed, 246 insertions, 7 deletions
diff --git a/mumd/src/main.rs b/mumd/src/main.rs
index 1608947..afc1b2e 100644
--- a/mumd/src/main.rs
+++ b/mumd/src/main.rs
@@ -1,6 +1,9 @@
mod audio;
mod network;
+mod command;
+mod state;
use crate::audio::Audio;
+use crate::state::Server;
use argparse::ArgumentParser;
use argparse::Store;
@@ -51,9 +54,12 @@ async fn main() {
audio.output_stream.play().unwrap();
let audio = Arc::new(Mutex::new(audio));
+ let server_state = Arc::new(Mutex::new(Server::new()));
+
// Run it
join!(
network::handle_tcp(
+ server_state,
server_addr,
server_host,
username,
@@ -61,6 +67,10 @@ async fn main() {
crypt_state_sender,
Arc::clone(&audio),
),
- network::handle_udp(server_addr, crypt_state_receiver, audio,),
+ network::handle_udp(
+ server_addr,
+ crypt_state_receiver,
+ audio,
+ ),
);
}
diff --git a/mumd/src/network.rs b/mumd/src/network.rs
index 8d9b0a1..cd36f21 100644
--- a/mumd/src/network.rs
+++ b/mumd/src/network.rs
@@ -1,4 +1,5 @@
use crate::audio::Audio;
+use crate::state::Server;
use bytes::Bytes;
use futures::channel::oneshot;
@@ -102,6 +103,7 @@ async fn authenticate(sink: Arc<Mutex<TcpSender>>, username: String) {
}
async fn listen_tcp(
+ server: Arc<Mutex<Server>>,
sink: Arc<Mutex<TcpSender>>,
mut stream: TcpReceiver,
crypt_state_sender: oneshot::Sender<ClientCryptState>,
@@ -141,33 +143,58 @@ async fn listen_tcp(
.expect("Server sent server_nonce with incorrect size"),
));
}
- ControlPacket::ServerSync(_) => {
+ ControlPacket::ServerSync(msg) => {
println!("Logged in!");
if let Some(sender) = crypt_state_sender.take() {
- let _ = sender.send(
+ sender.send(
crypt_state
.take()
.expect("Server didn't send us any CryptSetup packet!"),
);
}
+ let mut server = server.lock().unwrap();
+ server.parse_server_sync(msg);
+ match &server.welcome_text {
+ Some(s) => println!("Welcome: {}", s),
+ None => println!("No welcome found"),
+ }
+ for (_, channel) in server.channels() {
+ println!("Found channel {}", channel.name());
+ }
+ sink.lock().unwrap().send(msgs::UserList::new().into()).await.unwrap();
}
ControlPacket::Reject(msg) => {
println!("Login rejected: {:?}", msg);
}
ControlPacket::UserState(msg) => {
- println!("Found user {} with id {}", msg.get_name(), msg.get_session());
audio.lock().unwrap().add_client(msg.get_session());
+ let mut server = server.lock().unwrap();
+ let session = msg.get_session();
+ server.parse_user_state(msg);
+ let user = server.users().get(&session).unwrap();
+ println!("User {} connected to {}",
+ user.name(),
+ user.channel());
}
ControlPacket::UserRemove(msg) => {
println!("User {} left", msg.get_session());
audio.lock().unwrap().remove_client(msg.get_session());
}
+ ControlPacket::ChannelState(msg) => {
+ server.lock().unwrap().parse_channel_state(msg);
+ }
+ ControlPacket::ChannelRemove(msg) => {}
+ ControlPacket::UserList(msg) => {
+ println!("User list received");
+ println!("{:?}", msg);
+ }
_ => {}
}
}
}
pub async fn handle_tcp(
+ server: Arc<Mutex<Server>>,
server_addr: SocketAddr,
server_host: String,
username: String,
@@ -185,7 +212,7 @@ pub async fn handle_tcp(
join!(
send_pings(Arc::clone(&sink), 10),
- listen_tcp(sink, stream, crypt_state_sender, audio),
+ listen_tcp(server, sink, stream, crypt_state_sender, audio),
);
}
diff --git a/mumd/src/state.rs b/mumd/src/state.rs
new file mode 100644
index 0000000..791d26c
--- /dev/null
+++ b/mumd/src/state.rs
@@ -0,0 +1,201 @@
+use mumble_protocol::control::msgs;
+use std::collections::HashMap;
+use std::collections::hash_map::Entry;
+
+pub struct Server {
+ channels: HashMap<u32, Channel>,
+ users: HashMap<u32, User>,
+ pub welcome_text: Option<String>,
+}
+
+impl Server {
+ pub fn new() -> Self {
+ Self {
+ channels: HashMap::new(),
+ users: HashMap::new(),
+ welcome_text: None,
+ }
+ }
+
+ pub fn parse_server_sync(&mut self, mut msg: Box<msgs::ServerSync>) {
+ if msg.has_welcome_text() {
+ self.welcome_text = Some(msg.take_welcome_text());
+ }
+ }
+
+ pub fn parse_channel_state(&mut self, msg: Box<msgs::ChannelState>) {
+ if !msg.has_channel_id() {
+ eprintln!("Can't parse channel state without channel id");
+ return;
+ }
+ match self.channels.entry(msg.get_channel_id()) {
+ Entry::Vacant(e) => { e.insert(Channel::new(msg)); },
+ Entry::Occupied(mut e) => e.get_mut().parse_channel_state(msg),
+ }
+ }
+
+ pub fn parse_user_state(&mut self, msg: Box<msgs::UserState>) {
+ if !msg.has_session() {
+ eprintln!("Can't parse user state without session");
+ return;
+ }
+ match self.users.entry(msg.get_session()) {
+ Entry::Vacant(e) => { e.insert(User::new(msg)); },
+ Entry::Occupied(mut e) => e.get_mut().parse_user_state(msg),
+ }
+ }
+
+ pub fn channels(&self) -> &HashMap<u32, Channel> {
+ &self.channels
+ }
+
+ pub fn users(&self) -> &HashMap<u32, User> {
+ &self.users
+ }
+}
+
+
+pub struct Channel {
+ description: Option<String>,
+ links: Vec<u32>,
+ max_users: u32,
+ name: String,
+ parent: Option<u32>,
+ position: i32,
+}
+
+impl Channel {
+ pub fn new(mut msg: Box<msgs::ChannelState>) -> Self {
+ Self {
+ description: if msg.has_description() {
+ Some(msg.take_description())
+ } else {
+ None
+ },
+ links: Vec::new(),
+ max_users: msg.get_max_users(),
+ name: msg.take_name(),
+ parent: if msg.has_parent() {
+ Some(msg.get_parent())
+ } else {
+ None
+ },
+ position: msg.get_position(),
+ }
+ }
+
+ pub fn parse_channel_state(&mut self, mut msg: Box<msgs::ChannelState>) {
+ if msg.has_description() {
+ self.description = Some(msg.take_description());
+ }
+ self.links = msg.take_links();
+ if msg.has_max_users() {
+ self.max_users = msg.get_max_users();
+ }
+ if msg.has_name() {
+ self.name = msg.take_name();
+ }
+ if msg.has_parent() {
+ self.parent = Some(msg.get_parent());
+ }
+ if msg.has_position() {
+ self.position = msg.get_position();
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+}
+
+pub struct User {
+ channel: u32,
+ comment: Option<String>,
+ hash: Option<String>,
+ name: String,
+ priority_speaker: bool,
+ recording: bool,
+
+ suppress: bool, // by me
+ self_mute: bool, // by self
+ self_deaf: bool, // by self
+ mute: bool, // by admin
+ deaf: bool, // by admin
+}
+
+impl User {
+ pub fn new(mut msg: Box<msgs::UserState>) -> Self {
+ Self {
+ channel: msg.get_channel_id(),
+ comment: if msg.has_comment() {
+ Some(msg.take_comment())
+ } else {
+ None
+ },
+ hash: if msg.has_hash() {
+ Some(msg.take_hash())
+ } else {
+ None
+ },
+ name: msg.take_name(),
+ priority_speaker: msg.has_priority_speaker()
+ && msg.get_priority_speaker(),
+ recording: msg.has_recording()
+ && msg.get_recording(),
+ suppress: msg.has_suppress()
+ && msg.get_suppress(),
+ self_mute: msg.has_self_mute()
+ && msg.get_self_mute(),
+ self_deaf: msg.has_self_deaf()
+ && msg.get_self_deaf(),
+ mute: msg.has_mute()
+ && msg.get_mute(),
+ deaf: msg.has_deaf()
+ && msg.get_deaf(),
+ }
+ }
+
+ pub fn parse_user_state(&mut self, mut msg: Box<msgs::UserState>) {
+ if msg.has_channel_id() {
+ self.channel = msg.get_channel_id();
+ }
+ if msg.has_comment() {
+ self.comment = Some(msg.take_comment());
+ }
+ if msg.has_hash() {
+ self.hash = Some(msg.take_hash());
+ }
+ if msg.has_name() {
+ self.name = msg.take_name();
+ }
+ if msg.has_priority_speaker() {
+ self.priority_speaker = msg.get_priority_speaker();
+ }
+ if msg.has_recording() {
+ self.recording = msg.get_recording();
+ }
+ if msg.has_suppress() {
+ self.suppress = msg.get_suppress();
+ }
+ if msg.has_self_mute() {
+ self.self_mute = msg.get_self_mute();
+ }
+ if msg.has_self_deaf() {
+ self.self_deaf = msg.get_self_deaf();
+ }
+ if msg.has_mute() {
+ self.mute = msg.get_mute();
+ }
+ if msg.has_deaf() {
+ self.deaf = msg.get_deaf();
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn channel(&self) -> u32 {
+ self.channel
+ }
+}
diff --git a/todo.org b/todo.org
index d9dbf3c..dcd2739 100644
--- a/todo.org
+++ b/todo.org
@@ -2,8 +2,6 @@
* Bättre error handling
* Split audio input/output
-* Fixa att den blir ledsen om man andas fel
-Det ser ut att vara klienter med lägre bitrate som orsakar problem.
* Ljudvolymen
* REPL
** quit (+ graceful exit)
@@ -13,7 +11,10 @@ Det ser ut att vara klienter med lägre bitrate som orsakar problem.
* Kombinera flera ljudkällor rimligt (utan clipping)
* Mindre pub
* UDP crypt state resync?? Kommentar från exemplet
+Se Mumble.proto: CryptSetup. Både server och klient kan skicka en tom request
+för att skaffa en ny crypt.
* Refaktorera TCP-paket
* Dela upp network.rs i network/tcp.rs, network/udp.rs
* Coolare invalid cert-check
* Bättre logging
+https://crates.io/crates/log