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 add(&mut self, avp: Avp) {
82 self.header.message_length += avp.get_length() + avp.get_padding();
83 self.avps.push(avp);
84 }
85
86 pub fn add_avp<T: Into<AvpValue>>(
87 &mut self,
88 code: u32,
89 flags: AvpFlags,
90 vendor_id: Option<u32>,
91 value: T,
92 ) {
93 let avp: Avp = Avp::new(code, flags, vendor_id, value);
94 self.add(avp);
95 }
96
97 pub fn encode_to<W: Write>(&mut self, writer: &mut W) -> DiameterResult<()> {
98 writer.write(&self.header.version.to_be_bytes())?;
99 writer.write(&self.header.message_length.to_be_bytes()[1..])?;
100 writer.write(&self.header.command_flag.to_be_bytes())?;
101 writer.write(&self.header.command_code.get_code().to_be_bytes()[1..])?;
102 writer.write(&self.header.application_id.value().to_be_bytes())?;
103 writer.write(&self.header.hop_by_hop.to_be_bytes())?;
104 writer.write(&self.header.end_to_end.to_be_bytes())?;
105 for avp in self.avps.iter_mut() {
106 avp.encode_to(writer)?;
107 }
108 Ok(())
109 }
110
111 pub fn decode_from<R: Read>(
112 reader: &mut R,
113 dict: Arc<Dictionary>,
114 ) -> DiameterResult<DiameterMessage> {
115 let mut b = [0u8; 20];
116 reader.read_exact(&mut b)?;
117
118 let version = b[0];
119 let mut message_length = u32::from_be_bytes([0, b[1], b[2], b[3]]);
120 let command_flag = b[4];
121 let command_code = u32::from_be_bytes([b[4], b[5], b[6], b[7]]);
122 let application_id = u32::from_be_bytes([b[8], b[9], b[10], b[11]]);
123 let hop_by_hop = u32::from_be_bytes([b[12], b[13], b[14], b[15]]);
124 let end_to_end = u32::from_be_bytes([b[16], b[17], b[18], b[19]]);
125
126 let header = DiameterHeader {
127 version,
128 message_length,
129 command_flag,
130 application_id: ApplicationId::try_from(application_id)?,
131 command_code: CommandCode::try_from(command_code)?,
132 hop_by_hop,
133 end_to_end,
134 };
135
136 let mut message = DiameterMessage {
137 header,
138 avps: vec![],
139 };
140
141 message_length -= 20;
142 while message_length > 0 {
143 let avp = Avp::decode_from(reader, Arc::clone(&dict))?;
144 message_length = message_length - avp.get_length() - avp.get_padding();
145 message.add(avp);
146 }
147 Ok(message)
148 }
149}