diff --git a/examples/client.rs b/examples/client.rs index eb4bfe0aa8cd3b3fab57ef30172273d63d6385bc..48f89e5133263aff7963031be6e06ea700922d1d 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -1,5 +1,6 @@ extern crate coap; +use std::io::ErrorKind; use coap::packet::*; use coap::CoAPClient; @@ -23,7 +24,10 @@ fn main() { println!("Server reply: {}", String::from_utf8(response.payload).unwrap()); }, Err(e) => { - println!("Request error: {:?}", e); + match e.kind() { + ErrorKind::WouldBlock => println!("Request timeout"), + _ => println!("Request error: {:?}", e), + } } } } \ No newline at end of file diff --git a/examples/server.rs b/examples/server.rs index 38af78c9661b5ce613df7cad8ca1eb92a47d1a4e..b33505b45ba16ccf49971831cad96b246e55bd59 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -4,8 +4,9 @@ use std::io; use coap::packet::*; use coap::{CoAPServer, CoAPClient}; -fn request_handler(req: Packet, _resp: CoAPClient) { +fn request_handler(req: Packet, resp: CoAPClient) { println!("Receive request: {:?}", req); + resp.reply(&req, b"OK".to_vec()).unwrap(); } fn main() { diff --git a/src/client.rs b/src/client.rs index 13ec0fb065568ec73ef5810219f1829f393d0c86..904c5ead9aa4c477906144358c3b33507d606478 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,10 +1,13 @@ use std::io::{Result, Error, ErrorKind}; use std::net::{ToSocketAddrs, SocketAddr, UdpSocket}; +use std::time::Duration; use url::{UrlParser, SchemeType}; use num; use rand::{thread_rng, random, Rng}; use packet::{Packet, PacketType, OptionType}; +const DEFAULT_RECEIVE_TIMEOUT: u64 = 5; // 5s + pub struct CoAPClient { socket: UdpSocket, peer_addr: SocketAddr, @@ -17,17 +20,21 @@ impl CoAPClient { match iter.next() { Some(SocketAddr::V4(a)) => { UdpSocket::bind("0.0.0.0:0").and_then(|s| { - Ok(CoAPClient { - socket: s, - peer_addr: SocketAddr::V4(a), + 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| { - Ok(CoAPClient { - socket: s, - peer_addr: SocketAddr::V6(a), + s.set_read_timeout(Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0))).and_then(|_| { + Ok(CoAPClient { + socket: s, + peer_addr: SocketAddr::V6(a), + }) }) }) }, @@ -36,8 +43,8 @@ impl CoAPClient { }) } - /// Execute a request with the coap url. - pub fn request(url: &str) -> Result<Packet> { + // 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); @@ -72,6 +79,7 @@ impl CoAPClient { 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 @@ -88,6 +96,11 @@ impl CoAPClient { } } + /// 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))) + } + /// Response the client with the specifc payload. pub fn reply(&self, request_packet: &Packet, payload: Vec<u8>) -> Result<()> { let mut packet = Packet::new(); @@ -132,6 +145,11 @@ impl CoAPClient { } } + /// 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), @@ -144,7 +162,10 @@ impl CoAPClient { #[cfg(test)] mod test { use super::*; + use std::time::Duration; + use std::io::ErrorKind; use packet::{Packet, PacketType}; + use server::CoAPServer; #[test] fn test_request_error_url() { @@ -160,4 +181,16 @@ mod test { packet.header.set_type(PacketType::Acknowledgement); assert!(client.reply(&packet, b"Test".to_vec()).is_err()); } + + fn request_handler(_: Packet, _: CoAPClient) { + } + + #[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(); + assert_eq!(error.kind(), ErrorKind::WouldBlock); + } } \ No newline at end of file