lib.rs (8550B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 extern crate libc; 6 extern crate nserror; 7 extern crate rsdparsa; 8 9 use std::ffi::CString; 10 use std::os::raw::c_char; 11 use std::ptr; 12 13 use libc::size_t; 14 15 use std::rc::Rc; 16 17 use std::convert::{TryFrom, TryInto}; 18 19 use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; 20 use rsdparsa::address::ExplicitlyTypedAddress; 21 use rsdparsa::anonymizer::{AnonymizingClone, StatefulSdpAnonymizer}; 22 use rsdparsa::attribute_type::SdpAttribute; 23 use rsdparsa::error::SdpParserError; 24 use rsdparsa::media_type::{SdpMediaValue, SdpProtocolValue}; 25 use rsdparsa::{SdpBandwidth, SdpSession, SdpTiming}; 26 27 #[macro_use] 28 extern crate log; 29 30 pub mod attribute; 31 pub mod media_section; 32 pub mod network; 33 pub mod types; 34 35 use network::{ 36 get_bandwidth, origin_view_helper, RustAddressType, RustSdpConnection, RustSdpOrigin, 37 }; 38 pub use types::{StringView, NULL_STRING}; 39 40 #[no_mangle] 41 pub unsafe extern "C" fn parse_sdp( 42 sdp: StringView, 43 fail_on_warning: bool, 44 session: *mut *const SdpSession, 45 parser_error: *mut *const SdpParserError, 46 ) -> nsresult { 47 let sdp_str: String = match sdp.try_into() { 48 Ok(string) => string, 49 Err(boxed_error) => { 50 *session = ptr::null(); 51 *parser_error = Box::into_raw(Box::new(SdpParserError::Sequence { 52 message: format!("{}", boxed_error), 53 line_number: 0, 54 })); 55 return NS_ERROR_INVALID_ARG; 56 } 57 }; 58 59 let parser_result = rsdparsa::parse_sdp(&sdp_str, fail_on_warning); 60 match parser_result { 61 Ok(mut parsed) => { 62 *parser_error = match parsed.warnings.len() { 63 0 => ptr::null(), 64 _ => Box::into_raw(Box::new(parsed.warnings.remove(0))), 65 }; 66 *session = Rc::into_raw(Rc::new(parsed)); 67 NS_OK 68 } 69 Err(e) => { 70 *session = ptr::null(); 71 error!("Error parsing SDP in rust: {}", e); 72 *parser_error = Box::into_raw(Box::new(e)); 73 NS_ERROR_INVALID_ARG 74 } 75 } 76 } 77 78 #[no_mangle] 79 pub unsafe extern "C" fn create_anonymized_sdp_clone( 80 session: *const SdpSession, 81 ) -> *const SdpSession { 82 Rc::into_raw(Rc::new( 83 (*session).masked_clone(&mut StatefulSdpAnonymizer::new()), 84 )) 85 } 86 87 #[no_mangle] 88 pub unsafe extern "C" fn create_sdp_clone(session: *const SdpSession) -> *const SdpSession { 89 Rc::into_raw(Rc::new((*session).clone())) 90 } 91 92 #[no_mangle] 93 pub unsafe extern "C" fn sdp_free_session(sdp_ptr: *mut SdpSession) { 94 let sdp = Rc::from_raw(sdp_ptr); 95 drop(sdp); 96 } 97 98 #[no_mangle] 99 pub unsafe extern "C" fn sdp_new_reference(session: *mut SdpSession) -> *const SdpSession { 100 let original = Rc::from_raw(session); 101 let ret = Rc::into_raw(Rc::clone(&original)); 102 std::mem::forget(original); // So the original reference doesn't get dropped 103 ret 104 } 105 106 #[no_mangle] 107 pub unsafe extern "C" fn sdp_get_error_line_num(parser_error: *mut SdpParserError) -> size_t { 108 match *parser_error { 109 SdpParserError::Line { line_number, .. } 110 | SdpParserError::Unsupported { line_number, .. } 111 | SdpParserError::Sequence { line_number, .. } => line_number, 112 } 113 } 114 115 #[no_mangle] 116 // Callee must check that a nullptr is not returned 117 pub unsafe extern "C" fn sdp_get_error_message(parser_error: *mut SdpParserError) -> *mut c_char { 118 let message = format!("{}", *parser_error); 119 return match CString::new(message.as_str()) { 120 Ok(c_char_ptr) => c_char_ptr.into_raw(), 121 Err(_) => 0 as *mut c_char, 122 }; 123 } 124 125 #[no_mangle] 126 pub unsafe extern "C" fn sdp_free_error_message(message: *mut c_char) { 127 if message != 0 as *mut c_char { 128 let _tmp = CString::from_raw(message); 129 } 130 } 131 132 #[no_mangle] 133 pub unsafe extern "C" fn sdp_free_error(parser_error: *mut SdpParserError) { 134 let e = Box::from_raw(parser_error); 135 drop(e); 136 } 137 138 #[no_mangle] 139 pub unsafe extern "C" fn get_version(session: *const SdpSession) -> u64 { 140 (*session).get_version() 141 } 142 143 #[no_mangle] 144 pub unsafe extern "C" fn sdp_get_origin(session: *const SdpSession) -> RustSdpOrigin { 145 origin_view_helper((*session).get_origin()) 146 } 147 148 #[no_mangle] 149 pub unsafe extern "C" fn session_view(session: *const SdpSession) -> StringView { 150 StringView::from((*session).get_session()) 151 } 152 153 #[no_mangle] 154 pub unsafe extern "C" fn sdp_session_has_connection(session: *const SdpSession) -> bool { 155 (*session).connection.is_some() 156 } 157 158 #[no_mangle] 159 pub unsafe extern "C" fn sdp_get_session_connection( 160 session: *const SdpSession, 161 connection: *mut RustSdpConnection, 162 ) -> nsresult { 163 match (*session).connection { 164 Some(ref c) => { 165 *connection = RustSdpConnection::from(c); 166 NS_OK 167 } 168 None => NS_ERROR_INVALID_ARG, 169 } 170 } 171 172 #[no_mangle] 173 pub unsafe extern "C" fn sdp_add_media_section( 174 session: *mut SdpSession, 175 media_type: u32, 176 direction: u32, 177 port: u16, 178 protocol: u32, 179 addr_type: u32, 180 address: StringView, 181 ) -> nsresult { 182 let addr_type = match RustAddressType::try_from(addr_type) { 183 Ok(a) => a.into(), 184 Err(e) => { 185 return e; 186 } 187 }; 188 let address_string: String = match address.try_into() { 189 Ok(x) => x, 190 Err(boxed_error) => { 191 error!("Error while parsing string, description: {}", boxed_error); 192 return NS_ERROR_INVALID_ARG; 193 } 194 }; 195 let address = match ExplicitlyTypedAddress::try_from((addr_type, address_string.as_str())) { 196 Ok(a) => a, 197 Err(_) => { 198 return NS_ERROR_INVALID_ARG; 199 } 200 }; 201 202 let media_type = match media_type { 203 0 => SdpMediaValue::Audio, // MediaType::kAudio 204 1 => SdpMediaValue::Video, // MediaType::kVideo 205 3 => SdpMediaValue::Application, // MediaType::kApplication 206 _ => { 207 return NS_ERROR_INVALID_ARG; 208 } 209 }; 210 let protocol = match protocol { 211 20 => SdpProtocolValue::RtpSavpf, // Protocol::kRtpSavpf 212 21 => SdpProtocolValue::UdpTlsRtpSavp, // Protocol::kUdpTlsRtpSavp 213 22 => SdpProtocolValue::TcpDtlsRtpSavp, // Protocol::kTcpDtlsRtpSavp 214 24 => SdpProtocolValue::UdpTlsRtpSavpf, // Protocol::kUdpTlsRtpSavpf 215 25 => SdpProtocolValue::TcpDtlsRtpSavpf, // Protocol::kTcpTlsRtpSavpf 216 37 => SdpProtocolValue::DtlsSctp, // Protocol::kDtlsSctp 217 38 => SdpProtocolValue::UdpDtlsSctp, // Protocol::kUdpDtlsSctp 218 39 => SdpProtocolValue::TcpDtlsSctp, // Protocol::kTcpDtlsSctp 219 _ => { 220 return NS_ERROR_INVALID_ARG; 221 } 222 }; 223 let direction = match direction { 224 1 => SdpAttribute::Sendonly, 225 2 => SdpAttribute::Recvonly, 226 3 => SdpAttribute::Sendrecv, 227 _ => { 228 return NS_ERROR_INVALID_ARG; 229 } 230 }; 231 232 match (*session).add_media(media_type, direction, port as u32, protocol, address) { 233 Ok(_) => NS_OK, 234 Err(_) => NS_ERROR_INVALID_ARG, 235 } 236 } 237 238 #[repr(C)] 239 #[derive(Clone)] 240 pub struct RustSdpTiming { 241 pub start: u64, 242 pub stop: u64, 243 } 244 245 impl<'a> From<&'a SdpTiming> for RustSdpTiming { 246 fn from(timing: &SdpTiming) -> Self { 247 RustSdpTiming { 248 start: timing.start, 249 stop: timing.stop, 250 } 251 } 252 } 253 254 #[no_mangle] 255 pub unsafe extern "C" fn sdp_session_has_timing(session: *const SdpSession) -> bool { 256 (*session).timing.is_some() 257 } 258 259 #[no_mangle] 260 pub unsafe extern "C" fn sdp_session_timing( 261 session: *const SdpSession, 262 timing: *mut RustSdpTiming, 263 ) -> nsresult { 264 match (*session).timing { 265 Some(ref t) => { 266 *timing = RustSdpTiming::from(t); 267 NS_OK 268 } 269 None => NS_ERROR_INVALID_ARG, 270 } 271 } 272 273 #[no_mangle] 274 pub unsafe extern "C" fn sdp_media_section_count(session: *const SdpSession) -> size_t { 275 (*session).media.len() 276 } 277 278 #[no_mangle] 279 pub unsafe extern "C" fn get_sdp_bandwidth( 280 session: *const SdpSession, 281 bandwidth_type: *const c_char, 282 ) -> u32 { 283 get_bandwidth(&(*session).bandwidth, bandwidth_type) 284 } 285 286 #[no_mangle] 287 pub unsafe extern "C" fn sdp_get_session_bandwidth_vec( 288 session: *const SdpSession, 289 ) -> *const Vec<SdpBandwidth> { 290 &(*session).bandwidth 291 } 292 293 #[no_mangle] 294 pub unsafe extern "C" fn get_sdp_session_attributes( 295 session: *const SdpSession, 296 ) -> *const Vec<SdpAttribute> { 297 &(*session).attribute 298 }