Delete old CoAP implementation

It seems that this implementation of CoAP in Contiki is no longer
maintained in favor of the `er-coap` implementation. This commit
removes the code to prevent confusion and further bit-rot.
This commit is contained in:
Brad Campbell 2014-12-21 01:16:14 -05:00
parent c9324d133f
commit 6eaada0c3f
28 changed files with 0 additions and 3497 deletions

View File

@ -1,4 +0,0 @@
rest-coap_src = coap-common.c coap-server.c
APPS += rest-common
include $(CONTIKI)/apps/rest-common/Makefile.rest-common

View File

@ -1,113 +0,0 @@
/*
* coap-common.c
*
* Created on: Aug 30, 2010
* Author: dogan
*/
#ifdef CONTIKI_TARGET_NETSIM
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#else
#include "contiki.h"
#include "contiki-net.h"
#include <string.h>
#endif
#include "coap-common.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
void init_packet(coap_packet_t* packet)
{
packet->ver = 1;
packet->type = 0;
packet->option_count = 0;
packet->code = 0;
packet->tid = 0;
packet->options = NULL;
packet->url = NULL;
packet->url_len = 0;
packet->query = NULL;
packet->query_len = 0;
packet->payload = NULL;
packet->payload_len = 0;
}
int serialize_packet(coap_packet_t* packet, uint8_t* buffer)
{
int index = 0;
header_option_t* option = NULL;
uint16_t option_delta = 0;
buffer[0] = (packet->ver) << COAP_HEADER_VERSION_POSITION;
buffer[0] |= (packet->type) << COAP_HEADER_TYPE_POSITION;
buffer[0] |= packet->option_count;
buffer[1] = packet->code;
uint16_t temp = uip_htons(packet->tid);
memcpy(
(void*)&buffer[2],
(void*)(&temp),
sizeof(packet->tid));
index += 4;
PRINTF("serialize option_count %u\n", packet->option_count);
/*Options should be sorted beforehand*/
for (option = packet->options ; option ; option = option->next){
uint16_t delta = option->option - option_delta;
if ( !delta ){
PRINTF("WARNING: Delta==Zero\n");
}
buffer[index] = (delta) << COAP_HEADER_OPTION_DELTA_POSITION;
PRINTF("option %u len %u option diff %u option_value addr %x option addr %x next option addr %x", option->option, option->len, option->option - option_delta, (unsigned int) option->value, (unsigned int)option, (unsigned int)option->next);
int i = 0;
for ( ; i < option->len ; i++ ){
PRINTF(" (%u)", option->value[i]);
}
PRINTF("\n");
if (option->len < 0xF){
buffer[index] |= option->len;
index++;
} else{
buffer[index] |= (0xF); //1111
buffer[index + 1] = option->len - (0xF);
index += 2;
}
memcpy((char*)&buffer[index], option->value, option->len);
index += option->len;
option_delta = option->option;
}
if(packet->payload){
memcpy(&buffer[index], packet->payload, packet->payload_len);
index += packet->payload_len;
}
return index;
}

View File

@ -1,144 +0,0 @@
/*
* coap.h
*
* Created on: Aug 25, 2010
* Author: dogan
*/
#ifndef COAP_COMMON_H_
#define COAP_COMMON_H_
#include "contiki-net.h"
/*COAP method types*/
typedef enum {
COAP_GET = 1,
COAP_POST,
COAP_PUT,
COAP_DELETE
} coap_method_t;
typedef enum {
MESSAGE_TYPE_CON,
MESSAGE_TYPE_NON,
MESSAGE_TYPE_ACK,
MESSAGE_TYPE_RST
} message_type;
typedef enum {
OK_200 = 80,
CREATED_201 = 81,
NOT_MODIFIED_304 = 124,
BAD_REQUEST_400 = 160,
NOT_FOUND_404 = 164,
METHOD_NOT_ALLOWED_405 = 165,
UNSUPPORTED_MADIA_TYPE_415 = 175,
INTERNAL_SERVER_ERROR_500 = 200,
BAD_GATEWAY_502 = 202,
GATEWAY_TIMEOUT_504 = 204
} status_code_t;
typedef enum {
Option_Type_Content_Type = 1,
Option_Type_Max_Age = 2,
Option_Type_Etag = 4,
Option_Type_Uri_Authority = 5,
Option_Type_Location = 6,
Option_Type_Uri_Path = 9,
Option_Type_Subscription_Lifetime = 10,
Option_Type_Token = 11,
Option_Type_Block = 13,
Option_Type_Uri_Query = 15
} option_type;
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1,
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40,
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_X_BXML = 48,
APPLICATION_FASTINFOSET = 49,
APPLICATION_SOAP_FASTINFOSET = 50,
APPLICATION_JSON = 51
} content_type_t;
#define COAP_HEADER_VERSION_MASK 0xC0
#define COAP_HEADER_TYPE_MASK 0x30
#define COAP_HEADER_OPTION_COUNT_MASK 0x0F
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F
#define COAP_HEADER_VERSION_POSITION 6
#define COAP_HEADER_TYPE_POSITION 4
#define COAP_HEADER_OPTION_DELTA_POSITION 4
#define REQUEST_BUFFER_SIZE 200
#define DEFAULT_CONTENT_TYPE 0
#define DEFAULT_MAX_AGE 60
#define DEFAULT_URI_AUTHORITY ""
#define DEFAULT_URI_PATH ""
//keep open requests and their xactid
struct header_option_t
{
struct header_option_t* next;
uint16_t option;
uint16_t len;
uint8_t* value;
};
typedef struct header_option_t header_option_t;
struct block_option_t {
uint32_t number;
uint8_t more;
uint8_t size;
};
typedef struct block_option_t block_option_t;
typedef struct
{
uint8_t ver; //2-bits currently set to 1.
uint8_t type; //2-bits Confirmable (0), Non-Confirmable (1), Acknowledgment (2) or Reset (3)
uint8_t option_count; //4-bits
uint8_t code; //8-bits Method or response code
uint16_t tid; //16-bit unsigned integer
header_option_t* options;
char* url; //put it just as a shortcut or else need to parse options everytime to access it.
uint16_t url_len;
char* query;
uint16_t query_len;
uint16_t payload_len;
uint8_t* payload;
uip_ipaddr_t addr;
} coap_packet_t;
/*error definitions*/
typedef enum
{
NO_ERROR,
/*Memory errors*/
MEMORY_ALLOC_ERR,
MEMORY_BOUNDARY_EXCEEDED
} error_t;
int serialize_packet(coap_packet_t* request, uint8_t* buffer);
void init_packet(coap_packet_t* packet);
#endif /* COAP_COMMON_H_ */

View File

