use anyhow::Result; use log::{info, warn}; use sip::{ encoding::{ headermap::HeaderMap, headers::{Contact, From, To, UserAgent}, method::Method, response::Response, status::Status, uri::Uri, }, transaction::TransactionUser, transport::tcp::TcpTransport, }; use std::net::SocketAddr; use tokio::{ net::{TcpListener, TcpStream}, spawn, }; #[tokio::main] 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}"); spawn(async move { if let Err(e) = handle_client(stream, addr).await { warn!("client error: {e}") } info!("disconnect {addr}") }); } } async fn handle_client(stream: TcpStream, addr: SocketAddr) -> Result<()> { let transport = TcpTransport::new(stream).await?; let tu = TransactionUser::new(transport); loop { let req = tu.process_incoming().await?; if req.method == Method::Register { let from: From = req.headers.get_res()?; let to: To = req.headers.get_res()?; tu.respond( &req, Response { status: Status::Ok, headers: HeaderMap::new() .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?; } } } /* [2024-07-05T22:22:40Z DEBUG sip::transport::udp] SIP/2.0 200 OK Via: SIP/2.0/UDP 198.18.1.135:52125;branch=Uz7r7ysvrS91q9j9;rport=52125 Contact: ;expires=379;+sip.instance="" Contact: ;expires=411 Contact: ;expires=600 To: ;tag=81756f4e From: ;tag=-AK4OkphTFVZv50h Call-ID: U3Fyb6vT1BhWxiKG CSeq: 1 REGISTER User-Agent: AGFEO SIP V3.00.15 n (MAC=00094070069C) Content-Length: 0 */