From 7aa211a8d7ae2efeebd9362699a1aea4b5690e3d Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sat, 6 Jul 2024 17:37:35 +0200 Subject: start on sdp impl --- src/encoding/mod.rs | 9 ++++++++ src/encoding/request.rs | 3 +++ src/encoding/response.rs | 15 ++++++++++--- src/encoding/status.rs | 2 +- src/lib.rs | 1 + src/sdp/mod.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ src/transaction/auth.rs | 2 +- src/transaction/mod.rs | 4 +++- src/transport/udp.rs | 11 +++++++--- 9 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 src/sdp/mod.rs (limited to 'src') diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs index f0796c8..816aa01 100644 --- a/src/encoding/mod.rs +++ b/src/encoding/mod.rs @@ -35,3 +35,12 @@ impl FromStr for Message { } } } + +impl Message { + pub fn body_mut(&mut self) -> &mut String { + match self { + Message::Request(r) => &mut r.body, + Message::Response(r) => &mut r.body, + } + } +} diff --git a/src/encoding/request.rs b/src/encoding/request.rs index c62bab3..ab41b7c 100644 --- a/src/encoding/request.rs +++ b/src/encoding/request.rs @@ -7,6 +7,7 @@ pub struct Request { pub method: Method, pub uri: Uri, pub headers: HeaderMap, + pub body: String, } impl Display for Request { @@ -15,6 +16,7 @@ impl Display for Request { headers, method, uri, + .. } = self; write!(f, "{method} {uri} SIP/2.0\r\n")?; write!(f, "{headers}\r\n")?; @@ -46,6 +48,7 @@ impl FromStr for Request { let method = Method::from_str(method)?; Ok(Self { + body: String::new(), headers, method, uri, diff --git a/src/encoding/response.rs b/src/encoding/response.rs index ffd2878..0b7996c 100644 --- a/src/encoding/response.rs +++ b/src/encoding/response.rs @@ -6,6 +6,7 @@ use std::{fmt::Display, str::FromStr}; pub struct Response { pub status: Status, pub headers: HeaderMap, + pub body: String, } impl FromStr for Response { @@ -31,14 +32,22 @@ impl FromStr for Response { let headers = HeaderMap::parse(&mut lines)?; let status = Status::from_code(code); - Ok(Self { status, headers }) + Ok(Self { + status, + headers, + body: String::new(), + }) } } impl Display for Response { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { status, headers } = self; + let Self { + status, + headers, + body, + } = self; write!(f, "SIP/2.0 {} {status:?}\r\n", status.to_code())?; - write!(f, "{headers}\r\n")?; + write!(f, "{headers}\r\n{body}")?; Ok(()) } } diff --git a/src/encoding/status.rs b/src/encoding/status.rs index 9fe03d7..61b2d2a 100644 --- a/src/encoding/status.rs +++ b/src/encoding/status.rs @@ -1,6 +1,6 @@ macro_rules! status_enum { ($v:vis enum $name:ident { $($variant:ident = $value:literal),*, }) => { - #[derive(Debug, Clone)] + #[derive(Debug, Clone, Eq, PartialEq, Hash)] $v enum $name { $($variant),*, Other(u16) } impl $name { pub fn from_code(c: u16) -> Self { match c { $($value => Self::$variant),*, x => Self::Other(x) } } } impl $name { pub fn to_code(&self) -> u16 { match self { $(Self::$variant => $value),*, Self::Other(x) => *x } } } diff --git a/src/lib.rs b/src/lib.rs index 6c6cc3b..905922b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,4 @@ pub mod encoding; pub mod transport; pub mod transaction; +pub mod sdp; diff --git a/src/sdp/mod.rs b/src/sdp/mod.rs new file mode 100644 index 0000000..635c182 --- /dev/null +++ b/src/sdp/mod.rs @@ -0,0 +1,56 @@ +use anyhow::{anyhow, bail}; +use std::str::FromStr; + +pub struct SessionDescription { + version: String, + originator: String, + session_name: String, + session_information: Option, + description_uri: Option, + email_address: Option, + phone_number: Option, + connection_information: Vec, + bandwidth: Vec, + time_descriptions: Vec, + time_zone_adjustments: Option, + encryption_key: Option, + session_attribute: Vec, + media_descriptions: Vec, +} + +pub struct TimeDescription { + time: String, + repeat_times: Vec, +} + +pub struct MediaDescription { + name: String, + title: String, + connection_information: String, +} + +impl FromStr for SessionDescription { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result { + let mut version = None; + let mut originator = None; + let mut session_name = None; + let mut session_information = None; + let mut description_uri = None; + let mut email_address = None; + let mut phone_number = None; + let mut connection_information = Vec::new(); + let mut bandwidth = Vec::new(); + for line in s.lines() { + let (r#type, value) = line.split_once("=").ok_or(anyhow!("sdp line invalid"))?; + match r#type { + "v" => version = Some(value.to_string()), + "o" => originator = Some(value.to_string()), + "s" => session_name = Some(value.to_string()), + "s" => session_name = Some(value.to_string()), + x => bail!("unknown sdp type ({x:?})"), + } + } + Ok(Self {}) + } +} diff --git a/src/transaction/auth.rs b/src/transaction/auth.rs index f64bb4b..1b3a100 100644 --- a/src/transaction/auth.rs +++ b/src/transaction/auth.rs @@ -14,7 +14,7 @@ impl Authorization { username: &str, password: &str, ) -> Result { - let challenge = failed_response.headers.get::().unwrap()?; + let challenge = failed_response.headers.get_res::()?; Ok(Authorization { response: response_digest( diff --git a/src/transaction/mod.rs b/src/transaction/mod.rs index 601b134..3368c47 100644 --- a/src/transaction/mod.rs +++ b/src/transaction/mod.rs @@ -2,7 +2,7 @@ pub mod auth; use crate::{ encoding::{ - headers::{CSeq, CallID}, + headers::{CSeq, CallID, ContentLength}, request::Request, response::Response, Message, @@ -66,6 +66,7 @@ impl TransactionUser { .get::() .ok_or(anyhow!("call-id is mandatory"))??, ); + resp.headers.insert(ContentLength(resp.body.len())); self.transport.send(Message::Response(resp)).await?; Ok(()) } @@ -74,6 +75,7 @@ impl TransactionUser { let seq = self.sequence.fetch_add(1, Ordering::Relaxed); let cseq = CSeq(seq, request.method); request.headers.insert(cseq); + request.headers.insert(ContentLength(request.body.len())); let (tx, rx) = channel(4); diff --git a/src/transport/udp.rs b/src/transport/udp.rs index 78ca4f2..c0d7829 100644 --- a/src/transport/udp.rs +++ b/src/transport/udp.rs @@ -1,6 +1,6 @@ use super::Transport; use crate::encoding::Message; -use anyhow::Result; +use anyhow::{anyhow, Result}; use log::debug; use std::str::FromStr; use tokio::net::UdpSocket; @@ -19,8 +19,13 @@ impl Transport for UdpTransport { let mut buf = [0; 1024]; let size = self.sock.recv(&mut buf).await?; let message = String::from_utf8(buf[..size].to_vec())?; - debug!("<- {message}"); - Message::from_str(message.trim_end()) + let (head, body) = message + .split_once("\r\n\r\n") + .ok_or(anyhow!("header end missing"))?; + debug!("<- {head}\n\n{body}"); + let mut mesg = Message::from_str(head.trim_end())?; + *mesg.body_mut() = body.to_string(); + Ok(mesg) } async fn send(&self, request: Message) -> Result<()> { debug!("-> {request}"); -- cgit v1.2.3-70-g09d2