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 consts;
21pub mod options;
22
23#[cfg(feature = "client")]
24pub mod client;
25
26#[cfg(feature = "server")]
27pub mod server;
28
29use std::
30{
31    io::Error,
32    net::{ UdpSocket, SocketAddr },
33};
34
35use wincode::{ SchemaRead, SchemaWrite };
36
37use crate::
38{
39    crypto,
40    consts::SharedKeys,
41};
42
43#[cfg(not(feature = "server"))]
44use crate::options as chat_options;
45
46#[derive(Clone, PartialEq, SchemaRead, SchemaWrite)]
47pub enum VoiceCode
48{
49    PING, //CLIENT A -> CLIENT B
50    PONG, //CLIENT A <- CLIENT B
51}
52
53#[derive(SchemaRead, SchemaWrite)]
54pub struct VoicePacket //VOICE PACKET (WHAT IS BEING SENT)
55{
56    pub voice: Option<Vec<u8>>,   //MESSAGE
57    pub username: Option<String>, //USERNAME
58    pub code: Option<VoiceCode>,  //CODE
59    pub id: Option<usize>,        //ID OF USER
60    pub target_id: Option<usize>, //ID OF RECIPIENT
61    pub seq: usize,               //SEQUENCE NUMBER
62    pub timestamp: Option<u128>,  //TIME OF SENDING
63}
64
65impl Default for VoicePacket
66{
67    fn default() -> Self
68    {
69        VoicePacket
70        {
71            voice: None,
72            id: None,
73            target_id: None,
74            code: None,
75            username: None,
76            seq: 0,
77            timestamp: None,
78        }
79    }
80}
81
82pub fn send //SEND DATA TO UDP
83(
84    socket: &UdpSocket,
85    mut packet: VoicePacket,
86    #[cfg(feature = "server")] addr: &SocketAddr,
87    #[cfg(feature = "server")] recipient_id: &usize,
88    keys: &SharedKeys
89) -> Result<usize, Error>
90{
91    //SET SERVER SEQ
92    #[cfg(feature = "server")]
93    {
94        if let Some(mut conn) = server::CONNECTIONS.get_mut(recipient_id) &&
95            let Some(conn) = conn.0.as_mut()
96        {
97            packet.seq = conn.server_seq() + 1;
98            *conn.server_seq_mut() = packet.seq;
99        }
100    }
101
102    //SET SEQ
103    #[cfg(feature = "client")]
104    {
105        packet.seq = options::get_seq() + 1;
106        options::set_seq(packet.seq);
107    }
108
109    //SERIALIZE PACKET
110    let packet_bytes = wincode::serialize(&packet).expect("Encoding packet failed");
111
112    //ENCRYPT PACKET
113    #[cfg(feature = "server")]
114    let encrypted_bytes: Vec<u8>;
115
116    #[cfg(not(feature = "server"))]
117    let mut encrypted_bytes: Vec<u8>;
118
119    encrypted_bytes = crypto::encrypt_packet::< { consts::GRID_WIDTH }, { consts::GRID_HEIGHT } >(packet_bytes, keys);
120
121    //PREPEND ID TO PACKET
122    #[cfg(feature = "client")]
123    {
124        let id_be_bytes = packet.id.unwrap().to_be_bytes();
125        encrypted_bytes.splice(0..0, id_be_bytes);
126    }
127
128    #[cfg(feature = "server")]
129    {
130        socket.send_to(&encrypted_bytes, addr)
131    }
132
133    #[cfg(not(feature = "server"))]
134    {
135        socket.send(&encrypted_bytes)
136    }
137}
138
139
140pub fn receive(socket: &UdpSocket) -> Option<(VoicePacket, SocketAddr)> //RECEIVE UDP PACKET & DECODE
141{
142    let mut buffer = [0u8; 2048];
143    loop //BLOCK READING UNTIL PACKET ARRIVES
144    {
145        //CHECK FOR VOICE DISABLE
146        #[cfg(feature = "client")]
147        if !options::get_use_voice() { break None; }
148
149        let (len, addr) = match socket.recv_from(&mut buffer)
150        {
151            Ok(result) => result,
152            Err(_) => continue
153        };
154
155        let buffer_offset: usize;
156
157        //GET ID ON SERVER
158        let keys =
159        {
160            #[cfg(feature = "server")]
161            {
162                if len <= 8 { continue; } //INVALID PACKET
163
164                let id = match buffer[..8].try_into()
165                {
166                    Ok(id_be_bytes) => usize::from_be_bytes(id_be_bytes),
167                    Err(_) => continue
168                };
169
170                //REMOVE ID FROM BUFFER
171                buffer_offset = 8;
172
173                match server::find_key(&id)
174                {
175                    Some(k) => k,
176                    None => continue
177                }
178            }
179
180            #[cfg(not(feature = "server"))]
181            {
182                buffer_offset = 0;
183                chat_options::get_keys().unwrap()
184            }
185        };
186
187        //DECRYPT
188        let decrypted_bytes = match crypto::decrypt_packet::<{ consts::GRID_WIDTH }, { consts::GRID_HEIGHT }>
189            (buffer[buffer_offset..len].to_vec(), &keys)
190        {
191            Some(d) => d,
192            None => continue
193        };
194
195        //PACKET ARRIVED, DESERIALIZE
196        return match wincode::deserialize::<VoicePacket>(&decrypted_bytes)
197        {
198            Ok(packet) => Some((packet, addr)),
199            Err(_) => continue
200        }
201    }
202}