Skip to main content

why2_chat/network/voice/
mod.rs

1/*
2This is part of WHY2
3Copyright (C) 2022-2026 Václav Šmejkal
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 3 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program.  If not, see <https://www.gnu.org/licenses/>.
17*/
18
19//MODULES
20pub mod options;
21
22#[cfg(feature = "client")]
23pub mod client;
24
25#[cfg(feature = "server")]
26pub mod server;
27
28use std::
29{
30    io::Error,
31    net::{ UdpSocket, SocketAddr },
32};
33
34use wincode::{ SchemaRead, SchemaWrite };
35
36use crate::
37{
38    crypto,
39    options::SharedKeys,
40};
41
42#[cfg(not(feature = "server"))]
43use crate::options as chat_options;
44
45#[derive(Clone, PartialEq, SchemaRead, SchemaWrite)]
46pub enum VoiceCode
47{
48    PING, //CLIENT A -> CLIENT B
49    PONG, //CLIENT A <- CLIENT B
50}
51
52#[derive(SchemaRead, SchemaWrite)]
53pub struct VoicePacket //VOICE PACKET (WHAT IS BEING SENT)
54{
55    pub voice: Option<Vec<u8>>,   //MESSAGE
56    pub username: Option<String>, //USERNAME
57    pub code: Option<VoiceCode>,  //CODE
58    pub id: Option<usize>,        //ID OF USER
59    pub target_id: Option<usize>, //ID OF RECIPIENT
60    pub seq: usize,               //SEQUENCE NUMBER
61    pub timestamp: Option<u128>,  //TIME OF SENDING
62}
63
64impl Default for VoicePacket
65{
66    fn default() -> Self
67    {
68        VoicePacket
69        {
70            voice: None,
71            id: None,
72            target_id: None,
73            code: None,
74            username: None,
75            seq: 0,
76            timestamp: None,
77        }
78    }
79}
80
81pub fn send //SEND DATA TO UDP
82(
83    socket: &UdpSocket,
84    mut packet: VoicePacket,
85    #[cfg(feature = "server")] addr: &SocketAddr,
86    #[cfg(feature = "server")] recipient_id: &usize,
87    keys: &SharedKeys
88) -> Result<usize, Error>
89{
90    //SET SERVER SEQ
91    #[cfg(feature = "server")]
92    {
93        if let Some(mut conn) = server::CONNECTIONS.get_mut(recipient_id) &&
94            let Some(conn) = conn.0.as_mut()
95        {
96            packet.seq = conn.server_seq() + 1;
97            *conn.server_seq_mut() = packet.seq;
98        }
99    }
100
101    //SET SEQ
102    #[cfg(feature = "client")]
103    {
104        packet.seq = options::get_seq() + 1;
105        options::set_seq(packet.seq);
106    }
107
108    //SERIALIZE PACKET
109    let packet_bytes = wincode::serialize(&packet).expect("Encoding packet failed");
110
111    //ENCRYPT PACKET
112    #[cfg(feature = "server")]
113    let encrypted_bytes: Vec<u8>;
114
115    #[cfg(not(feature = "server"))]
116    let mut encrypted_bytes: Vec<u8>;
117
118    encrypted_bytes = crypto::encrypt_packet::< { options::GRID_WIDTH }, { options::GRID_HEIGHT } >(packet_bytes, keys);
119
120    //PREPEND ID TO PACKET
121    #[cfg(feature = "client")]
122    {
123        let id_be_bytes = packet.id.unwrap().to_be_bytes();
124        encrypted_bytes.splice(0..0, id_be_bytes);
125    }
126
127    #[cfg(feature = "server")]
128    {
129        socket.send_to(&encrypted_bytes, addr)
130    }
131
132    #[cfg(not(feature = "server"))]
133    {
134        socket.send(&encrypted_bytes)
135    }
136}
137
138
139pub fn receive(socket: &UdpSocket) -> Option<(VoicePacket, SocketAddr)> //RECEIVE UDP PACKET & DECODE
140{
141    let mut buffer = [0u8; 2048];
142    loop //BLOCK READING UNTIL PACKET ARRIVES
143    {
144        //CHECK FOR VOICE DISABLE
145        #[cfg(feature = "client")]
146        if !options::get_use_voice() { break None; }
147
148        let (len, addr) = match socket.recv_from(&mut buffer)
149        {
150            Ok(result) => result,
151            Err(_) => continue
152        };
153
154        let buffer_offset: usize;
155
156        //GET ID ON SERVER
157        let keys =
158        {
159            #[cfg(feature = "server")]
160            {
161                if len <= 8 { continue; } //INVALID PACKET
162
163                let id = match buffer[..8].try_into()
164                {
165                    Ok(id_be_bytes) => usize::from_be_bytes(id_be_bytes),
166                    Err(_) => continue
167                };
168
169                //REMOVE ID FROM BUFFER
170                buffer_offset = 8;
171
172                match server::find_key(&id)
173                {
174                    Some(k) => k,
175                    None => continue
176                }
177            }
178
179            #[cfg(not(feature = "server"))]
180            {
181                buffer_offset = 0;
182                chat_options::get_keys().unwrap()
183            }
184        };
185
186        //DECRYPT
187        let decrypted_bytes = match crypto::decrypt_packet::<{ options::GRID_WIDTH }, { options::GRID_HEIGHT }>
188            (buffer[buffer_offset..len].to_vec(), &keys)
189        {
190            Some(d) => d,
191            None => continue
192        };
193
194        //PACKET ARRIVED, DESERIALIZE
195        return match wincode::deserialize::<VoicePacket>(&decrypted_bytes)
196        {
197            Ok(packet) => Some((packet, addr)),
198            Err(_) => continue
199        }
200    }
201}