Skip to content
Snippets Groups Projects
Commit a021c24d authored by Joakim Lundberg's avatar Joakim Lundberg
Browse files

Test of Cargo build system

parent a4a05fca
No related branches found
No related tags found
No related merge requests found
[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"
# 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
```
[dependencies.core]
stage = 0
[dependencies.alloc]
stage = 0
[dependencies.compiler_builtins]
stage = 1
//! 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;
#[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));
}
This diff is collapsed.
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment