From c7d893a4665e077e17e60a2276bba536af80c935 Mon Sep 17 00:00:00 2001 From: csking101 Date: Sun, 10 Mar 2024 10:29:19 +0530 Subject: [PATCH] Removed `lazy_static` dependency (#42) Using `OnceLock` in place of `lazy_static` to initialize the required global maps. Signed-off-by: csking101 --- Cargo.toml | 1 - src/layers/ethernet/mod.rs | 18 ++++----- src/layers/ipv4.rs | 17 ++++---- src/layers/ipv6.rs | 17 ++++---- src/layers/linux_sll.rs | 4 +- src/layers/linux_sll2.rs | 4 +- src/layers/sctp.rs | 79 +++++++++++++++++++------------------- src/layers/tcp.rs | 17 ++++---- src/layers/udp.rs | 16 ++++---- src/packet.rs | 15 ++++---- 10 files changed, 88 insertions(+), 100 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bccd868..d0468b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ crate-type = ["cdylib", "rlib"] [dependencies] hex = {version = "0.4", features = ["serde"]} -lazy_static = "1" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0" } erased-serde = "0.4" diff --git a/src/layers/ethernet/mod.rs b/src/layers/ethernet/mod.rs index e0adfc8..a35914d 100644 --- a/src/layers/ethernet/mod.rs +++ b/src/layers/ethernet/mod.rs @@ -4,9 +4,8 @@ use core::convert::TryInto; // FIXME: Should work with no_std use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{RwLock,OnceLock}; -use lazy_static::lazy_static; use serde::Serialize; use crate::errors::Error; @@ -15,19 +14,18 @@ use crate::{Layer, Packet, ENCAP_TYPE_ETH}; pub const ETH_HEADER_LENGTH: usize = 14_usize; -lazy_static! { +pub fn get_ethertypes_map() -> &'static RwLock> { /// A Map maintaining EtherType -> Creator fns for Layer Creators of L3 Layers. /// /// The creator function simply creates a `default` L3 struct that implements the dissector /// for the Layer. - pub(crate) static ref ETHERTYPES_MAP: RwLock> = - RwLock::new(HashMap::new()); - + pub(crate) static ETHERTYPES_MAP: OnceLock>> = OnceLock::new(); + ETHERTYPES_MAP.get_or_init(|| RwLock::new(HashMap::new())) } // Register our Encap Types with the Packet. pub(crate) fn register_defaults() -> Result<(), Error> { - lazy_static::initialize(ÐERTYPES_MAP); + get_ethertypes_map(); Packet::register_encap_type(ENCAP_TYPE_ETH, Ethernet::creator) } @@ -38,9 +36,7 @@ pub(crate) fn register_defaults() -> Result<(), Error> { /// by calling this function. For example [`crate::layers::ipv4`] would call `register_ethertype` /// with [`EtherType`] value of 0x0800, passing the creator function for that layer. pub fn register_ethertype(eth_type: EtherType, layer: LayerCreatorFn) -> Result<(), Error> { - lazy_static::initialize(ÐERTYPES_MAP); - - let mut map = ETHERTYPES_MAP.write().unwrap(); + let mut map = get_ethertypes_map().write().unwrap(); if map.contains_key(ð_type) { return Err(Error::RegisterError(format!("ether_type: {}", eth_type))); } @@ -80,7 +76,7 @@ impl Layer for Ethernet { self.src_mac = bytes[6..12].try_into()?; self.ethertype = (bytes[12] as u16) << 8 | bytes[13] as u16; - let map = ETHERTYPES_MAP.read().unwrap(); + let map = get_ethertypes_map().read().unwrap(); let layer = map.get(&self.ethertype); match layer { None => Ok((None, ETH_HEADER_LENGTH)), diff --git a/src/layers/ipv4.rs b/src/layers/ipv4.rs index 83e8edb..548275f 100644 --- a/src/layers/ipv4.rs +++ b/src/layers/ipv4.rs @@ -3,9 +3,8 @@ use core::convert::TryInto as _; use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{OnceLock, RwLock}; -use lazy_static::lazy_static; use serde::Serialize; use crate::errors::Error; @@ -21,8 +20,9 @@ pub const IPV4_OPTION_RR: u8 = 7; pub const IPV4_OPTION_MTUP: u8 = 11; pub const IPV4_OPTION_MTUR: u8 = 12; -lazy_static! { - static ref PROTOCOLS_MAP: RwLock> = RwLock::new(HashMap::new()); +fn get_protocol_map() -> &'static RwLock> { + static PROTOCOLS_MAP: OnceLock>> = OnceLock::new(); + PROTOCOLS_MAP.get_or_init(|| RwLock::new(HashMap::new())) } // Register ourselves to well-known Layer 2 @@ -31,7 +31,7 @@ lazy_static! { pub(crate) fn register_defaults() -> Result<(), Error> { use crate::layers::ethernet::register_ethertype; - lazy_static::initialize(&PROTOCOLS_MAP); + get_protocol_map(); register_ethertype(crate::types::ETHERTYPE_IP, IPv4::creator)?; @@ -45,9 +45,7 @@ pub(crate) fn register_defaults() -> Result<(), Error> { /// protocol number 6 and similarly [UDP Protocol][`crate::layers::udp`] would call this function /// with a protocol number of 17. pub fn register_protocol(proto: u8, creator: LayerCreatorFn) -> Result<(), Error> { - lazy_static::initialize(&PROTOCOLS_MAP); - - let mut map = PROTOCOLS_MAP.write().unwrap(); + let mut map = get_protocol_map().write().unwrap(); if map.contains_key(&proto) { return Err(Error::RegisterError(format!("proto: {}", proto))); } @@ -291,8 +289,7 @@ impl Layer for IPv4 { let consumed = self.options_from_bytes(&bytes[decoded..], remaining)?; decoded += consumed; // remaining -= consumed; - - let map = PROTOCOLS_MAP.read().unwrap(); + let map = get_protocol_map().read().unwrap(); let layer = map.get(&self.proto); match layer { diff --git a/src/layers/ipv6.rs b/src/layers/ipv6.rs index 00f7d47..be72ad5 100644 --- a/src/layers/ipv6.rs +++ b/src/layers/ipv6.rs @@ -3,9 +3,8 @@ use core::convert::TryInto; use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{RwLock,OnceLock}; -use lazy_static::lazy_static; use serde::Serialize; use crate::errors::Error; @@ -15,8 +14,10 @@ use crate::Layer; /// Basic Length of the IPv6 Header pub const IPV6_BASE_HEADER_LENGTH: usize = 40_usize; -lazy_static! { - static ref NEXT_HEADERS_MAP: RwLock> = RwLock::new(HashMap::new()); + +fn get_next_headers_map() -> &'static RwLock> { + static NEXT_HEADERS_MAP: OnceLock>> = OnceLock::new(); + NEXT_HEADERS_MAP.get_or_init(|| RwLock::new(HashMap::new())) } // Register ourselves to well-known Layer 2 @@ -25,7 +26,7 @@ lazy_static! { pub(crate) fn register_defaults() -> Result<(), Error> { use crate::layers::ethernet::register_ethertype; - lazy_static::initialize(&NEXT_HEADERS_MAP); + get_next_headers_map(); register_ethertype(crate::types::ETHERTYPE_IP6, IPv6::creator)?; Ok(()) @@ -37,9 +38,7 @@ pub(crate) fn register_defaults() -> Result<(), Error> { /// Protocol][`crate::layers::tcp`] would call this function with a header value of 6 and creator /// function for [`TCP`][`crate::layers::tcp::TCP`]. pub fn register_next_header(header: u8, creator: LayerCreatorFn) -> Result<(), Error> { - lazy_static::initialize(&NEXT_HEADERS_MAP); - - let mut map = NEXT_HEADERS_MAP.write().unwrap(); + let mut map = get_next_headers_map().write().unwrap(); if map.contains_key(&header) { return Err(Error::RegisterError(format!( @@ -94,7 +93,7 @@ impl Layer for IPv6 { self.src_addr = bytes[8..24].try_into().unwrap(); self.dst_addr = bytes[24..40].try_into().unwrap(); - let map = NEXT_HEADERS_MAP.read().unwrap(); + let map = get_next_headers_map().read().unwrap(); let layer = map.get(&self.next_hdr); match layer { None => Ok((None, IPV6_BASE_HEADER_LENGTH)), diff --git a/src/layers/linux_sll.rs b/src/layers/linux_sll.rs index 71f55e3..9db152e 100644 --- a/src/layers/linux_sll.rs +++ b/src/layers/linux_sll.rs @@ -7,7 +7,7 @@ use serde::Serialize; use crate::errors::Error; use crate::{Layer, Packet, ENCAP_TYPE_LINUX_SLL}; -use crate::layers::ethernet::ETHERTYPES_MAP; +use crate::layers::ethernet::get_ethertypes_map; #[derive(Debug, Default, Serialize)] pub struct LinuxSll { @@ -49,7 +49,7 @@ impl Layer for LinuxSll { self.ll_addr = bytes[6..14].try_into().unwrap(); self.protocol = u16::from_be_bytes(bytes[14..16].try_into().unwrap()); - let map = ETHERTYPES_MAP.read().unwrap(); + let map = get_ethertypes_map().read().unwrap(); let layer = map.get(&self.protocol); match layer { None => Ok((None, LINUX_SLL_HEADER_LENGTH)), diff --git a/src/layers/linux_sll2.rs b/src/layers/linux_sll2.rs index 98cd202..365d2f3 100644 --- a/src/layers/linux_sll2.rs +++ b/src/layers/linux_sll2.rs @@ -7,7 +7,7 @@ use serde::Serialize; use crate::errors::Error; use crate::{Layer, Packet, ENCAP_TYPE_LINUX_SLL2}; -use crate::layers::ethernet::ETHERTYPES_MAP; +use crate::layers::ethernet::get_ethertypes_map; #[derive(Debug, Default, Serialize)] pub struct LinuxSll2 { @@ -53,7 +53,7 @@ impl Layer for LinuxSll2 { self.ll_addr_len = bytes[11]; self.ll_addr = bytes[12..20].try_into().unwrap(); - let map = ETHERTYPES_MAP.read().unwrap(); + let map = get_ethertypes_map().read().unwrap(); let layer = map.get(&self.proto_type); match layer { None => Ok((None, LINUX_SLL2_HEADER_LENGTH)), diff --git a/src/layers/sctp.rs b/src/layers/sctp.rs index fb68935..9dd2e37 100644 --- a/src/layers/sctp.rs +++ b/src/layers/sctp.rs @@ -2,9 +2,8 @@ use core::convert::TryInto; use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{RwLock,OnceLock}; -use lazy_static::lazy_static; use serde::{ser::SerializeStruct as _, Serialize, Serializer}; use crate::errors::Error; @@ -12,38 +11,42 @@ use crate::layers::{ipv4, ipv6}; use crate::types::LayerCreatorFn; use crate::Layer; -lazy_static! { +const UNKNOWN_CHUNK_TYPE: &str = "Unknown Chunk"; + +fn get_chunk_display_map() -> &'static HashMap { + static CHUNK_DISPLAY_MAP: OnceLock> = OnceLock::new(); + CHUNK_DISPLAY_MAP.get_or_init(|| { // A Map of Chunk Type to Display String - static ref CHUNK_DISPLAY_MAP: HashMap = { - let mut m = HashMap::new(); - m.insert(0, "DATA Chunk"); - m.insert(1, "INIT Chunk"); - m.insert(2, "INIT-ACK Chunk"); - m.insert(3, "SACK Chunk"); - m.insert(4, "HEARTBEAT Chunk"); - m.insert(5, "HEARTBEAT-ACK Chunk"); - m.insert(6, "ABORT Chunk"); - m.insert(7, "SHUTDOWN Chunk"); - m.insert(8, "SHUTDOWN-ACK Chunk"); - m.insert(9, "ERROR Chunk"); - m.insert(10, "COOKIE-ECHO Chunk"); - m.insert(11, "COOKIE-ACK Chunk"); - m.insert(12, "ECNE Chunk"); - m.insert(13, "CWR Chunk"); - m.insert(14, "SHUTDOWN_COMPLETE Chunk"); - m.insert(15, "AUTH Chunk"); - m.insert(64, "I-DATA Chunk"); - m.insert(128, "ASCONF-ACK Chunk"); - m.insert(130, "RE-CONFIG Chunk"); - m.insert(132, "PAD Chunk"); - m.insert(192, "FORWARD-TSN Chunk"); - m.insert(193, "ASCONF Chunk"); - m.insert(195, "I-FORWARD-TSN Chunk"); - m - }; - static ref UNKNOWN_CHUNK_TYPE: &'static str = "Unknown Chunk"; - - static ref SCTP_PROTOCOLS_MAP: RwLock> = RwLock::new(HashMap::new()); + let mut m = HashMap::new(); + m.insert(0, "DATA Chunk"); + m.insert(1, "INIT Chunk"); + m.insert(2, "INIT-ACK Chunk"); + m.insert(3, "SACK Chunk"); + m.insert(4, "HEARTBEAT Chunk"); + m.insert(5, "HEARTBEAT-ACK Chunk"); + m.insert(6, "ABORT Chunk"); + m.insert(7, "SHUTDOWN Chunk"); + m.insert(8, "SHUTDOWN-ACK Chunk"); + m.insert(9, "ERROR Chunk"); + m.insert(10, "COOKIE-ECHO Chunk"); + m.insert(11, "COOKIE-ACK Chunk"); + m.insert(12, "ECNE Chunk"); + m.insert(13, "CWR Chunk"); + m.insert(14, "SHUTDOWN_COMPLETE Chunk"); + m.insert(15, "AUTH Chunk"); + m.insert(64, "I-DATA Chunk"); + m.insert(128, "ASCONF-ACK Chunk"); + m.insert(130, "RE-CONFIG Chunk"); + m.insert(132, "PAD Chunk"); + m.insert(192, "FORWARD-TSN Chunk"); + m.insert(193, "ASCONF Chunk"); + m.insert(195, "I-FORWARD-TSN Chunk"); + m}) +} + +fn get_sctp_protocols_map() -> &'static RwLock> { + static SCTP_PROTOCOLS_MAP: OnceLock>> = OnceLock::new(); + SCTP_PROTOCOLS_MAP.get_or_init(|| RwLock::new(HashMap::new())) } /// SCTP Protocol Number @@ -53,9 +56,7 @@ pub const IPPROTO_SCTP: u8 = 132_u8; /// /// This will be used by M3UA (say) pub fn register_datachunk_protocol(proto: u32, creator: LayerCreatorFn) -> Result<(), Error> { - lazy_static::initialize(&SCTP_PROTOCOLS_MAP); - - let mut map = SCTP_PROTOCOLS_MAP.write().unwrap(); + let mut map = get_sctp_protocols_map().write().unwrap(); if map.contains_key(&proto) { return Err(Error::RegisterError(format!("SCTP Proto: {}", proto))); } @@ -66,7 +67,7 @@ pub fn register_datachunk_protocol(proto: u32, creator: LayerCreatorFn) -> Resul // Register ourselves With IPv4 and IPv6 pub(crate) fn register_defaults() -> Result<(), Error> { - lazy_static::initialize(&SCTP_PROTOCOLS_MAP); + get_sctp_protocols_map(); ipv4::register_protocol(IPPROTO_SCTP, SCTP::creator)?; ipv6::register_next_header(IPPROTO_SCTP, SCTP::creator)?; @@ -155,7 +156,7 @@ where let mut state = serializer.serialize_struct("chunks", chunks.len())?; for chunk in chunks { state.serialize_field( - CHUNK_DISPLAY_MAP + get_chunk_display_map() .get(&chunk.chunk_type()) .unwrap_or(&UNKNOWN_CHUNK_TYPE), chunk, @@ -218,7 +219,7 @@ impl SCTP { let payload_proto = u32::from_be_bytes(bytes[start..start + 4].try_into().unwrap()); start += 4; - let map = SCTP_PROTOCOLS_MAP.read().unwrap(); + let map = get_sctp_protocols_map().read().unwrap(); let layer_creator = map.get(&payload_proto); let payload = match layer_creator { None => { diff --git a/src/layers/tcp.rs b/src/layers/tcp.rs index 3ddbdf2..c90677a 100644 --- a/src/layers/tcp.rs +++ b/src/layers/tcp.rs @@ -2,9 +2,8 @@ use core::convert::TryInto; use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{RwLock,OnceLock}; -use lazy_static::lazy_static; use serde::Serialize; use crate::errors::Error; @@ -13,8 +12,10 @@ use crate::Layer; use crate::layers::{ipv4, ipv6}; -lazy_static! { - static ref TCP_APPS_MAP: RwLock> = RwLock::new(HashMap::new()); + +fn get_tcp_apps_map() -> &'static RwLock> { + static TCP_APPS_MAP: OnceLock>> = OnceLock::new(); + TCP_APPS_MAP.get_or_init(|| RwLock::new(HashMap::new())) } /// TCP header length @@ -25,7 +26,7 @@ pub const IPPROTO_TCP: u8 = 6_u8; // Register ourselves With IPv4 and IPv6 pub(crate) fn register_defaults() -> Result<(), Error> { - lazy_static::initialize(&TCP_APPS_MAP); + get_tcp_apps_map(); ipv4::register_protocol(IPPROTO_TCP, TCP::creator)?; ipv6::register_next_header(IPPROTO_TCP, TCP::creator)?; @@ -39,9 +40,7 @@ pub(crate) fn register_defaults() -> Result<(), Error> { /// the Source or Destination port matches one of the ports. For example HTTP Protocol layer would /// register itself with port 80 with the TCP layer. pub fn register_app(port: u16, app: LayerCreatorFn) -> Result<(), Error> { - lazy_static::initialize(&TCP_APPS_MAP); - - let mut map = TCP_APPS_MAP.write().unwrap(); + let mut map = get_tcp_apps_map().write().unwrap(); if map.contains_key(&port) { return Err(Error::RegisterError(format!("TCP Port: {}", port))); @@ -96,7 +95,7 @@ impl Layer for TCP { self.checksum = (bytes[16] as u16) << 8 | (bytes[17] as u16); self.urgent_ptr = (bytes[18] as u16) << 8 | (bytes[19] as u16); - let map = TCP_APPS_MAP.read().unwrap(); + let map = get_tcp_apps_map().read().unwrap(); let app = map.get(&self.dst_port).or_else(|| map.get(&self.src_port)); Ok((app.map(|creator_fn| creator_fn()), TCP_BASE_HEADER_LENGTH)) diff --git a/src/layers/udp.rs b/src/layers/udp.rs index 3b0d1f3..8f7c91e 100644 --- a/src/layers/udp.rs +++ b/src/layers/udp.rs @@ -1,9 +1,8 @@ //! UDP Layer use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{RwLock,OnceLock}; -use lazy_static::lazy_static; use serde::Serialize; use crate::errors::Error; @@ -12,8 +11,9 @@ use crate::Layer; use crate::layers::{ipv4, ipv6}; -lazy_static! { - static ref UDP_APPS_MAP: RwLock> = RwLock::new(HashMap::new()); +fn get_udp_apps_map() -> &'static RwLock> { + static UDP_APPS_MAP: OnceLock>> = OnceLock::new(); + UDP_APPS_MAP.get_or_init(|| RwLock::new(HashMap::new())) } /// UDP header length @@ -23,7 +23,7 @@ pub const IPPROTO_UDP: u8 = 17_u8; // Register UDP with Protocol Handler in IPv4 and IPv6 pub(crate) fn register_defaults() -> Result<(), Error> { - lazy_static::initialize(&UDP_APPS_MAP); + get_udp_apps_map(); ipv4::register_protocol(IPPROTO_UDP, UDP::creator)?; ipv6::register_next_header(IPPROTO_UDP, UDP::creator)?; @@ -36,9 +36,7 @@ pub(crate) fn register_defaults() -> Result<(), Error> { /// This is a public API function for an App whose dissector should be called after UDP Layer's if /// the Source or Destination port matches one of the ports. pub fn register_app(port: u16, app: LayerCreatorFn) -> Result<(), Error> { - lazy_static::initialize(&UDP_APPS_MAP); - - let mut map = UDP_APPS_MAP.write().unwrap(); + let mut map = get_udp_apps_map().write().unwrap(); if map.contains_key(&port) { return Err(Error::RegisterError(format!("UDP Port: {}", port))); @@ -81,7 +79,7 @@ impl Layer for UDP { self.length = (bytes[4] as u16) << 8 | (bytes[5] as u16); self.checksum = (bytes[6] as u16) << 8 | (bytes[7] as u16); - let map = UDP_APPS_MAP.read().unwrap(); + let map = get_udp_apps_map().read().unwrap(); let app = map.get(&self.dst_port).or_else(|| map.get(&self.src_port)); Ok((app.map(|creator_fn| creator_fn()), UDP_HEADER_LENGTH)) diff --git a/src/packet.rs b/src/packet.rs index 56e6ffe..bd5f082 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -4,9 +4,8 @@ use core::fmt::Debug; // FIXME: Should work with `no_std` use std::collections::HashMap; -use std::sync::RwLock; +use std::sync::{OnceLock, RwLock}; -use lazy_static::lazy_static; use serde::{ser::SerializeStruct, Serialize, Serializer}; use crate::errors::Error; @@ -16,9 +15,9 @@ use crate::Layer; #[cfg(feature = "python-bindings")] use pyo3::prelude::*; -lazy_static! { - static ref ENCAP_TYPES_MAP: RwLock> = - RwLock::new(HashMap::new()); +fn get_encap_types_map() -> &'static RwLock> { + static ENCAP_TYPES_MAP: OnceLock>> = OnceLock::new(); + ENCAP_TYPES_MAP.get_or_init(|| RwLock::new(HashMap::new())) } #[derive(Debug, Default, Serialize)] @@ -28,7 +27,7 @@ struct Timestamp { } pub(crate) fn register_defaults() -> Result<(), Error> { - lazy_static::initialize(&ENCAP_TYPES_MAP); + get_encap_types_map(); Ok(()) } @@ -112,7 +111,7 @@ impl Packet { /// `scalpel` itself. A client will want to register it's own decoding function by using this /// API. pub fn register_encap_type(encap: EncapType, creator: LayerCreatorFn) -> Result<(), Error> { - let mut map = ENCAP_TYPES_MAP.write().unwrap(); + let mut map = get_encap_types_map().write().unwrap(); if map.contains_key(&encap) { return Err(Error::RegisterError(format!("Encap: {}", encap))); } @@ -132,7 +131,7 @@ impl Packet { let l2: Box; { - let map = ENCAP_TYPES_MAP.read().unwrap(); + let map = get_encap_types_map().read().unwrap(); let creator_fn = map.get(&encap); if creator_fn.is_none() { let _ = core::mem::replace(&mut p.unprocessed, bytes.into());