diameter_interface/modeling/
diameter.rs1use crate::errors::DiameterResult;
34use crate::modeling::avp::avp::{Avp, AvpFlags, AvpValue};
35use crate::modeling::message::application_id::ApplicationId;
36use crate::modeling::message::command_code::CommandCode;
37use crate::modeling::message::command_flags::CommandFlag;
38use crate::modeling::message::dictionary::Dictionary;
39use std::io::{Read, Write};
40use std::sync::Arc;
41
42#[derive(Debug)]
43pub struct DiameterMessage {
44 header: DiameterHeader,
45 avps: Vec<Avp>,
46}
47
48#[derive(Debug)]
49pub struct DiameterHeader {
50 version: u8,
51 message_length: u32, command_flag: u8,
53 command_code: CommandCode, application_id: ApplicationId,
55 hop_by_hop: u32,
56 end_to_end: u32,
57}
58
59impl DiameterMessage {
60 pub fn new(
61 command_flag: CommandFlag,
62 command_code: CommandCode,
63 application_id: ApplicationId,
64 hop_by_hop: u32,
65 end_to_end: u32,
66 ) -> Self {
67 Self {
68 header: DiameterHeader {
69 version: 1,
70 message_length: 20,
71 command_flag: command_flag.value(),
72 command_code,
73 application_id,
74 hop_by_hop,
75 end_to_end,
76 },
77 avps: vec![],
78 }
79 }
80
81 pub fn get_version(&self) -> u8 {
90 self.header.version
91 }
92
93 pub fn get_length(&self) -> u32 {
94 self.header.message_length
95 }
96
97 pub fn get_command_flag(&self) -> u8 {
98 self.header.command_flag
99 }
100
101 pub fn get_command_code(&self) -> &CommandCode {
102 &self.header.command_code
103 }
104
105 pub fn get_application_id(&self) -> &ApplicationId {
106 &self.header.application_id
107 }
108
109 pub fn get_hop_by_hop(&self) -> u32 {
110 self.header.hop_by_hop
111 }
112
113 pub fn get_end_to_end(&self) -> u32 {
114 self.header.end_to_end
115 }
116
117 pub fn get_avps(&self) -> &Vec<Avp> {
118 &self.avps
119 }
120
121 pub fn get_avp(&self, code: u32) -> Option<&Avp> {
122 self.avps.iter().find(|avp| avp.get_code() == code)
123 }
124
125 pub fn add(&mut self, avp: Avp) {
126 self.header.message_length += avp.get_length() + avp.get_padding();
127 self.avps.push(avp);
128 }
129
130 pub fn add_avp<T: Into<AvpValue>>(
131 &mut self,
132 code: u32,
133 flags: AvpFlags,
134 vendor_id: Option<u32>,
135 value: T,
136 ) {
137 let avp: Avp = Avp::new(code, flags, vendor_id, value);
138 self.add(avp);
139 }
140
141 pub fn encode_to<W: Write>(&mut self, writer: &mut W) -> DiameterResult<()> {
142 writer.write(&self.header.version.to_be_bytes())?;
143 writer.write(&self.header.message_length.to_be_bytes()[1..])?;
144 writer.write(&self.header.command_flag.to_be_bytes())?;
145 writer.write(&self.header.command_code.get_code().to_be_bytes()[1..])?;
146 writer.write(&self.header.application_id.value().to_be_bytes())?;
147 writer.write(&self.header.hop_by_hop.to_be_bytes())?;
148 writer.write(&self.header.end_to_end.to_be_bytes())?;
149 for avp in self.avps.iter_mut() {
150 avp.encode_to(writer)?;
151 }
152 Ok(())
153 }
154
155 pub fn decode_from<R: Read>(
156 reader: &mut R,
157 dict: Arc<Dictionary>,
158 ) -> DiameterResult<DiameterMessage> {
159 let mut b = [0u8; 20];
160 reader.read_exact(&mut b)?;
161
162 let version = b[0];
163 let mut message_length = u32::from_be_bytes([0, b[1], b[2], b[3]]);
164 let command_flag = b[4];
165 let command_code = u32::from_be_bytes([b[4], b[5], b[6], b[7]]);
166 let application_id = u32::from_be_bytes([b[8], b[9], b[10], b[11]]);
167 let hop_by_hop = u32::from_be_bytes([b[12], b[13], b[14], b[15]]);
168 let end_to_end = u32::from_be_bytes([b[16], b[17], b[18], b[19]]);
169
170 let header = DiameterHeader {
171 version,
172 message_length,
173 command_flag,
174 application_id: ApplicationId::try_from(application_id)?,
175 command_code: CommandCode::try_from(command_code)?,
176 hop_by_hop,
177 end_to_end,
178 };
179
180 let mut message = DiameterMessage {
181 header,
182 avps: vec![],
183 };
184
185 message_length -= 20;
186 while message_length > 0 {
187 let avp = Avp::decode_from(reader, Arc::clone(&dict))?;
188 message_length = message_length - avp.get_length() - avp.get_padding();
189 message.add(avp);
190 }
191 Ok(message)
192 }
193}