soe_network_parser_lib/modules/
soe_packet_extraction.rs

1use super::pcap_extraction::*;
2use h1emu_core::soeprotocol::Soeprotocol;
3use h1emu_core::soeprotocol_packets_structs::{AckPacket, DataPacket, SubBasePackets};
4use serde_derive::Deserialize;
5use serde_derive::Serialize;
6use serde_json::*;
7use std::collections::HashMap;
8use std::fs;
9
10#[derive(Serialize, Deserialize)]
11struct ExtractedPacketSmall {
12    name: String,
13}
14
15pub fn extract_soe_packets(
16    extracted_packets: Vec<ExtractedPacket>,
17    output_directory: &String,
18    use_crc: bool,
19    crc_seed: u32,
20    write_packets_to_files: bool,
21    max_packets: usize,
22) -> HashMap<String, Vec<Value>> {
23    let mut protocol = Soeprotocol::initialize(use_crc, crc_seed);
24    let mut index: u32 = 0;
25    let mut parsed_packets: Vec<Value> = Vec::new();
26    let mut parsed_server_packets: Vec<Value> = Vec::new();
27    let mut parsed_client_packets: Vec<Value> = Vec::new();
28    let mut parsed_packets_map: HashMap<String, Vec<Value>> = HashMap::new();
29
30    for extracted_packet in extracted_packets {
31        let parsed_data = protocol.parse(extracted_packet.data);
32        parsed_packets.push(json!(parsed_data));
33        // use serde to serialize the json with ExtractedPacketSmall
34        let extracted_packet_small: ExtractedPacketSmall =
35            serde_json::from_str(&parsed_data).unwrap();
36        index += 1;
37        if extracted_packet.sender == "server" {
38            parsed_server_packets.push(json!(parsed_data));
39        } else {
40            parsed_client_packets.push(json!(parsed_data));
41        }
42        if write_packets_to_files {
43            let mut file_name: String = output_directory.to_owned();
44            file_name.push_str(&index.to_string());
45            file_name.push_str("-");
46            file_name.push_str(&extracted_packet.sender);
47            file_name.push_str("-");
48            file_name.push_str(extracted_packet_small.name.as_str());
49            file_name.push_str(".json");
50            fs::write(file_name, parsed_data).expect("Unable to write to file");
51        }
52        if max_packets > 0 && index as usize >= max_packets {
53            break;
54        }
55    }
56    if write_packets_to_files {
57        let mut file_name: String = output_directory.to_owned();
58        file_name.push_str("0-full.json");
59        fs::write(
60            file_name,
61            serde_json::to_string_pretty(&parsed_packets).unwrap(),
62        )
63        .expect("Unable to write to file");
64    }
65    parsed_packets_map.insert("client".to_owned(), parsed_client_packets);
66    parsed_packets_map.insert("server".to_owned(), parsed_server_packets);
67    return parsed_packets_map;
68}
69
70fn contain_multiple_acks(packet: &SubBasePackets) -> bool {
71    // count the number of packets named "Ack" inside the MultiPacket
72    let mut ack_count: u32 = 0;
73    for packet_part in &packet.sub_packets {
74        if packet_part.name == "Ack" {
75            ack_count += 1;
76        }
77    }
78    return ack_count > 1;
79}
80
81struct Stats {
82    multiple_acks_per_buffer: u32,
83    total_multi_packets: u32,
84    total_acks: u32,
85    useless_acks: u32,
86    useless_outoforder: u32,
87    total_outoforder: u32,
88    last_ack: u16,
89    last_sequence: HashMap<u16, bool>,
90    resended_data: u32,
91    total_data_packets: u32,
92}
93fn analyse_packets(parsed_packets: &Vec<Value>, stats: &mut Stats) -> () {
94    for parsed_packet in parsed_packets {
95        let extracted_packet_small: ExtractedPacketSmall =
96            serde_json::from_str(&parsed_packet.as_str().unwrap()).unwrap();
97        match extracted_packet_small.name.as_str() {
98            "MultiPacket" => {
99                stats.total_multi_packets += 1;
100                let packet: SubBasePackets =
101                    serde_json::from_str(&parsed_packet.as_str().unwrap()).unwrap();
102                if contain_multiple_acks(&packet) {
103                    stats.multiple_acks_per_buffer += 1;
104                }
105                for packet_part in packet.sub_packets {
106                    if packet_part.name == "Ack" {
107                        stats.total_acks += 1;
108                        if packet_part.sequence.unwrap() < stats.last_ack {
109                            stats.useless_acks += 1;
110                        } else {
111                            stats.last_ack = packet_part.sequence.unwrap();
112                        }
113                    } else if packet_part.name == "OutOfOrder" {
114                        stats.total_outoforder += 1;
115                        if packet_part.sequence.unwrap() < stats.last_ack {
116                            stats.useless_outoforder += 1;
117                        }
118                    }
119                }
120            }
121            "Ack" => {
122                stats.total_acks += 1;
123                let packet: AckPacket =
124                    serde_json::from_str(&parsed_packet.as_str().unwrap()).unwrap();
125                if packet.sequence < stats.last_ack {
126                    stats.useless_acks += 1;
127                }
128                stats.last_ack = packet.sequence;
129            }
130            "OutOfOrder" => {
131                stats.total_outoforder += 1;
132                let packet: AckPacket =
133                    serde_json::from_str(&parsed_packet.as_str().unwrap()).unwrap();
134                if packet.sequence < stats.last_ack {
135                    stats.useless_outoforder += 1;
136                }
137            }
138            "Data" => {
139                let packet: DataPacket =
140                    serde_json::from_str(&parsed_packet.as_str().unwrap()).unwrap();
141                if stats.last_sequence.contains_key(&packet.sequence) {
142                    stats.resended_data += 1;
143                } else {
144                    stats.last_sequence.insert(packet.sequence, true);
145                }
146                stats.total_data_packets += 1;
147            }
148            "DataFragment" => {
149                let packet: DataPacket =
150                    serde_json::from_str(&parsed_packet.as_str().unwrap()).unwrap();
151                if stats.last_sequence.contains_key(&packet.sequence) {
152                    stats.resended_data += 1;
153                } else {
154                    stats.last_sequence.insert(packet.sequence, true);
155                }
156                stats.total_data_packets += 1;
157            }
158            _ => {}
159        }
160    }
161}
162
163fn log_stats(stats: Stats) -> () {
164    if stats.total_multi_packets > 0 {
165        // Log the pourcentage of multiple acks per buffer
166        println!(
167            "{}% of multiple acks per buffer",
168            (stats.multiple_acks_per_buffer * 100) as f32 / stats.total_multi_packets as f32
169        );
170    }
171    if stats.total_acks > 0 {
172        // Log the pourcentage of useless acks
173        println!(
174            "{}% of useless acks",
175            (stats.useless_acks * 100) as f32 / stats.total_acks as f32
176        );
177    }
178    if stats.total_outoforder > 0 {
179        // Log the pourcentage of useless outoforder
180        println!(
181            "{}% of useless outoforder",
182            (stats.useless_outoforder * 100) as f32 / stats.total_outoforder as f32
183        );
184    }
185    if stats.total_data_packets > 0 {
186        // Log the pourcentage of resended data from client
187        println!(
188            "{}% of resended data",
189            ((stats.resended_data + 1) * 100) as f32 / stats.total_data_packets as f32
190        );
191    }
192}
193pub fn analyze_soe_packets(parsed_packets: HashMap<String, Vec<Value>>) {
194    let server_packets = parsed_packets.get("server").unwrap();
195
196    let mut server_stats = Stats {
197        multiple_acks_per_buffer: 0,
198        total_multi_packets: 0,
199        total_acks: 0,
200        useless_acks: 0,
201        useless_outoforder: 0,
202        total_outoforder: 0,
203        last_ack: 0,
204        last_sequence: HashMap::new(),
205        resended_data: 0,
206        total_data_packets: 0,
207    };
208    analyse_packets(server_packets, &mut server_stats);
209
210    println!("server packets stats");
211
212    log_stats(server_stats);
213
214    let client_packets = parsed_packets.get("client").unwrap();
215
216    let mut client_stats = Stats {
217        multiple_acks_per_buffer: 0,
218        total_multi_packets: 0,
219        total_acks: 0,
220        useless_acks: 0,
221        useless_outoforder: 0,
222        total_outoforder: 0,
223        last_ack: 0,
224        last_sequence: HashMap::new(),
225        resended_data: 0,
226        total_data_packets: 0,
227    };
228    analyse_packets(client_packets, &mut client_stats);
229
230    println!("client packets stats");
231
232    log_stats(client_stats);
233}