diff options
author | metamuffin <metamuffin@disroot.org> | 2024-07-06 17:37:35 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-07-06 17:37:35 +0200 |
commit | 7aa211a8d7ae2efeebd9362699a1aea4b5690e3d (patch) | |
tree | e0af8720ee3b770688600a8ea025de2ce81e5017 | |
parent | 7177367ae41a5e2d6ed401f60ee1455812dd8ffb (diff) | |
download | sip-rs-7aa211a8d7ae2efeebd9362699a1aea4b5690e3d.tar sip-rs-7aa211a8d7ae2efeebd9362699a1aea4b5690e3d.tar.bz2 sip-rs-7aa211a8d7ae2efeebd9362699a1aea4b5690e3d.tar.zst |
start on sdp impl
-rw-r--r-- | examples/server.rs | 22 | ||||
-rw-r--r-- | src/encoding/mod.rs | 9 | ||||
-rw-r--r-- | src/encoding/request.rs | 3 | ||||
-rw-r--r-- | src/encoding/response.rs | 15 | ||||
-rw-r--r-- | src/encoding/status.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/sdp/mod.rs | 56 | ||||
-rw-r--r-- | src/transaction/auth.rs | 2 | ||||
-rw-r--r-- | src/transaction/mod.rs | 4 | ||||
-rw-r--r-- | src/transport/udp.rs | 11 |
10 files changed, 109 insertions, 16 deletions
diff --git a/examples/server.rs b/examples/server.rs index 60a2b33..b58557a 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -9,12 +9,13 @@ use sip::{ method::Method, response::Response, status::Status, + uri::Uri, }, transaction::TransactionUser, - transport::tcp::TcpTransport, + transport::{tcp::TcpTransport, udp::UdpTransport}, }; use tokio::{ - net::{TcpListener, TcpStream}, + net::{TcpListener, TcpStream, UdpSocket}, spawn, }; @@ -23,6 +24,7 @@ async fn main() -> Result<()> { env_logger::init_from_env("LOG"); let listener = TcpListener::bind("0.0.0.0:5060").await?; info!("tcp listener bound to {}", listener.local_addr().unwrap()); + loop { let (stream, addr) = listener.accept().await?; info!("connect {addr}"); @@ -51,11 +53,17 @@ async fn handle_client(stream: TcpStream, addr: SocketAddr) -> Result<()> { Response { status: Status::Ok, headers: HeaderMap::new() - .add(Contact(format!("<sip:{username}@{addr}>;expires=600"))) - .add(From(to.0)) - .add(To(from.0)) - .add(UserAgent("siptest v0.1.0".to_string())) - .add(ContentLength(0)), + .add(Contact { + display_name: None, + uri: Uri { + content: format!("sip:username@{addr}"), + }, + params: ";expires=600".to_string(), + }) + .add(to) + .add(from) + .add(UserAgent("siptest v0.1.0".to_string())), + body: String::new(), }, ) .await?; 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 } } } @@ -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<String>, + description_uri: Option<String>, + email_address: Option<String>, + phone_number: Option<String>, + connection_information: Vec<String>, + bandwidth: Vec<String>, + time_descriptions: Vec<TimeDescription>, + time_zone_adjustments: Option<String>, + encryption_key: Option<String>, + session_attribute: Vec<String>, + media_descriptions: Vec<MediaDescription>, +} + +pub struct TimeDescription { + time: String, + repeat_times: Vec<String>, +} + +pub struct MediaDescription { + name: String, + title: String, + connection_information: String, +} + +impl FromStr for SessionDescription { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result<Self, Self::Err> { + 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<Authorization> { - let challenge = failed_response.headers.get::<WWWAuthenticate>().unwrap()?; + let challenge = failed_response.headers.get_res::<WWWAuthenticate>()?; 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<T: Transport> TransactionUser<T> { .get::<CallID>() .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<T: Transport> TransactionUser<T> { 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}"); |