From e4c8547831abcae0ae993f586d5cfcbf01373dcc Mon Sep 17 00:00:00 2001 From: James Munns <james.munns@gmail.com> Date: Wed, 29 Jun 2016 23:03:46 +0200 Subject: [PATCH] Run rust format. No functional change. --- src/client.rs | 314 ++++++------ src/lib.rs | 6 +- src/packet.rs | 1319 +++++++++++++++++++++++++------------------------ src/server.rs | 504 +++++++++---------- 4 files changed, 1091 insertions(+), 1052 deletions(-) diff --git a/src/client.rs b/src/client.rs index 84b8617..e5c5c89 100644 --- a/src/client.rs +++ b/src/client.rs @@ -9,167 +9,171 @@ use packet::{Packet, PacketType, OptionType}; const DEFAULT_RECEIVE_TIMEOUT: u64 = 5; // 5s pub struct CoAPClient { - socket: UdpSocket, - peer_addr: SocketAddr, + socket: UdpSocket, + peer_addr: SocketAddr, } impl CoAPClient { - /// Create a CoAP client with the peer address. - pub fn new<A: ToSocketAddrs>(addr: A) -> Result<CoAPClient> { - addr.to_socket_addrs().and_then(|mut iter| { - match iter.next() { - Some(SocketAddr::V4(a)) => { - UdpSocket::bind("0.0.0.0:0").and_then(|s| { - s.set_read_timeout(Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))).and_then(|_| { - Ok(CoAPClient { - socket: s, - peer_addr: SocketAddr::V4(a), - }) - }) - }) - }, - Some(SocketAddr::V6(a)) => { - UdpSocket::bind(":::0").and_then(|s| { - s.set_read_timeout(Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))).and_then(|_| { - Ok(CoAPClient { - socket: s, - peer_addr: SocketAddr::V6(a), - }) - }) - }) - }, - None => Err(Error::new(ErrorKind::Other, "no address")) - } - }) - } - - /// Execute a request with the coap url and a specific timeout. Default timeout is 5s. - pub fn request_with_timeout(url: &str, timeout: Option<Duration>) -> Result<Packet> { - let mut url_parser = UrlParser::new(); - url_parser.scheme_type_mapper(Self::coap_scheme_type_mapper); - - match url_parser.parse(url) { - Ok(url_params) => { - let mut packet = Packet::new(); - packet.header.set_version(1); - packet.header.set_type(PacketType::Confirmable); - packet.header.set_code("0.01"); - - let message_id = thread_rng().gen_range(0, num::pow(2u32, 16)) as u16; - packet.header.set_message_id(message_id); - - let mut token: Vec<u8> = vec!(1, 1, 1, 1); - for x in token.iter_mut() { - *x = random() - } - packet.set_token(token.clone()); - - let domain = match url_params.domain() { - Some(d) => d, - None => return Err(Error::new(ErrorKind::InvalidInput, "domain error")) - }; - let port = url_params.port_or_default().unwrap(); - - if let Some(path) = url_params.path() { - for p in path.iter() { - packet.add_option(OptionType::UriPath, p.clone().into_bytes().to_vec()); - } - }; - - let client = try!(Self::new((domain, port))); - try!(client.send(&packet)); - - try!(client.set_receive_timeout(timeout)); - match client.receive() { - Ok(receive_packet) => { - if receive_packet.header.get_message_id() == message_id - && *receive_packet.get_token() == token { - return Ok(receive_packet) - } else { - return Err(Error::new(ErrorKind::Other, "receive invalid data")) - } - }, - Err(e) => Err(e) - } - }, - Err(_) => Err(Error::new(ErrorKind::InvalidInput, "url error")) - } - } - - /// Execute a request with the coap url. - pub fn request(url: &str) -> Result<Packet> { - Self::request_with_timeout(url, Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))) - } - - /// Execute a request. - pub fn send(&self, packet: &Packet) -> Result<()> { - match packet.to_bytes() { - Ok(bytes) => { - let size = try!(self.socket.send_to(&bytes[..], self.peer_addr)); - if size == bytes.len() { - Ok(()) - } else { - Err(Error::new(ErrorKind::Other, "send length error")) - } - }, - Err(_) => Err(Error::new(ErrorKind::InvalidInput, "packet error")) - } - } - - /// Receive a response. - pub fn receive(&self) -> Result<Packet> { - let mut buf = [0; 1500]; - - let (nread, _src) = try!(self.socket.recv_from(&mut buf)); - match Packet::from_bytes(&buf[..nread]) { - Ok(packet) => Ok(packet), - Err(_) => Err(Error::new(ErrorKind::InvalidInput, "packet error")) - } - } - - /// Set the receive timeout. - pub fn set_receive_timeout(&self, dur: Option<Duration>) -> Result<()> { - self.socket.set_read_timeout(dur) - } - - fn coap_scheme_type_mapper(scheme: &str) -> SchemeType { - match scheme { - "coap" => SchemeType::Relative(5683), - _ => SchemeType::NonRelative, - } - } + /// Create a CoAP client with the peer address. + pub fn new<A: ToSocketAddrs>(addr: A) -> Result<CoAPClient> { + addr.to_socket_addrs().and_then(|mut iter| { + match iter.next() { + Some(SocketAddr::V4(a)) => { + UdpSocket::bind("0.0.0.0:0").and_then(|s| { + s.set_read_timeout(Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))) + .and_then(|_| { + Ok(CoAPClient { + socket: s, + peer_addr: SocketAddr::V4(a), + }) + }) + }) + } + Some(SocketAddr::V6(a)) => { + UdpSocket::bind(":::0").and_then(|s| { + s.set_read_timeout(Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))) + .and_then(|_| { + Ok(CoAPClient { + socket: s, + peer_addr: SocketAddr::V6(a), + }) + }) + }) + } + None => Err(Error::new(ErrorKind::Other, "no address")), + } + }) + } + + /// Execute a request with the coap url and a specific timeout. Default timeout is 5s. + pub fn request_with_timeout(url: &str, timeout: Option<Duration>) -> Result<Packet> { + let mut url_parser = UrlParser::new(); + url_parser.scheme_type_mapper(Self::coap_scheme_type_mapper); + + match url_parser.parse(url) { + Ok(url_params) => { + let mut packet = Packet::new(); + packet.header.set_version(1); + packet.header.set_type(PacketType::Confirmable); + packet.header.set_code("0.01"); + + let message_id = thread_rng().gen_range(0, num::pow(2u32, 16)) as u16; + packet.header.set_message_id(message_id); + + let mut token: Vec<u8> = vec![1, 1, 1, 1]; + for x in token.iter_mut() { + *x = random() + } + packet.set_token(token.clone()); + + let domain = match url_params.domain() { + Some(d) => d, + None => return Err(Error::new(ErrorKind::InvalidInput, "domain error")), + }; + let port = url_params.port_or_default().unwrap(); + + if let Some(path) = url_params.path() { + for p in path.iter() { + packet.add_option(OptionType::UriPath, p.clone().into_bytes().to_vec()); + } + }; + + let client = try!(Self::new((domain, port))); + try!(client.send(&packet)); + + try!(client.set_receive_timeout(timeout)); + match client.receive() { + Ok(receive_packet) => { + if receive_packet.header.get_message_id() == message_id && + *receive_packet.get_token() == token { + return Ok(receive_packet); + } else { + return Err(Error::new(ErrorKind::Other, "receive invalid data")); + } + } + Err(e) => Err(e), + } + } + Err(_) => Err(Error::new(ErrorKind::InvalidInput, "url error")), + } + } + + /// Execute a request with the coap url. + pub fn request(url: &str) -> Result<Packet> { + Self::request_with_timeout(url, Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))) + } + + /// Execute a request. + pub fn send(&self, packet: &Packet) -> Result<()> { + match packet.to_bytes() { + Ok(bytes) => { + let size = try!(self.socket.send_to(&bytes[..], self.peer_addr)); + if size == bytes.len() { + Ok(()) + } else { + Err(Error::new(ErrorKind::Other, "send length error")) + } + } + Err(_) => Err(Error::new(ErrorKind::InvalidInput, "packet error")), + } + } + + /// Receive a response. + pub fn receive(&self) -> Result<Packet> { + let mut buf = [0; 1500]; + + let (nread, _src) = try!(self.socket.recv_from(&mut buf)); + match Packet::from_bytes(&buf[..nread]) { + Ok(packet) => Ok(packet), + Err(_) => Err(Error::new(ErrorKind::InvalidInput, "packet error")), + } + } + + /// Set the receive timeout. + pub fn set_receive_timeout(&self, dur: Option<Duration>) -> Result<()> { + self.socket.set_read_timeout(dur) + } + + fn coap_scheme_type_mapper(scheme: &str) -> SchemeType { + match scheme { + "coap" => SchemeType::Relative(5683), + _ => SchemeType::NonRelative, + } + } } #[cfg(test)] mod test { - use super::*; - use std::time::Duration; - use std::io::ErrorKind; - use packet::Packet; - use server::CoAPServer; - - #[test] - fn test_request_error_url() { - assert!(CoAPClient::request("http://127.0.0.1").is_err()); - assert!(CoAPClient::request("coap://127.0.0.").is_err()); - assert!(CoAPClient::request("127.0.0.1").is_err()); - } - - fn request_handler(_: Packet, _:Option<Packet>) -> Option<Packet> { - None - } - - #[test] - fn test_request_timeout() { - let mut server = CoAPServer::new("127.0.0.1:5684").unwrap(); - server.handle(request_handler).unwrap(); - - let error = CoAPClient::request_with_timeout("coap://127.0.0.1:5684/Rust", Some(Duration::new(1, 0))).unwrap_err(); - if cfg!(windows) { - assert_eq!(error.kind(), ErrorKind::TimedOut); - } else { - assert_eq!(error.kind(), ErrorKind::WouldBlock); - } - } + use super::*; + use std::time::Duration; + use std::io::ErrorKind; + use packet::Packet; + use server::CoAPServer; + + #[test] + fn test_request_error_url() { + assert!(CoAPClient::request("http://127.0.0.1").is_err()); + assert!(CoAPClient::request("coap://127.0.0.").is_err()); + assert!(CoAPClient::request("127.0.0.1").is_err()); + } + + fn request_handler(_: Packet, _: Option<Packet>) -> Option<Packet> { + None + } + + #[test] + fn test_request_timeout() { + let mut server = CoAPServer::new("127.0.0.1:5684").unwrap(); + server.handle(request_handler).unwrap(); + + let error = CoAPClient::request_with_timeout("coap://127.0.0.1:5684/Rust", + Some(Duration::new(1, 0))) + .unwrap_err(); + if cfg!(windows) { + assert_eq!(error.kind(), ErrorKind::TimedOut); + } else { + assert_eq!(error.kind(), ErrorKind::WouldBlock); + } + } } diff --git a/src/lib.rs b/src/lib.rs index 6d7483e..5344b44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ //! Implementation of the [CoAP Protocol][spec]. //! -//! This library provides both a client interface (`CoAPClient`) and a server interface (`CoAPServer`). +//! This library provides both a client interface (`CoAPClient`) +//! and a server interface (`CoAPServer`). //! //! [spec]: https://tools.ietf.org/html/rfc7252 //! @@ -72,7 +73,8 @@ extern crate threadpool; extern crate url; extern crate num; extern crate rand; -#[cfg(test)] extern crate quickcheck; +#[cfg(test)] +extern crate quickcheck; #[macro_use] extern crate log; diff --git a/src/packet.rs b/src/packet.rs index 27adf69..58d2a4a 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -10,713 +10,738 @@ macro_rules! u8_to_unsigned_be { #[derive(PartialEq, Eq, Debug)] pub enum PacketType { - Confirmable, - NonConfirmable, - Acknowledgement, - Reset, - Invalid, + Confirmable, + NonConfirmable, + Acknowledgement, + Reset, + Invalid, } #[derive(Default, Debug, RustcEncodable, RustcDecodable)] pub struct PacketHeaderRaw { - ver_type_tkl: u8, - code: u8, - message_id: u16 + ver_type_tkl: u8, + code: u8, + message_id: u16, } #[derive(Debug)] pub struct PacketHeader { - ver_type_tkl: u8, - pub code: PacketClass, - message_id: u16 + ver_type_tkl: u8, + pub code: PacketClass, + message_id: u16, } #[derive(Debug, PartialEq)] pub enum PacketClass { - Empty, - Request(Requests), - Response(Responses), - Reserved + Empty, + Request(Requests), + Response(Responses), + Reserved, } #[derive(Debug, PartialEq)] pub enum Requests { - Get, - Post, - Put, - Delete + Get, + Post, + Put, + Delete, } #[derive(Debug, PartialEq)] pub enum Responses { - // 200 Codes - Created, - Deleted, - Valid, - Changed, - Content, - - // 400 Codes - BadRequest, - Unauthorized, - BadOption, - Forbidden, - NotFound, - MethodNotAllowed, - NotAcceptable, - PreconditionFailed, - RequestEntityTooLarge, - UnsupportedContentFormat, - - // 500 Codes - InternalServerError, - NotImplemented, - BadGateway, - ServiceUnavailable, - GatewayTimeout, - ProxyingNotSupported + // 200 Codes + Created, + Deleted, + Valid, + Changed, + Content, + + // 400 Codes + BadRequest, + Unauthorized, + BadOption, + Forbidden, + NotFound, + MethodNotAllowed, + NotAcceptable, + PreconditionFailed, + RequestEntityTooLarge, + UnsupportedContentFormat, + + // 500 Codes + InternalServerError, + NotImplemented, + BadGateway, + ServiceUnavailable, + GatewayTimeout, + ProxyingNotSupported, } pub fn class_to_code(class: &PacketClass) -> u8 { - return match *class { - PacketClass::Empty => 0x00, - - PacketClass::Request(Requests::Get) => 0x01, - PacketClass::Request(Requests::Post) => 0x02, - PacketClass::Request(Requests::Put) => 0x03, - PacketClass::Request(Requests::Delete) => 0x04, - - PacketClass::Response(Responses::Created) => 0x41, - PacketClass::Response(Responses::Deleted) => 0x42, - PacketClass::Response(Responses::Valid) => 0x43, - PacketClass::Response(Responses::Changed) => 0x44, - PacketClass::Response(Responses::Content) => 0x45, - - PacketClass::Response(Responses::BadRequest) => 0x80, - PacketClass::Response(Responses::Unauthorized) => 0x81, - PacketClass::Response(Responses::BadOption) => 0x82, - PacketClass::Response(Responses::Forbidden) => 0x83, - PacketClass::Response(Responses::NotFound) => 0x84, - PacketClass::Response(Responses::MethodNotAllowed) => 0x85, - PacketClass::Response(Responses::NotAcceptable) => 0x86, - PacketClass::Response(Responses::PreconditionFailed) => 0x8C, - PacketClass::Response(Responses::RequestEntityTooLarge) => 0x8D, - PacketClass::Response(Responses::UnsupportedContentFormat) => 0x8F, - - PacketClass::Response(Responses::InternalServerError) => 0x90, - PacketClass::Response(Responses::NotImplemented) => 0x91, - PacketClass::Response(Responses::BadGateway) => 0x92, - PacketClass::Response(Responses::ServiceUnavailable) => 0x93, - PacketClass::Response(Responses::GatewayTimeout) => 0x94, - PacketClass::Response(Responses::ProxyingNotSupported) => 0x95, - - _ => 0xFF, - } as u8 + return match *class { + PacketClass::Empty => 0x00, + + PacketClass::Request(Requests::Get) => 0x01, + PacketClass::Request(Requests::Post) => 0x02, + PacketClass::Request(Requests::Put) => 0x03, + PacketClass::Request(Requests::Delete) => 0x04, + + PacketClass::Response(Responses::Created) => 0x41, + PacketClass::Response(Responses::Deleted) => 0x42, + PacketClass::Response(Responses::Valid) => 0x43, + PacketClass::Response(Responses::Changed) => 0x44, + PacketClass::Response(Responses::Content) => 0x45, + + PacketClass::Response(Responses::BadRequest) => 0x80, + PacketClass::Response(Responses::Unauthorized) => 0x81, + PacketClass::Response(Responses::BadOption) => 0x82, + PacketClass::Response(Responses::Forbidden) => 0x83, + PacketClass::Response(Responses::NotFound) => 0x84, + PacketClass::Response(Responses::MethodNotAllowed) => 0x85, + PacketClass::Response(Responses::NotAcceptable) => 0x86, + PacketClass::Response(Responses::PreconditionFailed) => 0x8C, + PacketClass::Response(Responses::RequestEntityTooLarge) => 0x8D, + PacketClass::Response(Responses::UnsupportedContentFormat) => 0x8F, + + PacketClass::Response(Responses::InternalServerError) => 0x90, + PacketClass::Response(Responses::NotImplemented) => 0x91, + PacketClass::Response(Responses::BadGateway) => 0x92, + PacketClass::Response(Responses::ServiceUnavailable) => 0x93, + PacketClass::Response(Responses::GatewayTimeout) => 0x94, + PacketClass::Response(Responses::ProxyingNotSupported) => 0x95, + + _ => 0xFF, + } as u8; } pub fn code_to_class(code: &u8) -> PacketClass { - match *code { - 0x00 => PacketClass::Empty, - - 0x01 => PacketClass::Request(Requests::Get), - 0x02 => PacketClass::Request(Requests::Post), - 0x03 => PacketClass::Request(Requests::Put), - 0x04 => PacketClass::Request(Requests::Delete), - - 0x41 => PacketClass::Response(Responses::Created), - 0x42 => PacketClass::Response(Responses::Deleted), - 0x43 => PacketClass::Response(Responses::Valid), - 0x44 => PacketClass::Response(Responses::Changed), - 0x45 => PacketClass::Response(Responses::Content), - - 0x80 => PacketClass::Response(Responses::BadRequest), - 0x81 => PacketClass::Response(Responses::Unauthorized), - 0x82 => PacketClass::Response(Responses::BadOption), - 0x83 => PacketClass::Response(Responses::Forbidden), - 0x84 => PacketClass::Response(Responses::NotFound), - 0x85 => PacketClass::Response(Responses::MethodNotAllowed), - 0x86 => PacketClass::Response(Responses::NotAcceptable), - 0x8C => PacketClass::Response(Responses::PreconditionFailed), - 0x8D => PacketClass::Response(Responses::RequestEntityTooLarge), - 0x8F => PacketClass::Response(Responses::UnsupportedContentFormat), - - 0x90 => PacketClass::Response(Responses::InternalServerError), - 0x91 => PacketClass::Response(Responses::NotImplemented), - 0x92 => PacketClass::Response(Responses::BadGateway), - 0x93 => PacketClass::Response(Responses::ServiceUnavailable), - 0x94 => PacketClass::Response(Responses::GatewayTimeout), - 0x95 => PacketClass::Response(Responses::ProxyingNotSupported), - - _ => PacketClass::Reserved, - } + match *code { + 0x00 => PacketClass::Empty, + + 0x01 => PacketClass::Request(Requests::Get), + 0x02 => PacketClass::Request(Requests::Post), + 0x03 => PacketClass::Request(Requests::Put), + 0x04 => PacketClass::Request(Requests::Delete), + + 0x41 => PacketClass::Response(Responses::Created), + 0x42 => PacketClass::Response(Responses::Deleted), + 0x43 => PacketClass::Response(Responses::Valid), + 0x44 => PacketClass::Response(Responses::Changed), + 0x45 => PacketClass::Response(Responses::Content), + + 0x80 => PacketClass::Response(Responses::BadRequest), + 0x81 => PacketClass::Response(Responses::Unauthorized), + 0x82 => PacketClass::Response(Responses::BadOption), + 0x83 => PacketClass::Response(Responses::Forbidden), + 0x84 => PacketClass::Response(Responses::NotFound), + 0x85 => PacketClass::Response(Responses::MethodNotAllowed), + 0x86 => PacketClass::Response(Responses::NotAcceptable), + 0x8C => PacketClass::Response(Responses::PreconditionFailed), + 0x8D => PacketClass::Response(Responses::RequestEntityTooLarge), + 0x8F => PacketClass::Response(Responses::UnsupportedContentFormat), + + 0x90 => PacketClass::Response(Responses::InternalServerError), + 0x91 => PacketClass::Response(Responses::NotImplemented), + 0x92 => PacketClass::Response(Responses::BadGateway), + 0x93 => PacketClass::Response(Responses::ServiceUnavailable), + 0x94 => PacketClass::Response(Responses::GatewayTimeout), + 0x95 => PacketClass::Response(Responses::ProxyingNotSupported), + + _ => PacketClass::Reserved, + } } pub fn code_to_str(code: &u8) -> String { - let class_code = (0xE0 & code) >> 5; - let detail_code = 0x1F & code; + let class_code = (0xE0 & code) >> 5; + let detail_code = 0x1F & code; - return format!("{}.{:02}", class_code, detail_code); + return format!("{}.{:02}", class_code, detail_code); } pub fn class_to_str(class: &PacketClass) -> String { - return code_to_str(&class_to_code(class)); + return code_to_str(&class_to_code(class)); } impl PacketHeader { - - pub fn new() -> PacketHeader { - return PacketHeader::from_raw(&PacketHeaderRaw::default()); - } - - pub fn from_raw(raw: &PacketHeaderRaw) -> PacketHeader { - return PacketHeader { - ver_type_tkl: raw.ver_type_tkl, - code: code_to_class(&raw.code), - message_id: raw.message_id, - } - } - - pub fn to_raw(&self) -> PacketHeaderRaw { - return PacketHeaderRaw { - ver_type_tkl: self.ver_type_tkl, - code: class_to_code(&self.code), - message_id: self.message_id, - } - } - - #[inline] - pub fn set_version(&mut self, v: u8) { - let type_tkl = 0x3F & self.ver_type_tkl; - self.ver_type_tkl = v << 6 | type_tkl; - } - - #[inline] - pub fn get_version(&self) -> u8 { - return self.ver_type_tkl >> 6; - } - - #[inline] - pub fn set_type(&mut self, t: PacketType) { - let tn = match t { - PacketType::Confirmable => 0, - PacketType::NonConfirmable => 1, - PacketType::Acknowledgement => 2, - PacketType::Reset => 3, - _ => unreachable!(), - }; - - let ver_tkl = 0xCF & self.ver_type_tkl; - self.ver_type_tkl = tn << 4 | ver_tkl; - } - - #[inline] - pub fn get_type(&self) -> PacketType { - let tn = (0x30 & self.ver_type_tkl) >> 4; - match tn { - 0 => PacketType::Confirmable, - 1 => PacketType::NonConfirmable, - 2 => PacketType::Acknowledgement, - 3 => PacketType::Reset, - _ => PacketType::Invalid, - } - } - - #[inline] - fn set_token_length(&mut self, tkl: u8) { - assert_eq!(0xF0 & tkl, 0); - - let ver_type = 0xF0 & self.ver_type_tkl; - self.ver_type_tkl = tkl | ver_type; - } - - #[inline] - fn get_token_length(&self) -> u8 { - return 0x0F & self.ver_type_tkl; - } - - pub fn set_code(&mut self, code: &str) { - let code_vec: Vec<&str> = code.split('.').collect(); - assert_eq!(code_vec.len(), 2); - - let class_code = code_vec[0].parse::<u8>().unwrap(); - let detail_code = code_vec[1].parse::<u8>().unwrap(); - assert_eq!(0xF8 & class_code, 0); - assert_eq!(0xE0 & detail_code, 0); - - self.code = code_to_class(&(class_code << 5 | detail_code)); - } - - pub fn get_code(&self) -> String { - class_to_str(&self.code) - } - - #[inline] - pub fn set_message_id(&mut self, message_id: u16) { - self.message_id = message_id; - } - - #[inline] - pub fn get_message_id(&self) -> u16 { - return self.message_id; - } + pub fn new() -> PacketHeader { + return PacketHeader::from_raw(&PacketHeaderRaw::default()); + } + + pub fn from_raw(raw: &PacketHeaderRaw) -> PacketHeader { + return PacketHeader { + ver_type_tkl: raw.ver_type_tkl, + code: code_to_class(&raw.code), + message_id: raw.message_id, + }; + } + + pub fn to_raw(&self) -> PacketHeaderRaw { + return PacketHeaderRaw { + ver_type_tkl: self.ver_type_tkl, + code: class_to_code(&self.code), + message_id: self.message_id, + }; + } + + #[inline] + pub fn set_version(&mut self, v: u8) { + let type_tkl = 0x3F & self.ver_type_tkl; + self.ver_type_tkl = v << 6 | type_tkl; + } + + #[inline] + pub fn get_version(&self) -> u8 { + return self.ver_type_tkl >> 6; + } + + #[inline] + pub fn set_type(&mut self, t: PacketType) { + let tn = match t { + PacketType::Confirmable => 0, + PacketType::NonConfirmable => 1, + PacketType::Acknowledgement => 2, + PacketType::Reset => 3, + _ => unreachable!(), + }; + + let ver_tkl = 0xCF & self.ver_type_tkl; + self.ver_type_tkl = tn << 4 | ver_tkl; + } + + #[inline] + pub fn get_type(&self) -> PacketType { + let tn = (0x30 & self.ver_type_tkl) >> 4; + match tn { + 0 => PacketType::Confirmable, + 1 => PacketType::NonConfirmable, + 2 => PacketType::Acknowledgement, + 3 => PacketType::Reset, + _ => PacketType::Invalid, + } + } + + #[inline] + fn set_token_length(&mut self, tkl: u8) { + assert_eq!(0xF0 & tkl, 0); + + let ver_type = 0xF0 & self.ver_type_tkl; + self.ver_type_tkl = tkl | ver_type; + } + + #[inline] + fn get_token_length(&self) -> u8 { + return 0x0F & self.ver_type_tkl; + } + + pub fn set_code(&mut self, code: &str) { + let code_vec: Vec<&str> = code.split('.').collect(); + assert_eq!(code_vec.len(), 2); + + let class_code = code_vec[0].parse::<u8>().unwrap(); + let detail_code = code_vec[1].parse::<u8>().unwrap(); + assert_eq!(0xF8 & class_code, 0); + assert_eq!(0xE0 & detail_code, 0); + + self.code = code_to_class(&(class_code << 5 | detail_code)); + } + + pub fn get_code(&self) -> String { + class_to_str(&self.code) + } + + #[inline] + pub fn set_message_id(&mut self, message_id: u16) { + self.message_id = message_id; + } + + #[inline] + pub fn get_message_id(&self) -> u16 { + return self.message_id; + } } #[derive(Debug)] pub enum ParseError { - InvalidHeader, - InvalidTokenLength, - InvalidOptionDelta, - InvalidOptionLength, + InvalidHeader, + InvalidTokenLength, + InvalidOptionDelta, + InvalidOptionLength, } #[derive(Debug)] pub enum PackageError { - InvalidHeader, - InvalidPacketLength, + InvalidHeader, + InvalidPacketLength, } #[derive(PartialEq, Eq, Debug)] pub enum OptionType { - IfMatch, - UriHost, - ETag, - IfNoneMatch, - Observe, - UriPort, - LocationPath, - UriPath, - ContentFormat, - MaxAge, - UriQuery, - Accept, - LocationQuery, - Block2, - Block1, - ProxyUri, - ProxyScheme, - Size1 + IfMatch, + UriHost, + ETag, + IfNoneMatch, + Observe, + UriPort, + LocationPath, + UriPath, + ContentFormat, + MaxAge, + UriQuery, + Accept, + LocationQuery, + Block2, + Block1, + ProxyUri, + ProxyScheme, + Size1, } #[derive(Debug)] pub struct Packet { - pub header: PacketHeader, - token: Vec<u8>, - options: BTreeMap<usize, LinkedList<Vec<u8>>>, - pub payload: Vec<u8>, + pub header: PacketHeader, + token: Vec<u8>, + options: BTreeMap<usize, LinkedList<Vec<u8>>>, + pub payload: Vec<u8>, } impl Packet { - pub fn new() -> Packet { - Packet { - header: PacketHeader::new(), - token: Vec::new(), - options: BTreeMap::new(), - payload: Vec::new(), - } - } - - pub fn set_token(&mut self, token: Vec<u8>) { - self.header.set_token_length(token.len() as u8); - self.token = token; - } - - pub fn get_token(&self) -> &Vec<u8> { - return &self.token; - } - - pub fn set_option(&mut self, tp: OptionType, value: LinkedList<Vec<u8>>) { - let num = Self::get_option_number(tp); - self.options.insert(num, value); - } - - pub fn set_payload(&mut self, payload: Vec<u8>){ - self.payload = payload; - } - - pub fn add_option(&mut self, tp: OptionType, value: Vec<u8>) { - let num = Self::get_option_number(tp); - match self.options.get_mut(&num) { - Some(list) => { - list.push_back(value); - return; - }, - None => (), - }; - - let mut list = LinkedList::new(); - list.push_back(value); - self.options.insert(num, list); - } - - pub fn get_option(&self, tp: OptionType) -> Option<LinkedList<Vec<u8>>> { - let num = Self::get_option_number(tp); - match self.options.get(&num) { - Some(options) => Some(options.clone()), - None => None - } - } - - /// Decodes a byte slice and construct the equivalent Packet. - pub fn from_bytes(buf: &[u8]) -> Result<Packet, ParseError> { - let header_result: bincode::DecodingResult<PacketHeaderRaw> = bincode::decode(buf); - match header_result { - Ok(raw_header) => { - let header = PacketHeader::from_raw(&raw_header); - let token_length = header.get_token_length(); - let options_start: usize = 4 + token_length as usize; - - if token_length > 8 { - return Err(ParseError::InvalidTokenLength); - } - - if options_start > buf.len() { - return Err(ParseError::InvalidTokenLength); - } - - let token = buf[4..options_start].to_vec(); - - let mut idx = options_start; - let mut options_number = 0; - let mut options: BTreeMap<usize, LinkedList<Vec<u8>>> = BTreeMap::new(); - while idx < buf.len() { - let byte = buf[idx]; - - if byte == 255 || idx > buf.len() { - break; - } - - let mut delta = (byte >> 4) as usize; - let mut length = (byte & 0xF) as usize; - - idx += 1; - - // Check for special delta characters - match delta { - 13 => { - if idx >= buf.len() { - return Err(ParseError::InvalidOptionLength); - } - delta = buf[idx] as usize + 13; - idx += 1; - }, - 14 => { - if idx + 1 >= buf.len() { - return Err(ParseError::InvalidOptionLength); - } - - delta = (u16::from_be(u8_to_unsigned_be!(buf, idx, idx + 1, u16)) + 269) as usize; - idx += 2; - }, - 15 => { - return Err(ParseError::InvalidOptionDelta); - } - _ => {} - }; - - // Check for special length characters - match length { - 13 => { - if idx >= buf.len() { - return Err(ParseError::InvalidOptionLength); - } - - length = buf[idx] as usize + 13; - idx += 1; - }, - 14 => { - if idx + 1 >= buf.len() { - return Err(ParseError::InvalidOptionLength); - } - - length = (u16::from_be(u8_to_unsigned_be!(buf, idx, idx + 1, u16)) + 269) as usize; - idx += 2; - }, - 15 => { - return Err(ParseError::InvalidOptionLength); - }, - _ => {} - }; - - options_number += delta; - - let end = idx + length; - if end > buf.len() { - return Err(ParseError::InvalidOptionLength); - } - let options_value = buf[idx..end].to_vec(); - - if options.contains_key(&options_number) { - let mut options_list = options.get_mut(&options_number).unwrap(); - options_list.push_back(options_value); - } else { - let mut list = LinkedList::new(); - list.push_back(options_value); - options.insert(options_number, list); - } - - idx += length; - } - - let mut payload = Vec::new(); - if idx < buf.len() { - payload = buf[(idx + 1)..buf.len()].to_vec(); - } - - - Ok(Packet { - header: header, - token: token, - options: options, - payload: payload, - }) - }, - Err(_) => Err(ParseError::InvalidHeader), - } - } - - /// Returns a vector of bytes representing the Packet. - pub fn to_bytes(&self) -> Result<Vec<u8>, PackageError> { - let mut options_delta_length = 0; - let mut options_bytes: Vec<u8> = Vec::new(); - for (number, value_list) in self.options.iter() { - for value in value_list.iter() { - let mut header: Vec<u8> = Vec::with_capacity(1 + 2 + 2); - let delta = number - options_delta_length; - - let mut byte: u8 = 0; - if delta <= 12 { - byte |= (delta << 4) as u8; - } else if delta < 269 { - byte |= 13 << 4; - } else { - byte |= 14 << 4; - } - if value.len() <= 12 { - byte |= value.len() as u8; - } else if value.len() < 269 { - byte |= 13; - } else { - byte |= 14; - } - header.push(byte); - - if delta > 12 && delta < 269 { - header.push((delta - 13) as u8); - } else if delta >= 269 { - let fix = (delta - 269) as u16; - header.push((fix >> 8) as u8); - header.push((fix & 0xFF) as u8); - } - - if value.len() > 12 && value.len() < 269 { - header.push((value.len() - 13) as u8); - } else if value.len() >= 269 { - let fix = (value.len() - 269) as u16; - header.push((fix >> 8) as u8); - header.push((fix & 0xFF) as u8); - } - - options_delta_length += delta; - - options_bytes.reserve(header.len() + value.len()); - unsafe { - use std::ptr; - let buf_len = options_bytes.len(); - ptr::copy(header.as_ptr(), options_bytes.as_mut_ptr().offset(buf_len as isize), header.len()); - ptr::copy(value.as_ptr(), options_bytes.as_mut_ptr().offset((buf_len + header.len()) as isize), value.len()); - options_bytes.set_len(buf_len + header.len() + value.len()); - } - } - } - - let mut buf_length = 4 + self.payload.len() + self.token.len(); - if self.header.code != PacketClass::Empty && self.payload.len() != 0 { - buf_length += 1; - } - buf_length += options_bytes.len(); - - if buf_length > 1280 { - return Err(PackageError::InvalidPacketLength); - } - - let mut buf: Vec<u8> = Vec::with_capacity(buf_length); - let header_result: bincode::EncodingResult<()> = bincode::encode_into(&self.header.to_raw(), &mut buf, bincode::SizeLimit::Infinite); - match header_result { - Ok(_) => { - buf.reserve(self.token.len() + options_bytes.len()); - unsafe { - use std::ptr; - let buf_len = buf.len(); - ptr::copy(self.token.as_ptr(), buf.as_mut_ptr().offset(buf_len as isize), self.token.len()); - ptr::copy(options_bytes.as_ptr(), buf.as_mut_ptr().offset((buf_len + self.token.len()) as isize), options_bytes.len()); - buf.set_len(buf_len + self.token.len() + options_bytes.len()); - } - - if self.header.code != PacketClass::Empty && self.payload.len() != 0 { - buf.push(0xFF); - buf.reserve(self.payload.len()); - unsafe { - use std::ptr; - let buf_len = buf.len(); - ptr::copy(self.payload.as_ptr(), buf.as_mut_ptr().offset(buf.len() as isize), self.payload.len()); - buf.set_len(buf_len + self.payload.len()); - } - } - Ok(buf) - }, - Err(_) => Err(PackageError::InvalidHeader), - } - } - - fn get_option_number(tp: OptionType) -> usize { - match tp { - OptionType::IfMatch => 1, - OptionType::UriHost => 3, - OptionType::ETag => 4, - OptionType::IfNoneMatch => 5, - OptionType::Observe => 6, - OptionType::UriPort => 7, - OptionType::LocationPath => 8, - OptionType::UriPath => 11, - OptionType::ContentFormat => 12, - OptionType::MaxAge => 14, - OptionType::UriQuery => 15, - OptionType::Accept => 17, - OptionType::LocationQuery => 20, - OptionType::Block2 => 23, - OptionType::Block1 => 27, - OptionType::ProxyUri => 35, - OptionType::ProxyScheme => 39, - OptionType::Size1 => 60, - } - } + pub fn new() -> Packet { + Packet { + header: PacketHeader::new(), + token: Vec::new(), + options: BTreeMap::new(), + payload: Vec::new(), + } + } + + pub fn set_token(&mut self, token: Vec<u8>) { + self.header.set_token_length(token.len() as u8); + self.token = token; + } + + pub fn get_token(&self) -> &Vec<u8> { + return &self.token; + } + + pub fn set_option(&mut self, tp: OptionType, value: LinkedList<Vec<u8>>) { + let num = Self::get_option_number(tp); + self.options.insert(num, value); + } + + pub fn set_payload(&mut self, payload: Vec<u8>) { + self.payload = payload; + } + + pub fn add_option(&mut self, tp: OptionType, value: Vec<u8>) { + let num = Self::get_option_number(tp); + match self.options.get_mut(&num) { + Some(list) => { + list.push_back(value); + return; + } + None => (), + }; + + let mut list = LinkedList::new(); + list.push_back(value); + self.options.insert(num, list); + } + + pub fn get_option(&self, tp: OptionType) -> Option<LinkedList<Vec<u8>>> { + let num = Self::get_option_number(tp); + match self.options.get(&num) { + Some(options) => Some(options.clone()), + None => None, + } + } + + /// Decodes a byte slice and construct the equivalent Packet. + pub fn from_bytes(buf: &[u8]) -> Result<Packet, ParseError> { + let header_result: bincode::DecodingResult<PacketHeaderRaw> = bincode::decode(buf); + match header_result { + Ok(raw_header) => { + let header = PacketHeader::from_raw(&raw_header); + let token_length = header.get_token_length(); + let options_start: usize = 4 + token_length as usize; + + if token_length > 8 { + return Err(ParseError::InvalidTokenLength); + } + + if options_start > buf.len() { + return Err(ParseError::InvalidTokenLength); + } + + let token = buf[4..options_start].to_vec(); + + let mut idx = options_start; + let mut options_number = 0; + let mut options: BTreeMap<usize, LinkedList<Vec<u8>>> = BTreeMap::new(); + while idx < buf.len() { + let byte = buf[idx]; + + if byte == 255 || idx > buf.len() { + break; + } + + let mut delta = (byte >> 4) as usize; + let mut length = (byte & 0xF) as usize; + + idx += 1; + + // Check for special delta characters + match delta { + 13 => { + if idx >= buf.len() { + return Err(ParseError::InvalidOptionLength); + } + delta = buf[idx] as usize + 13; + idx += 1; + } + 14 => { + if idx + 1 >= buf.len() { + return Err(ParseError::InvalidOptionLength); + } + + delta = (u16::from_be(u8_to_unsigned_be!(buf, idx, idx + 1, u16)) + + 269) as usize; + idx += 2; + } + 15 => { + return Err(ParseError::InvalidOptionDelta); + } + _ => {} + }; + + // Check for special length characters + match length { + 13 => { + if idx >= buf.len() { + return Err(ParseError::InvalidOptionLength); + } + + length = buf[idx] as usize + 13; + idx += 1; + } + 14 => { + if idx + 1 >= buf.len() { + return Err(ParseError::InvalidOptionLength); + } + + length = (u16::from_be(u8_to_unsigned_be!(buf, idx, idx + 1, u16)) + + 269) as usize; + idx += 2; + } + 15 => { + return Err(ParseError::InvalidOptionLength); + } + _ => {} + }; + + options_number += delta; + + let end = idx + length; + if end > buf.len() { + return Err(ParseError::InvalidOptionLength); + } + let options_value = buf[idx..end].to_vec(); + + if options.contains_key(&options_number) { + let mut options_list = options.get_mut(&options_number).unwrap(); + options_list.push_back(options_value); + } else { + let mut list = LinkedList::new(); + list.push_back(options_value); + options.insert(options_number, list); + } + + idx += length; + } + + let mut payload = Vec::new(); + if idx < buf.len() { + payload = buf[(idx + 1)..buf.len()].to_vec(); + } + + + Ok(Packet { + header: header, + token: token, + options: options, + payload: payload, + }) + } + Err(_) => Err(ParseError::InvalidHeader), + } + } + + /// Returns a vector of bytes representing the Packet. + pub fn to_bytes(&self) -> Result<Vec<u8>, PackageError> { + let mut options_delta_length = 0; + let mut options_bytes: Vec<u8> = Vec::new(); + for (number, value_list) in self.options.iter() { + for value in value_list.iter() { + let mut header: Vec<u8> = Vec::with_capacity(1 + 2 + 2); + let delta = number - options_delta_length; + + let mut byte: u8 = 0; + if delta <= 12 { + byte |= (delta << 4) as u8; + } else if delta < 269 { + byte |= 13 << 4; + } else { + byte |= 14 << 4; + } + if value.len() <= 12 { + byte |= value.len() as u8; + } else if value.len() < 269 { + byte |= 13; + } else { + byte |= 14; + } + header.push(byte); + + if delta > 12 && delta < 269 { + header.push((delta - 13) as u8); + } else if delta >= 269 { + let fix = (delta - 269) as u16; + header.push((fix >> 8) as u8); + header.push((fix & 0xFF) as u8); + } + + if value.len() > 12 && value.len() < 269 { + header.push((value.len() - 13) as u8); + } else if value.len() >= 269 { + let fix = (value.len() - 269) as u16; + header.push((fix >> 8) as u8); + header.push((fix & 0xFF) as u8); + } + + options_delta_length += delta; + + options_bytes.reserve(header.len() + value.len()); + unsafe { + use std::ptr; + let buf_len = options_bytes.len(); + ptr::copy(header.as_ptr(), + options_bytes.as_mut_ptr().offset(buf_len as isize), + header.len()); + ptr::copy(value.as_ptr(), + options_bytes.as_mut_ptr().offset((buf_len + header.len()) as isize), + value.len()); + options_bytes.set_len(buf_len + header.len() + value.len()); + } + } + } + + let mut buf_length = 4 + self.payload.len() + self.token.len(); + if self.header.code != PacketClass::Empty && self.payload.len() != 0 { + buf_length += 1; + } + buf_length += options_bytes.len(); + + if buf_length > 1280 { + return Err(PackageError::InvalidPacketLength); + } + + let mut buf: Vec<u8> = Vec::with_capacity(buf_length); + let header_result: bincode::EncodingResult<()> = + bincode::encode_into(&self.header.to_raw(), + &mut buf, + bincode::SizeLimit::Infinite); + match header_result { + Ok(_) => { + buf.reserve(self.token.len() + options_bytes.len()); + unsafe { + use std::ptr; + let buf_len = buf.len(); + ptr::copy(self.token.as_ptr(), + buf.as_mut_ptr().offset(buf_len as isize), + self.token.len()); + ptr::copy(options_bytes.as_ptr(), + buf.as_mut_ptr().offset((buf_len + self.token.len()) as isize), + options_bytes.len()); + buf.set_len(buf_len + self.token.len() + options_bytes.len()); + } + + if self.header.code != PacketClass::Empty && self.payload.len() != 0 { + buf.push(0xFF); + buf.reserve(self.payload.len()); + unsafe { + use std::ptr; + let buf_len = buf.len(); + ptr::copy(self.payload.as_ptr(), + buf.as_mut_ptr().offset(buf.len() as isize), + self.payload.len()); + buf.set_len(buf_len + self.payload.len()); + } + } + Ok(buf) + } + Err(_) => Err(PackageError::InvalidHeader), + } + } + + fn get_option_number(tp: OptionType) -> usize { + match tp { + OptionType::IfMatch => 1, + OptionType::UriHost => 3, + OptionType::ETag => 4, + OptionType::IfNoneMatch => 5, + OptionType::Observe => 6, + OptionType::UriPort => 7, + OptionType::LocationPath => 8, + OptionType::UriPath => 11, + OptionType::ContentFormat => 12, + OptionType::MaxAge => 14, + OptionType::UriQuery => 15, + OptionType::Accept => 17, + OptionType::LocationQuery => 20, + OptionType::Block2 => 23, + OptionType::Block1 => 27, + OptionType::ProxyUri => 35, + OptionType::ProxyScheme => 39, + OptionType::Size1 => 60, + } + } } /// Convert a request to a response pub fn auto_response(request_packet: &Packet) -> Option<Packet> { - let mut packet = Packet::new(); - - packet.header.set_version(1); - let response_type = match request_packet.header.get_type() { - PacketType::Confirmable => PacketType::Acknowledgement, - PacketType::NonConfirmable => PacketType::NonConfirmable, - _ => return None - }; - packet.header.set_type(response_type); - packet.header.code = PacketClass::Response(Responses::Content); - packet.header.set_message_id(request_packet.header.get_message_id()); - packet.set_token(request_packet.get_token().clone()); - - packet.payload = request_packet.payload.clone(); - - Some(packet) - } + let mut packet = Packet::new(); + + packet.header.set_version(1); + let response_type = match request_packet.header.get_type() { + PacketType::Confirmable => PacketType::Acknowledgement, + PacketType::NonConfirmable => PacketType::NonConfirmable, + _ => return None, + }; + packet.header.set_type(response_type); + packet.header.code = PacketClass::Response(Responses::Content); + packet.header.set_message_id(request_packet.header.get_message_id()); + packet.set_token(request_packet.get_token().clone()); + + packet.payload = request_packet.payload.clone(); + + Some(packet) +} #[cfg(test)] mod test { - use super::*; - use std::collections::LinkedList; - - #[test] - fn test_header_codes() { - for code in 0..255 { - let class = code_to_class(&code); - let code_str = code_to_str(&code); - let class_str = class_to_str(&class); - - // Reserved class could technically be many codes - // so only check valid items - if class != PacketClass::Reserved { - assert_eq!(class_to_code(&class), code); - assert_eq!(code_str, class_str); - } - } - } - - #[test] - fn test_decode_packet_with_options() { - let buf = [0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69, 0x04, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31]; - let packet = Packet::from_bytes(&buf); - assert!(packet.is_ok()); - let packet = packet.unwrap(); - assert_eq!(packet.header.get_version(), 1); - assert_eq!(packet.header.get_type(), PacketType::Confirmable); - assert_eq!(packet.header.get_token_length(), 4); - assert_eq!(packet.header.code, PacketClass::Request(Requests::Get)); - assert_eq!(packet.header.get_message_id(), 33950); - assert_eq!(*packet.get_token(), vec!(0x51, 0x55, 0x77, 0xE8)); - assert_eq!(packet.options.len(), 2); - - let uri_path = packet.get_option(OptionType::UriPath); - assert!(uri_path.is_some()); - let uri_path = uri_path.unwrap(); - let mut expected_uri_path = LinkedList::new(); - expected_uri_path.push_back("Hi".as_bytes().to_vec()); - expected_uri_path.push_back("Test".as_bytes().to_vec()); - assert_eq!(uri_path, expected_uri_path); - - let uri_query = packet.get_option(OptionType::UriQuery); - assert!(uri_query.is_some()); - let uri_query = uri_query.unwrap(); - let mut expected_uri_query = LinkedList::new(); - expected_uri_query.push_back("a=1".as_bytes().to_vec()); - assert_eq!(uri_query, expected_uri_query); - } - - #[test] - fn test_decode_packet_with_payload() { - let buf = [0x64, 0x45, 0x13, 0xFD, 0xD0, 0xE2, 0x4D, 0xAC, 0xFF, 0x48, 0x65, 0x6C, 0x6C, 0x6F]; - let packet = Packet::from_bytes(&buf); - assert!(packet.is_ok()); - let packet = packet.unwrap(); - assert_eq!(packet.header.get_version(), 1); - assert_eq!(packet.header.get_type(), PacketType::Acknowledgement); - assert_eq!(packet.header.get_token_length(), 4); - assert_eq!(packet.header.code, PacketClass::Response(Responses::Content)); - assert_eq!(packet.header.get_message_id(), 5117); - assert_eq!(*packet.get_token(), vec!(0xD0, 0xE2, 0x4D, 0xAC)); - assert_eq!(packet.payload, "Hello".as_bytes().to_vec()); - } - - #[test] - fn test_encode_packet_with_options() { - let mut packet = Packet::new(); - packet.header.set_version(1); - packet.header.set_type(PacketType::Confirmable); - packet.header.code = PacketClass::Request(Requests::Get); - packet.header.set_message_id(33950); - packet.set_token(vec!(0x51, 0x55, 0x77, 0xE8)); - packet.add_option(OptionType::UriPath, b"Hi".to_vec()); - packet.add_option(OptionType::UriPath, b"Test".to_vec()); - packet.add_option(OptionType::UriQuery, b"a=1".to_vec()); - assert_eq!(packet.to_bytes().unwrap(), vec!(0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69, 0x04, 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31)); - } - - #[test] - fn test_encode_packet_with_payload() { - let mut packet = Packet::new(); - packet.header.set_version(1); - packet.header.set_type(PacketType::Acknowledgement); - packet.header.code = PacketClass::Response(Responses::Content); - packet.header.set_message_id(5117); - packet.set_token(vec!(0xD0, 0xE2, 0x4D, 0xAC)); - packet.payload = "Hello".as_bytes().to_vec(); - assert_eq!(packet.to_bytes().unwrap(), vec!(0x64, 0x45, 0x13, 0xFD, 0xD0, 0xE2, 0x4D, 0xAC, 0xFF, 0x48, 0x65, 0x6C, 0x6C, 0x6F)); - } - - #[test] - fn test_malicious_packet() { - use rand; - use quickcheck::{QuickCheck, StdGen, TestResult}; - - fn run(x: Vec<u8>) -> TestResult { - match Packet::from_bytes(&x[..]) { - Ok(packet) => { - TestResult::from_bool(packet.get_token().len() == packet.header.get_token_length() as usize) - }, - Err(_) => TestResult::passed() - } - } - QuickCheck::new().tests(10000).gen(StdGen::new(rand::thread_rng(), 1500)).quickcheck(run as fn(Vec<u8>) -> TestResult) - } + use super::*; + use std::collections::LinkedList; + + #[test] + fn test_header_codes() { + for code in 0..255 { + let class = code_to_class(&code); + let code_str = code_to_str(&code); + let class_str = class_to_str(&class); + + // Reserved class could technically be many codes + // so only check valid items + if class != PacketClass::Reserved { + assert_eq!(class_to_code(&class), code); + assert_eq!(code_str, class_str); + } + } + } + + #[test] + fn test_decode_packet_with_options() { + let buf = [0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69, 0x04, 0x54, + 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31]; + let packet = Packet::from_bytes(&buf); + assert!(packet.is_ok()); + let packet = packet.unwrap(); + assert_eq!(packet.header.get_version(), 1); + assert_eq!(packet.header.get_type(), PacketType::Confirmable); + assert_eq!(packet.header.get_token_length(), 4); + assert_eq!(packet.header.code, PacketClass::Request(Requests::Get)); + assert_eq!(packet.header.get_message_id(), 33950); + assert_eq!(*packet.get_token(), vec![0x51, 0x55, 0x77, 0xE8]); + assert_eq!(packet.options.len(), 2); + + let uri_path = packet.get_option(OptionType::UriPath); + assert!(uri_path.is_some()); + let uri_path = uri_path.unwrap(); + let mut expected_uri_path = LinkedList::new(); + expected_uri_path.push_back("Hi".as_bytes().to_vec()); + expected_uri_path.push_back("Test".as_bytes().to_vec()); + assert_eq!(uri_path, expected_uri_path); + + let uri_query = packet.get_option(OptionType::UriQuery); + assert!(uri_query.is_some()); + let uri_query = uri_query.unwrap(); + let mut expected_uri_query = LinkedList::new(); + expected_uri_query.push_back("a=1".as_bytes().to_vec()); + assert_eq!(uri_query, expected_uri_query); + } + + #[test] + fn test_decode_packet_with_payload() { + let buf = [0x64, 0x45, 0x13, 0xFD, 0xD0, 0xE2, 0x4D, 0xAC, 0xFF, 0x48, 0x65, 0x6C, 0x6C, + 0x6F]; + let packet = Packet::from_bytes(&buf); + assert!(packet.is_ok()); + let packet = packet.unwrap(); + assert_eq!(packet.header.get_version(), 1); + assert_eq!(packet.header.get_type(), PacketType::Acknowledgement); + assert_eq!(packet.header.get_token_length(), 4); + assert_eq!(packet.header.code, + PacketClass::Response(Responses::Content)); + assert_eq!(packet.header.get_message_id(), 5117); + assert_eq!(*packet.get_token(), vec![0xD0, 0xE2, 0x4D, 0xAC]); + assert_eq!(packet.payload, "Hello".as_bytes().to_vec()); + } + + #[test] + fn test_encode_packet_with_options() { + let mut packet = Packet::new(); + packet.header.set_version(1); + packet.header.set_type(PacketType::Confirmable); + packet.header.code = PacketClass::Request(Requests::Get); + packet.header.set_message_id(33950); + packet.set_token(vec![0x51, 0x55, 0x77, 0xE8]); + packet.add_option(OptionType::UriPath, b"Hi".to_vec()); + packet.add_option(OptionType::UriPath, b"Test".to_vec()); + packet.add_option(OptionType::UriQuery, b"a=1".to_vec()); + assert_eq!(packet.to_bytes().unwrap(), + vec![0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69, 0x04, + 0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31]); + } + + #[test] + fn test_encode_packet_with_payload() { + let mut packet = Packet::new(); + packet.header.set_version(1); + packet.header.set_type(PacketType::Acknowledgement); + packet.header.code = PacketClass::Response(Responses::Content); + packet.header.set_message_id(5117); + packet.set_token(vec![0xD0, 0xE2, 0x4D, 0xAC]); + packet.payload = "Hello".as_bytes().to_vec(); + assert_eq!(packet.to_bytes().unwrap(), + vec![0x64, 0x45, 0x13, 0xFD, 0xD0, 0xE2, 0x4D, 0xAC, 0xFF, 0x48, 0x65, 0x6C, + 0x6C, 0x6F]); + } + + #[test] + fn test_malicious_packet() { + use rand; + use quickcheck::{QuickCheck, StdGen, TestResult}; + + fn run(x: Vec<u8>) -> TestResult { + match Packet::from_bytes(&x[..]) { + Ok(packet) => { + TestResult::from_bool(packet.get_token().len() == + packet.header.get_token_length() as usize) + } + Err(_) => TestResult::passed(), + } + } + QuickCheck::new() + .tests(10000) + .gen(StdGen::new(rand::thread_rng(), 1500)) + .quickcheck(run as fn(Vec<u8>) -> TestResult) + } } diff --git a/src/server.rs b/src/server.rs index f71c211..03c23c3 100644 --- a/src/server.rs +++ b/src/server.rs @@ -14,287 +14,295 @@ pub type RxQueue = mpsc::Receiver<CoAPResponse>; #[derive(Debug)] pub enum CoAPServerError { - NetworkError, - EventLoopError, - AnotherHandlerIsRunning, + NetworkError, + EventLoopError, + AnotherHandlerIsRunning, } #[derive(Debug)] pub struct CoAPResponse { - pub address: SocketAddr, - pub response: Packet + pub address: SocketAddr, + pub response: Packet, } pub trait CoAPHandler: Sync + Send + Copy { - fn handle(&self, Packet, Option<Packet>) -> Option<Packet>; + fn handle(&self, Packet, Option<Packet>) -> Option<Packet>; } -impl<F> CoAPHandler for F where F: Fn(Packet, Option<Packet>) -> Option<Packet>, F: Sync + Send + Copy { - fn handle(&self, request: Packet, response: Option<Packet>) -> Option<Packet> { - return self(request, response); - } +impl<F> CoAPHandler for F + where F: Fn(Packet, Option<Packet>) -> Option<Packet>, + F: Sync + Send + Copy +{ + fn handle(&self, request: Packet, response: Option<Packet>) -> Option<Packet> { + return self(request, response); + } } struct UdpHandler<H: CoAPHandler + 'static> { - socket: UdpSocket, - thread_pool: ThreadPool, - tx_sender: TxQueue, - coap_handler: H + socket: UdpSocket, + thread_pool: ThreadPool, + tx_sender: TxQueue, + coap_handler: H, } impl<H: CoAPHandler + 'static> UdpHandler<H> { - fn new(socket: UdpSocket, thread_pool: ThreadPool, tx_sender: TxQueue, coap_handler: H) -> UdpHandler<H> { - UdpHandler { - socket: socket, - thread_pool: thread_pool, - tx_sender: tx_sender, - coap_handler: coap_handler - } - } + fn new(socket: UdpSocket, + thread_pool: ThreadPool, + tx_sender: TxQueue, + coap_handler: H) + -> UdpHandler<H> { + UdpHandler { + socket: socket, + thread_pool: thread_pool, + tx_sender: tx_sender, + coap_handler: coap_handler, + } + } } impl<H: CoAPHandler + 'static> Handler for UdpHandler<H> { - type Timeout = usize; - type Message = (); - - fn ready(&mut self, _: &mut EventLoop<UdpHandler<H>>, _: Token, events: EventSet) { - if !events.is_readable() { - warn!("Unreadable Event"); - return; - } - - let coap_handler = self.coap_handler; - let mut buf = [0; 1500]; - - match self.socket.recv_from(&mut buf) { - Ok(Some((nread, src))) => { - debug!("Handling request from {}", src); - let response_q = self.tx_sender.clone(); - self.thread_pool.execute(move || { - match Packet::from_bytes(&buf[..nread]) { - Ok(packet) => { - // Pre-generate a response - let auto_resp = auto_response(&packet); - // Dispatch user handler, if there is a response packet - // send the reply via the TX thread - match coap_handler.handle(packet, auto_resp) { - Some(response) => { - debug!("Response: {:?}", response); - response_q.send(CoAPResponse{ - address: src, - response: response - }).unwrap(); - }, - None => { - debug!("No response"); - } - }; - }, - Err(_) => { - error!("Failed to parse request"); - return; - } - }; - }); - }, - _ => { - error!("Failed to read from socket"); - panic!("unexpected error"); - }, - } - - } - - fn notify(&mut self, event_loop: &mut EventLoop<UdpHandler<H>>, _: ()) { - info!("Shutting down request handler"); - event_loop.shutdown(); - } + type Timeout = usize; + type Message = (); + + fn ready(&mut self, _: &mut EventLoop<UdpHandler<H>>, _: Token, events: EventSet) { + if !events.is_readable() { + warn!("Unreadable Event"); + return; + } + + let coap_handler = self.coap_handler; + let mut buf = [0; 1500]; + + match self.socket.recv_from(&mut buf) { + Ok(Some((nread, src))) => { + debug!("Handling request from {}", src); + let response_q = self.tx_sender.clone(); + self.thread_pool.execute(move || { + match Packet::from_bytes(&buf[..nread]) { + Ok(packet) => { + // Pre-generate a response + let auto_resp = auto_response(&packet); + // Dispatch user handler, if there is a response packet + // send the reply via the TX thread + match coap_handler.handle(packet, auto_resp) { + Some(response) => { + debug!("Response: {:?}", response); + response_q.send(CoAPResponse { + address: src, + response: response, + }) + .unwrap(); + } + None => { + debug!("No response"); + } + }; + } + Err(_) => { + error!("Failed to parse request"); + return; + } + }; + }); + } + _ => { + error!("Failed to read from socket"); + panic!("unexpected error"); + } + } + + } + + fn notify(&mut self, event_loop: &mut EventLoop<UdpHandler<H>>, _: ()) { + info!("Shutting down request handler"); + event_loop.shutdown(); + } } pub struct CoAPServer { - socket: UdpSocket, - event_sender: Option<Sender<()>>, - event_thread: Option<thread::JoinHandle<()>>, - tx_thread: Option<thread::JoinHandle<()>>, - worker_num: usize, + socket: UdpSocket, + event_sender: Option<Sender<()>>, + event_thread: Option<thread::JoinHandle<()>>, + tx_thread: Option<thread::JoinHandle<()>>, + worker_num: usize, } impl CoAPServer { - /// Creates a CoAP server listening on the given address. - pub fn new<A: ToSocketAddrs>(addr: A) -> std::io::Result<CoAPServer> { - addr.to_socket_addrs().and_then(|mut iter| { - match iter.next() { - Some(ad) => { - UdpSocket::bound(&ad).and_then(|s| Ok(CoAPServer { - socket: s, - event_sender: None, - event_thread: None, - tx_thread: None, - worker_num: DEFAULT_WORKER_NUM, - })) - }, - None => Err(Error::new(ErrorKind::Other, "no address")) - } - }) - } - - /// Starts handling requests with the handler - pub fn handle<H: CoAPHandler + 'static>(&mut self, handler: H) -> Result<(), CoAPServerError> { - let socket; - - // Early return error checking - if let Some(_) = self.event_sender { - error!("Handler already running!"); - return Err(CoAPServerError::AnotherHandlerIsRunning); - } - match self.socket.try_clone() { - Ok(good_socket) => { - socket = good_socket - }, - Err(_) => { - error!("Network Error!"); - return Err(CoAPServerError::NetworkError); - }, - } - - // Create resources - let worker_num = self.worker_num; - let (tx, rx) = mpsc::channel(); - let (tx_send, tx_recv) : (TxQueue, RxQueue) = mpsc::channel(); - let tx_only = self.socket.try_clone().unwrap(); - - // Setup and spawn single TX thread - let tx_thread = thread::spawn(move || { - transmit_handler(tx_recv, tx_only); - }); - - // Setup and spawn event loop thread, which will spawn - // children threads which handle incomining requests - let thread = thread::spawn(move || { - let thread_pool = ThreadPool::new(worker_num); - let mut event_loop = EventLoop::new().unwrap(); - event_loop.register(&socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap(); - - tx.send(event_loop.channel()).unwrap(); - - event_loop.run(&mut UdpHandler::new(socket, thread_pool, tx_send, handler)).unwrap(); - }); - - // Ensure threads started successfully - match rx.recv() { - Ok(event_sender) => { - self.event_sender = Some(event_sender); - self.event_thread = Some(thread); - self.tx_thread = Some(tx_thread); - Ok(()) - }, - Err(_) => Err(CoAPServerError::EventLoopError) - } - } - - /// Stop the server. - pub fn stop(&mut self) { - let event_sender = self.event_sender.take(); - match event_sender { - Some(ref sender) => { - sender.send(()).unwrap(); - self.event_thread.take().map(|g| g.join()); - }, - _ => {}, - } - } - - /// Set the number of threads for handling requests - pub fn set_worker_num(&mut self, worker_num: usize) { - self.worker_num = worker_num; - } + /// Creates a CoAP server listening on the given address. + pub fn new<A: ToSocketAddrs>(addr: A) -> std::io::Result<CoAPServer> { + addr.to_socket_addrs().and_then(|mut iter| { + match iter.next() { + Some(ad) => { + UdpSocket::bound(&ad).and_then(|s| { + Ok(CoAPServer { + socket: s, + event_sender: None, + event_thread: None, + tx_thread: None, + worker_num: DEFAULT_WORKER_NUM, + }) + }) + } + None => Err(Error::new(ErrorKind::Other, "no address")), + } + }) + } + + /// Starts handling requests with the handler + pub fn handle<H: CoAPHandler + 'static>(&mut self, handler: H) -> Result<(), CoAPServerError> { + let socket; + + // Early return error checking + if let Some(_) = self.event_sender { + error!("Handler already running!"); + return Err(CoAPServerError::AnotherHandlerIsRunning); + } + match self.socket.try_clone() { + Ok(good_socket) => socket = good_socket, + Err(_) => { + error!("Network Error!"); + return Err(CoAPServerError::NetworkError); + } + } + + // Create resources + let worker_num = self.worker_num; + let (tx, rx) = mpsc::channel(); + let (tx_send, tx_recv): (TxQueue, RxQueue) = mpsc::channel(); + let tx_only = self.socket.try_clone().unwrap(); + + // Setup and spawn single TX thread + let tx_thread = thread::spawn(move || { + transmit_handler(tx_recv, tx_only); + }); + + // Setup and spawn event loop thread, which will spawn + // children threads which handle incomining requests + let thread = thread::spawn(move || { + let thread_pool = ThreadPool::new(worker_num); + let mut event_loop = EventLoop::new().unwrap(); + event_loop.register(&socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap(); + + tx.send(event_loop.channel()).unwrap(); + + event_loop.run(&mut UdpHandler::new(socket, thread_pool, tx_send, handler)).unwrap(); + }); + + // Ensure threads started successfully + match rx.recv() { + Ok(event_sender) => { + self.event_sender = Some(event_sender); + self.event_thread = Some(thread); + self.tx_thread = Some(tx_thread); + Ok(()) + } + Err(_) => Err(CoAPServerError::EventLoopError), + } + } + + /// Stop the server. + pub fn stop(&mut self) { + let event_sender = self.event_sender.take(); + match event_sender { + Some(ref sender) => { + sender.send(()).unwrap(); + self.event_thread.take().map(|g| g.join()); + } + _ => {} + } + } + + /// Set the number of threads for handling requests + pub fn set_worker_num(&mut self, worker_num: usize) { + self.worker_num = worker_num; + } } fn transmit_handler(tx_recv: RxQueue, tx_only: UdpSocket) { - // Note! We should only transmit with this UDP Socket - // TODO: Add better support for failure detection or logging - loop { - match tx_recv.recv() { - Ok(q_res) => { - match q_res.response.to_bytes() { - Ok(bytes) => { - let _ = tx_only.send_to(&bytes[..], &q_res.address); - }, - Err(_) => { - error!("Failed to decode response"); - } - } - }, - // recv error occurs when all transmitters are terminited - // (when all UDP Handlers are closed) - Err(_) => { - info!("Shutting down Transmit Handler"); - break; - } - } - } + // Note! We should only transmit with this UDP Socket + // TODO: Add better support for failure detection or logging + loop { + match tx_recv.recv() { + Ok(q_res) => { + match q_res.response.to_bytes() { + Ok(bytes) => { + let _ = tx_only.send_to(&bytes[..], &q_res.address); + } + Err(_) => { + error!("Failed to decode response"); + } + } + } + // recv error occurs when all transmitters are terminited + // (when all UDP Handlers are closed) + Err(_) => { + info!("Shutting down Transmit Handler"); + break; + } + } + } } impl Drop for CoAPServer { - fn drop(&mut self) { - self.stop(); - } + fn drop(&mut self) { + self.stop(); + } } #[cfg(test)] mod test { - use super::*; - use packet::{Packet, PacketType, OptionType}; - use client::CoAPClient; - - fn request_handler(req: Packet, response: Option<Packet>) -> Option<Packet> { - let uri_path_list = req.get_option(OptionType::UriPath).unwrap(); - assert!(uri_path_list.len() == 1); - - match response { - Some(mut packet) => { - packet.set_payload(uri_path_list.front().unwrap().clone()); - Some(packet) - }, - _ => None - } - } - - #[test] - fn test_echo_server() { - let mut server = CoAPServer::new("127.0.0.1:5683").unwrap(); - server.handle(request_handler).unwrap(); - - let client = CoAPClient::new("127.0.0.1:5683").unwrap(); - let mut packet = Packet::new(); - packet.header.set_version(1); - packet.header.set_type(PacketType::Confirmable); - packet.header.set_code("0.01"); - packet.header.set_message_id(1); - packet.set_token(vec!(0x51, 0x55, 0x77, 0xE8)); - packet.add_option(OptionType::UriPath, b"test-echo".to_vec()); - client.send(&packet).unwrap(); - - let recv_packet = client.receive().unwrap(); - assert_eq!(recv_packet.payload, b"test-echo".to_vec()); - } - - #[test] - fn test_echo_server_no_token() { - let mut server = CoAPServer::new("127.0.0.1:5683").unwrap(); - server.handle(request_handler).unwrap(); - - let client = CoAPClient::new("127.0.0.1:5683").unwrap(); - let mut packet = Packet::new(); - packet.header.set_version(1); - packet.header.set_type(PacketType::Confirmable); - packet.header.set_code("0.01"); - packet.header.set_message_id(1); - packet.add_option(OptionType::UriPath, b"test-echo".to_vec()); - client.send(&packet).unwrap(); - - let recv_packet = client.receive().unwrap(); - assert_eq!(recv_packet.payload, b"test-echo".to_vec()); - } + use super::*; + use packet::{Packet, PacketType, OptionType}; + use client::CoAPClient; + + fn request_handler(req: Packet, response: Option<Packet>) -> Option<Packet> { + let uri_path_list = req.get_option(OptionType::UriPath).unwrap(); + assert!(uri_path_list.len() == 1); + + match response { + Some(mut packet) => { + packet.set_payload(uri_path_list.front().unwrap().clone()); + Some(packet) + } + _ => None, + } + } + + #[test] + fn test_echo_server() { + let mut server = CoAPServer::new("127.0.0.1:5683").unwrap(); + server.handle(request_handler).unwrap(); + + let client = CoAPClient::new("127.0.0.1:5683").unwrap(); + let mut packet = Packet::new(); + packet.header.set_version(1); + packet.header.set_type(PacketType::Confirmable); + packet.header.set_code("0.01"); + packet.header.set_message_id(1); + packet.set_token(vec![0x51, 0x55, 0x77, 0xE8]); + packet.add_option(OptionType::UriPath, b"test-echo".to_vec()); + client.send(&packet).unwrap(); + + let recv_packet = client.receive().unwrap(); + assert_eq!(recv_packet.payload, b"test-echo".to_vec()); + } + + #[test] + fn test_echo_server_no_token() { + let mut server = CoAPServer::new("127.0.0.1:5683").unwrap(); + server.handle(request_handler).unwrap(); + + let client = CoAPClient::new("127.0.0.1:5683").unwrap(); + let mut packet = Packet::new(); + packet.header.set_version(1); + packet.header.set_type(PacketType::Confirmable); + packet.header.set_code("0.01"); + packet.header.set_message_id(1); + packet.add_option(OptionType::UriPath, b"test-echo".to_vec()); + client.send(&packet).unwrap(); + + let recv_packet = client.receive().unwrap(); + assert_eq!(recv_packet.payload, b"test-echo".to_vec()); + } } -- GitLab