diff options
Diffstat (limited to 'src/encoding')
-rw-r--r-- | src/encoding/headermap.rs | 60 | ||||
-rw-r--r-- | src/encoding/headers.rs | 182 | ||||
-rw-r--r-- | src/encoding/method.rs | 39 | ||||
-rw-r--r-- | src/encoding/mod.rs | 46 | ||||
-rw-r--r-- | src/encoding/request.rs | 57 | ||||
-rw-r--r-- | src/encoding/response.rs | 53 | ||||
-rw-r--r-- | src/encoding/status.rs | 63 | ||||
-rw-r--r-- | src/encoding/uri.rs | 55 |
8 files changed, 0 insertions, 555 deletions
diff --git a/src/encoding/headermap.rs b/src/encoding/headermap.rs deleted file mode 100644 index 01e1962..0000000 --- a/src/encoding/headermap.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::headers::Header; -use anyhow::{anyhow, Result}; -use std::fmt::Display; - -#[derive(Debug, Clone)] -pub struct HeaderMap(pub Vec<(String, String)>); - -impl HeaderMap { - pub fn new() -> Self { - Self(vec![]) - } - pub fn add<H: Header>(mut self, h: H) -> Self { - self.0.push((H::NAME.to_string(), format!("{h}"))); - self - } - pub fn insert<H: Header>(&mut self, h: H) { - self.0.push((H::NAME.to_string(), format!("{h}"))); - } - pub fn get_raw(&self, name: &str) -> Option<&str> { - self.0 - .iter() - .find(|(k, _)| k.eq_ignore_ascii_case(name)) - .map(|(_, v)| v.as_str()) - } - pub fn get<H: Header>(&self) -> Option<Result<H>> { - self.get_raw(H::NAME).map(H::from_str) - } - pub fn get_res<H: Header>(&self) -> Result<H> { - self.get().ok_or(anyhow!("{} header missing", H::NAME))? - } - pub fn insert_raw(&mut self, key: String, value: String) { - self.0.push((key, value)) - } -} - -impl Display for HeaderMap { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for (k, v) in &self.0 { - write!(f, "{k}: {v}\r\n")?; - } - Ok(()) - } -} -impl HeaderMap { - pub fn parse<'a>(lines: &mut impl Iterator<Item = &'a str>) -> Result<Self> { - let mut headers = HeaderMap::new(); - for line in lines { - // TODO multiline values - let (key, value) = line.split_once(":").ok_or(anyhow!("header malformed"))?; - headers.insert_raw(key.trim().to_string(), value.trim().to_string()) - } - Ok(headers) - } -} - -impl FromIterator<(String, String)> for HeaderMap { - fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self { - Self(Vec::from_iter(iter)) - } -} diff --git a/src/encoding/headers.rs b/src/encoding/headers.rs deleted file mode 100644 index e880739..0000000 --- a/src/encoding/headers.rs +++ /dev/null @@ -1,182 +0,0 @@ -use super::{headermap::HeaderMap, method::Method, uri::Uri}; -use anyhow::{anyhow, bail, Result}; -use std::{fmt::Display, str::FromStr}; - -macro_rules! header { - ($hname:literal, struct $name:ident($type:ty)) => { - #[derive(Debug)] - pub struct $name(pub $type); - impl Header for $name { - const NAME: &'static str = $hname; - } - impl Display for $name { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } - } - impl FromStr for $name { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok($name(<$type>::from_str(s)?)) - } - } - }; -} - -pub trait Header: FromStr<Err = anyhow::Error> + Display { - const NAME: &'static str; -} - -header!("Content-Length", struct ContentLength(usize)); -header!("Content-Type", struct ContentType(String)); -header!("Call-ID", struct CallID(String)); -header!("Via", struct Via(String)); -header!("Max-Forwards", struct MaxForwards(usize)); -header!("From", struct From(String)); -header!("To", struct To(String)); -header!("User-Agent", struct UserAgent(String)); -header!("Allow", struct Allow(String)); - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -pub struct CSeq(pub u32, pub Method); - -impl Header for CSeq { - const NAME: &'static str = "CSeq"; -} -impl Display for CSeq { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} {}", self.0, self.1) - } -} -impl FromStr for CSeq { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - let (seq, method) = s.split_once(" ").ok_or(anyhow!("method missing"))?; - Ok(CSeq(seq.parse()?, method.parse()?)) - } -} - -#[derive(Debug)] -pub struct WWWAuthenticate { - pub realm: String, - pub nonce: String, -} -impl Header for WWWAuthenticate { - const NAME: &'static str = "WWW-Authenticate"; -} -impl Display for WWWAuthenticate { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Digest realm={:?}, nonce={:?}", self.realm, self.nonce) - } -} -impl FromStr for WWWAuthenticate { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - // TODO this is totally wrong - let kvs = s - .strip_prefix("Digest ") - .ok_or(anyhow!("type not digest"))? - .split(",") - .map(|e| { - let Some((k, v)) = e.split_once("=") else { - bail!("not a KV-pair") - }; - Ok((k.trim().to_string(), v.trim().to_string())) - }) - .try_collect::<HeaderMap>()?; - Ok(WWWAuthenticate { - realm: unquote( - &kvs.get_raw("realm") - .ok_or(anyhow!("realm missing"))? - .to_string(), - )?, - nonce: unquote( - &kvs.get_raw("nonce") - .ok_or(anyhow!("nonce missing"))? - .to_string(), - )?, - }) - } -} - -#[derive(Debug, Clone)] -pub struct Authorization { - pub username: String, - pub realm: String, - pub uri: String, - pub nonce: String, - pub response: String, -} -impl Header for Authorization { - const NAME: &'static str = "Authorization"; -} -impl Display for Authorization { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { - username, - realm, - nonce, - uri, - response, - } = self; - write!( - f, - "Digest username={username:?},\r\n realm={realm:?},\r\n nonce={nonce:?},\r\n uri={uri:?},\r\n response={response:?},\r\n algorithm=MD5" - ) - } -} -impl FromStr for Authorization { - type Err = anyhow::Error; - fn from_str(_s: &str) -> Result<Self, Self::Err> { - todo!() - } -} - -pub fn unquote(v: &str) -> Result<String> { - Ok(v.strip_prefix("\"") - .ok_or(anyhow!("start quote missing"))? - .strip_suffix("\"") - .ok_or(anyhow!("end quote missing"))? - .to_string()) -} - -#[derive(Debug)] -pub struct Contact { - pub display_name: Option<String>, - pub uri: Uri, - pub params: String, -} - -impl Header for Contact { - const NAME: &'static str = "Contact"; -} -impl Display for Contact { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { - display_name, - uri, - params, - } = self; - if let Some(display_name) = display_name { - write!(f, "{display_name} <{uri}>{params}") - } else { - write!(f, "<{uri}>{params}") - } - } -} -impl FromStr for Contact { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - let (display_name, rest) = s.split_once("<").ok_or(anyhow!("malformed contact"))?; - let (uri, params) = rest.split_once(">;").ok_or(anyhow!("malformed contact"))?; - Ok(Self { - display_name: if display_name.is_empty() { - None - } else { - Some(display_name.to_string()) - }, - params: params.to_string(), - uri: Uri::from_str(uri)?, - }) - } -} diff --git a/src/encoding/method.rs b/src/encoding/method.rs deleted file mode 100644 index 6d38cab..0000000 --- a/src/encoding/method.rs +++ /dev/null @@ -1,39 +0,0 @@ -use anyhow::bail; -use std::{fmt::Display, str::FromStr}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Method { - Register, - Invite, - Ack, - Options, - Cancel, - Bye, -} - -impl Display for Method { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - Method::Register => "REGISTER", - Method::Invite => "INVITE", - Method::Ack => "ACK", - Method::Options => "OPTIONS", - Method::Cancel => "CANCEL", - Method::Bye => "BYE", - }) - } -} -impl FromStr for Method { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "REGISTER" => Method::Register, - "INVITE" => Method::Invite, - "ACK" => Method::Ack, - "OPTIONS" => Method::Options, - "CANCEL" => Method::Cancel, - "BYE" => Method::Bye, - _ => bail!("unknown method"), - }) - } -} diff --git a/src/encoding/mod.rs b/src/encoding/mod.rs deleted file mode 100644 index 816aa01..0000000 --- a/src/encoding/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::{fmt::Display, str::FromStr}; - -use request::Request; -use response::Response; - -pub mod headermap; -pub mod headers; -pub mod method; -pub mod request; -pub mod response; -pub mod status; -pub mod uri; - -#[derive(Debug, Clone)] -pub enum Message { - Request(Request), - Response(Response), -} - -impl Display for Message { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Message::Request(r) => write!(f, "{r}"), - Message::Response(r) => write!(f, "{r}"), - } - } -} -impl FromStr for Message { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - if s.starts_with("SIP/") { - Response::from_str(s).map(Message::Response) - } else { - Request::from_str(s).map(Message::Request) - } - } -} - -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 deleted file mode 100644 index ab41b7c..0000000 --- a/src/encoding/request.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::{headermap::HeaderMap, method::Method, uri::Uri}; -use anyhow::{anyhow, bail}; -use std::{fmt::Display, str::FromStr}; - -#[derive(Debug, Clone)] -pub struct Request { - pub method: Method, - pub uri: Uri, - pub headers: HeaderMap, - pub body: String, -} - -impl Display for Request { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { - headers, - method, - uri, - .. - } = self; - write!(f, "{method} {uri} SIP/2.0\r\n")?; - write!(f, "{headers}\r\n")?; - Ok(()) - } -} -impl FromStr for Request { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - let mut lines = s.lines(); - let statusline = lines.next().ok_or(anyhow!("status line missing"))?; - let (method, rest) = statusline - .split_once(" ") - .ok_or(anyhow!("status line malformed"))?; - let (uri, sipver) = rest - .split_once(" ") - .ok_or(anyhow!("status line malformed"))?; - - let Some(ver) = sipver.strip_prefix("SIP/") else { - bail!("sip version malformed"); - }; - if ver != "2.0" { - bail!("sip version {ver:?} is not supported"); - } - - let uri = Uri::from_str(uri)?; - - let headers = HeaderMap::parse(&mut lines)?; - 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 deleted file mode 100644 index 0b7996c..0000000 --- a/src/encoding/response.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::{headermap::HeaderMap, status::Status}; -use anyhow::{anyhow, bail, Context}; -use std::{fmt::Display, str::FromStr}; - -#[derive(Debug, Clone)] -pub struct Response { - pub status: Status, - pub headers: HeaderMap, - pub body: String, -} - -impl FromStr for Response { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - let mut lines = s.lines(); - let statusline = lines.next().ok_or(anyhow!("status line missing"))?; - let (sipver, rest) = statusline - .split_once(" ") - .ok_or(anyhow!("status line malformed"))?; - let (code, _status_str) = rest - .split_once(" ") - .ok_or(anyhow!("status line malformed"))?; - let code = u16::from_str(code).context("status code")?; - - let Some(ver) = sipver.strip_prefix("SIP/") else { - bail!("sip version malformed"); - }; - if ver != "2.0" { - bail!("sip version {ver:?} is not supported"); - } - - let headers = HeaderMap::parse(&mut lines)?; - - let status = Status::from_code(code); - 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, - body, - } = self; - write!(f, "SIP/2.0 {} {status:?}\r\n", status.to_code())?; - write!(f, "{headers}\r\n{body}")?; - Ok(()) - } -} diff --git a/src/encoding/status.rs b/src/encoding/status.rs deleted file mode 100644 index 61b2d2a..0000000 --- a/src/encoding/status.rs +++ /dev/null @@ -1,63 +0,0 @@ -macro_rules! status_enum { - ($v:vis enum $name:ident { $($variant:ident = $value:literal),*, }) => { - #[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 } } } - }; -} - -status_enum!( - pub enum Status { - Trying = 100, - Ringing = 180, - CallIsBeingForwarded = 181, - Queued = 182, - SessionProgress = 183, - Ok = 200, - MultipleChoices = 300, - MovedPermanently = 301, - MovedTemporarily = 302, - UseProxy = 305, - AlternativeService = 380, - BadRequest = 400, - Unauthorized = 401, - PaymentRequired = 402, - Forbidden = 403, - NotFound = 404, - MethodNotAllowed = 405, - NotAcceptable = 406, - ProxyAuthenticationRequired = 407, - RequestTimeout = 408, - Gone = 410, - RequestEntityTooLarge = 413, - RequestURITooLarge = 414, - UnsupportedMediaType = 415, - UnsupportedURIScheme = 416, - BadExtension = 420, - ExtensionRequired = 421, - IntervalTooBrief = 423, - TemporarilyNotAvailable = 480, - CallLegTransactionDoesNotExist = 481, - LoopDetected = 482, - TooManyHops = 483, - AddressIncomplete = 484, - Ambiguous = 485, - BusyHere = 486, - RequestTerminated = 487, - NotAcceptableHere = 488, - RequestPending = 491, - Undecipherable = 493, - InternalServerError = 500, - NotImplemented = 501, - BadGateway = 502, - ServiceUnavailable = 503, - ServerTimeout = 504, - SIPVersionNotSupported = 505, - MessageTooLarge = 513, - BusyEverywhere = 600, - Decline = 603, - DoesNotExistAnywhere = 604, - GlobalNotAcceptable = 606, - } -); diff --git a/src/encoding/uri.rs b/src/encoding/uri.rs deleted file mode 100644 index b1a1282..0000000 --- a/src/encoding/uri.rs +++ /dev/null @@ -1,55 +0,0 @@ -use anyhow::anyhow; -use std::{fmt::Display, str::FromStr}; - -#[derive(Debug, Clone)] -pub struct Uri { - pub protocol: String, - pub localpart: Option<String>, - pub addr: String, - pub params: String, -} - -impl Display for Uri { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self { - protocol, - localpart, - addr, - params, - } = self; - write!( - f, - "{protocol}:{}{addr}{}", - if let Some(localpart) = localpart { - format!("{localpart}@") - } else { - "".to_string() - }, - if params.is_empty() { - "".to_string() - } else { - format!(";{params}") - } - )?; - Ok(()) - } -} -impl FromStr for Uri { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result<Self, Self::Err> { - let (pr, s) = s.split_once(":").ok_or(anyhow!("protocol sep"))?; - let (lp, s) = s.split_once("@").unwrap_or(("", s)); - let (addr, params) = s.split_once(";").unwrap_or((s, "")); - - Ok(Self { - addr: addr.to_owned(), - localpart: if lp.is_empty() { - None - } else { - Some(lp.to_string()) - }, - params: params.to_string(), - protocol: pr.to_string(), - }) - } -} |