@ -1,545 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /*for isxdigit*/
#include "contiki.h"
#include "contiki-net.h"
#include "buffer.h"
#include "coap-server.h"
#include "rest-util.h"
#include "rest.h" /*added for periodic_resource*/
#include "dev/leds.h"
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
#include "static-routing.h"
#endif
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#define MAX_PAYLOAD_LEN 120
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
static struct uip_udp_conn *server_conn;
static uint16_t current_tid;
static service_callback service_cbk = NULL;
void
coap_set_service_callback(service_callback callback)
{
service_cbk = callback;
}
void
parse_message(coap_packet_t* packet, uint8_t* buf, uint16_t size)
{
int processed = 0;
int i = 0;
PRINTF("parse_message size %d-->\n",size);
init_packet(packet);
packet->ver = (buf[0] & COAP_HEADER_VERSION_MASK) >> COAP_HEADER_VERSION_POSITION;
packet->type = (buf[0] & COAP_HEADER_TYPE_MASK) >> COAP_HEADER_TYPE_POSITION;
packet->option_count = buf[0] & COAP_HEADER_OPTION_COUNT_MASK;
packet->code = buf[1];
packet->tid = (buf[2] << 8) + buf[3];
processed += 4;
if (packet->option_count) {
int option_index = 0;
uint8_t option_delta;
uint16_t option_len;
uint8_t* option_buf = buf + processed;
packet->options = (header_option_t*)allocate_buffer(sizeof(header_option_t) * packet->option_count);
if (packet->options) {
header_option_t* current_option = packet->options;
header_option_t* prev_option = NULL;
while(option_index < packet->option_count) {
/*FIXME : put boundary controls*/
option_delta = (option_buf[i] & COAP_HEADER_OPTION_DELTA_MASK) >> COAP_HEADER_OPTION_DELTA_POSITION;
option_len = (option_buf[i] & COAP_HEADER_OPTION_SHORT_LENGTH_MASK);
i++;
if (option_len == 0xf) {
option_len += option_buf[i];
i++;
}
current_option->option = option_delta;
current_option->len = option_len;
current_option->value = option_buf + i;
if (option_index) {
prev_option->next = current_option;
/*This field defines the difference between the option Type of
* this option and the previous option (or zero for the first option)*/
current_option->option += prev_option->option;
}
if (current_option->option == Option_Type_Uri_Path) {
packet->url = (char*)current_option->value;
packet->url_len = current_option->len;
} else if (current_option->option == Option_Type_Uri_Query){
packet->query = (char*)current_option->value;
packet->query_len = current_option->len;
}
PRINTF("OPTION %d %u %s \n", current_option->option, current_option->len, current_option->value);
i += option_len;
option_index++;
prev_option = current_option++;
}
current_option->next = NULL;
} else {
PRINTF("MEMORY ERROR\n"); /*FIXME : add control here*/
return;
}
}
processed += i;
/**/
if (processed < size) {
packet->payload = &buf[processed];
packet->payload_len = size - processed;
}
/*FIXME url is not decoded - is necessary?*/
/*If query is not already provided via Uri_Query option then check URL*/
if (packet->url && !packet->query) {
if ((packet->query = strchr(packet->url, '?'))) {
uint16_t total_url_len = packet->url_len;
/*set query len and update url len so that it does not include query part now*/
packet->url_len = packet->query - packet->url;
packet->query++;
packet->query_len = packet->url + total_url_len - packet->query;
PRINTF("url %s, url_len %u, query %s, query_len %u\n", packet->url, packet->url_len, packet->query, packet->query_len);
}
}
PRINTF("PACKET ver:%d type:%d oc:%d \ncode:%d tid:%u url:%s len:%u payload:%s pay_len %u\n", (int)packet->ver, (int)packet->type, (int)packet->option_count, (int)packet->code, packet->tid, packet->url, packet->url_len, packet->payload, packet->payload_len);
}
int
coap_get_query_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size)
{
if (packet->query) {
return get_variable(name, packet->query, packet->query_len, output, output_size, 0);
}
return 0;
}
int
coap_get_post_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size)
{
if (packet->payload) {
return get_variable(name, packet->payload, packet->payload_len, output, output_size, 1);
}
return 0;
}
static header_option_t*
allocate_header_option(uint16_t variable_len)
{
PRINTF("sizeof header_option_t %u variable size %u\n", sizeof(header_option_t), variable_len);
uint8_t* buffer = allocate_buffer(sizeof(header_option_t) + variable_len);
if (buffer){
header_option_t* option = (header_option_t*) buffer;
option->next = NULL;
option->len = 0;
option->value = buffer + sizeof(header_option_t);
return option;
}
return NULL;
}
/*FIXME : does not overwrite the same option yet.*/
int
coap_set_option(coap_packet_t* packet, option_type option_type, uint16_t len, uint8_t* value)
{
PRINTF("coap_set_option len %u\n", len);
header_option_t* option = allocate_header_option(len);
if (option){
option->next = NULL;
option->len = len;
option->option = option_type;
memcpy(option->value, value, len);
header_option_t* option_current = packet->options;
header_option_t* prev = NULL;
while (option_current){
if (option_current->option > option->option){
break;
}
prev = option_current;
option_current = option_current->next;
}
if (!prev){
if (option_current){
option->next = option_current;
}
packet->options = option;
} else{
option->next = option_current;
prev->next = option;
}
packet->option_count++;
PRINTF("option->len %u option->option %u option->value %x next %x\n", option->len, option->option, (unsigned int) option->value, (unsigned int)option->next);
int i = 0;
for ( ; i < option->len ; i++ ){
PRINTF(" (%u)", option->value[i]);
}
PRINTF("\n");
return 1;
}
return 0;
}
header_option_t*
coap_get_option(coap_packet_t* packet, option_type option_type)
{
PRINTF("coap_get_option count: %u--> \n", packet->option_count);
int i = 0;
header_option_t* current_option = packet->options;
for (; i < packet->option_count; current_option = current_option->next, i++) {
PRINTF("Current option: %u\n", current_option->option);
if (current_option->option == option_type){
return current_option;
}
}
return NULL;
}
static void
fill_error_packet(coap_packet_t* packet, int error, uint16_t tid)
{
packet->ver=1;
packet->option_count=0;
packet->url=NULL;
packet->options=NULL;
switch (error){
case MEMORY_ALLOC_ERR:
packet->code=INTERNAL_SERVER_ERROR_500;
packet->tid=tid;
packet->type=MESSAGE_TYPE_ACK;
break;
default:
break;
}
}
static void
init_response(coap_packet_t* request, coap_packet_t* response)
{
init_packet(response);
if(request->type == MESSAGE_TYPE_CON) {
response->code = OK_200;
response->tid = request->tid;
response->type = MESSAGE_TYPE_ACK;
}
}
uint16_t
coap_get_payload(coap_packet_t* packet, uint8_t** payload)
{
if (packet->payload) {
*payload = packet->payload;
return packet->payload_len;
} else {
*payload = NULL;
return 0;
}
}
int
coap_set_payload(coap_packet_t* packet, uint8_t* payload, uint16_t size)
{
packet->payload = copy_to_buffer(payload, size);
if (packet->payload) {
packet->payload_len = size;
return 1;
}
return 0;
}
int
coap_set_header_content_type(coap_packet_t* packet, content_type_t content_type)
{
uint16_t len = 1;
return coap_set_option(packet, Option_Type_Content_Type, len, (uint8_t*) &content_type);
}
content_type_t
coap_get_header_content_type(coap_packet_t* packet)
{
header_option_t* option = coap_get_option(packet, Option_Type_Content_Type);
if (option){
return (uint8_t)(*(option->value));
}
return DEFAULT_CONTENT_TYPE;
}
int
coap_get_header_subscription_lifetime(coap_packet_t* packet, uint32_t* lifetime)
{
PRINTF("coap_get_header_subscription_lifetime --> \n");
header_option_t* option = coap_get_option(packet, Option_Type_Subscription_Lifetime);
if (option){
PRINTF("Subs Found len %u (first byte %u)\n", option->len, (uint16_t)option->value[0]);
*lifetime = read_int(option->value, option->len);
return 1;
}
return 0;
}
int
coap_set_header_subscription_lifetime(coap_packet_t* packet, uint32_t lifetime)
{
uint8_t temp[4];
uint16_t len = write_variable_int(temp, lifetime);
return coap_set_option(packet, Option_Type_Subscription_Lifetime, len, temp);
}
int
coap_get_header_block(coap_packet_t* packet, block_option_t* block)
{
uint32_t all_block;
PRINTF("coap_get_header_block --> \n");
header_option_t* option = coap_get_option(packet, Option_Type_Block);
if (option){
PRINTF("Block Found len %u (first byte %u)\n", option->len, (uint16_t)option->value[0]);
all_block = read_int(option->value, option->len);
block->number = all_block >> 4;
block->more = (all_block & 0x8) >> 3;
block->size = (all_block & 0x7);
return 1;
}
return 0;
}
int
coap_set_header_block(coap_packet_t* packet, uint32_t number, uint8_t more, uint8_t size)
{
uint8_t temp[4];
size = log_2(size/16);
number = number << 4;
number |= (more << 3) & 0x8;
number |= size & 0x7;
uint16_t len = write_variable_int(temp, number);
PRINTF("number %lu, more %u, size %u block[0] %u block[1] %u block[2] %u block[3] %u\n",
number, (uint16_t)more, (uint16_t)size, (uint16_t)temp[0], (uint16_t)temp[1], (uint16_t)temp[2], (uint16_t)temp[3]);
return coap_set_option(packet, Option_Type_Block, len, temp);
}
int
coap_set_header_uri(coap_packet_t* packet, char* uri)
{
return coap_set_option(packet, Option_Type_Uri_Path, strlen(uri), (uint8_t*) uri);
}
int
coap_set_header_etag(coap_packet_t* packet, uint8_t* etag, uint8_t size)
{
return coap_set_option(packet, Option_Type_Etag, size, etag);
}
void
coap_set_code(coap_packet_t* packet, status_code_t code)
{
packet->code = (uint8_t)code;
}
coap_method_t
coap_get_method(coap_packet_t* packet)
{
return (coap_method_t)packet->code;
}
void
coap_set_method(coap_packet_t* packet, coap_method_t method)
{
packet->code = (uint8_t)method;
}
static void send_request(coap_packet_t* request, struct uip_udp_conn *client_conn)
{
char buf[MAX_PAYLOAD_LEN];
int data_size = 0;
data_size = serialize_packet(request, buf);
PRINTF("Created a connection with the server ");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n",
uip_htons(client_conn->lport), uip_htons(client_conn->rport));
PRINTF("Sending to: ");
PRINT6ADDR(&client_conn->ripaddr);
uip_udp_packet_send(client_conn, buf, data_size);
}
static int
handle_incoming_data(void)
{
int error=NO_ERROR;
char buf[MAX_PAYLOAD_LEN];
PRINTF("uip_datalen received %u \n",(uint16_t)uip_datalen());
char* data = (char *)uip_appdata + uip_ext_len;
uint16_t datalen = uip_datalen() - uip_ext_len;
int data_size = 0;
if (uip_newdata()) {
((char *)data)[datalen] = 0;
PRINTF("Server received: '%s' (port:%u) from ", (char *)data, uip_htons(UIP_UDP_BUF->srcport));
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
if (init_buffer(COAP_DATA_BUFF_SIZE)) {
coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
parse_message(request, (uint8_t*)data, datalen);
uip_ipaddr_copy(&request->addr, &UIP_IP_BUF->srcipaddr);
if (request->type != MESSAGE_TYPE_ACK) {
coap_packet_t* response = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
init_response(request, response);
if (service_cbk) {
service_cbk(request, response);
}
data_size = serialize_packet(response, buf);
}
delete_buffer();
} else {
PRINTF("Memory Alloc Error\n");
error = MEMORY_ALLOC_ERR;
/*FIXME : Crappy way of accessing TID of the incoming packet, fix it!*/
coap_packet_t error_packet;
fill_error_packet(&error_packet,error, (data[2] << 8) + data[3]);
data_size = serialize_packet(&error_packet, buf);
}
uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr);
server_conn->rport = UIP_UDP_BUF->srcport;
PRINTF("Responding with message size: %d\n",data_size);
uip_udp_packet_send(server_conn, buf, data_size);
/* Restore server connection to allow data from any node */
memset(&server_conn->ripaddr, 0, sizeof(server_conn->ripaddr));
server_conn->rport = 0;
}
return error;
}
process_event_t resource_changed_event;
void
resource_changed(struct periodic_resource_t* resource)
{
process_post(&coap_server, resource_changed_event, (process_data_t)resource);
}
/*---------------------------------------------------------------------------*/
PROCESS(coap_server, "Coap Server");
PROCESS_THREAD(coap_server, ev, data)
{
PROCESS_BEGIN();
PRINTF("COAP SERVER\n");
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
set_global_address();
configure_routing();
#endif
current_tid = random_rand();
resource_changed_event = process_alloc_event();
/* new connection with remote host */
server_conn = udp_new(NULL, uip_htons(0), NULL);
udp_bind(server_conn, uip_htons(MOTE_SERVER_LISTEN_PORT));
PRINTF("Local/remote port %u/%u\n", uip_htons(server_conn->lport), uip_htons(server_conn->rport));
while(1) {
PROCESS_YIELD();
if(ev == tcpip_event) {
handle_incoming_data();
} else if (ev == resource_changed_event) {
periodic_resource_t* resource = (periodic_resource_t*)data;
PRINTF("resource_changed_event \n");
if (init_buffer(COAP_DATA_BUFF_SIZE)) {
coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
init_packet(request);
coap_set_code(request, COAP_GET);
request->tid = current_tid++;
coap_set_header_subscription_lifetime(request, resource->lifetime);
coap_set_header_uri(request, (char *)resource->resource->url);
if (resource->periodic_request_generator) {
resource->periodic_request_generator(request);
}
if (!resource->client_conn) {
/*FIXME send port is fixed for now to 61616*/
resource->client_conn = udp_new(&resource->addr, uip_htons(61616), NULL);
udp_bind(resource->client_conn, uip_htons(MOTE_CLIENT_LISTEN_PORT));
}
if (resource->client_conn) {
send_request(request, resource->client_conn);
}
delete_buffer();
}
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -1,54 +0,0 @@
#ifndef COAPSERVER_H_
#define COAPSERVER_H_
#define COAP_DATA_BUFF_SIZE 300
#include "contiki.h"
#include "coap-common.h"
/*Declare process*/
PROCESS_NAME(coap_server);
#define MOTE_SERVER_LISTEN_PORT 61616
#define MOTE_CLIENT_LISTEN_PORT 61617
void parse_message(coap_packet_t* packet, uint8_t* buf, uint16_t size);
uint16_t coap_get_payload(coap_packet_t* packet, uint8_t** payload);
int coap_set_payload(coap_packet_t* packet, uint8_t* payload, uint16_t size);
content_type_t coap_get_header_content_type(coap_packet_t* packet);
int coap_set_header_content_type(coap_packet_t* packet, content_type_t content_type);
int coap_get_header_subscription_lifetime(coap_packet_t* packet, uint32_t* lifetime);
int coap_set_header_subscription_lifetime(coap_packet_t* packet, uint32_t lifetime);
int coap_get_header_block(coap_packet_t* packet, block_option_t* block);
int coap_set_header_block(coap_packet_t* packet, uint32_t number, uint8_t more, uint8_t size);
int coap_set_header_uri(coap_packet_t* packet, char* uri);
int coap_set_header_etag(coap_packet_t* packet, uint8_t* etag, uint8_t size);
void coap_set_code(coap_packet_t* packet, status_code_t code);
coap_method_t coap_get_method(coap_packet_t* packet);
void coap_set_method(coap_packet_t* packet, coap_method_t method);
int coap_get_query_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size);
int coap_get_post_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size);
header_option_t* coap_get_option(coap_packet_t* packet, option_type option_type);
int coap_set_option(coap_packet_t* packet, option_type option_type, uint16_t len, uint8_t* value);
/*Type definition of the service callback*/
typedef int (*service_callback) (coap_packet_t* request, coap_packet_t* response);
/*
*Setter of the service callback, this callback will be called in case of HTTP request.
*/
void coap_set_service_callback(service_callback callback);
struct periodic_resource_t;
void resource_changed(struct periodic_resource_t* resource);
#endif /* COAPSERVER_H_ */

View File

@ -1 +0,0 @@
rest-common_src = rest.c rest-util.c buffer.c static-routing.c

View File

@ -1,79 +0,0 @@
/*
* buffer.c
*
* Created on: Oct 19, 2010
* Author: dogan
*/
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "buffer.h"
uint8_t* data_buffer;
uint16_t buffer_size;
uint16_t buffer_index;
void
delete_buffer(void)
{
if (data_buffer) {
free(data_buffer);
data_buffer = NULL;
buffer_index = 0;
buffer_size = 0;
}
}
uint8_t*
init_buffer(uint16_t size)
{
delete_buffer();
data_buffer = (uint8_t*)malloc(size);
if (data_buffer) {
buffer_size = size;
}
buffer_index = 0;
return data_buffer;
}
uint8_t*
allocate_buffer(uint16_t size)
{
uint8_t* buffer = NULL;
int rem = 0;
/*To get rid of alignment problems, always allocate even size*/
rem = size % 4;
if (rem) {
size+=(4-rem);
}
if (buffer_index + size < buffer_size) {
buffer = data_buffer + buffer_index;
buffer_index += size;
}
return buffer;
}
uint8_t*
copy_to_buffer(void* data, uint16_t len)
{
uint8_t* buffer = allocate_buffer(len);
if (buffer) {
memcpy(buffer, data, len);
}
return buffer;
}
uint8_t*
copy_text_to_buffer(char* text)
{
uint8_t* buffer = allocate_buffer(strlen(text) + 1);
if (buffer) {
strcpy(buffer, text);
}
return buffer;
}

View File

@ -1,17 +0,0 @@
/*
* buffer.h
*
* Created on: Oct 19, 2010
* Author: dogan
*/
#ifndef BUFFER_H_
#define BUFFER_H_
void delete_buffer(void);
uint8_t* init_buffer(uint16_t size);
uint8_t* allocate_buffer(uint16_t size);
uint8_t* copy_to_buffer(void* data, uint16_t len);
uint8_t* copy_text_to_buffer(char* text);
#endif /* BUFFER_H_ */

View File

@ -1,118 +0,0 @@
#include <stddef.h> /*for size_t*/
#include <ctype.h> /*for isxdigit*/
#include <string.h>
#include "contiki-net.h"
/*Copied from mangoose http server*/
size_t
decode(const char *src, size_t srclen, char *dst, size_t dstlen, int is_form)
{
size_t i, j;
int a, b;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
for (i = j = 0; i < srclen && j < dstlen - 1; i++, j++) {
if (src[i] == '%' &&
isxdigit(* (unsigned char *) (src + i + 1)) &&
isxdigit(* (unsigned char *) (src + i + 2))) {
a = tolower(* (unsigned char *) (src + i + 1));
b = tolower(* (unsigned char *) (src + i + 2));
dst[j] = ((HEXTOI(a) << 4) | HEXTOI(b)) & 0xff;
i += 2;
} else if (is_form && src[i] == '+') {
dst[j] = ' ';
} else {
dst[j] = src[i];
}
}
dst[j] = '\0'; /* Null-terminate the destination */
return ( i == srclen );
}
/*Copied from mangoose http server*/
int
get_variable(const char *name, const char *buffer, size_t buflen, char* output, size_t output_len, int decode_type)
{
const char *start = NULL, *end = NULL, *end_of_value;
size_t var_len = 0;
/*initialize the output buffer first*/
*output = 0;
var_len = strlen(name);
end = buffer + buflen;
for (start = buffer; start + var_len < end; start++){
if ((start == buffer || start[-1] == '&') && start[var_len] == '=' &&
! strncmp(name, start, var_len)) {
/* Point p to variable value */
start += var_len + 1;
/* Point s to the end of the value */
end_of_value = (const char *) memchr(start, '&', end - start);
if (end_of_value == NULL) {
end_of_value = end;
}
return decode(start, end_of_value - start, output, output_len, decode_type);
}
}
return 0;
}
uint32_t
read_int(uint8_t *buf, uint8_t size)
{
uint32_t data = 0;
if (size >= 1 && size <= 4) {
uint8_t *p = (uint8_t *)&data;
memcpy(p + 4 - size, buf, size);
}
return uip_ntohl(data);
}
int
write_int(uint8_t *buf, uint32_t data, uint8_t size)
{
int success = 0;
if (size >= 1 && size <= 4) {
data = uip_htonl(data);
memcpy(buf, ((char*)(&data)) + 4 - size, size);
success = size;
}
return success;
}
int
write_variable_int(uint8_t *buf, uint32_t data)
{
uint8_t size = 4;
if (data <= 0xFF) {
size = 1;
} else if (data <= 0xFFFF) {
size = 2;
} else if (data <= 0xFFFFFF) {
size = 3;
}
return write_int(buf, data, size);
}
uint16_t log_2(uint16_t value)
{
uint16_t result = 0;
do {
value = value >> 1;
result++;
} while (value);
return result ? result - 1 : result;
}

View File

@ -1,20 +0,0 @@
/*
* rest-util.h
*
* Created on: Oct 26, 2010
* Author: dogan
*/
#ifndef RESTUTIL_H_
#define RESTUTIL_H_
size_t decode(const char *src, size_t srclen, char *dst, size_t dstlen, int is_form);
int get_variable(const char *name, const char *buffer, size_t buflen, char* output, size_t output_len, int decode_type);
uint32_t read_int(uint8_t *buf, uint8_t size);
int write_int(uint8_t *buf, uint32_t data, uint8_t size);
int write_variable_int(uint8_t *buf, uint32_t data);
uint16_t log_2(uint16_t value);
#endif /* RESTUTIL_H_ */

View File

@ -1,333 +0,0 @@
#include "contiki.h"
#include <string.h> /*for string operations in match_addresses*/
#include "rest.h"
#include "buffer.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
/*FIXME it is possible to define some of the rest functions as MACROs rather than functions full of ifdefs.*/
PROCESS_NAME(rest_manager_process);
LIST(restful_services);
LIST(restful_periodic_services);
void
rest_init(void)
{
list_init(restful_services);
#ifdef WITH_COAP
coap_set_service_callback(rest_invoke_restful_service);
#else /*WITH_COAP*/
http_set_service_callback(rest_invoke_restful_service);
#endif /*WITH_COAP*/
/*Start rest framework process*/
process_start(&rest_manager_process, NULL);
}
void
rest_activate_resource(resource_t* resource)
{
/*add it to the restful web service link list*/
list_add(restful_services, resource);
}
void
rest_activate_periodic_resource(periodic_resource_t* periodic_resource)
{
list_add(restful_periodic_services, periodic_resource);
rest_activate_resource(periodic_resource->resource);
}
void
rest_set_user_data(resource_t* resource, void* user_data)
{
resource->user_data = user_data;
}
void*
rest_get_user_data(resource_t* resource)
{
return resource->user_data;
}
void
rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler)
{
resource->pre_handler = pre_handler;
}
void
rest_set_post_handler(resource_t* resource, restful_post_handler post_handler)
{
resource->post_handler = post_handler;
}
list_t
rest_get_resources(void)
{
return restful_services;
}
void
rest_set_response_status(RESPONSE* response, status_code_t status)
{
#ifdef WITH_COAP
coap_set_code(response, status);
#else /*WITH_COAP*/
http_set_status(response, status);
#endif /*WITH_COAP*/
}
#ifdef WITH_COAP
static method_t coap_to_rest_method(coap_method_t method)
{
return (method_t)(1 << (method - 1));
}
static coap_method_t rest_to_coap_method(method_t method)
{
coap_method_t coap_method = COAP_GET;
switch (method) {
case METHOD_GET:
coap_method = COAP_GET;
break;
case METHOD_POST:
coap_method = COAP_POST;
break;
case METHOD_PUT:
coap_method = COAP_PUT;
break;
case METHOD_DELETE:
coap_method = COAP_DELETE;
break;
default:
break;
}
return coap_method;
}
#endif /*WITH_COAP*/
method_t
rest_get_method_type(REQUEST* request)
{
#ifdef WITH_COAP
return coap_to_rest_method(coap_get_method(request));
#else
return (method_t)(request->request_type);
#endif
}
/*Only defined for COAP for now.*/
#ifdef WITH_COAP
void
rest_set_method_type(REQUEST* request, method_t method)
{
coap_set_method(request, rest_to_coap_method(method));
}
#endif /*WITH_COAP*/
void
rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size)
{
#ifdef WITH_COAP
coap_set_payload(response, payload, size);
#else
http_set_res_payload(response, payload, size);
#endif /*WITH_COAP*/
}
/*Only defined for COAP for now.*/
#ifdef WITH_COAP
void
rest_set_request_payload(REQUEST* request, uint8_t* payload, uint16_t size)
{
coap_set_payload(request, payload, size);
}
#endif /*WITH_COAP*/
int
rest_get_query_variable(REQUEST* request, const char *name, char* output, uint16_t output_size)
{
#ifdef WITH_COAP
return coap_get_query_variable(request, name, output, output_size);
#else
return http_get_query_variable(request, name, output, output_size);
#endif /*WITH_COAP*/
}
int
rest_get_post_variable(REQUEST* request, const char *name, char* output, uint16_t output_size)
{
#ifdef WITH_COAP
return coap_get_post_variable(request, name, output, output_size);
#else
return http_get_post_variable(request, name, output, output_size);
#endif /*WITH_COAP*/
}
content_type_t
rest_get_header_content_type(REQUEST* request)
{
#ifdef WITH_COAP
return coap_get_header_content_type(request);
#else
return http_get_header_content_type(request);
#endif /*WITH_COAP*/
}
int
rest_set_header_content_type(RESPONSE* response, content_type_t content_type)
{
#ifdef WITH_COAP
return coap_set_header_content_type(response, content_type);
#else
return http_set_res_header(response, HTTP_HEADER_NAME_CONTENT_TYPE, http_get_content_type_string(content_type), 1);
#endif /*WITH_COAP*/
}
int
rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size)
{
#ifdef WITH_COAP
return coap_set_header_etag(response, etag, size);
#else
/*FIXME for now etag should be a "/0" ending string for http part*/
char temp_etag[10];
memcpy(temp_etag, etag, size);
temp_etag[size] = 0;
return http_set_res_header(response, HTTP_HEADER_NAME_ETAG, temp_etag, 1);
#endif /*WITH_COAP*/
}
int
rest_invoke_restful_service(REQUEST* request, RESPONSE* response)
{
int found = 0;
const char* url = request->url;
uint16_t url_len = request->url_len;
PRINTF("rest_invoke_restful_service url %s url_len %d -->\n", url, url_len);
resource_t* resource = NULL;
for (resource = (resource_t*)list_head(restful_services); resource; resource = resource->next) {
/*if the web service handles that kind of requests and urls matches*/
if (url && strlen(resource->url) == url_len && strncmp(resource->url, url, url_len) == 0){
found = 1;
method_t method = rest_get_method_type(request);
PRINTF("method %u, resource->methods_to_handle %u\n", (uint16_t)method, resource->methods_to_handle);
if (resource->methods_to_handle & method) {
/*FIXME Need to move somewhere else*/
#ifdef WITH_COAP
uint32_t lifetime = 0;
if (coap_get_header_subscription_lifetime(request, &lifetime)) {
PRINTF("Lifetime %lu\n", lifetime);
periodic_resource_t* periodic_resource = NULL;
for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services);
periodic_resource;
periodic_resource = periodic_resource->next) {
if (periodic_resource->resource == resource) {
PRINTF("Periodic Resource Found\n");
PRINT6ADDR(&request->addr);
periodic_resource->lifetime = lifetime;
stimer_set(periodic_resource->lifetime_timer, lifetime);
uip_ipaddr_copy(&periodic_resource->addr, &request->addr);
}
}
}
#endif /*WITH_COAP*/
/*call pre handler if it exists*/
if (!resource->pre_handler || resource->pre_handler(request, response)) {
/* call handler function*/
resource->handler(request, response);
/*call post handler if it exists*/
if (resource->post_handler) {
resource->post_handler(request, response);
}
}
} else {
rest_set_response_status(response, METHOD_NOT_ALLOWED_405);
}
break;
}
}
if (!found) {
rest_set_response_status(response, NOT_FOUND_404);
}
return found;
}
PROCESS(rest_manager_process, "Rest Process");
PROCESS_THREAD(rest_manager_process, ev, data)
{
PROCESS_BEGIN();
/*start the coap or http server*/
process_start(SERVER_PROCESS, NULL);
PROCESS_PAUSE();
/*Periodic resources are only available to COAP implementation*/
#if 0
#ifdef WITH_COAP
periodic_resource_t* periodic_resource = NULL;
for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services); periodic_resource; periodic_resource = periodic_resource->next) {
if (periodic_resource->period) {
PRINTF("Set timer for Res: %s to %lu\n", periodic_resource->resource->url, periodic_resource->period);
etimer_set(periodic_resource->handler_cb_timer, periodic_resource->period);
}
}
while(1) {
PROCESS_WAIT_EVENT();
if (ev == PROCESS_EVENT_TIMER) {
for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services);periodic_resource;periodic_resource = periodic_resource->next) {
if (periodic_resource->period && etimer_expired(periodic_resource->handler_cb_timer)) {
PRINTF("Etimer expired for %s (period:%lu life:%lu)\n", periodic_resource->resource->url, periodic_resource->period, periodic_resource->lifetime);
/*call the periodic handler function if exists*/
if (periodic_resource->periodic_handler) {
if ((periodic_resource->periodic_handler)(periodic_resource->resource)) {
PRINTF("RES CHANGE\n");
if (!stimer_expired(periodic_resource->lifetime_timer)) {
PRINTF("TIMER NOT EXPIRED\n");
resource_changed(periodic_resource);
periodic_resource->lifetime = stimer_remaining(periodic_resource->lifetime_timer);
} else {
periodic_resource->lifetime = 0;
}
}
PRINTF("%s lifetime %lu (%lu) expired %d\n", periodic_resource->resource->url, stimer_remaining(periodic_resource->lifetime_timer), periodic_resource->lifetime, stimer_expired(periodic_resource->lifetime_timer));
}
etimer_reset(periodic_resource->handler_cb_timer);
}
}
}
}
#endif /*WITH_COAP*/
#endif
PROCESS_END();
}

View File

@ -1,179 +0,0 @@
#ifndef REST_H_
#define REST_H_
/*includes*/
#include "contiki.h"
#include "contiki-lib.h"
#ifdef WITH_COAP
#include "coap-common.h"
#include "coap-server.h"
#define REQUEST coap_packet_t
#define RESPONSE coap_packet_t
#define SERVER_PROCESS (&coap_server)
#else /*WITH_COAP*/
/*WITH_HTTP*/
#include "http-common.h"
#include "http-server.h"
#define REQUEST http_request_t
#define RESPONSE http_response_t
#define SERVER_PROCESS (&http_server)
#endif /*WITH_COAP*/
struct resource_t;
/*REST method types*/
typedef enum {
METHOD_GET = (1 << 0),
METHOD_POST = (1 << 1),
METHOD_PUT = (1 << 2),
METHOD_DELETE = (1 << 3)
} method_t;
/*Signature of handler functions*/
typedef void (*restful_handler) (REQUEST* request, RESPONSE* response);
typedef int (*restful_pre_handler) (REQUEST* request, RESPONSE* response);
typedef void (*restful_post_handler) (REQUEST* request, RESPONSE* response);
typedef int (*restful_periodic_handler) (struct resource_t* resource);
typedef void (*restful_periodic_request_generator) (REQUEST* request);
/*
* Data structure representing a resource in REST.
*/
struct resource_t {
struct resource_t *next; /*points to next resource defined*/
method_t methods_to_handle; /*handled HTTP methods*/
const char* url; /*handled URL*/
restful_handler handler; /*handler function*/
restful_pre_handler pre_handler; /*to be called before handler, may perform initializations*/
restful_post_handler post_handler; /*to be called after handler, may perform finalizations (cleanup, etc)*/
void* user_data; /*pointer to user specific data*/
};
typedef struct resource_t resource_t;
struct periodic_resource_t {
struct periodic_resource_t *next;
resource_t *resource;
uint32_t period;
struct etimer* handler_cb_timer;
struct stimer* lifetime_timer;
restful_periodic_handler periodic_handler;
restful_periodic_request_generator periodic_request_generator;
uint32_t lifetime;
uip_ipaddr_t addr;
struct uip_udp_conn *client_conn;
};
typedef struct periodic_resource_t periodic_resource_t;
/*
* Macro to define a Resource
* Resources are statically defined for the sake of efficiency and better memory management.
*/
#define RESOURCE(name, methods_to_handle, url) \
void name##_handler(REQUEST*, RESPONSE*); \
resource_t resource_##name = {NULL, methods_to_handle, url, name##_handler, NULL, NULL, NULL}
/*
* Macro to define a Periodic Resource
*/
#define PERIODIC_RESOURCE(name, methods_to_handle, url, period) \
RESOURCE(name, methods_to_handle, url); \
int name##_periodic_handler(resource_t*); \
void name##_periodic_request_generator(REQUEST*); \
struct etimer handler_cb_timer_##name; \
struct stimer lifetime_timer_##name; \
periodic_resource_t periodic_resource_##name = {NULL, &resource_##name, period, &handler_cb_timer_##name, &lifetime_timer_##name, name##_periodic_handler, name##_periodic_request_generator, 0}
/*
* Initializes REST framework and starts HTTP or COAP process
*/
void rest_init(void);
/*
* Resources wanted to be accessible should be activated with the following code.
*/
void rest_activate_resource(resource_t* resource);
void rest_activate_periodic_resource(periodic_resource_t* periodic_resource);
/*
* To be called by HTTP/COAP server as a callback function when a new service request appears.
* This function dispatches the corresponding RESTful service.
*/
int rest_invoke_restful_service(REQUEST* request, RESPONSE* response);
/*
* Returns the resource list
*/
list_t rest_get_resources(void);
/*
* Returns query variable in the URL.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int rest_get_query_variable(REQUEST* request, const char *name, char* output, uint16_t output_size);
/*
* Returns variable in the Post Data/Payload.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int rest_get_post_variable(REQUEST* request, const char *name, char* output, uint16_t output_size);
method_t rest_get_method_type(REQUEST* request);
void rest_set_method_type(REQUEST* request, method_t method);
/*
* Getter for the request content type
*/
content_type_t rest_get_header_content_type(REQUEST* request);
/*
* Setter for the response content type
*/
int rest_set_header_content_type(RESPONSE* response, content_type_t content_type);
/*
* Setter for the response etag header
*/
int rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size);
/*
* Setter for the status code (200, 201, etc) of the response.
*/
void rest_set_response_status(RESPONSE* response, status_code_t status);
/*
* Setter for the payload of the request and response
*/
void rest_set_request_payload(RESPONSE* response, uint8_t* payload, uint16_t size);
void rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size);
/*
* Getter method for user specific data.
*/
void* rest_get_user_data(resource_t* resource);
/*
* Setter method for user specific data.
*/
void rest_set_user_data(resource_t* resource, void* user_data);
/*
* Sets the pre handler function of the Resource.
* If set, this function will be called just before the original handler function.
* Can be used to setup work before resource handling.
*/
void rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler);
/*
* Sets the post handler function of the Resource.
* If set, this function will be called just after the original handler function.
* Can be used to do cleanup (deallocate memory, etc) after resource handling.
*/
void rest_set_post_handler(resource_t* resource, restful_post_handler post_handler);
#endif /*REST_H_*/

View File

@ -1,71 +0,0 @@
/*
* static-routing.c
*
* Created on: Oct 12, 2010
* Author: dogan
*/
#include "static-routing.h"
#if !defined (CONTIKI_TARGET_MINIMAL_NET) /* Any other targets will be added here (&& ! defined (OTHER))*/
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#if !UIP_CONF_IPV6_RPL
#include "contiki-net.h"
#include "sys/node-id.h"
void set_global_address(void)
{
uip_ipaddr_t ipaddr;
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
}
void configure_routing(void)
{
PRINTF("configure_routing\n");
if (node_id < 10) { /*COOJA*/
/*Go to desktop machine over border router*/
ADD_ROUTE(DESKTOP_MACHINE_ID, COOJA_BORDER_ROUTER_ID);
} else { /*SKY*/
if (node_id < 20) { /*First hops (ids between 10-20)*/
/*Go to desktop machine over border router*/
ADD_ROUTE(DESKTOP_MACHINE_ID, BORDER_ROUTER_ID);
}
switch(node_id) {
case 12:
ADD_ROUTE(22, 22); /*Go to next hop over the local address of next hop*/
break;
case 13:
ADD_ROUTE(23, 23); /*Go to next hop over the local address of next hop*/
break;
case 22:
ADD_ROUTE(0, 12); /*Go to desktop machine over the corresponding first hop*/
break;
case 23:
ADD_ROUTE(0, 13); /*Go to desktop machine over the corresponding first hop*/
break;
default:
break;
}
}
}
#endif /*!UIP_CONF_IPV6_RPL*/
#endif /*CONTIKI_TARGET_MINIMAL_NET*/

View File

@ -1,61 +0,0 @@
/*
* static-routing.h
*
* Created on: Oct 12, 2010
* Author: dogan
*/
#ifndef STATICROUTING_H_
#define STATICROUTING_H_
#if !defined (CONTIKI_TARGET_MINIMAL_NET)
#define NODE_IP(nodeid,type,ipaddr) NODE_##nodeid##_##type(ipaddr)
/*desktop machine*/
#define DESKTOP_MACHINE_ID 0
#define NODE_0_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0x0001)
/*Cooja Nodes*/
#define COOJA_BORDER_ROUTER_ID 1
#define NODE_1_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101)
#define NODE_1_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101)
#define NODE_2_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202)
#define NODE_2_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202)
#define NODE_3_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7403, 0x0003, 0x0303)
#define NODE_3_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7403, 0x0003, 0x0303)
#define NODE_6_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7406, 0x0006, 0x0606)
#define NODE_6_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7406, 0x0006, 0x0606)
/*real nodes*/
#define BORDER_ROUTER_ID 11
#define NODE_11_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xd5f1)
#define NODE_11_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xd5f1)
#define NODE_12_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a)
#define NODE_12_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x1160, 0xf95a)
#define NODE_13_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x3575)
#define NODE_13_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x3575)
#define NODE_22_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6)
#define NODE_22_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x116e, 0xc0f6)
#define NODE_23_GLOBAL(ipaddr) uip_ip6addr(ipaddr, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x0d5a)
#define NODE_23_LOCAL(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7400, 0x117d, 0x0d5a)
#define ADD_ROUTE(node_global,node_local)\
do{\
uip_ipaddr_t ipaddr_local, ipaddr_global;\
NODE_IP(node_global, GLOBAL, &ipaddr_global);\
NODE_IP(node_local, LOCAL, &ipaddr_local);\
uip_ds6_route_add(&ipaddr_global, 128, &ipaddr_local);\
}while(0)
void set_global_address(void);
void configure_routing(void);
#endif /*CONTIKI_TARGET_MINIMAL_NET*/
#endif /* STATICROUTING_H_ */

View File

@ -1,4 +0,0 @@
rest-http_src = http-common.c http-server.c
APPS += rest-common
include $(CONTIKI)/apps/rest-common/Makefile.rest-common

View File

@ -1,29 +0,0 @@
#include "http-common.h"
/*needed for web services giving all path (http://172.16.79.0/services/light1)
* instead relative (/services/light1) in HTTP request. Ex: Restlet lib.*/
const char* http_string = "http";
/*HTTP method strings*/
const char* http_get_string = "GET";
const char* http_head_string = "HEAD";
const char* http_post_string = "POST";
const char* http_put_string = "PUT";
const char* http_delete_string = "DELETE";
const char* httpv1_1 = "HTTP/1.1";
const char* line_end = "\r\n";
const char* contiki = "Contiki";
const char* close = "close";
/*header names*/
const char* HTTP_HEADER_NAME_CONTENT_TYPE = "Content-Type";
const char* HTTP_HEADER_NAME_CONTENT_LENGTH = "Content-Length";
const char* HTTP_HEADER_NAME_LOCATION = "Location";
const char* HTTP_HEADER_NAME_CONNECTION = "Connection";
const char* HTTP_HEADER_NAME_SERVER = "Server";
const char* HTTP_HEADER_NAME_HOST = "Host";
const char* HTTP_HEADER_NAME_IF_NONE_MATCH = "If-None-Match";
const char* HTTP_HEADER_NAME_ETAG = "ETag";
const char* header_delimiter = ": ";

View File

@ -1,143 +0,0 @@
#ifndef HTTPCOMMON_H_
#define HTTPCOMMON_H_
/*includes*/
#include "contiki.h"
#include "contiki-net.h"
/*current state of the request, waiting: handling request, output: sending response*/
#define STATE_WAITING 0
#define STATE_OUTPUT 1
/*definitions of the line ending characters*/
#define LINE_FEED_CHAR '\n'
#define CARRIAGE_RETURN_CHAR '\r'
/*needed for web services giving all path (http://172.16.79.0/services/light1)
* instead relative (/services/light1) in HTTP request. Ex: Restlet lib. does it*/
extern const char* http_string;
/*HTTP method strings*/
extern const char* http_get_string;
extern const char* http_head_string;
extern const char* http_post_string;
extern const char* http_put_string;
extern const char* http_delete_string;
extern const char* httpv1_1;
extern const char* line_end;
extern const char* contiki;
extern const char* close;
/*header names*/
extern const char* HTTP_HEADER_NAME_CONTENT_TYPE;
extern const char* HTTP_HEADER_NAME_CONTENT_LENGTH;
extern const char* HTTP_HEADER_NAME_LOCATION;
extern const char* HTTP_HEADER_NAME_CONNECTION;
extern const char* HTTP_HEADER_NAME_SERVER;
extern const char* HTTP_HEADER_NAME_HOST;
extern const char* HTTP_HEADER_NAME_IF_NONE_MATCH;
extern const char* HTTP_HEADER_NAME_ETAG;
extern const char* header_delimiter;
/*Configuration parameters*/
#define HTTP_PORT 8080
#define HTTP_DATA_BUFF_SIZE 600
#define INCOMING_DATA_BUFF_SIZE 102 /*100+2, 100 = max url len, 2 = space char+'\0'*/
/*HTTP method types*/
typedef enum {
HTTP_METHOD_GET = (1 << 0),
HTTP_METHOD_POST = (1 << 1),
HTTP_METHOD_PUT = (1 << 2),
HTTP_METHOD_DELETE = (1 << 3)
} http_method_t;
//DY : FIXME right now same enum names with COAP with different values. Will this work fine?
typedef enum {
OK_200 = 200,
CREATED_201 = 201,
NOT_MODIFIED_304 = 304,
BAD_REQUEST_400 = 400,
NOT_FOUND_404 = 404,
METHOD_NOT_ALLOWED_405 = 405,
REQUEST_URI_TOO_LONG_414 = 414,
UNSUPPORTED_MADIA_TYPE_415 = 415,
INTERNAL_SERVER_ERROR_500 = 500,
BAD_GATEWAY_502 = 502,
SERVICE_UNAVAILABLE_503 = 503,
GATEWAY_TIMEOUT_504 = 504
} status_code_t;
typedef enum {
TEXT_PLAIN,
TEXT_XML,
TEXT_CSV,
TEXT_HTML,
APPLICATION_XML,
APPLICATION_EXI,
APPLICATION_JSON,
APPLICATION_LINK_FORMAT,
APPLICATION_WWW_FORM,
UNKNOWN_CONTENT_TYPE
} content_type_t;
/*Header type*/
struct http_header_t {
struct http_header_t* next;
char* name;
char* value;
};
typedef struct http_header_t http_header_t;
/*This structure contains information about the HTTP request.*/
struct http_request_t {
char* url;
uint16_t url_len;
http_method_t request_type; /* GET, POST, etc */
char* query;
uint16_t query_len;
http_header_t* headers;
uint16_t payload_len;
uint8_t* payload;
};
typedef struct http_request_t http_request_t;
/*This structure contains information about the HTTP response.*/
struct http_response_t {
status_code_t status_code;
char* status_string;
http_header_t* headers;
uint16_t payload_len;
uint8_t* payload;
};
typedef struct http_response_t http_response_t;
/*This structure contains information about the TCP Connection.*/
typedef struct {
struct psock sin, sout; /*Protosockets for incoming and outgoing communication*/
struct pt outputpt;
char inputbuf[INCOMING_DATA_BUFF_SIZE]; /*to put incoming data in*/
uint8_t state;
http_request_t request;
http_response_t response;
} connection_state_t;
/*error definitions*/
typedef enum {
HTTP_NO_ERROR,
/*Memory errors*/
HTTP_MEMORY_ALLOC_ERR,
HTTP_MEMORY_BOUNDARY_EXCEEDED,
/*specific errors*/
HTTP_XML_NOT_VALID,
HTTP_SOAP_MESSAGE_NOT_VALID,
HTTP_URL_TOO_LONG,
HTTP_URL_INVALID
} http_error_t;
#endif /*HTTPCOMMON_H_*/

View File

@ -1,653 +0,0 @@
#include <stdio.h>
#include <stdlib.h> /*for atoi*/
#include <string.h>
#include "contiki.h"
#include "http-server.h"
#include "buffer.h"
#include "rest-util.h"
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
#include "static-routing.h"
#endif
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
static void
init_response(http_response_t* response)
{
response->status_code = OK_200;
response->status_string = NULL;
response->headers = NULL;
response->payload = NULL;
response->payload_len = 0;
}
static void
init_request(http_request_t* request)
{
request->request_type = 0;
request->url = NULL;
request->url_len = 0;
request->query = NULL;
request->query_len = 0;
request->headers = NULL;
request->payload = NULL;
request->payload_len = 0;
}
/**
* Initializes the connection state by clearing out the data structures
*/
static void
init_connection(connection_state_t* conn_state)
{
conn_state->state = STATE_WAITING;
init_request(&conn_state->request);
init_response(&conn_state->response);
}
void
http_set_status(http_response_t* response, status_code_t status)
{
response->status_code = status;
}
static http_header_t*
allocate_header(uint16_t variable_len)
{
PRINTF("sizeof http_header_t %u variable size %u\n", sizeof(http_header_t), variable_len);
uint8_t* buffer = allocate_buffer(sizeof(http_header_t) + variable_len);
if (buffer) {
http_header_t* option = (http_header_t*) buffer;
option->next = NULL;
option->name = NULL;
option->value = buffer + sizeof(http_header_t);
return option;
}
return NULL;
}
int
http_set_res_header(http_response_t* response, const char* name, const char* value, int copy)
{
PRINTF("http_set_res_header (copy:%d) %s:%s\n", copy, name, value);
uint16_t size = 0;
http_header_t* current_header = NULL;
http_header_t* head = NULL;
if (copy) {
size += strlen(value) + 1;
}
current_header = allocate_header(size);
if (current_header) {
current_header->name = (char*)name;
if (copy) {
strcpy(current_header->value, value);
} else {
current_header->value = (char*)value;
}
head = response->headers;
response->headers = current_header;
if (head) {
current_header->next = head;
}
return 1;
}
return 0;
}
static const char* is_request_hdr_needed(const char* header_name)
{
const char* header = NULL;
/*FIXME add needed headers here*/
if (strcmp(header_name, HTTP_HEADER_NAME_CONTENT_LENGTH) == 0) {
header = HTTP_HEADER_NAME_CONTENT_LENGTH;
} else if (strcmp(header_name, HTTP_HEADER_NAME_CONTENT_TYPE) == 0) {
header = HTTP_HEADER_NAME_CONTENT_TYPE;
}
return header;
}
static service_callback service_cbk = NULL;
void
http_set_service_callback(service_callback callback)
{
service_cbk = callback;
}
const char* content_types[] = {
"text/plain",
"text/xml",
"text/csv",
"text/html",
"application/xml",
"application/exi",
"application/json",
"application/link-format",
"application/x-www-form-urlencoded",
};
const char*
http_get_content_type_string(content_type_t content_type)
{
return content_types[content_type];
}
char*
get_default_status_string(status_code_t status_code)
{
char* value = NULL;
switch(status_code) {
case 200:
value = "OK";
break;
case 201:
value = "Created";
break;
case 202:
value = "Accepted";
break;
case 204:
value = "No Content";
break;
case 304:
value = "Not Modified";
break;
case 400:
value = "Bad Request" ;
break;
case 404:
value = "Not Found" ;
break;
case 405:
value = "Method Not Allowed" ;
break;
case 406:
value = "Not Acceptable" ;
break;
case 414:
value = "Request-URI Too Long" ;
break;
case 415:
value = "Unsupported Media Type" ;
break;
case 500:
value = "Internal Server Error" ;
break;
case 501:
value = "Not Implemented" ;
break;
case 503:
value = "Service Unavailable" ;
break;
/*FIXME : will be removed later, put to catch the unhandled statuses.*/
default:
value = "$$BUG$$";
break;
}
return value;
}
int
http_get_query_variable(http_request_t* request, const char *name, char* output, uint16_t output_size)
{
if (request->query) {
return get_variable(name, request->query, request->query_len, output, output_size, 0);
}
return 0;
}
int
http_get_post_variable(http_request_t* request, const char *name, char* output, uint16_t output_size)
{
if (request->payload) {
return get_variable(name, request->payload, request->payload_len, output, output_size, 1);
}
return 0;
}
static int
is_method_handled(connection_state_t* conn_state, const char* method)
{
/*other method types can be added here if needed*/
if(strncmp(method, http_get_string, 3) == 0) {
conn_state->request.request_type = HTTP_METHOD_GET;
} else if (strncmp(method, http_post_string, 4) == 0) {
conn_state->request.request_type = HTTP_METHOD_POST;
} else if (strncmp(method, http_put_string, 3) == 0) {
conn_state->request.request_type = HTTP_METHOD_PUT;
} else if (strncmp(method, http_delete_string, 3) == 0) {
conn_state->request.request_type = HTTP_METHOD_DELETE;
} else {
PRINTF("No Method supported : %s\nstate : %d\n", conn_state->inputbuf, conn_state->state);
return 0;
}
return 1;
}
static int
parse_url(connection_state_t* conn_state, char* url)
{
int error = HTTP_NO_ERROR;
int full_url_path = 0;
/*even for default index.html there is / Ex: GET / HTTP/1.1*/
if (url[0] != '/') {
/*if url is complete (http://...) rather than relative*/
if (strncmp(url, http_string, 4) != 0 ) {
PRINTF("Url not valid : %s \n",url);
error = HTTP_URL_INVALID;
} else {
full_url_path = 1;
}
}
if (error == HTTP_NO_ERROR) {
char* url_buffer = url;
if (full_url_path) {
unsigned char num_of_slash = 0;
do {
url_buffer = strchr( ++url_buffer, '/' );
PRINTF("Buffer : %s %d\n", url_buffer, num_of_slash);
} while (url_buffer && ++num_of_slash < 3);
}
PRINTF("Url found :%s\n", url_buffer);
/*Get rid of the first slash*/
if (url_buffer && ++url_buffer) {
conn_state->request.url = (char*) copy_text_to_buffer(url_buffer);
conn_state->request.url_len = strlen(url_buffer);
if ((conn_state->request.query = strchr(conn_state->request.url, '?'))) {
*(conn_state->request.query++) = 0;
/*update url len - decrease the size of query*/
conn_state->request.url_len = strlen(conn_state->request.url);
conn_state->request.query_len = strlen(conn_state->request.query);
}
PRINTF("url %s, url_len %u, query %s, query_len %u\n", conn_state->request.url, conn_state->request.url_len, conn_state->request.query, conn_state->request.query_len);
/*FIXME url is not decoded - should be done here*/
} else {
error = HTTP_URL_INVALID;
}
}
return error;
}
static int
parse_header(connection_state_t* conn_state, char* inputbuf)
{
PRINTF("parse_header --->\n");
const char* header_name = NULL;
char* delimiter = strchr(inputbuf, ':');
if (delimiter) {
*delimiter++ = 0; /*after increment delimiter will point space char*/
header_name = is_request_hdr_needed(inputbuf);
if (header_name && delimiter) {
char* buffer = delimiter;
if (buffer[0] == ' ') {
buffer++;
}
http_header_t* current_header = NULL;
http_header_t* head = NULL;
current_header = allocate_header(strlen(buffer));
if (current_header) {
current_header->name = (char*)header_name;
strcpy(current_header->value, buffer);
}
head = conn_state->request.headers;
conn_state->request.headers = current_header;
if (head) {
current_header->next = head;
}
return 1;
}
}
return 0;
}
int
http_set_res_payload(http_response_t* response, uint8_t* payload, uint16_t size)
{
response->payload = copy_to_buffer(payload, size);
if (response->payload) {
response->payload_len = size;
return 1;
}
return 0;
}
static const char*
get_header(http_header_t* headers, const char* hdr_name)
{
for (;headers; headers = headers->next) {
if (strcmp(headers->name, hdr_name) == 0) {
return headers->value;
}
}
return NULL;
}
const char* http_get_req_header(http_request_t* request, const char* name)
{
return get_header(request->headers, name);
}
content_type_t http_get_header_content_type(http_request_t* request)
{
const char* content_type_string = http_get_req_header(request, HTTP_HEADER_NAME_CONTENT_TYPE);
if (content_type_string) {
int i = 0;
for(; i < sizeof(content_types)/sizeof(const char*) ; i++) {
if (strcmp(content_types[i], content_type_string)) {
return (content_type_t)i;
}
}
}
return UNKNOWN_CONTENT_TYPE;
}
static
PT_THREAD(handle_request(connection_state_t* conn_state))
{
static int error;
const char* content_len;
PSOCK_BEGIN(&(conn_state->sin));
content_len = NULL;
error = HTTP_NO_ERROR; /*always reinit static variables due to protothreads*/
PRINTF("Request--->\n");
//read method
PSOCK_READTO(&(conn_state->sin), ' ');
if (!is_method_handled(conn_state, conn_state->inputbuf)) {
/*method not handled*/
http_set_status(&conn_state->response, SERVICE_UNAVAILABLE_503);
conn_state->state = STATE_OUTPUT;
} else {
/*read until the end of url*/
PSOCK_READTO(&(conn_state->sin), ' ');
/*-1 is needed since it also includes space char*/
if (conn_state->inputbuf[PSOCK_DATALEN(&(conn_state->sin)) - 1] != ' ' ) {
error = HTTP_URL_TOO_LONG;
}
conn_state->inputbuf[PSOCK_DATALEN(&(conn_state->sin)) - 1] = 0;
PRINTF("Read URL:%s\n", conn_state->inputbuf);
if (error == HTTP_NO_ERROR) {
error = parse_url(conn_state, conn_state->inputbuf);
}
if (error != HTTP_NO_ERROR) {
if (error == HTTP_URL_TOO_LONG) {
http_set_status(&conn_state->response, REQUEST_URI_TOO_LONG_414);
} else {
http_set_status(&conn_state->response, BAD_REQUEST_400);
}
conn_state->state = STATE_OUTPUT;
} else {
/*read until the end of HTTP version - not used yet*/
PSOCK_READTO(&(conn_state->sin), LINE_FEED_CHAR);
PRINTF("After URL:%s\n", conn_state->inputbuf);
/*FIXME : PSOCK_READTO takes just a single delimiter so I read till the end of line
but now it may not fit in the buffer. If PSOCK_READTO would take two delimiters,
we would have read until : and <CR> so it would not be blocked.*/
/*Read the headers and store the necessary ones*/
do {
/*read the next line*/
PSOCK_READTO(&(conn_state->sin), LINE_FEED_CHAR);
conn_state->inputbuf[ PSOCK_DATALEN(&(conn_state->sin)) - 1] = 0;
/*if headers finished then stop the infinite loop*/
if (conn_state->inputbuf[0] == CARRIAGE_RETURN_CHAR || conn_state->inputbuf[0] == 0) {
PRINTF("Finished Headers!\n\n");
break;
}
parse_header(conn_state, conn_state->inputbuf);
}
while(1);
content_len = get_header(conn_state->request.headers, HTTP_HEADER_NAME_CONTENT_LENGTH);
if (content_len) {
conn_state->request.payload_len = atoi(content_len);
PRINTF("Post Data Size string: %s int: %d\n", content_len, conn_state->request.payload_len);
}
if (conn_state->request.payload_len) {
static uint16_t read_bytes = 0;
/*init the static variable again*/
read_bytes = 0;
conn_state->request.payload = allocate_buffer(conn_state->request.payload_len + 1);
if (conn_state->request.payload) {
do {
PSOCK_READBUF(&(conn_state->sin));
/*null terminate the buffer in case it is a string.*/
conn_state->inputbuf[PSOCK_DATALEN(&(conn_state->sin))] = 0;
memcpy(conn_state->request.payload + read_bytes, conn_state->inputbuf, PSOCK_DATALEN(&(conn_state->sin)));
read_bytes += PSOCK_DATALEN(&(conn_state->sin));
} while (read_bytes < conn_state->request.payload_len);
conn_state->request.payload[read_bytes++] = 0;
PRINTF("PostData => %s \n", conn_state->request.payload);
} else {
error = HTTP_MEMORY_ALLOC_ERR;
}
}
if (error == HTTP_NO_ERROR) {
if (service_cbk) {
service_cbk(&conn_state->request, &conn_state->response);
}
} else {
PRINTF("Error:%d\n",error);
http_set_status(&conn_state->response, INTERNAL_SERVER_ERROR_500);
}
conn_state->state = STATE_OUTPUT;
}
}
PSOCK_END(&(conn_state->sin));
}
static
PT_THREAD(send_data(connection_state_t* conn_state))
{
uint16_t index;
http_response_t* response;
http_header_t* header;
uint8_t* buffer;
PSOCK_BEGIN(&(conn_state->sout));
PRINTF("send_data -> \n");
index = 0;
response = &conn_state->response;
header = response->headers;
buffer = allocate_buffer(200);
/*FIXME: what is the best solution here to send the data. Right now, if buffer is not allocated, no data is sent!*/
if (buffer) {
index += sprintf(buffer + index, "%s %d %s%s", httpv1_1, response->status_code, response->status_string, line_end);
for (;header;header = header->next) {
PRINTF("header %u \n", (uint16_t)header);
index += sprintf(buffer + index, "%s%s%s%s", header->name, header_delimiter, header->value, line_end);
}
index += sprintf(buffer + index, "%s", line_end);
memcpy(buffer + index, response->payload, response->payload_len);
index += response->payload_len;
PRINTF("Sending Data(size %d): %s \n", index, buffer);
PSOCK_SEND(&(conn_state->sout), buffer, index);
} else {
PRINTF("BUFF ERROR: send_data!\n");
}
PSOCK_END(&(conn_state->sout));
}
static
PT_THREAD(handle_response(connection_state_t* conn_state))
{
PT_BEGIN(&(conn_state->outputpt));
PRINTF("handle_response ->\n");
http_set_res_header(&conn_state->response, HTTP_HEADER_NAME_CONNECTION, close, 0);
http_set_res_header(&conn_state->response, HTTP_HEADER_NAME_SERVER, contiki, 0);
if (!(conn_state->response.status_string)) {
conn_state->response.status_string =
get_default_status_string(conn_state->response.status_code);
}
PT_WAIT_THREAD(&(conn_state->outputpt), send_data(conn_state));
PRINTF("<-- handle_response\n\n\n");
PSOCK_CLOSE(&(conn_state->sout));
PT_END(&(conn_state->outputpt));
}
static void
handle_connection(connection_state_t* conn_state)
{
if (conn_state->state == STATE_WAITING) {
handle_request(conn_state);
}
if (conn_state->state == STATE_OUTPUT) {
handle_response(conn_state);
}
}
PROCESS(http_server, "Httpd Process");
PROCESS_THREAD(http_server, ev, data)
{
connection_state_t *conn_state;
PROCESS_BEGIN();
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
set_global_address();
configure_routing();
#endif /*!UIP_CONF_IPV6_RPL*/
#ifdef CONTIKI_TARGET_SKY
PRINTF("##RF CHANNEL : %d##\n",RF_CHANNEL);
#endif //CONTIKI_TARGET_SKY
tcp_listen(uip_htons(HTTP_PORT));
/*
* We loop for ever, accepting new connections.
*/
while(1) {
PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);
conn_state = (connection_state_t *)data;
if(uip_connected()) {
PRINTF("##Connected##\n");
if(init_buffer(HTTP_DATA_BUFF_SIZE)) {
conn_state = (connection_state_t*)allocate_buffer(sizeof(connection_state_t));
if (conn_state) {
tcp_markconn(uip_conn, conn_state);
/*initialize connection state*/
init_connection(conn_state);
/*-1 is needed to be able to null terminate the strings in the buffer, especially good for debugging (to have null terminated strings)*/
PSOCK_INIT(&(conn_state->sin), (uint8_t*)conn_state->inputbuf, sizeof(conn_state->inputbuf) - 1);
PSOCK_INIT(&(conn_state->sout), (uint8_t*)conn_state->inputbuf, sizeof(conn_state->inputbuf) - 1);
PT_INIT(&(conn_state->outputpt));
handle_connection(conn_state);
} else {
PRINTF("Memory Alloc Error. Aborting!\n");
uip_abort();
}
}
} else if (uip_aborted() || uip_closed() || uip_timedout()) {
if (conn_state) {
delete_buffer();
/*Following 2 lines are needed since this part of code is somehow executed twice so it tries to free the same region twice.
Potential bug in uip*/
conn_state = NULL;
tcp_markconn(uip_conn, conn_state);
}
} else {
handle_connection(conn_state);
}
}
PROCESS_END();
}

View File

@ -1,59 +0,0 @@
#ifndef HTTPSERVER_H_
#define HTTPSERVER_H_
#include "http-common.h"
#include "rest.h"
/*Declare process*/
PROCESS_NAME(http_server);
/*Type definition of the service callback*/
typedef int (*service_callback) (http_request_t* request, http_response_t* response);
/*
*Setter of the service callback, this callback will be called in case of HTTP request.
*/
void http_set_service_callback(service_callback callback);
/*
* Setter for the status code (200, 201, etc) of the response.
*/
void http_set_status(http_response_t* response, status_code_t status);
/*
* Adds the header name and value provided to the response.
* Name of the header should be hardcoded since it is accessed from code segment
* (not copied to buffer) whereas value of the header can be copied
* depending on the relevant parameter. This is needed since some values may be
* generated dynamically (ex: e-tag value)
*/
int http_set_res_header(http_response_t* response, const char* name, const char* value, int copy);
/*
* Returns the value of the header name provided. Return NULL if header does not exist.
*/
const char* http_get_req_header(http_request_t* request, const char* name);
int http_set_res_payload(http_response_t* response, uint8_t* payload, uint16_t size);
/*
* Returns query variable in the URL.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int http_get_query_variable(http_request_t* request, const char *name, char* output, uint16_t output_size);
/*
* Returns variable in the Post Data.
* Returns true if the variable found, false otherwise.
* Variable is put in the buffer provided.
*/
int http_get_post_variable(http_request_t* request, const char *name, char* output, uint16_t output_size);
/*
* Get the header "Content-Type".
*/
const char* http_get_content_type_string(content_type_t content_type);
content_type_t http_get_header_content_type(http_request_t* request);
#endif /*HTTPSERVER_H_*/

View File

@ -1,31 +0,0 @@
all: rest-server-example coap-client-example
ifndef TARGET
TARGET=sky
endif
CONTIKI=../..
WITH_COAP = 1
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
ifeq ($(WITH_COAP), 1)
CFLAGS += -DWITH_COAP
APPS += rest-coap
else
CFLAGS += -DWITH_HTTP
APPS += rest-http
endif
CONTIKI_WITH_IPV6 = 1
include $(CONTIKI)/Makefile.include
$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c
(cd $(CONTIKI)/tools && $(MAKE) tunslip6)
connect-router: $(CONTIKI)/tools/tunslip6
sudo $(CONTIKI)/tools/tunslip6 aaaa::1/64
connect-router-cooja: $(CONTIKI)/tools/tunslip6
sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 aaaa::1/64

View File

@ -1,137 +0,0 @@
REST example
============
Open a terminal and go to "<CONTIKI_HOME>/examples/rest-example/" directory.
MAIN EXAMPLE: rest-server-example.c : A RESTful server example showing how to
use the REST layer to develop server-side applications (possible to run it over
either COAP or HTTP) To use COAP as the underlying application protocol, one
should define WITH_COAP = 1 in rest-example/Makefile. Otherwise, HTTP is used.
Look at the source code to see which resources are available. (check the
RESOURCE macros in the code). Each resource has a handler function which is
called by the REST layer to serve the request. (i.e. "helloworld" resource has
a handler function named "helloworld_handler" which is called when a web
service request is received for "helloworld" resource.)
To run REST examples in COOJA on Linux
--------------------------------------------
Accessing the server from outside:
1. Start COOJA and load the simulation "rest-server-example.csc" by the following command.
make TARGET=cooja rest-server-example.csc
2. After loading the COOJA file, open another another terminal pointing to the
same directory and connect to the COOJA simulation using tunslip6:
make connect-router-cooja
3. You need to use a COAP or HTTP client to interact with the COOJA nodes
running REST code. In this setting, two servers are available: IP addresses
are aaaa::0212:7402:0002:0202 and aaaa::0212:7403:0003:0303. COAP uses
61616, whereas HTTP uses 8080 port in default configuration. First, ping
the COOJA nodes to test the connectivity.
ping6 aaaa::0212:7402:0002:0202
ping6 aaaa::0212:7403:0003:0303
HTTP Examples
-------------
You can use curl as an http client to interact with the COOJA motes running
REST code.
curl -H "User-Agent: curl" aaaa::0212:7402:0002:0202:8080/helloworld #get helloworld plain text
curl -H "User-Agent: curl" aaaa::0212:7402:0002:0202:8080/led?color=green -d mode=off -i #turn off the green led
curl -H "User-Agent: curl" aaaa::0212:7402:0002:0202:8080/.well-known/core -i
curl -X POST -H "User-Agent: curl" aaaa::0212:7402:0002:0202:8080/helloworld #method not allowed
COAP Examples
-------------
You should run a COAP client on your computer. You can use the URLs and methods
provided above in HTTP examples to test the COAP Server. For example, Matthias
Kovatsch has developed a CoAP Firefox plug-in which is accessible via
[http://people.inf.ethz.ch/mkovatsc/#pro](http://people.inf.ethz.ch/mkovatsc/#pro)
Accessing the server inside the sensor network: (Note: Provided only for COAP
implementation) Start COOJA and load the simulation
"coap-client-server-example.csc" by the following command.
make TARGET=cooja coap-client-server-example.csc
coap-client-server-example.csc : Runs rest-server-example.c as the server (over
COAP) (IP:aaaa::0212:7401:0001:0101) in one node and coap-client-example.c as
the client (IP: aaaa::0212:7402:0002:0202) in another node. Client
periodically accesses resources of server and prints the payload.
Note: If the generated binary is bigger than the MOTE code size, then you will
get a "region text is full" error. Right now, REST+HTTP example uses (Contiki
& ContikiMAC & uIPv6 & RPL & HTTP Server & REST Layer) which does not fit in
Tmote Sky memory. To save same code space and make the example fit, you can
define static routes rather than using RPL or use nullrdc rather than
ContikiMAC. If border router does not fit, then first try to update the
Makefile of border router in <CONTIKI_HOME>/examples/ipv6/rpl-border-router by
setting WITH_WEBSERVER=0.
To run REST server on real nodes (i.e. tmote sky)
--------------------------------------------
1. Program the nodes with the rest-server-example
make TARGET=sky rest-server-example.upload
2. Disconnect the nodes and program one node with the RPL border router
cd ../ipv6/rpl-border-router && make TARGET=sky border-router.upload
3. Connect to the border router using tunslip6:
make connect-router
4. Reconnect the motes, open new terminal for each mote and run the following
command to note their IP addresses (after running the command reset the
corresponding mote to get IP address printed)
make login TARGET=sky MOTE=2 #Shows the prints for first mote
make login TARGET=sky MOTE=3 #For second mote and so on.
5. Test the connectivity by pinging them.
ping6 <IPv6 Address of the MOTE>
6. Remaining parts are the same with the COOJA example. (i.e. if it is a COAP
Server, it's available at <NODE_IP_ADDR>:61616)
To run REST server with minimal-net on Linux
--------------------------------------------
1. Compile with minimal-net setting.
make rest-server-example TARGET=minimal-net
2. Run the generated executable with sudo and note the IP address of the server
which will be printed right after.
sudo ./rest-server-example.minimal-net
3. How to access and test the server is same with the other settings. (i.e. if
it is a COAP Server, it's available at <IP_ADDRESS_FROM_STEP_2>:61616 and if
it's a HTTP Server it is available at <IP_ADDRESS_FROM_STEP_2>:8080)
TODO
----
- Better option handling needed - ex: critical options are not differentiated
for now. Need to add support for some such as Tokens. Also, C/E difference
should be added.
- Reilable message sending is missing. i.e. client example should resend
request in case ACK does not arrive. Same for server pushing (in case of
subscriptions)
- Add Block transfer example
- Add Subscription example
- Add an Android/Java COAP Client to Contikiprojects to be able to interact
with Contiki.
- COAP-specific Method Codes

View File

@ -1,123 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "rest.h"
#include "buffer.h"
#define DEBUG 1
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
#define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7401, 0x0001, 0x0101)
#define LOCAL_PORT 61617
#define REMOTE_PORT 61616
char temp[100];
int xact_id;
static uip_ipaddr_t server_ipaddr;
static struct uip_udp_conn *client_conn;
static struct etimer et;
#define MAX_PAYLOAD_LEN 100
#define NUMBER_OF_URLS 3
char* service_urls[NUMBER_OF_URLS] = {"light", ".well-known/core", "helloworld"};
static void
response_handler(coap_packet_t* response)
{
uint16_t payload_len = 0;
uint8_t* payload = NULL;
payload_len = coap_get_payload(response, &payload);
PRINTF("Response transaction id: %u", response->tid);
if (payload) {
memcpy(temp, payload, payload_len);
temp[payload_len] = 0;
PRINTF(" payload: %s\n", temp);
}
}
static void
send_data(void)
{
char buf[MAX_PAYLOAD_LEN];
if (init_buffer(COAP_DATA_BUFF_SIZE)) {
int data_size = 0;
int service_id = random_rand() % NUMBER_OF_URLS;
coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
init_packet(request);
coap_set_method(request, COAP_GET);
request->tid = xact_id++;
request->type = MESSAGE_TYPE_CON;
coap_set_header_uri(request, service_urls[service_id]);
data_size = serialize_packet(request, buf);
PRINTF("Client sending request to:[");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF("]:%u/%s\n", (uint16_t)REMOTE_PORT, service_urls[service_id]);
uip_udp_packet_send(client_conn, buf, data_size);
delete_buffer();
}
}
static void
handle_incoming_data()
{
PRINTF("Incoming packet size: %u \n", (uint16_t)uip_datalen());
if (init_buffer(COAP_DATA_BUFF_SIZE)) {
if (uip_newdata()) {
coap_packet_t* response = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
if (response) {
parse_message(response, uip_appdata, uip_datalen());
response_handler(response);
}
}
delete_buffer();
}
}
PROCESS(coap_client_example, "COAP Client Example");
AUTOSTART_PROCESSES(&coap_client_example);
PROCESS_THREAD(coap_client_example, ev, data)
{
PROCESS_BEGIN();
SERVER_NODE(&server_ipaddr);
/* new connection with server */
client_conn = udp_new(&server_ipaddr, UIP_HTONS(REMOTE_PORT), NULL);
udp_bind(client_conn, UIP_HTONS(LOCAL_PORT));
PRINTF("Created a connection with the server ");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n",
UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport));
etimer_set(&et, 5 * CLOCK_SECOND);
while(1) {
PROCESS_YIELD();
if (etimer_expired(&et)) {
send_data();
etimer_reset(&et);
} else if (ev == tcpip_event) {
handle_incoming_data();
}
}
PROCESS_END();
}

View File

@ -1,147 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
<simulation>
<title>coap-client-server-example</title>
<delaytime>-2147483648</delaytime>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>100.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.mspmote.SkyMoteType
<identifier>sky1</identifier>
<description>CoapServer</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/rest-example/rest-server-example.c</source>
<commands EXPORT="discard">make rest-server-example.sky TARGET=sky</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/rest-example/rest-server-example.sky</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<motetype>
org.contikios.cooja.mspmote.SkyMoteType
<identifier>sky2</identifier>
<description>CoapClient</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/rest-example/coap-client-example.c</source>
<commands EXPORT="discard">make coap-client-example.sky TARGET=sky</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/rest-example/coap-client-example.sky</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>54.5338749671737</x>
<y>36.41934631024719</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>49.41583327244326</x>
<y>52.00647916206431</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>sky2</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>318</width>
<z>2</z>
<height>172</height>
<location_x>0</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Visualizer
<plugin_config>
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.AddressVisualizerSkin</skin>
<viewport>3.686023978928717 0.0 0.0 3.686023978928717 -20.14794638096936 -127.69712925102564</viewport>
</plugin_config>
<width>271</width>
<z>0</z>
<height>211</height>
<location_x>666</location_x>
<location_y>41</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter />
</plugin_config>
<width>1263</width>
<z>1</z>
<height>199</height>
<location_x>0</location_x>
<location_y>339</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.TimeLine
<plugin_config>
<mote>0</mote>
<mote>1</mote>
<showRadioRXTX />
<showRadioHW />
<showLEDs />
<split>125</split>
<zoomfactor>500.0</zoomfactor>
</plugin_config>
<width>1263</width>
<z>3</z>
<height>150</height>
<location_x>0</location_x>
<location_y>538</location_y>
</plugin>
</simconf>

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
*/
#ifndef PROJECT_RPL_WEB_CONF_H_
#define PROJECT_RPL_WEB_CONF_H_
/* Disabling RDC and CSMA for demo purposes. Core updates often
require more memory. */
/* For projects, optimize memory and enable RDC and CSMA again. */
#undef NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
#undef NETSTACK_CONF_MAC
#define NETSTACK_CONF_MAC nullmac_driver
#ifndef QUEUEBUF_CONF_NUM
#define QUEUEBUF_CONF_NUM 6
#endif
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 140
#endif
#ifndef UIP_CONF_RECEIVE_WINDOW
#define UIP_CONF_RECEIVE_WINDOW 60
#endif
#ifndef WEBSERVER_CONF_CFS_CONNS
#define WEBSERVER_CONF_CFS_CONNS 2
#endif
#endif /* PROJECT_RPL_WEB_CONF_H_ */

View File

@ -1,180 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "rest.h"
#if defined (PLATFORM_HAS_LIGHT)
#include "dev/light-sensor.h"
#endif
#if defined (PLATFORM_HAS_BATT)
#include "dev/battery-sensor.h"
#endif
#if defined (PLATFORM_HAS_SHT11)
#include "dev/sht11/sht11-sensor.h"
#endif
#if defined (PLATFORM_HAS_LEDS)
#include "dev/leds.h"
#endif
#define DEBUG 1
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINT6ADDR(addr) PRINTF(" %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x ", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
#define PRINTLLADDR(lladdr) PRINTF(" %02x:%02x:%02x:%02x:%02x:%02x ",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5])
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#endif
char temp[100];
/* Resources are defined by RESOURCE macro, signature: resource name, the http methods it handles and its url*/
RESOURCE(helloworld, METHOD_GET, "helloworld");
/* For each resource defined, there corresponds an handler method which should be defined too.
* Name of the handler method should be [resource name]_handler
* */
void
helloworld_handler(REQUEST* request, RESPONSE* response)
{
sprintf(temp,"Hello World!\n");
rest_set_header_content_type(response, TEXT_PLAIN);
rest_set_response_payload(response, (uint8_t*)temp, strlen(temp));
}
RESOURCE(discover, METHOD_GET, ".well-known/core");
void
discover_handler(REQUEST* request, RESPONSE* response)
{
char temp[100];
int index = 0;
index += sprintf(temp + index, "%s,", "</helloworld>;n=\"HelloWorld\"");
#if defined (PLATFORM_HAS_LEDS)
index += sprintf(temp + index, "%s,", "</led>;n=\"LedControl\"");
#endif
#if defined (PLATFORM_HAS_LIGHT)
index += sprintf(temp + index, "%s", "</light>;n=\"Light\"");
#endif
rest_set_response_payload(response, (uint8_t*)temp, strlen(temp));
rest_set_header_content_type(response, APPLICATION_LINK_FORMAT);
}
#if defined (PLATFORM_HAS_LIGHT)
uint16_t light_photosynthetic;
uint16_t light_solar;
void
read_light_sensor(uint16_t* light_1, uint16_t* light_2)
{
*light_1 = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC);
*light_2 = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR);
}
/*A simple getter example. Returns the reading from light sensor with a simple etag*/
RESOURCE(light, METHOD_GET, "light");
void
light_handler(REQUEST* request, RESPONSE* response)
{
read_light_sensor(&light_photosynthetic, &light_solar);
sprintf(temp,"%u;%u", light_photosynthetic, light_solar);
char etag[4] = "ABCD";
rest_set_header_content_type(response, TEXT_PLAIN);
rest_set_header_etag(response, etag, sizeof(etag));
rest_set_response_payload(response, temp, strlen(temp));
}
#endif /*PLATFORM_HAS_LIGHT*/
#if defined (PLATFORM_HAS_LEDS)
/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/
RESOURCE(led, METHOD_POST | METHOD_PUT , "led");
void
led_handler(REQUEST* request, RESPONSE* response)
{
char color[10];
char mode[10];
uint8_t led = 0;
int success = 1;
if (rest_get_query_variable(request, "color", color, 10)) {
PRINTF("color %s\n", color);
if (!strcmp(color,"red")) {
led = LEDS_RED;
} else if(!strcmp(color,"green")) {
led = LEDS_GREEN;
} else if ( !strcmp(color,"blue") ) {
led = LEDS_BLUE;
} else {
success = 0;
}
} else {
success = 0;
}
if (success && rest_get_post_variable(request, "mode", mode, 10)) {
PRINTF("mode %s\n", mode);
if (!strcmp(mode, "on")) {
leds_on(led);
} else if (!strcmp(mode, "off")) {
leds_off(led);
} else {
success = 0;
}
} else {
success = 0;
}
if (!success) {
rest_set_response_status(response, BAD_REQUEST_400);
}
}
/*A simple actuator example. Toggles the red led*/
RESOURCE(toggle, METHOD_GET | METHOD_PUT | METHOD_POST, "toggle");
void
toggle_handler(REQUEST* request, RESPONSE* response)
{
leds_toggle(LEDS_RED);
}
#endif /*defined (CONTIKI_HAS_LEDS)*/
PROCESS(rest_server_example, "Rest Server Example");
AUTOSTART_PROCESSES(&rest_server_example);
PROCESS_THREAD(rest_server_example, ev, data)
{
PROCESS_BEGIN();
#ifdef WITH_COAP
PRINTF("COAP Server\n");
#else
PRINTF("HTTP Server\n");
#endif
rest_init();
#if defined (PLATFORM_HAS_LIGHT)
SENSORS_ACTIVATE(light_sensor);
rest_activate_resource(&resource_light);
#endif
#if defined (PLATFORM_HAS_LEDS)
rest_activate_resource(&resource_led);
rest_activate_resource(&resource_toggle);
#endif /*defined (PLATFORM_HAS_LEDS)*/
rest_activate_resource(&resource_helloworld);
rest_activate_resource(&resource_discover);
PROCESS_END();
}

View File

@ -1,185 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
<simulation>
<title>REST with RPL router</title>
<delaytime>-2147483648</delaytime>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>50.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.mspmote.SkyMoteType
<identifier>rplroot</identifier>
<description>Sky RPL Root</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.c</source>
<commands EXPORT="discard">make border-router.sky TARGET=sky</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.sky</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<motetype>
org.contikios.cooja.mspmote.SkyMoteType
<identifier>skyweb</identifier>
<description>Rest</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/rest-example/rest-server-example.c</source>
<commands EXPORT="discard">make rest-server-example.sky TARGET=sky</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/rest-example/rest-server-example.sky</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>33.260163187353555</x>
<y>30.643217359962595</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<motetype_identifier>rplroot</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>62.239287566073514</x>
<y>34.43810269527116</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>skyweb</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>47.68359039801751</x>
<y>47.26544238238854</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>3</id>
</interface_config>
<motetype_identifier>skyweb</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>259</width>
<z>1</z>
<height>179</height>
<location_x>0</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Visualizer
<plugin_config>
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.AttributeVisualizerSkin</skin>
<viewport>10.505309204322225 0.0 0.0 10.505309204322225 -249.89475921566975 -141.01191150973983</viewport>
</plugin_config>
<width>819</width>
<z>5</z>
<height>563</height>
<location_x>35</location_x>
<location_y>306</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter />
</plugin_config>
<width>762</width>
<z>0</z>
<height>326</height>
<location_x>36</location_x>
<location_y>296</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.RadioLogger
<plugin_config>
<split>150</split>
<analyzers name="6lowpan" />
</plugin_config>
<width>815</width>
<z>4</z>
<height>385</height>
<location_x>255</location_x>
<location_y>8</location_y>
</plugin>
<plugin>
SerialSocketServer
<mote_arg>0</mote_arg>
<width>422</width>
<z>3</z>
<height>74</height>
<location_x>1234</location_x>
<location_y>93</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.TimeLine
<plugin_config>
<mote>0</mote>
<mote>1</mote>
<showRadioRXTX />
<showRadioHW />
<showLEDs />
<showWatchpoints />
<split>125</split>
<zoomfactor>25.49079397896416</zoomfactor>
</plugin_config>
<width>1624</width>
<z>2</z>
<height>252</height>
<location_x>166</location_x>
<location_y>699</location_y>
</plugin>
</simconf>

View File

@ -128,12 +128,6 @@
#define UIP_CONF_UDP 1
#if (WITH_COAP==7) || (WITH_COAP==6) || (WITH_COAP==3)
#define UIP_CONF_TCP 0
#else
#define UIP_CONF_TCP 1
#endif /* WITH_COAP */
#define UIP_CONF_ROUTER 1
#define UIP_CONF_ND6_SEND_RA 0

View File

@ -20,7 +20,6 @@ powertrace/sky \
rime/sky \
rime/z1 \
ravenusbstick/avr-ravenusb \
rest-example/sky \
servreg-hack/sky \
sky/sky \
sky-ip/sky \