From a021c24d17a01c8516fb014ddc14d7ca2279a8da Mon Sep 17 00:00:00 2001
From: Joakim Lundberg <joakim@joakimlundberg.com>
Date: Tue, 30 Jan 2018 23:08:20 +0100
Subject: [PATCH] Test of Cargo build system

---
 utils/xoap/Cargo.toml             |  27 ++
 utils/xoap/README.md              |  73 ++++
 utils/xoap/Xargo.toml             |   9 +
 utils/xoap/src/lib.rs             |  23 ++
 utils/xoap/src/message/header.rs  | 251 ++++++++++++
 utils/xoap/src/message/packet.rs  | 608 ++++++++++++++++++++++++++++++
 utils/xoap/src/message/request.rs |  87 +++++
 7 files changed, 1078 insertions(+)
 create mode 100644 utils/xoap/Cargo.toml
 create mode 100644 utils/xoap/README.md
 create mode 100644 utils/xoap/Xargo.toml
 create mode 100644 utils/xoap/src/lib.rs
 create mode 100644 utils/xoap/src/message/header.rs
 create mode 100644 utils/xoap/src/message/packet.rs
 create mode 100644 utils/xoap/src/message/request.rs

diff --git a/utils/xoap/Cargo.toml b/utils/xoap/Cargo.toml
new file mode 100644
index 0000000..0f30954
--- /dev/null
+++ b/utils/xoap/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "xoap"
+version = "0.1.0"
+description = "A CoAP library for bare-metal applications"
+readme = "README.md"
+documentation = ""
+repository = ""
+license = "MIT OR Apache-2.0"
+authors = ["Joakim Lundberg <joakim@joakimlundberg.com>"]
+keywords = ["CoAP", "xoap"]
+
+[dependencies]
+#alloc-cortex-m = {}
+
+[dependencies.smoltcp]
+version = "0.4"
+default-features = false
+features = ["alloc"] 
+
+[dependencies.nb]
+git = "https://github.com/japaric/nb"
+
+[dependencies.cast]
+default-features = false
+version = "0.2.2"
+
+
diff --git a/utils/xoap/README.md b/utils/xoap/README.md
new file mode 100644
index 0000000..718e891
--- /dev/null
+++ b/utils/xoap/README.md
@@ -0,0 +1,73 @@
+# xoap
+[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
+
+A fast and stable [Constrained Application Protocol(CoAP)](https://tools.ietf.org/html/rfc7252) library implemented in Rust.
+
+built from
+[Documentation](http://covertness.github.io/coap-rs/coap/index.html)
+
+## Installation
+
+First add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+xoap = "0.5"
+```
+
+Then, add this to your crate root:
+
+```rust
+extern crate xoap;
+```
+
+## Example
+
+### Server:
+```rust
+extern crate xoap;
+
+use std::io;
+use xoap::{CoAPServer, CoAPResponse, CoAPRequest};
+
+fn request_handler(req: CoAPRequest) -> Option<CoAPResponse> {
+    println!("Receive request: {:?}", req);
+
+    // Return the auto-generated response
+    req.response
+}
+
+fn main() {
+    let addr = "127.0.0.1:5683";
+
+    let mut server = CoAPServer::new(addr).unwrap();
+    server.handle(request_handler).unwrap();
+
+    println!("Server up on {}", addr);
+    println!("Press any key to stop...");
+    io::stdin().read_line(&mut String::new()).unwrap();
+
+    println!("Server shutdown");
+}
+```
+
+### Client:
+```rust
+extern crate coap;
+
+use coap::{CoAPClient, CoAPResponse};
+
+fn main() {
+    let url = "coap://127.0.0.1:5683/Rust";
+    println!("Client request: {}", url);
+
+    let response: CoAPResponse = CoAPClient::request(url).unwrap();
+    println!("Server reply: {}", String::from_utf8(response.message.payload).unwrap());
+}
+```
+
+## Benchmark
+```bash
+$ cargo run --example server
+$ cargo bench
+```
diff --git a/utils/xoap/Xargo.toml b/utils/xoap/Xargo.toml
new file mode 100644
index 0000000..fbb3999
--- /dev/null
+++ b/utils/xoap/Xargo.toml
@@ -0,0 +1,9 @@
+[dependencies.core]
+stage = 0
+
+[dependencies.alloc]
+stage = 0
+
+[dependencies.compiler_builtins]
+stage = 1
+
diff --git a/utils/xoap/src/lib.rs b/utils/xoap/src/lib.rs
new file mode 100644
index 0000000..483e4a0
--- /dev/null
+++ b/utils/xoap/src/lib.rs
@@ -0,0 +1,23 @@
+//! Implementation of the [CoAP Protocol][spec].
+//!
+//! This library provides both a client interface (`CoAPClient`)
+//!   and a server interface (`CoAPServer`).
+//!
+//! [spec]: https://tools.ietf.org/html/rfc7252
+//!
+
+#![deny(missing_docs)]
+#![deny(warnings)]
+#[allow(deprecated)]
+#![feature(collections)]
+#![no_std]
+#![allow(unused_mut)]
+
+//#[macro_use]
+extern crate smoltcp;
+extern crate nb;
+extern crate cast;
+extern crate alloc_cortex_m;
+#[macro_use]
+extern crate collections;
+
diff --git a/utils/xoap/src/message/header.rs b/utils/xoap/src/message/header.rs
new file mode 100644
index 0000000..9482561
--- /dev/null
+++ b/utils/xoap/src/message/header.rs
@@ -0,0 +1,251 @@
+#[derive(Default, Debug, RustcEncodable, RustcDecodable)]
+pub struct HeaderRaw {
+    ver_type_tkl: u8,
+    code: u8,
+    message_id: u16,
+}
+
+#[derive(Debug)]
+pub struct Header {
+    ver_type_tkl: u8,
+    pub code: MessageClass,
+    message_id: u16,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum MessageClass {
+    Empty,
+    RequestType(Requests),
+    ResponseType(Responses),
+    Reserved,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Requests {
+    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,
+}
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum MessageType {
+    Confirmable,
+    NonConfirmable,
+    Acknowledgement,
+    Reset,
+    Invalid,
+}
+
+impl Header {
+    pub fn new() -> Header {
+        return Header::from_raw(&HeaderRaw::default());
+    }
+
+    pub fn from_raw(raw: &HeaderRaw) -> Header {
+        return Header {
+            ver_type_tkl: raw.ver_type_tkl,
+            code: code_to_class(&raw.code),
+            message_id: raw.message_id,
+        };
+    }
+
+    pub fn to_raw(&self) -> HeaderRaw {
+        return HeaderRaw {
+            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: MessageType) {
+        let tn = match t {
+            MessageType::Confirmable => 0,
+            MessageType::NonConfirmable => 1,
+            MessageType::Acknowledgement => 2,
+            MessageType::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) -> MessageType {
+        let tn = (0x30 & self.ver_type_tkl) >> 4;
+        match tn {
+            0 => MessageType::Confirmable,
+            1 => MessageType::NonConfirmable,
+            2 => MessageType::Acknowledgement,
+            3 => MessageType::Reset,
+            _ => MessageType::Invalid,
+        }
+    }
+
+    #[inline]
+    pub 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]
+    pub 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 class_to_code(class: &MessageClass) -> u8 {
+    return match *class {
+        MessageClass::Empty => 0x00,
+
+        MessageClass::RequestType(Requests::Get) => 0x01,
+        MessageClass::RequestType(Requests::Post) => 0x02,
+        MessageClass::RequestType(Requests::Put) => 0x03,
+        MessageClass::RequestType(Requests::Delete) => 0x04,
+
+        MessageClass::ResponseType(Responses::Created) => 0x41,
+        MessageClass::ResponseType(Responses::Deleted) => 0x42,
+        MessageClass::ResponseType(Responses::Valid) => 0x43,
+        MessageClass::ResponseType(Responses::Changed) => 0x44,
+        MessageClass::ResponseType(Responses::Content) => 0x45,
+
+        MessageClass::ResponseType(Responses::BadRequest) => 0x80,
+        MessageClass::ResponseType(Responses::Unauthorized) => 0x81,
+        MessageClass::ResponseType(Responses::BadOption) => 0x82,
+        MessageClass::ResponseType(Responses::Forbidden) => 0x83,
+        MessageClass::ResponseType(Responses::NotFound) => 0x84,
+        MessageClass::ResponseType(Responses::MethodNotAllowed) => 0x85,
+        MessageClass::ResponseType(Responses::NotAcceptable) => 0x86,
+        MessageClass::ResponseType(Responses::PreconditionFailed) => 0x8C,
+        MessageClass::ResponseType(Responses::RequestEntityTooLarge) => 0x8D,
+        MessageClass::ResponseType(Responses::UnsupportedContentFormat) => 0x8F,
+
+        MessageClass::ResponseType(Responses::InternalServerError) => 0x90,
+        MessageClass::ResponseType(Responses::NotImplemented) => 0x91,
+        MessageClass::ResponseType(Responses::BadGateway) => 0x92,
+        MessageClass::ResponseType(Responses::ServiceUnavailable) => 0x93,
+        MessageClass::ResponseType(Responses::GatewayTimeout) => 0x94,
+        MessageClass::ResponseType(Responses::ProxyingNotSupported) => 0x95,
+
+        _ => 0xFF,
+    } as u8;
+}
+
+pub fn code_to_class(code: &u8) -> MessageClass {
+    match *code {
+        0x00 => MessageClass::Empty,
+
+        0x01 => MessageClass::RequestType(Requests::Get),
+        0x02 => MessageClass::RequestType(Requests::Post),
+        0x03 => MessageClass::RequestType(Requests::Put),
+        0x04 => MessageClass::RequestType(Requests::Delete),
+
+        0x41 => MessageClass::ResponseType(Responses::Created),
+        0x42 => MessageClass::ResponseType(Responses::Deleted),
+        0x43 => MessageClass::ResponseType(Responses::Valid),
+        0x44 => MessageClass::ResponseType(Responses::Changed),
+        0x45 => MessageClass::ResponseType(Responses::Content),
+
+        0x80 => MessageClass::ResponseType(Responses::BadRequest),
+        0x81 => MessageClass::ResponseType(Responses::Unauthorized),
+        0x82 => MessageClass::ResponseType(Responses::BadOption),
+        0x83 => MessageClass::ResponseType(Responses::Forbidden),
+        0x84 => MessageClass::ResponseType(Responses::NotFound),
+        0x85 => MessageClass::ResponseType(Responses::MethodNotAllowed),
+        0x86 => MessageClass::ResponseType(Responses::NotAcceptable),
+        0x8C => MessageClass::ResponseType(Responses::PreconditionFailed),
+        0x8D => MessageClass::ResponseType(Responses::RequestEntityTooLarge),
+        0x8F => MessageClass::ResponseType(Responses::UnsupportedContentFormat),
+
+        0x90 => MessageClass::ResponseType(Responses::InternalServerError),
+        0x91 => MessageClass::ResponseType(Responses::NotImplemented),
+        0x92 => MessageClass::ResponseType(Responses::BadGateway),
+        0x93 => MessageClass::ResponseType(Responses::ServiceUnavailable),
+        0x94 => MessageClass::ResponseType(Responses::GatewayTimeout),
+        0x95 => MessageClass::ResponseType(Responses::ProxyingNotSupported),
+
+        _ => MessageClass::Reserved,
+    }
+}
+
+pub fn code_to_str(code: &u8) -> String {
+    let class_code = (0xE0 & code) >> 5;
+    let detail_code = 0x1F & code;
+
+    return format!("{}.{:02}", class_code, detail_code);
+}
+
+pub fn class_to_str(class: &MessageClass) -> String {
+    return code_to_str(&class_to_code(class));
+}
diff --git a/utils/xoap/src/message/packet.rs b/utils/xoap/src/message/packet.rs
new file mode 100644
index 0000000..9a25fbe
--- /dev/null
+++ b/utils/xoap/src/message/packet.rs
@@ -0,0 +1,608 @@
+//use bincode;
+use alloc::BTreeMap;
+use alloc::LinkedList;
+
+//use num::FromPrimitive;
+
+use message::header;
+
+macro_rules! u8_to_unsigned_be {
+    ($src:ident, $start:expr, $end:expr, $t:ty) => ({
+        (0 .. $end - $start + 1).rev().fold(0, |acc, i| acc | $src[$start+i] as $t << i * 8)
+    })
+}
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum CoAPOption {
+    IfMatch,
+    UriHost,
+    ETag,
+    IfNoneMatch,
+    Observe,
+    UriPort,
+    LocationPath,
+    UriPath,
+    ContentFormat,
+    MaxAge,
+    UriQuery,
+    Accept,
+    LocationQuery,
+    Block2,
+    Block1,
+    ProxyUri,
+    ProxyScheme,
+    Size1,
+}
+
+enum_from_primitive! {
+#[derive(PartialEq, Eq, Debug)]
+pub enum ContentFormat {
+    TextPlain = 0,
+    ApplicationLinkFormat = 40,
+    ApplicationXML = 41,
+    ApplicationOctetStream = 42,
+    ApplicationEXI = 47,
+    ApplicationJSON = 50,
+}
+}
+
+#[derive(Debug)]
+pub enum PackageError {
+    InvalidHeader,
+    InvalidPacketLength,
+}
+
+#[derive(Debug)]
+pub enum ParseError {
+    InvalidHeader,
+    InvalidTokenLength,
+    InvalidOptionDelta,
+    InvalidOptionLength,
+}
+
+#[derive(Debug)]
+pub struct Packet {
+    pub header: header::Header,
+    token: Vec<u8>,
+    options: BTreeMap<usize, LinkedList<Vec<u8>>>,
+    pub payload: Vec<u8>,
+}
+
+impl Packet {
+    pub fn new() -> Packet {
+        Packet {
+            header: header::Header::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: CoAPOption, value: LinkedList<Vec<u8>>) {
+        let num = Self::get_option_number(tp);
+        self.options.insert(num, value);
+    }
+
+    pub fn set_content_format(&mut self, cf: ContentFormat) {
+        let content_format = cf as u16;
+        let msb = (content_format >> 8) as u8;
+        let lsb = (content_format & 0xFF) as u8;
+
+        let content_format: Vec<u8> = vec![msb, lsb];
+        self.add_option(CoAPOption::ContentFormat, content_format);
+    }
+
+    pub fn set_payload(&mut self, payload: Vec<u8>) {
+        self.payload = payload;
+    }
+
+    pub fn add_option(&mut self, tp: CoAPOption, 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: CoAPOption) -> Option<LinkedList<Vec<u8>>> {
+        let num = Self::get_option_number(tp);
+        match self.options.get(&num) {
+            Some(options) => Some(options.clone()),
+            None => None,
+        }
+    }
+
+    pub fn get_content_format(&self) -> Option<ContentFormat> {
+        if let Some(list) = self.get_option(CoAPOption::ContentFormat) {
+            if let Some(vector) = list.front() {
+                let msb = vector[0] as u16;
+                let lsb = vector[1] as u16;
+                let number = (msb << 8) + lsb;
+
+                return ContentFormat::from_u16(number);
+            }
+        }
+
+        None
+    }
+
+    /// Decodes a byte slice and construct the equivalent Packet.
+    pub fn from_bytes(buf: &[u8]) -> Result<Packet, ParseError> {
+        let header_result: bincode::DecodingResult<header::HeaderRaw> = bincode::decode(buf);
+        match header_result {
+            Ok(raw_header) => {
+                let header = header::Header::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 != header::MessageClass::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 != header::MessageClass::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: CoAPOption) -> usize {
+        match tp {
+            CoAPOption::IfMatch => 1,
+            CoAPOption::UriHost => 3,
+            CoAPOption::ETag => 4,
+            CoAPOption::IfNoneMatch => 5,
+            CoAPOption::Observe => 6,
+            CoAPOption::UriPort => 7,
+            CoAPOption::LocationPath => 8,
+            CoAPOption::UriPath => 11,
+            CoAPOption::ContentFormat => 12,
+            CoAPOption::MaxAge => 14,
+            CoAPOption::UriQuery => 15,
+            CoAPOption::Accept => 17,
+            CoAPOption::LocationQuery => 20,
+            CoAPOption::Block2 => 23,
+            CoAPOption::Block1 => 27,
+            CoAPOption::ProxyUri => 35,
+            CoAPOption::ProxyScheme => 39,
+            CoAPOption::Size1 => 60,
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use super::super::header;
+    use std::collections::LinkedList;
+
+    #[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(), header::MessageType::Confirmable);
+        assert_eq!(packet.header.get_token_length(), 4);
+        assert_eq!(
+            packet.header.code,
+            header::MessageClass::RequestType(header::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(CoAPOption::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(CoAPOption::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(),
+            header::MessageType::Acknowledgement
+        );
+        assert_eq!(packet.header.get_token_length(), 4);
+        assert_eq!(
+            packet.header.code,
+            header::MessageClass::ResponseType(header::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(header::MessageType::Confirmable);
+        packet.header.code = header::MessageClass::RequestType(header::Requests::Get);
+        packet.header.set_message_id(33950);
+        packet.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
+        packet.add_option(CoAPOption::UriPath, b"Hi".to_vec());
+        packet.add_option(CoAPOption::UriPath, b"Test".to_vec());
+        packet.add_option(CoAPOption::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(header::MessageType::Acknowledgement);
+        packet.header.code = header::MessageClass::ResponseType(header::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_encode_decode_content_format() {
+        let mut packet = Packet::new();
+        packet.set_content_format(ContentFormat::ApplicationJSON);
+        assert_eq!(
+            ContentFormat::ApplicationJSON,
+            packet.get_content_format().unwrap()
+        )
+    }
+
+    #[test]
+    fn test_decode_empty_content_format() {
+        let packet = Packet::new();
+        assert!(packet.get_content_format().is_none());
+    }
+
+    #[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/utils/xoap/src/message/request.rs b/utils/xoap/src/message/request.rs
new file mode 100644
index 0000000..8ccff79
--- /dev/null
+++ b/utils/xoap/src/message/request.rs
@@ -0,0 +1,87 @@
+use message::IsMessage;
+use message::response::CoAPResponse;
+use message::packet::Packet;
+use message::header::Header;
+//use std::net::SocketAddr;
+
+#[derive(Debug)]
+pub struct CoAPRequest {
+    pub message: Packet,
+    pub response: Option<CoAPResponse>,
+    pub source: Option<SocketAddr>,
+}
+
+impl CoAPRequest {
+    pub fn new() -> CoAPRequest {
+        CoAPRequest {
+            response: None,
+            message: Packet::new(),
+            source: None,
+        }
+    }
+
+    pub fn from_packet(packet: Packet, source: &SocketAddr) -> CoAPRequest {
+        CoAPRequest {
+            response: CoAPResponse::new(&packet),
+            message: packet,
+            source: Some(source.clone()),
+        }
+    }
+}
+
+impl IsMessage for CoAPRequest {
+    fn get_message(&self) -> &Packet {
+        &self.message
+    }
+    fn get_mut_message(&mut self) -> &mut Packet {
+        &mut self.message
+    }
+    fn get_header(&self) -> &Header {
+        &self.message.header
+    }
+    fn get_mut_header(&mut self) -> &mut Header {
+        &mut self.message.header
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use message::packet::{Packet, CoAPOption};
+    use message::header::MessageType;
+    use message::IsMessage;
+    use std::net::SocketAddr;
+    use std::str::FromStr;
+
+    #[test]
+    fn test_request_create() {
+
+        let mut packet = Packet::new();
+        let mut request1 = CoAPRequest::new();
+
+        packet.set_token(vec![0x17, 0x38]);
+        request1.set_token(vec![0x17, 0x38]);
+
+        packet.add_option(CoAPOption::UriPath, b"test-interface".to_vec());
+        request1.add_option(CoAPOption::UriPath, b"test-interface".to_vec());
+
+        packet.header.set_message_id(42);
+        request1.set_message_id(42);
+
+        packet.header.set_version(2);
+        request1.set_version(2);
+
+        packet.header.set_type(MessageType::Confirmable);
+        request1.set_type(MessageType::Confirmable);
+
+        packet.header.set_code("0.04");
+        request1.set_code("0.04");
+
+        let request2 = CoAPRequest::from_packet(packet,
+                                                &SocketAddr::from_str("127.0.0.1:1234").unwrap());
+
+        assert_eq!(request1.message.to_bytes().unwrap(),
+                   request2.message.to_bytes().unwrap());
+
+    }
+}
\ No newline at end of file
-- 
GitLab