Merge remote-tracking branch 'upstream/master'
Conflicts: core/net/ip/uip-nameserver.c
This commit is contained in:
commit
35becbbcb5
320 changed files with 15107 additions and 7316 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -24,6 +24,7 @@
|
|||
*.c128
|
||||
*.c64
|
||||
*.cc2538dk
|
||||
*.remote
|
||||
*.srf06-cc26xx
|
||||
*.ev-aducrf101mkxz
|
||||
*.report
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
|||
[submodule "tools/cc2538-bsl"]
|
||||
path = tools/cc2538-bsl
|
||||
url = https://github.com/JelmerT/cc2538-bsl.git
|
||||
[submodule "cpu/cc26xx/lib/cc26xxware"]
|
||||
path = cpu/cc26xx/lib/cc26xxware
|
||||
url = https://github.com/g-oikonomou/cc26xxware.git
|
||||
|
|
18
.travis.yml
18
.travis.yml
|
@ -30,7 +30,7 @@ before_script:
|
|||
- sudo apt-get -qq install libc6:i386 libgcc1:i386 gcc-4.6-base:i386
|
||||
libstdc++5:i386 libstdc++6:i386
|
||||
|
||||
## Install old APCS ARM toolchain for mc1233x, cc2538 and mbxxx
|
||||
## Install old APCS ARM toolchain for mc1233x and mbxxx
|
||||
- if [ ${BUILD_ARCH:-0} = arm-apcs ] ; then
|
||||
$WGET https://raw.githubusercontent.com/wiki/malvira/libmc1322x/files/arm-2008q3-66-arm-none-eabi-i686-pc-linux-gnu.tar.bz2 &&
|
||||
tar xjf arm-2008q3*.tar.bz2 -C /tmp/ &&
|
||||
|
@ -41,20 +41,14 @@ before_script:
|
|||
|
||||
## Install mainline ARM toolchain. gcc-arm-none-eabi is available
|
||||
## in Ubuntu >= 14.04, but this external PPA is needed for 12.04.
|
||||
- if [ ${BUILD_ARCH:-0} = arm ] ; then
|
||||
## Install srecord
|
||||
- if [ ${BUILD_ARCH:-0} = arm-aapcs ] ; then
|
||||
sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded &&
|
||||
sudo apt-get -qq update &&
|
||||
sudo apt-get -qq install gcc-arm-none-eabi &&
|
||||
sudo apt-get -qq install gcc-arm-none-eabi srecord &&
|
||||
arm-none-eabi-gcc --version ;
|
||||
fi
|
||||
|
||||
## Download and extract cc26xxware
|
||||
- if [ ${BUILD_ARCH:-0} = arm ] ; then
|
||||
wget http://www.ti.com/lit/sw/swrc296/swrc296.zip &&
|
||||
unzip swrc296.zip &&
|
||||
export TI_CC26XXWARE=cc26xxware_2_20_06_14829 ;
|
||||
fi
|
||||
|
||||
## Install RL78 GCC toolchain
|
||||
- sudo apt-get install libncurses5:i386 zlib1g:i386
|
||||
- $WGET http://adamdunkels.github.io/contiki-fork/gnurl78-v13.02-elf_1-2_i386.deb &&
|
||||
|
@ -105,11 +99,13 @@ env:
|
|||
## of environment variable defined below
|
||||
- BUILD_TYPE='doxygen' BUILD_CATEGORY='doxygen'
|
||||
- BUILD_TYPE='compile-base' BUILD_CATEGORY='compile'
|
||||
- BUILD_TYPE='compile-tools' BUILD_CATEGORY='compile'
|
||||
- BUILD_TYPE='collect'
|
||||
- BUILD_TYPE='collect-lossy'
|
||||
- BUILD_TYPE='rpl'
|
||||
- BUILD_TYPE='rime'
|
||||
- BUILD_TYPE='ipv6'
|
||||
- BUILD_TYPE='ip64' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='hello-world'
|
||||
- BUILD_TYPE='base'
|
||||
# XXX: netperf disabled b/c it's flaky
|
||||
|
@ -122,6 +118,6 @@ env:
|
|||
- BUILD_TYPE='compile-8051-ports' BUILD_CATEGORY='compile' BUILD_ARCH='8051'
|
||||
- BUILD_TYPE='compile-arm-apcs-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-apcs'
|
||||
- BUILD_TYPE='compile-6502-ports' BUILD_CATEGORY='compile' BUILD_ARCH='6502'
|
||||
- BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm'
|
||||
- BUILD_TYPE='compile-arm-ports' BUILD_CATEGORY='compile' BUILD_ARCH='arm-aapcs'
|
||||
- BUILD_TYPE='slip-radio' MAKE_TARGETS='cooja'
|
||||
- BUILD_TYPE='llsec' MAKE_TARGETS='cooja'
|
||||
|
|
|
@ -147,7 +147,6 @@ endif
|
|||
|
||||
ifdef MODULES
|
||||
UNIQUEMODULES = $(call uniq,$(MODULES))
|
||||
MODULESSUBST = ${subst /,-,$(UNIQUEMODULES)}
|
||||
MODULEDIRS = ${wildcard ${addprefix $(CONTIKI)/, $(UNIQUEMODULES)}}
|
||||
MODULES_SOURCES = ${foreach d, $(MODULEDIRS), ${subst ${d}/,,${wildcard $(d)/*.c}}}
|
||||
CONTIKI_SOURCEFILES += $(MODULES_SOURCES)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
|
||||
*/
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
|
||||
*/
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "er-coap-separate.h"
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "contiki.h"
|
||||
#include "sys/cc.h"
|
||||
#include "contiki-net.h"
|
||||
|
||||
#include "er-coap.h"
|
||||
|
|
|
@ -79,10 +79,6 @@ enum { OPTION_MAP_SIZE = sizeof(uint8_t) * 8 };
|
|||
#define SET_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] |= 1 << (opt % OPTION_MAP_SIZE))
|
||||
#define IS_OPTION(packet, opt) ((packet)->options[opt / OPTION_MAP_SIZE] & (1 << (opt % OPTION_MAP_SIZE)))
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
/* parsed message struct */
|
||||
typedef struct {
|
||||
uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */
|
||||
|
|
|
@ -57,13 +57,12 @@
|
|||
|
||||
#include "lib/assert.h"
|
||||
#include "lib/list.h"
|
||||
#include "sys/cc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#define PRINTF(...) PRINTF(__VA_ARGS__)
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
rest-coap_src = coap-common.c coap-server.c
|
||||
|
||||
APPS += rest-common
|
||||
include $(CONTIKI)/apps/rest-common/Makefile.rest-common
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -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_ */
|
|
@ -1 +0,0 @@
|
|||
rest-common_src = rest.c rest-util.c buffer.c static-routing.c
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
|
@ -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_*/
|
|
@ -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*/
|
|
@ -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_ */
|
|
@ -62,10 +62,6 @@
|
|||
#define REST_MAX_CHUNK_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
struct resource_s;
|
||||
struct periodic_resource_s;
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
rest-http_src = http-common.c http-server.c
|
||||
|
||||
APPS += rest-common
|
||||
include $(CONTIKI)/apps/rest-common/Makefile.rest-common
|
|
@ -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 = ": ";
|
|
@ -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_*/
|
|
@ -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();
|
||||
}
|
|
@ -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_*/
|
|
@ -9,7 +9,7 @@ shell_src = shell.c shell-reboot.c shell-vars.c shell-ps.c \
|
|||
shell_dsc = shell-dsc.c
|
||||
|
||||
ifeq ($(CONTIKI_WITH_RIME),1)
|
||||
shell_src += shell-rime.c shell-sendtest.c shell-netfile.c \
|
||||
shell_src += shell-rime.c shell-sendtest.c \
|
||||
shell-rime-ping.c shell-rime-sniff.c shell-rime-netcmd.c \
|
||||
shell-rime-debug.c shell-rime-debug-runicast.c \
|
||||
shell-rime-sendcmd.c shell-download.c shell-rime-neighbors.c \
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* A brief description of what this file is.
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "shell-netfile.h"
|
||||
#include "net/rime/rime.h"
|
||||
#include "net/rime/rudolph0.h"
|
||||
#include "dev/leds.h"
|
||||
|
||||
#include "cfs/cfs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FILENAME_LEN 20
|
||||
|
||||
static struct rudolph0_conn rudolph0_conn;
|
||||
static char filename[FILENAME_LEN];
|
||||
static int receiving_file;
|
||||
static struct pt recvnetfilept;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(shell_netfile_process, "netfile");
|
||||
SHELL_COMMAND(netfile_command,
|
||||
"netfile",
|
||||
"netfile: send file to entire network",
|
||||
&shell_netfile_process);
|
||||
PROCESS(shell_recvnetfile_process, "recvnetfile");
|
||||
SHELL_COMMAND(recvnetfile_command,
|
||||
"recvnetfile",
|
||||
"recvnetfile: receive file from network and print to output",
|
||||
&shell_recvnetfile_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
write_chunk_pt(struct rudolph0_conn *c, int offset, int flag,
|
||||
uint8_t *data, int datalen)
|
||||
{
|
||||
PT_BEGIN(&recvnetfilept);
|
||||
|
||||
PT_WAIT_UNTIL(&recvnetfilept, receiving_file);
|
||||
leds_on(LEDS_YELLOW);
|
||||
leds_on(LEDS_RED);
|
||||
PT_WAIT_UNTIL(&recvnetfilept, flag == RUDOLPH0_FLAG_NEWFILE);
|
||||
leds_off(LEDS_RED);
|
||||
|
||||
do {
|
||||
if(datalen > 0) {
|
||||
shell_output(&recvnetfile_command, data, datalen, "", 0);
|
||||
/* printf("write_chunk wrote %d bytes at %d\n", datalen, offset);*/
|
||||
}
|
||||
PT_YIELD(&recvnetfilept);
|
||||
} while(flag != RUDOLPH0_FLAG_LASTCHUNK);
|
||||
|
||||
shell_output(&recvnetfile_command, data, datalen, "", 0);
|
||||
/* printf("write_chunk wrote %d bytes at %d\n", datalen, offset);*/
|
||||
shell_output(&recvnetfile_command, "", 0, "", 0);
|
||||
leds_off(LEDS_YELLOW);
|
||||
receiving_file = 0;
|
||||
process_post(&shell_recvnetfile_process, PROCESS_EVENT_CONTINUE, NULL);
|
||||
|
||||
PT_END(&recvnetfilept);
|
||||
}
|
||||
static void
|
||||
write_chunk(struct rudolph0_conn *c, int offset, int flag,
|
||||
uint8_t *data, int datalen)
|
||||
{
|
||||
write_chunk_pt(c, offset, flag, data, datalen);
|
||||
}
|
||||
|
||||
static int
|
||||
read_chunk(struct rudolph0_conn *c, int offset, uint8_t *to, int maxsize)
|
||||
{
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
fd = cfs_open(filename, CFS_READ);
|
||||
|
||||
cfs_seek(fd, offset, CFS_SEEK_SET);
|
||||
ret = cfs_read(fd, to, maxsize);
|
||||
/* printf("read_chunk %d bytes at %d, %d\n", ret, offset, (unsigned char)to[0]);*/
|
||||
cfs_close(fd);
|
||||
return ret;
|
||||
}
|
||||
CC_CONST_FUNCTION static struct rudolph0_callbacks rudolph0_callbacks =
|
||||
{/*(void (*)(struct rudolph0_conn *, int, int, uint8_t *, int))*/
|
||||
write_chunk,
|
||||
read_chunk};
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_netfile_process, ev, data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
PROCESS_BEGIN();
|
||||
|
||||
if(data != NULL) {
|
||||
rudolph0_send(&rudolph0_conn, CLOCK_SECOND);
|
||||
|
||||
strncpy(filename, data, FILENAME_LEN);
|
||||
fd = cfs_open(filename, CFS_READ);
|
||||
if(fd < 0) {
|
||||
shell_output_str(&netfile_command, "netfile: could not open file ", filename);
|
||||
} else {
|
||||
cfs_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(shell_recvnetfile_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
|
||||
PT_INIT(&recvnetfilept);
|
||||
receiving_file = 1;
|
||||
while(1) {
|
||||
struct shell_input *input;
|
||||
|
||||
PROCESS_WAIT_EVENT();
|
||||
|
||||
if(ev == shell_event_input) {
|
||||
input = data;
|
||||
if(input->len1 + input->len2 == 0) {
|
||||
receiving_file = 0;
|
||||
PROCESS_EXIT();
|
||||
}
|
||||
} else if(receiving_file == 0) {
|
||||
PROCESS_EXIT();
|
||||
}
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
shell_netfile_init(void)
|
||||
{
|
||||
receiving_file = 0;
|
||||
shell_register_command(&netfile_command);
|
||||
shell_register_command(&recvnetfile_command);
|
||||
|
||||
rudolph0_open(&rudolph0_conn, SHELL_RIME_CHANNEL_NETFILE,
|
||||
&rudolph0_callbacks);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
|
@ -42,6 +42,7 @@
|
|||
#include "sys/energest.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sys/cc.h"
|
||||
|
||||
struct power_msg {
|
||||
uint16_t len;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "sys/cc.h"
|
||||
#include "shell-sky.h"
|
||||
|
||||
#include "dev/watchdog.h"
|
||||
|
@ -84,8 +85,6 @@ SHELL_COMMAND(rfchannel_command,
|
|||
"rfchannel <channel>: change CC2420 radio channel (11 - 26)",
|
||||
&shell_rfchannel_process);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define MAX(a, b) ((a) > (b)? (a): (b))
|
||||
#define MIN(a, b) ((a) < (b)? (a): (b))
|
||||
struct spectrum {
|
||||
int channel[16];
|
||||
};
|
||||
|
|
|
@ -36,13 +36,10 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "contiki.h"
|
||||
#include "sys/cc.h"
|
||||
#include "shell.h"
|
||||
#include "telnet.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(shell_tcpsend_process, "tcpsend");
|
||||
SHELL_COMMAND(tcpsend_command,
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "sys/cc.h"
|
||||
#include "shell-time.h"
|
||||
|
||||
#include "sys/clock.h"
|
||||
|
@ -51,11 +52,6 @@
|
|||
#define MAX_COMMANDLENGTH 64
|
||||
#define PERIOD_INTERVAL 60
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(shell_time_process, "time");
|
||||
SHELL_COMMAND(time_command,
|
||||
|
|
|
@ -382,7 +382,6 @@ struct shell_input {
|
|||
#include "shell-httpd.h"
|
||||
#include "shell-irc.h"
|
||||
#include "shell-memdebug.h"
|
||||
#include "shell-netfile.h"
|
||||
#include "shell-netperf.h"
|
||||
#include "shell-netstat.h"
|
||||
#include "shell-ping.h"
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include "contiki-lib.h"
|
||||
#include "contiki-net.h"
|
||||
#include "lib/petsciiconv.h"
|
||||
|
@ -103,7 +104,6 @@ static uint8_t connected;
|
|||
|
||||
#define MAX_SILENCE_TIME (CLOCK_SECOND * 30)
|
||||
|
||||
#define MIN(a, b) ((a) < (b)? (a): (b))
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
buf_init(struct telnetd_buf *buf)
|
||||
|
|
|
@ -1125,8 +1125,6 @@ cfs_read(int fd, void *buf, unsigned size)
|
|||
* ordinary file if the page has no log record.
|
||||
*/
|
||||
for(bytes_left = size; bytes_left > 0; bytes_left -= r) {
|
||||
r = -1;
|
||||
|
||||
lp.offset = fdp->offset;
|
||||
lp.buf = buf;
|
||||
lp.size = bytes_left;
|
||||
|
|
|
@ -57,36 +57,36 @@ extern unsigned char spi_busy;
|
|||
void spi_init(void);
|
||||
|
||||
/* Write one character to SPI */
|
||||
#define SPI_WRITE(data) \
|
||||
do { \
|
||||
SPI_WAITFORTx_BEFORE(); \
|
||||
SPI_TXBUF = data; \
|
||||
SPI_WAITFOREOTx(); \
|
||||
#define SPI_WRITE(data) \
|
||||
do { \
|
||||
SPI_WAITFORTx_BEFORE(); \
|
||||
SPI_TXBUF = data; \
|
||||
SPI_WAITFOREOTx(); \
|
||||
} while(0)
|
||||
|
||||
/* Write one character to SPI - will not wait for end
|
||||
useful for multiple writes with wait after final */
|
||||
#define SPI_WRITE_FAST(data) \
|
||||
do { \
|
||||
SPI_WAITFORTx_BEFORE(); \
|
||||
SPI_TXBUF = data; \
|
||||
SPI_WAITFORTx_AFTER(); \
|
||||
#define SPI_WRITE_FAST(data) \
|
||||
do { \
|
||||
SPI_WAITFORTx_BEFORE(); \
|
||||
SPI_TXBUF = data; \
|
||||
SPI_WAITFORTx_AFTER(); \
|
||||
} while(0)
|
||||
|
||||
/* Read one character from SPI */
|
||||
#define SPI_READ(data) \
|
||||
do { \
|
||||
SPI_TXBUF = 0; \
|
||||
SPI_WAITFOREORx(); \
|
||||
data = SPI_RXBUF; \
|
||||
#define SPI_READ(data) \
|
||||
do { \
|
||||
SPI_TXBUF = 0; \
|
||||
SPI_WAITFOREORx(); \
|
||||
data = SPI_RXBUF; \
|
||||
} while(0)
|
||||
|
||||
/* Flush the SPI read register */
|
||||
#ifndef SPI_FLUSH
|
||||
#define SPI_FLUSH() \
|
||||
do { \
|
||||
SPI_RXBUF; \
|
||||
} while(0);
|
||||
do { \
|
||||
SPI_RXBUF; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#endif /* SPI_H_ */
|
||||
|
|
|
@ -72,14 +72,13 @@ static unsigned char ascii2petscii[128] = {
|
|||
0x58,0x59,0x5a,0xdb,0xdd,0xdd,0x5e,0xdf,
|
||||
};
|
||||
|
||||
static unsigned int i;
|
||||
static unsigned char *ptr;
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
void
|
||||
petsciiconv_toascii(char *buf, unsigned int len)
|
||||
{
|
||||
static char c;
|
||||
unsigned int i;
|
||||
char *ptr;
|
||||
char c;
|
||||
|
||||
ptr = buf;
|
||||
for(i = len; i > 0; --i) {
|
||||
|
@ -108,6 +107,9 @@ petsciiconv_toascii(char *buf, unsigned int len)
|
|||
void
|
||||
petsciiconv_topetscii(char *buf, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
char *ptr;
|
||||
|
||||
ptr = buf;
|
||||
for(i = len; i > 0; --i) {
|
||||
*ptr = ascii2petscii[*ptr & 0x7f];
|
||||
|
|
|
@ -65,10 +65,6 @@
|
|||
#define SETTINGS_BOTTOM_ADDR (SETTINGS_TOP_ADDR + 1 - SETTINGS_MAX_SIZE)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?a:b)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
#if SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||
uint8_t size_extra;
|
||||
|
|
682
core/net/http-socket/http-socket.c
Normal file
682
core/net/http-socket/http-socket.c
Normal file
|
@ -0,0 +1,682 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Thingsquare, http://www.thingsquare.com/.
|
||||
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT HOLDER 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.
|
||||
*
|
||||
*/
|
||||
#include "contiki-net.h"
|
||||
#include "ip64-addr.h"
|
||||
#include "http-socket.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_PATHLEN 80
|
||||
#define MAX_HOSTLEN 40
|
||||
PROCESS(http_socket_process, "HTTP socket process");
|
||||
LIST(socketlist);
|
||||
|
||||
static void removesocket(struct http_socket *s);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
call_callback(struct http_socket *s, http_socket_event_t e,
|
||||
const uint8_t *data, uint16_t datalen)
|
||||
{
|
||||
if(s->callback != NULL) {
|
||||
s->callback(s, s->callbackptr, e,
|
||||
data, datalen);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
parse_header_init(struct http_socket *s)
|
||||
{
|
||||
PT_INIT(&s->headerpt);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
parse_header_byte(struct http_socket *s, char c)
|
||||
{
|
||||
PT_BEGIN(&s->headerpt);
|
||||
|
||||
memset(&s->header, -1, sizeof(s->header));
|
||||
|
||||
/* Skip the HTTP response */
|
||||
while(c != ' ') {
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
|
||||
/* Skip the space */
|
||||
PT_YIELD(&s->headerpt);
|
||||
/* Read three characters of HTTP status and convert to BCD */
|
||||
s->header.status_code = 0;
|
||||
for(s->header_chars = 0; s->header_chars < 3; s->header_chars++) {
|
||||
s->header.status_code = s->header.status_code << 4 | (c - '0');
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
|
||||
if(s->header.status_code == 0x200 || s->header.status_code == 0x206) {
|
||||
/* Read headers until data */
|
||||
|
||||
while(1) {
|
||||
/* Skip characters until end of line */
|
||||
do {
|
||||
while(c != '\r') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
} while(c != '\n');
|
||||
s->header_chars--;
|
||||
PT_YIELD(&s->headerpt);
|
||||
|
||||
if(s->header_chars == 0) {
|
||||
/* This was an empty line, i.e. the end of headers */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Start of line */
|
||||
s->header_chars = 0;
|
||||
|
||||
/* Read header field */
|
||||
while(c != ' ' && c != '\t' && c != ':' && c != '\r' &&
|
||||
s->header_chars < sizeof(s->header_field) - 1) {
|
||||
s->header_field[s->header_chars++] = c;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
s->header_field[s->header_chars] = '\0';
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
if(c == ':') {
|
||||
/* Skip the colon */
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
if(!strcmp(s->header_field, "Content-Length")) {
|
||||
s->header.content_length = 0;
|
||||
while(isdigit((int)c)) {
|
||||
s->header.content_length = s->header.content_length * 10 + c - '0';
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
} else if(!strcmp(s->header_field, "Content-Range")) {
|
||||
/* Skip the bytes-unit token */
|
||||
while(c != ' ' && c != '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
s->header.content_range.first_byte_pos = 0;
|
||||
while(isdigit((int)c)) {
|
||||
s->header.content_range.first_byte_pos =
|
||||
s->header.content_range.first_byte_pos * 10 + c - '0';
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
if(c == '-') {
|
||||
/* Skip the dash */
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
s->header.content_range.last_byte_pos = 0;
|
||||
while(isdigit((int)c)) {
|
||||
s->header.content_range.last_byte_pos =
|
||||
s->header.content_range.last_byte_pos * 10 + c - '0';
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
if(c == '/') {
|
||||
/* Skip the slash */
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
/* Skip linear white spaces */
|
||||
while(c == ' ' || c == '\t') {
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
if(c != '*') {
|
||||
s->header.content_range.instance_length = 0;
|
||||
while(isdigit((int)c)) {
|
||||
s->header.content_range.instance_length =
|
||||
s->header.content_range.instance_length * 10 + c - '0';
|
||||
s->header_chars++;
|
||||
PT_YIELD(&s->headerpt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* All headers read, now read data */
|
||||
call_callback(s, HTTP_SOCKET_HEADER, (void *)&s->header, sizeof(s->header));
|
||||
|
||||
/* Should exit the pt here to indicate that all headers have been
|
||||
read */
|
||||
PT_EXIT(&s->headerpt);
|
||||
} else {
|
||||
if(s->header.status_code == 0x404) {
|
||||
printf("File not found\n");
|
||||
} else if(s->header.status_code == 0x301 || s->header.status_code == 0x302) {
|
||||
printf("File moved (not handled)\n");
|
||||
}
|
||||
|
||||
call_callback(s, HTTP_SOCKET_ERR, (void *)&s->header, sizeof(s->header));
|
||||
tcp_socket_close(&s->s);
|
||||
removesocket(s);
|
||||
PT_EXIT(&s->headerpt);
|
||||
}
|
||||
|
||||
|
||||
PT_END(&s->headerpt);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
input_pt(struct http_socket *s,
|
||||
const uint8_t *inputptr, int inputdatalen)
|
||||
{
|
||||
int i;
|
||||
PT_BEGIN(&s->pt);
|
||||
|
||||
/* Parse the header */
|
||||
s->header_received = 0;
|
||||
do {
|
||||
for(i = 0; i < inputdatalen; i++) {
|
||||
if(!PT_SCHEDULE(parse_header_byte(s, inputptr[i]))) {
|
||||
s->header_received = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
inputdatalen -= i;
|
||||
inputptr += i;
|
||||
|
||||
if(s->header_received == 0) {
|
||||
/* If we have not yet received the full header, we wait for the
|
||||
next packet to arrive. */
|
||||
PT_YIELD(&s->pt);
|
||||
}
|
||||
} while(s->header_received == 0);
|
||||
|
||||
s->bodylen = 0;
|
||||
do {
|
||||
/* Receive the data */
|
||||
call_callback(s, HTTP_SOCKET_DATA, inputptr, inputdatalen);
|
||||
|
||||
/* Close the connection if the expected content length has been received */
|
||||
if(s->header.content_length >= 0 && s->bodylen < s->header.content_length) {
|
||||
s->bodylen += inputdatalen;
|
||||
if(s->bodylen >= s->header.content_length) {
|
||||
tcp_socket_close(&s->s);
|
||||
}
|
||||
}
|
||||
|
||||
PT_YIELD(&s->pt);
|
||||
} while(inputdatalen > 0);
|
||||
|
||||
PT_END(&s->pt);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
start_timeout_timer(struct http_socket *s)
|
||||
{
|
||||
PROCESS_CONTEXT_BEGIN(&http_socket_process);
|
||||
etimer_set(&s->timeout_timer, HTTP_SOCKET_TIMEOUT);
|
||||
PROCESS_CONTEXT_END(&http_socket_process);
|
||||
s->timeout_timer_started = 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
input(struct tcp_socket *tcps, void *ptr,
|
||||
const uint8_t *inputptr, int inputdatalen)
|
||||
{
|
||||
struct http_socket *s = ptr;
|
||||
|
||||
input_pt(s, inputptr, inputdatalen);
|
||||
start_timeout_timer(s);
|
||||
|
||||
return 0; /* all data consumed */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
parse_url(const char *url, char *host, uint16_t *portptr, char *path)
|
||||
{
|
||||
const char *urlptr;
|
||||
int i;
|
||||
const char *file;
|
||||
uint16_t port;
|
||||
|
||||
if(url == NULL) {
|
||||
printf("null url\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't even try to go further if the URL is empty. */
|
||||
if(strlen(url) == 0) {
|
||||
printf("empty url\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* See if the URL starts with http:// and remove it. Otherwise, we
|
||||
assume it is an implicit http://. */
|
||||
if(strncmp(url, "http://", strlen("http://")) == 0) {
|
||||
urlptr = url + strlen("http://");
|
||||
} else {
|
||||
urlptr = url;
|
||||
}
|
||||
|
||||
/* Find host part of the URL. */
|
||||
if(*urlptr == '[') {
|
||||
/* Handle IPv6 addresses - scan for matching ']' */
|
||||
urlptr++;
|
||||
for(i = 0; i < MAX_HOSTLEN; ++i) {
|
||||
if(*urlptr == ']') {
|
||||
if(host != NULL) {
|
||||
host[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(host != NULL) {
|
||||
host[i] = *urlptr;
|
||||
}
|
||||
++urlptr;
|
||||
}
|
||||
} else {
|
||||
for(i = 0; i < MAX_HOSTLEN; ++i) {
|
||||
if(*urlptr == 0 ||
|
||||
*urlptr == '/' ||
|
||||
*urlptr == ' ' ||
|
||||
*urlptr == ':') {
|
||||
if(host != NULL) {
|
||||
host[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(host != NULL) {
|
||||
host[i] = *urlptr;
|
||||
}
|
||||
++urlptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the port. Default is 80. */
|
||||
port = 80;
|
||||
if(*urlptr == ':') {
|
||||
port = 0;
|
||||
do {
|
||||
++urlptr;
|
||||
if(*urlptr >= '0' && *urlptr <= '9') {
|
||||
port = (10 * port) + (*urlptr - '0');
|
||||
}
|
||||
} while(*urlptr >= '0' &&
|
||||
*urlptr <= '9');
|
||||
}
|
||||
if(portptr != NULL) {
|
||||
*portptr = port;
|
||||
}
|
||||
/* Find file part of the URL. */
|
||||
while(*urlptr != '/' && *urlptr != 0) {
|
||||
++urlptr;
|
||||
}
|
||||
if(*urlptr == '/') {
|
||||
file = urlptr;
|
||||
} else {
|
||||
file = "/";
|
||||
}
|
||||
if(path != NULL) {
|
||||
strncpy(path, file, MAX_PATHLEN);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
removesocket(struct http_socket *s)
|
||||
{
|
||||
etimer_stop(&s->timeout_timer);
|
||||
s->timeout_timer_started = 0;
|
||||
list_remove(socketlist, s);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
event(struct tcp_socket *tcps, void *ptr,
|
||||
tcp_socket_event_t e)
|
||||
{
|
||||
struct http_socket *s = ptr;
|
||||
char host[MAX_HOSTLEN];
|
||||
char path[MAX_PATHLEN];
|
||||
uint16_t port;
|
||||
char str[42];
|
||||
int len;
|
||||
|
||||
if(e == TCP_SOCKET_CONNECTED) {
|
||||
printf("Connected\n");
|
||||
if(parse_url(s->url, host, &port, path)) {
|
||||
tcp_socket_send_str(tcps, s->postdata != NULL ? "POST " : "GET ");
|
||||
if(s->proxy_port != 0) {
|
||||
/* If we are configured to route through a proxy, we should
|
||||
provide the full URL as the path. */
|
||||
tcp_socket_send_str(tcps, s->url);
|
||||
} else {
|
||||
tcp_socket_send_str(tcps, path);
|
||||
}
|
||||
tcp_socket_send_str(tcps, " HTTP/1.1\r\n");
|
||||
tcp_socket_send_str(tcps, "Connection: close\r\n");
|
||||
tcp_socket_send_str(tcps, "Host: ");
|
||||
tcp_socket_send_str(tcps, host);
|
||||
tcp_socket_send_str(tcps, "\r\n");
|
||||
if(s->postdata != NULL) {
|
||||
if(s->content_type) {
|
||||
tcp_socket_send_str(tcps, "Content-Type: ");
|
||||
tcp_socket_send_str(tcps, s->content_type);
|
||||
tcp_socket_send_str(tcps, "\r\n");
|
||||
}
|
||||
tcp_socket_send_str(tcps, "Content-Length: ");
|
||||
sprintf(str, "%u", s->postdatalen);
|
||||
tcp_socket_send_str(tcps, str);
|
||||
tcp_socket_send_str(tcps, "\r\n");
|
||||
} else if(s->length || s->pos > 0) {
|
||||
tcp_socket_send_str(tcps, "Range: bytes=");
|
||||
if(s->length) {
|
||||
if(s->pos >= 0) {
|
||||
sprintf(str, "%llu-%llu", s->pos, s->pos + s->length - 1);
|
||||
} else {
|
||||
sprintf(str, "-%llu", s->length);
|
||||
}
|
||||
} else {
|
||||
sprintf(str, "%llu-", s->pos);
|
||||
}
|
||||
tcp_socket_send_str(tcps, str);
|
||||
tcp_socket_send_str(tcps, "\r\n");
|
||||
}
|
||||
tcp_socket_send_str(tcps, "\r\n");
|
||||
if(s->postdata != NULL && s->postdatalen) {
|
||||
len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
|
||||
s->postdata += len;
|
||||
s->postdatalen -= len;
|
||||
}
|
||||
}
|
||||
parse_header_init(s);
|
||||
} else if(e == TCP_SOCKET_CLOSED) {
|
||||
call_callback(s, HTTP_SOCKET_CLOSED, NULL, 0);
|
||||
removesocket(s);
|
||||
printf("Closed\n");
|
||||
} else if(e == TCP_SOCKET_TIMEDOUT) {
|
||||
call_callback(s, HTTP_SOCKET_TIMEDOUT, NULL, 0);
|
||||
removesocket(s);
|
||||
printf("Timedout\n");
|
||||
} else if(e == TCP_SOCKET_ABORTED) {
|
||||
call_callback(s, HTTP_SOCKET_ABORTED, NULL, 0);
|
||||
removesocket(s);
|
||||
printf("Aborted\n");
|
||||
} else if(e == TCP_SOCKET_DATA_SENT) {
|
||||
if(s->postdata != NULL && s->postdatalen) {
|
||||
len = tcp_socket_send(tcps, s->postdata, s->postdatalen);
|
||||
s->postdata += len;
|
||||
s->postdatalen -= len;
|
||||
} else {
|
||||
start_timeout_timer(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int
|
||||
start_request(struct http_socket *s)
|
||||
{
|
||||
uip_ip4addr_t ip4addr;
|
||||
uip_ip6addr_t ip6addr;
|
||||
uip_ip6addr_t *addr;
|
||||
char host[MAX_HOSTLEN];
|
||||
char path[MAX_PATHLEN];
|
||||
uint16_t port;
|
||||
int ret;
|
||||
|
||||
if(parse_url(s->url, host, &port, path)) {
|
||||
|
||||
printf("url %s host %s port %d path %s\n",
|
||||
s->url, host, port, path);
|
||||
|
||||
/* Check if we are to route the request through a proxy. */
|
||||
if(s->proxy_port != 0) {
|
||||
/* The proxy address should be an IPv6 address. */
|
||||
uip_ip6addr_copy(&ip6addr, &s->proxy_addr);
|
||||
port = s->proxy_port;
|
||||
} else if(uiplib_ip6addrconv(host, &ip6addr) == 0) {
|
||||
/* First check if the host is an IP address. */
|
||||
if(uiplib_ip4addrconv(host, &ip4addr) != 0) {
|
||||
ip64_addr_4to6(&ip4addr, &ip6addr);
|
||||
} else {
|
||||
/* Try to lookup the hostname. If it fails, we initiate a hostname
|
||||
lookup. */
|
||||
ret = resolv_lookup(host, &addr);
|
||||
if(ret == RESOLV_STATUS_UNCACHED ||
|
||||
ret == RESOLV_STATUS_EXPIRED) {
|
||||
resolv_query(host);
|
||||
puts("Resolving host...");
|
||||
return HTTP_SOCKET_OK;
|
||||
}
|
||||
if(addr != NULL) {
|
||||
s->did_tcp_connect = 1;
|
||||
tcp_socket_connect(&s->s, addr, port);
|
||||
return HTTP_SOCKET_OK;
|
||||
} else {
|
||||
return HTTP_SOCKET_ERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
tcp_socket_connect(&s->s, &ip6addr, port);
|
||||
return HTTP_SOCKET_OK;
|
||||
} else {
|
||||
return HTTP_SOCKET_ERR;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(http_socket_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
|
||||
while(1) {
|
||||
|
||||
PROCESS_WAIT_EVENT();
|
||||
|
||||
if(ev == resolv_event_found && data != NULL) {
|
||||
struct http_socket *s;
|
||||
const char *name = data;
|
||||
/* Either found a hostname, or not. We need to go through the
|
||||
list of http sockets and figure out to which connection this
|
||||
reply corresponds, then either restart the HTTP get, or kill
|
||||
it (if no hostname was found). */
|
||||
for(s = list_head(socketlist);
|
||||
s != NULL;
|
||||
s = list_item_next(s)) {
|
||||
char host[MAX_HOSTLEN];
|
||||
if(s->did_tcp_connect) {
|
||||
/* We already connected, ignored */
|
||||
} else if(parse_url(s->url, host, NULL, NULL) &&
|
||||
strcmp(name, host) == 0) {
|
||||
if(resolv_lookup(name, NULL) == RESOLV_STATUS_CACHED) {
|
||||
/* Hostname found, restart get. */
|
||||
start_request(s);
|
||||
} else {
|
||||
/* Hostname not found, kill connection. */
|
||||
call_callback(s, HTTP_SOCKET_HOSTNAME_NOT_FOUND, NULL, 0);
|
||||
removesocket(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(ev == PROCESS_EVENT_TIMER) {
|
||||
struct http_socket *s;
|
||||
struct etimer *timeout_timer = data;
|
||||
/*
|
||||
* A socket time-out has occurred. We need to go through the list of HTTP
|
||||
* sockets and figure out to which socket this timer event corresponds,
|
||||
* then close this socket.
|
||||
*/
|
||||
for(s = list_head(socketlist);
|
||||
s != NULL;
|
||||
s = list_item_next(s)) {
|
||||
if(timeout_timer == &s->timeout_timer && s->timeout_timer_started) {
|
||||
tcp_socket_close(&s->s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
init(void)
|
||||
{
|
||||
static uint8_t inited = 0;
|
||||
if(inited == 0) {
|
||||
process_start(&http_socket_process, NULL);
|
||||
list_init(socketlist);
|
||||
inited = 1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
http_socket_init(struct http_socket *s)
|
||||
{
|
||||
init();
|
||||
uip_create_unspecified(&s->proxy_addr);
|
||||
s->proxy_port = 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
initialize_socket(struct http_socket *s)
|
||||
{
|
||||
s->pos = 0;
|
||||
s->length = 0;
|
||||
s->postdata = NULL;
|
||||
s->postdatalen = 0;
|
||||
s->timeout_timer_started = 0;
|
||||
PT_INIT(&s->pt);
|
||||
tcp_socket_register(&s->s, s,
|
||||
s->inputbuf, sizeof(s->inputbuf),
|
||||
s->outputbuf, sizeof(s->outputbuf),
|
||||
input, event);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
http_socket_get(struct http_socket *s,
|
||||
const char *url,
|
||||
int64_t pos,
|
||||
uint64_t length,
|
||||
http_socket_callback_t callback,
|
||||
void *callbackptr)
|
||||
{
|
||||
initialize_socket(s);
|
||||
strncpy(s->url, url, sizeof(s->url));
|
||||
s->pos = pos;
|
||||
s->length = length;
|
||||
s->callback = callback;
|
||||
s->callbackptr = callbackptr;
|
||||
|
||||
s->did_tcp_connect = 0;
|
||||
|
||||
list_add(socketlist, s);
|
||||
|
||||
return start_request(s);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
http_socket_post(struct http_socket *s,
|
||||
const char *url,
|
||||
const void *postdata,
|
||||
uint16_t postdatalen,
|
||||
const char *content_type,
|
||||
http_socket_callback_t callback,
|
||||
void *callbackptr)
|
||||
{
|
||||
initialize_socket(s);
|
||||
strncpy(s->url, url, sizeof(s->url));
|
||||
s->postdata = postdata;
|
||||
s->postdatalen = postdatalen;
|
||||
s->content_type = content_type;
|
||||
|
||||
s->callback = callback;
|
||||
s->callbackptr = callbackptr;
|
||||
|
||||
s->did_tcp_connect = 0;
|
||||
|
||||
list_add(socketlist, s);
|
||||
|
||||
return start_request(s);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
http_socket_close(struct http_socket *socket)
|
||||
{
|
||||
struct http_socket *s;
|
||||
for(s = list_head(socketlist);
|
||||
s != NULL;
|
||||
s = list_item_next(s)) {
|
||||
if(s == socket) {
|
||||
tcp_socket_close(&s->s);
|
||||
removesocket(s);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
http_socket_set_proxy(struct http_socket *s,
|
||||
const uip_ipaddr_t *addr, uint16_t port)
|
||||
{
|
||||
uip_ipaddr_copy(&s->proxy_addr, addr);
|
||||
s->proxy_port = port;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
121
core/net/http-socket/http-socket.h
Normal file
121
core/net/http-socket/http-socket.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2013, Thingsquare, http://www.thingsquare.com/.
|
||||
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT HOLDER 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 HTTP_SOCKET_H
|
||||
#define HTTP_SOCKET_H
|
||||
|
||||
#include "tcp-socket.h"
|
||||
|
||||
struct http_socket;
|
||||
|
||||
typedef enum {
|
||||
HTTP_SOCKET_ERR,
|
||||
HTTP_SOCKET_OK,
|
||||
HTTP_SOCKET_HEADER,
|
||||
HTTP_SOCKET_DATA,
|
||||
HTTP_SOCKET_CLOSED,
|
||||
HTTP_SOCKET_TIMEDOUT,
|
||||
HTTP_SOCKET_ABORTED,
|
||||
HTTP_SOCKET_HOSTNAME_NOT_FOUND,
|
||||
} http_socket_event_t;
|
||||
|
||||
struct http_socket_header {
|
||||
uint16_t status_code;
|
||||
int64_t content_length;
|
||||
struct {
|
||||
int64_t first_byte_pos;
|
||||
int64_t last_byte_pos;
|
||||
int64_t instance_length;
|
||||
} content_range;
|
||||
};
|
||||
|
||||
typedef void (* http_socket_callback_t)(struct http_socket *s,
|
||||
void *ptr,
|
||||
http_socket_event_t ev,
|
||||
const uint8_t *data,
|
||||
uint16_t datalen);
|
||||
|
||||
#define MAX(n, m) (((n) < (m)) ? (m) : (n))
|
||||
|
||||
#define HTTP_SOCKET_INPUTBUFSIZE UIP_TCP_MSS
|
||||
#define HTTP_SOCKET_OUTPUTBUFSIZE MAX(UIP_TCP_MSS, 128)
|
||||
|
||||
#define HTTP_SOCKET_URLLEN 128
|
||||
|
||||
#define HTTP_SOCKET_TIMEOUT ((2 * 60 + 30) * CLOCK_SECOND)
|
||||
|
||||
struct http_socket {
|
||||
struct http_socket *next;
|
||||
struct tcp_socket s;
|
||||
uip_ipaddr_t proxy_addr;
|
||||
uint16_t proxy_port;
|
||||
int64_t pos;
|
||||
uint64_t length;
|
||||
const uint8_t *postdata;
|
||||
uint16_t postdatalen;
|
||||
http_socket_callback_t callback;
|
||||
void *callbackptr;
|
||||
int did_tcp_connect;
|
||||
char url[HTTP_SOCKET_URLLEN];
|
||||
uint8_t inputbuf[HTTP_SOCKET_INPUTBUFSIZE];
|
||||
uint8_t outputbuf[HTTP_SOCKET_OUTPUTBUFSIZE];
|
||||
|
||||
struct etimer timeout_timer;
|
||||
uint8_t timeout_timer_started;
|
||||
struct pt pt, headerpt;
|
||||
int header_chars;
|
||||
char header_field[15];
|
||||
struct http_socket_header header;
|
||||
uint8_t header_received;
|
||||
uint64_t bodylen;
|
||||
const char *content_type;
|
||||
};
|
||||
|
||||
void http_socket_init(struct http_socket *s);
|
||||
|
||||
int http_socket_get(struct http_socket *s, const char *url,
|
||||
int64_t pos, uint64_t length,
|
||||
http_socket_callback_t callback,
|
||||
void *callbackptr);
|
||||
|
||||
int http_socket_post(struct http_socket *s, const char *url,
|
||||
const void *postdata,
|
||||
uint16_t postdatalen,
|
||||
const char *content_type,
|
||||
http_socket_callback_t callback,
|
||||
void *callbackptr);
|
||||
|
||||
int http_socket_close(struct http_socket *socket);
|
||||
|
||||
void http_socket_set_proxy(struct http_socket *s,
|
||||
const uip_ipaddr_t *addr, uint16_t port);
|
||||
|
||||
|
||||
#endif /* HTTP_SOCKET_H */
|
|
@ -787,7 +787,7 @@ newdata(void)
|
|||
|
||||
static int8_t i;
|
||||
|
||||
register struct namemap *namemapptr;
|
||||
register struct namemap *namemapptr = NULL;
|
||||
|
||||
struct dns_answer *ans;
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ slipdev_send(void)
|
|||
ptr = &uip_buf[UIP_LLH_LEN];
|
||||
for(i = 0; i < uip_len; ++i) {
|
||||
if(i == UIP_TCPIP_HLEN) {
|
||||
ptr = (char *)uip_appdata;
|
||||
ptr = (uint8_t *)uip_appdata;
|
||||
}
|
||||
c = *ptr++;
|
||||
switch(c) {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "sys/cc.h"
|
||||
#include "contiki-net.h"
|
||||
|
||||
#include "lib/list.h"
|
||||
|
@ -39,7 +40,8 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static void relisten(struct tcp_socket *s);
|
||||
|
||||
LIST(socketlist);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -58,8 +60,8 @@ senddata(struct tcp_socket *s)
|
|||
{
|
||||
int len = MIN(s->output_data_max_seg, uip_mss());
|
||||
|
||||
if(s->output_data_len > 0) {
|
||||
len = MIN(s->output_data_len, len);
|
||||
if(s->output_senddata_len > 0) {
|
||||
len = MIN(s->output_senddata_len, len);
|
||||
s->output_data_send_nxt = len;
|
||||
uip_send(s->output_data_ptr, len);
|
||||
}
|
||||
|
@ -68,21 +70,27 @@ senddata(struct tcp_socket *s)
|
|||
static void
|
||||
acked(struct tcp_socket *s)
|
||||
{
|
||||
if(s->output_data_len > 0) {
|
||||
if(s->output_senddata_len > 0) {
|
||||
/* Copy the data in the outputbuf down and update outputbufptr and
|
||||
outputbuf_lastsent */
|
||||
|
||||
if(s->output_data_send_nxt > 0) {
|
||||
memcpy(&s->output_data_ptr[0],
|
||||
&s->output_data_ptr[s->output_data_send_nxt],
|
||||
s->output_data_maxlen - s->output_data_send_nxt);
|
||||
&s->output_data_ptr[s->output_data_send_nxt],
|
||||
s->output_data_maxlen - s->output_data_send_nxt);
|
||||
}
|
||||
if(s->output_data_len < s->output_data_send_nxt) {
|
||||
printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
|
||||
s->output_data_len,
|
||||
s->output_data_send_nxt);
|
||||
s->output_data_len,
|
||||
s->output_data_send_nxt);
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
uip_abort();
|
||||
call_event(s, TCP_SOCKET_ABORTED);
|
||||
relisten(s);
|
||||
return;
|
||||
}
|
||||
s->output_data_len -= s->output_data_send_nxt;
|
||||
s->output_senddata_len = s->output_data_len;
|
||||
s->output_data_send_nxt = 0;
|
||||
|
||||
call_event(s, TCP_SOCKET_DATA_SENT);
|
||||
|
@ -134,6 +142,11 @@ appcall(void *state)
|
|||
{
|
||||
struct tcp_socket *s = state;
|
||||
|
||||
if(s != NULL && s->c != NULL && s->c != uip_conn) {
|
||||
/* Safe-guard: this should not happen, as the incoming event relates to
|
||||
* a previous connection */
|
||||
return;
|
||||
}
|
||||
if(uip_connected()) {
|
||||
/* Check if this connection originated in a local listen
|
||||
socket. We do this by checking the state pointer - if NULL,
|
||||
|
@ -176,8 +189,10 @@ appcall(void *state)
|
|||
}
|
||||
|
||||
if(uip_aborted()) {
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
call_event(s, TCP_SOCKET_ABORTED);
|
||||
relisten(s);
|
||||
|
||||
}
|
||||
|
||||
if(s == NULL) {
|
||||
|
@ -203,13 +218,16 @@ appcall(void *state)
|
|||
if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
|
||||
s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
|
||||
uip_close();
|
||||
s->c = NULL;
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
call_event(s, TCP_SOCKET_CLOSED);
|
||||
s->c = NULL;
|
||||
/*call_event(s, TCP_SOCKET_CLOSED);*/
|
||||
relisten(s);
|
||||
}
|
||||
|
||||
if(uip_closed()) {
|
||||
tcp_markconn(uip_conn, NULL);
|
||||
s->c = NULL;
|
||||
call_event(s, TCP_SOCKET_CLOSED);
|
||||
relisten(s);
|
||||
}
|
||||
|
@ -255,6 +273,7 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||
s->ptr = ptr;
|
||||
s->input_data_ptr = input_databuf;
|
||||
s->input_data_maxlen = input_databuf_len;
|
||||
s->output_data_len = 0;
|
||||
s->output_data_ptr = output_databuf;
|
||||
s->output_data_maxlen = output_databuf_len;
|
||||
s->input_callback = input_callback;
|
||||
|
@ -268,12 +287,15 @@ tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_connect(struct tcp_socket *s,
|
||||
uip_ipaddr_t *ipaddr,
|
||||
uint16_t port)
|
||||
const uip_ipaddr_t *ipaddr,
|
||||
uint16_t port)
|
||||
{
|
||||
if(s == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if(s->c != NULL) {
|
||||
tcp_markconn(s->c, NULL);
|
||||
}
|
||||
PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
|
||||
s->c = tcp_connect(ipaddr, uip_htons(port), s);
|
||||
PROCESS_CONTEXT_END();
|
||||
|
@ -317,7 +339,7 @@ tcp_socket_unlisten(struct tcp_socket *s)
|
|||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_send(struct tcp_socket *s,
|
||||
const uint8_t *data, int datalen)
|
||||
const uint8_t *data, int datalen)
|
||||
{
|
||||
int len;
|
||||
|
||||
|
@ -329,6 +351,11 @@ tcp_socket_send(struct tcp_socket *s,
|
|||
|
||||
memcpy(&s->output_data_ptr[s->output_data_len], data, len);
|
||||
s->output_data_len += len;
|
||||
|
||||
if(s->output_senddata_len == 0) {
|
||||
s->output_senddata_len = s->output_data_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -365,3 +392,9 @@ tcp_socket_unregister(struct tcp_socket *s)
|
|||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
tcp_socket_max_sendlen(struct tcp_socket *s)
|
||||
{
|
||||
return s->output_data_maxlen - s->output_data_len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#ifndef TCP_SOCKET_H
|
||||
#define TCP_SOCKET_H
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
struct tcp_socket;
|
||||
|
||||
typedef enum {
|
||||
|
@ -95,6 +97,7 @@ struct tcp_socket {
|
|||
uint16_t output_data_maxlen;
|
||||
uint16_t output_data_len;
|
||||
uint16_t output_data_send_nxt;
|
||||
uint16_t output_senddata_len;
|
||||
uint16_t output_data_max_seg;
|
||||
|
||||
uint8_t flags;
|
||||
|
@ -170,7 +173,7 @@ int tcp_socket_register(struct tcp_socket *s, void *ptr,
|
|||
*
|
||||
*/
|
||||
int tcp_socket_connect(struct tcp_socket *s,
|
||||
uip_ipaddr_t *ipaddr,
|
||||
const uip_ipaddr_t *ipaddr,
|
||||
uint16_t port);
|
||||
|
||||
/**
|
||||
|
@ -266,4 +269,19 @@ int tcp_socket_close(struct tcp_socket *s);
|
|||
*
|
||||
*/
|
||||
int tcp_socket_unregister(struct tcp_socket *s);
|
||||
|
||||
/**
|
||||
* \brief The maximum amount of data that could currently be sent
|
||||
* \param s A pointer to a TCP socket
|
||||
* \return The number of bytes available in the output buffer
|
||||
*
|
||||
* This function queries the TCP socket and returns the
|
||||
* number of bytes available in the output buffer. This
|
||||
* function is used before calling tcp_socket_send() to
|
||||
* ensure that one application level message can be held
|
||||
* in the output buffer.
|
||||
*
|
||||
*/
|
||||
int tcp_socket_max_sendlen(struct tcp_socket *s);
|
||||
|
||||
#endif /* TCP_SOCKET_H */
|
||||
|
|
|
@ -228,7 +228,7 @@ packet_input(void)
|
|||
#if UIP_TCP
|
||||
#if UIP_ACTIVE_OPEN
|
||||
struct uip_conn *
|
||||
tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
|
||||
tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
|
||||
{
|
||||
struct uip_conn *c;
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ CCIF void tcp_unlisten(uint16_t port);
|
|||
* memory could not be allocated for the connection.
|
||||
*
|
||||
*/
|
||||
CCIF struct uip_conn *tcp_connect(uip_ipaddr_t *ripaddr, uint16_t port,
|
||||
CCIF struct uip_conn *tcp_connect(const uip_ipaddr_t *ripaddr, uint16_t port,
|
||||
void *appstate);
|
||||
|
||||
/**
|
||||
|
|
|
@ -600,7 +600,7 @@ void uip_unlisten(uint16_t port);
|
|||
* or NULL if no connection could be allocated.
|
||||
*
|
||||
*/
|
||||
struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, uint16_t port);
|
||||
struct uip_conn *uip_connect(const uip_ipaddr_t *ripaddr, uint16_t port);
|
||||
|
||||
|
||||
|
||||
|
@ -1030,10 +1030,10 @@ struct uip_udp_conn *uip_udp_new(const uip_ipaddr_t *ripaddr, uint16_t rport);
|
|||
#define uip_ipaddr_copy(dest, src) (*(dest) = *(src))
|
||||
#endif
|
||||
#ifndef uip_ip4addr_copy
|
||||
#define uip_ip4addr_copy(dest, src) (*(dest) = *(src))
|
||||
#define uip_ip4addr_copy(dest, src) (*((uip_ip4addr_t *)dest) = *((uip_ip4addr_t *)src))
|
||||
#endif
|
||||
#ifndef uip_ip6addr_copy
|
||||
#define uip_ip6addr_copy(dest, src) (*(dest) = *(src))
|
||||
#define uip_ip6addr_copy(dest, src) (*((uip_ip6addr_t *)dest) = *((uip_ip6addr_t *)src))
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
The `ip64-addr` module converts between IPv4 addresses and
|
||||
IPv4-encoded IPv6 addresses. It is used in IPv6 networks that are
|
||||
attached to the IPv4 world through an `ip64` router. With such a
|
||||
router, IPv6 nodes in the network can reach IPv4 nodes by using their
|
||||
IPv6-encoded address.
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
@ -148,6 +149,7 @@ ip64_addrmap_lookup(const uip_ip6addr_t *ip6addr,
|
|||
m->ip6port == ip6port &&
|
||||
uip_ip4addr_cmp(&m->ip4addr, ip4addr) &&
|
||||
uip_ip6addr_cmp(&m->ip6addr, ip6addr)) {
|
||||
m->ip6to4++;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +168,7 @@ ip64_addrmap_lookup_port(uint16_t mapped_port, uint8_t protocol)
|
|||
m->protocol, protocol);
|
||||
if(m->mapped_port == mapped_port &&
|
||||
m->protocol == protocol) {
|
||||
m->ip4to6++;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +207,8 @@ ip64_addrmap_create(const uip_ip6addr_t *ip6addr,
|
|||
m->ip6port = ip6port;
|
||||
m->protocol = protocol;
|
||||
m->flags = FLAGS_NONE;
|
||||
m->ip6to4 = 1;
|
||||
m->ip4to6 = 0;
|
||||
timer_set(&m->timer, 0);
|
||||
|
||||
/* Pick a new, unused local port. First make sure that the
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
@ -40,6 +41,7 @@ struct ip64_addrmap_entry {
|
|||
struct timer timer;
|
||||
uip_ip6addr_t ip6addr;
|
||||
uip_ip4addr_t ip4addr;
|
||||
uint32_t ip6to4, ip4to6;
|
||||
uint16_t mapped_port;
|
||||
uint16_t ip6port;
|
||||
uint16_t ip4port;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
259
core/net/ip64/ip64-dns64.c
Normal file
259
core/net/ip64/ip64-dns64.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
|
||||
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT HOLDER 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ip64.h"
|
||||
#include "ip64-addr.h"
|
||||
#include "ip64-dns64.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#undef PRINTF
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else /* DEBUG */
|
||||
#define PRINTF(...)
|
||||
#endif /* DEBUG */
|
||||
|
||||
struct dns_hdr {
|
||||
uint8_t id[2];
|
||||
uint8_t flags1, flags2;
|
||||
#define DNS_FLAG1_RESPONSE 0x80
|
||||
#define DNS_FLAG1_OPCODE_STATUS 0x10
|
||||
#define DNS_FLAG1_OPCODE_INVERSE 0x08
|
||||
#define DNS_FLAG1_OPCODE_STANDARD 0x00
|
||||
#define DNS_FLAG1_AUTHORATIVE 0x04
|
||||
#define DNS_FLAG1_TRUNC 0x02
|
||||
#define DNS_FLAG1_RD 0x01
|
||||
#define DNS_FLAG2_RA 0x80
|
||||
#define DNS_FLAG2_ERR_MASK 0x0f
|
||||
#define DNS_FLAG2_ERR_NONE 0x00
|
||||
#define DNS_FLAG2_ERR_NAME 0x03
|
||||
uint8_t numquestions[2];
|
||||
uint8_t numanswers[2];
|
||||
uint8_t numauthrr[2];
|
||||
uint8_t numextrarr[2];
|
||||
};
|
||||
|
||||
#define DNS_QUESTION_TYPE0 0
|
||||
#define DNS_QUESTION_TYPE1 1
|
||||
#define DNS_QUESTION_CLASS0 2
|
||||
#define DNS_QUESTION_CLASS1 3
|
||||
#define DNS_QUESTION_SIZE 4
|
||||
|
||||
struct dns_answer {
|
||||
/* DNS answer record starts with either a domain name or a pointer
|
||||
* to a name already present somewhere in the packet. */
|
||||
uint8_t type[2];
|
||||
uint8_t class[2];
|
||||
uint8_t ttl[4];
|
||||
uint8_t len[2];
|
||||
union {
|
||||
uint8_t ip6[16];
|
||||
uint8_t ip4[4];
|
||||
} addr;
|
||||
};
|
||||
|
||||
#define DNS_TYPE_A 1
|
||||
#define DNS_TYPE_AAAA 28
|
||||
|
||||
#define DNS_CLASS_IN 1
|
||||
#define DNS_CLASS_ANY 255
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ip64_dns64_6to4(const uint8_t *ipv6data, int ipv6datalen,
|
||||
uint8_t *ipv4data, int ipv4datalen)
|
||||
{
|
||||
int i, j;
|
||||
int qlen;
|
||||
uint8_t *qdata;
|
||||
uint8_t *q;
|
||||
struct dns_hdr *hdr;
|
||||
|
||||
hdr = (struct dns_hdr *)ipv4data;
|
||||
PRINTF("ip64_dns64_6to4 id: %02x%02x\n", hdr->id[0], hdr->id[1]);
|
||||
PRINTF("ip64_dns64_6to4 flags1: 0x%02x\n", hdr->flags1);
|
||||
PRINTF("ip64_dns64_6to4 flags2: 0x%02x\n", hdr->flags2);
|
||||
PRINTF("ip64_dns64_6to4 numquestions: 0x%02x\n", ((hdr->numquestions[0] << 8) + hdr->numquestions[1]));
|
||||
PRINTF("ip64_dns64_6to4 numanswers: 0x%02x\n", ((hdr->numanswers[0] << 8) + hdr->numanswers[1]));
|
||||
PRINTF("ip64_dns64_6to4 numauthrr: 0x%02x\n", ((hdr->numauthrr[0] << 8) + hdr->numauthrr[1]));
|
||||
PRINTF("ip64_dns64_6to4 numextrarr: 0x%02x\n", ((hdr->numextrarr[0] << 8) + hdr->numextrarr[1]));
|
||||
|
||||
/* Find the DNS question header by scanning through the question
|
||||
labels. */
|
||||
qdata = ipv4data + sizeof(struct dns_hdr);
|
||||
for(i = 0; i < ((hdr->numquestions[0] << 8) + hdr->numquestions[1]); i++) {
|
||||
do {
|
||||
qlen = *qdata;
|
||||
qdata++;
|
||||
for(j = 0; j < qlen; j++) {
|
||||
qdata++;
|
||||
if(qdata > ipv4data + ipv4datalen) {
|
||||
PRINTF("ip64_dns64_6to4: packet ended while parsing\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while(qlen != 0);
|
||||
q = qdata;
|
||||
if(q[DNS_QUESTION_CLASS0] == 0 && q[DNS_QUESTION_CLASS1] == DNS_CLASS_IN &&
|
||||
q[DNS_QUESTION_TYPE0] == 0 && q[DNS_QUESTION_TYPE1] == DNS_TYPE_AAAA) {
|
||||
q[DNS_QUESTION_TYPE1] = DNS_TYPE_A;
|
||||
}
|
||||
|
||||
qdata += DNS_QUESTION_SIZE;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
ip64_dns64_4to6(const uint8_t *ipv4data, int ipv4datalen,
|
||||
uint8_t *ipv6data, int ipv6datalen)
|
||||
{
|
||||
uint8_t n;
|
||||
int i, j;
|
||||
int qlen, len;
|
||||
const uint8_t *qdata, *adata;
|
||||
uint8_t *qcopy, *acopy, *lenptr;
|
||||
uint8_t *q;
|
||||
struct dns_hdr *hdr;
|
||||
|
||||
hdr = (struct dns_hdr *)ipv4data;
|
||||
PRINTF("ip64_dns64_4to6 id: %02x%02x\n", hdr->id[0], hdr->id[1]);
|
||||
PRINTF("ip64_dns64_4to6 flags1: 0x%02x\n", hdr->flags1);
|
||||
PRINTF("ip64_dns64_4to6 flags2: 0x%02x\n", hdr->flags2);
|
||||
PRINTF("ip64_dns64_4to6 numquestions: 0x%02x\n", ((hdr->numquestions[0] << 8) + hdr->numquestions[1]));
|
||||
PRINTF("ip64_dns64_4to6 numanswers: 0x%02x\n", ((hdr->numanswers[0] << 8) + hdr->numanswers[1]));
|
||||
PRINTF("ip64_dns64_4to6 numauthrr: 0x%02x\n", ((hdr->numauthrr[0] << 8) + hdr->numauthrr[1]));
|
||||
PRINTF("ip64_dns64_4to6 numextrarr: 0x%02x\n", ((hdr->numextrarr[0] << 8) + hdr->numextrarr[1]));
|
||||
|
||||
/* Find the DNS answer header by scanning through the question
|
||||
labels. */
|
||||
qdata = ipv4data + sizeof(struct dns_hdr);
|
||||
qcopy = ipv6data + sizeof(struct dns_hdr);
|
||||
for(i = 0; i < ((hdr->numquestions[0] << 8) + hdr->numquestions[1]); i++) {
|
||||
do {
|
||||
qlen = *qdata;
|
||||
qdata++;
|
||||
qcopy++;
|
||||
for(j = 0; j < qlen; j++) {
|
||||
qdata++;
|
||||
qcopy++;
|
||||
if(qdata > ipv4data + ipv4datalen) {
|
||||
PRINTF("ip64_dns64_4to6: packet ended while parsing\n");
|
||||
return ipv6datalen;
|
||||
}
|
||||
}
|
||||
} while(qlen != 0);
|
||||
q = qcopy;
|
||||
if(q[DNS_QUESTION_CLASS0] == 0 && q[DNS_QUESTION_CLASS1] == DNS_CLASS_IN &&
|
||||
q[DNS_QUESTION_TYPE0] == 0 && q[DNS_QUESTION_TYPE1] == DNS_TYPE_AAAA) {
|
||||
q[DNS_QUESTION_TYPE1] = DNS_TYPE_AAAA;
|
||||
}
|
||||
|
||||
qdata += DNS_QUESTION_SIZE;
|
||||
qcopy += DNS_QUESTION_SIZE;
|
||||
}
|
||||
|
||||
adata = qdata;
|
||||
acopy = qcopy;
|
||||
|
||||
/* Go through the answers section and update the answers. */
|
||||
for(i = 0; i < ((hdr->numanswers[0] << 8) + hdr->numanswers[1]); i++) {
|
||||
|
||||
n = *adata;
|
||||
if(n & 0xc0) {
|
||||
/* Short-hand name format: 2 bytes */
|
||||
*acopy++ = *adata++;
|
||||
*acopy++ = *adata++;
|
||||
} else {
|
||||
/* Name spelled out */
|
||||
do {
|
||||
n = *adata;
|
||||
adata++;
|
||||
acopy++;
|
||||
for(j = 0; j < n; j++) {
|
||||
*acopy++ = *adata++;
|
||||
}
|
||||
} while(n != 0);
|
||||
}
|
||||
|
||||
if(adata[0] == 0 && adata[1] == DNS_TYPE_A) {
|
||||
/* Update the type field from A to AAAA */
|
||||
*acopy = *adata;
|
||||
acopy++;
|
||||
adata++;
|
||||
*acopy = DNS_TYPE_AAAA;
|
||||
acopy++;
|
||||
adata++;
|
||||
|
||||
/* Get the length of the address record. Should be 4. */
|
||||
lenptr = &acopy[6];
|
||||
len = (adata[6] << 8) + adata[7];
|
||||
|
||||
/* Copy the class, the TTL, and the data length */
|
||||
memcpy(acopy, adata, 2 + 4 + 2);
|
||||
acopy += 8;
|
||||
adata += 8;
|
||||
|
||||
if(len == 4) {
|
||||
uip_ip4addr_t addr;
|
||||
uip_ipaddr(&addr, adata[0], adata[1], adata[2], adata[3]);
|
||||
ip64_addr_4to6(&addr, (uip_ip6addr_t *)acopy);
|
||||
|
||||
adata += len;
|
||||
acopy += 16;
|
||||
lenptr[0] = 0;
|
||||
lenptr[1] = 16;
|
||||
ipv6datalen += 12;
|
||||
|
||||
} else {
|
||||
memcpy(acopy, adata, len);
|
||||
acopy += len;
|
||||
adata += len;
|
||||
}
|
||||
} else {
|
||||
len = (adata[8] << 8) + adata[9];
|
||||
|
||||
/* Copy the type, class, the TTL, and the data length */
|
||||
memcpy(acopy, adata, 2 + 2 + 4 + 2);
|
||||
acopy += 10;
|
||||
adata += 10;
|
||||
|
||||
/* Copy the data */
|
||||
memcpy(acopy, adata, len);
|
||||
acopy += len;
|
||||
adata += len;
|
||||
}
|
||||
}
|
||||
return ipv6datalen;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
40
core/net/ip64/ip64-dns64.h
Normal file
40
core/net/ip64/ip64-dns64.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
|
||||
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT HOLDER 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 IP64_DNS64_H_
|
||||
#define IP64_DNS64_H_
|
||||
|
||||
void ip64_dns64_6to4(const uint8_t *ipv6data, int ipv6datalen,
|
||||
uint8_t *ipv4data, int ipv4datalen);
|
||||
int ip64_dns64_4to6(const uint8_t *ipv4data, int ipv4datalen,
|
||||
uint8_t *ipv6data, int ipv6datalen);
|
||||
|
||||
#endif /* IP64_DNS64_H_ */
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
@ -58,7 +59,8 @@
|
|||
#include "ip64-special-ports.h"
|
||||
#include "ip64-eth-interface.h"
|
||||
#include "ip64-slip-interface.h"
|
||||
|
||||
#include "ip64-dns64.h"
|
||||
#include "net/ipv6/uip-ds6.h"
|
||||
#include "ip64-ipv4-dhcp.h"
|
||||
#include "contiki-net.h"
|
||||
|
||||
|
@ -172,6 +174,8 @@ static uip_ip4addr_t ipv4_broadcast_addr;
|
|||
#define TCP_SYN 0x02
|
||||
#define TCP_RST 0x04
|
||||
|
||||
#define DNS_PORT 53
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
ip64_init(void)
|
||||
|
@ -366,7 +370,7 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
|||
struct icmpv6_hdr *icmpv6hdr;
|
||||
uint16_t ipv6len, ipv4len;
|
||||
struct ip64_addrmap_entry *m;
|
||||
|
||||
|
||||
v6hdr = (struct ipv6_hdr *)ipv6packet;
|
||||
v4hdr = (struct ipv4_hdr *)resultpacket;
|
||||
|
||||
|
@ -434,6 +438,15 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
|||
case IP_PROTO_UDP:
|
||||
PRINTF("ip64_6to4: UDP header\n");
|
||||
v4hdr->proto = IP_PROTO_UDP;
|
||||
|
||||
/* Check if this is a DNS request. If so, we should rewrite it
|
||||
with the DNS64 module. */
|
||||
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
|
||||
ip64_dns64_6to4((uint8_t *)v6hdr + IPV6_HDRLEN + sizeof(struct udp_hdr),
|
||||
ipv6len - IPV6_HDRLEN - sizeof(struct udp_hdr),
|
||||
(uint8_t *)udphdr + sizeof(struct udp_hdr),
|
||||
BUFSIZE - IPV4_HDRLEN - sizeof(struct udp_hdr));
|
||||
}
|
||||
/* Compute and check the UDP checksum - since we're going to
|
||||
recompute it ourselves, we must ensure that it was correct in
|
||||
the first place. */
|
||||
|
@ -572,9 +585,18 @@ ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len,
|
|||
} else {
|
||||
ip64_addrmap_set_lifetime(m, DEFAULT_LIFETIME);
|
||||
|
||||
/* Treat DNS requests specially: since the are one-shot, we
|
||||
/* Treat UDP packets from the IPv6 network to a multicast
|
||||
address on the IPv4 network differently: since there is
|
||||
no way for packets from the IPv4 network to go back to
|
||||
the IPv6 network on these mappings, we'll mark them as
|
||||
recyclable. */
|
||||
if(v4hdr->destipaddr.u8[0] == 224) {
|
||||
ip64_addrmap_set_recycleble(m);
|
||||
}
|
||||
|
||||
/* Treat DNS requests differently: since the are one-shot, we
|
||||
mark them as recyclable. */
|
||||
if(udphdr->destport == UIP_HTONS(53)) {
|
||||
if(udphdr->destport == UIP_HTONS(DNS_PORT)) {
|
||||
ip64_addrmap_set_recycleble(m);
|
||||
}
|
||||
}
|
||||
|
@ -706,6 +728,21 @@ ip64_4to6(const uint8_t *ipv4packet, const uint16_t ipv4packet_len,
|
|||
switch(v4hdr->proto) {
|
||||
case IP_PROTO_UDP:
|
||||
v6hdr->nxthdr = IP_PROTO_UDP;
|
||||
/* Check if this is a DNS request. If so, we should rewrite it
|
||||
with the DNS64 module. */
|
||||
if(udphdr->srcport == UIP_HTONS(DNS_PORT)) {
|
||||
int len;
|
||||
|
||||
len = ip64_dns64_4to6((uint8_t *)v4hdr + IPV4_HDRLEN + sizeof(struct udp_hdr),
|
||||
ipv4len - IPV4_HDRLEN - sizeof(struct udp_hdr),
|
||||
(uint8_t *)v6hdr + IPV6_HDRLEN + sizeof(struct udp_hdr),
|
||||
ipv6_packet_len - sizeof(struct udp_hdr));
|
||||
ipv6_packet_len = len + sizeof(struct udp_hdr);
|
||||
v6hdr->len[0] = ipv6_packet_len >> 8;
|
||||
v6hdr->len[1] = ipv6_packet_len & 0xff;
|
||||
ipv6len = ipv6_packet_len + IPV6_HDRLEN;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case IP_PROTO_TCP:
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* 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 copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
|
|
|
@ -262,8 +262,8 @@ uip_over_mesh_send(void)
|
|||
if(BUF->proto == UIP_PROTO_TCP) {
|
||||
#if NETSTACK_CONF_WITH_RIME
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_ERELIABLE, 1);
|
||||
#endif /* NETSTACK_CONF_WITH_RIME */
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
|
||||
#endif /* NETSTACK_CONF_WITH_RIME */
|
||||
/* packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, PACKETBUF_ATTR_PACKET_TYPE_STREAM);*/
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,8 @@
|
|||
#include "net/ipv4/uip-neighbor.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "sys/cc.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Variable definitions. */
|
||||
|
||||
|
@ -386,7 +388,7 @@ uip_init(void)
|
|||
/*---------------------------------------------------------------------------*/
|
||||
#if UIP_ACTIVE_OPEN
|
||||
struct uip_conn *
|
||||
uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
{
|
||||
register struct uip_conn *conn, *cconn;
|
||||
|
||||
|
@ -1953,7 +1955,6 @@ void
|
|||
uip_send(const void *data, int len)
|
||||
{
|
||||
int copylen;
|
||||
#define MIN(a,b) ((a) < (b)? (a): (b))
|
||||
copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN -
|
||||
(int)((char *)uip_sappdata - (char *)&uip_buf[UIP_LLH_LEN + UIP_TCPIP_HLEN]));
|
||||
if(copylen > 0) {
|
||||
|
|
|
@ -1336,11 +1336,6 @@ send_packet(linkaddr_t *dest)
|
|||
packetbuf_set_addr(PACKETBUF_ADDR_SENDER,(void*)&uip_lladdr);
|
||||
#endif
|
||||
|
||||
/* Force acknowledge from sender (test hardware autoacks) */
|
||||
#if SICSLOWPAN_CONF_ACK_ALL
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, 1);
|
||||
#endif
|
||||
|
||||
/* Provide a callback function to receive the result of
|
||||
a packet transmission. */
|
||||
NETSTACK_LLSEC.send(&packet_sent, NULL);
|
||||
|
@ -1388,6 +1383,7 @@ output(const uip_lladdr_t *localdest)
|
|||
set_packet_attrs();
|
||||
}
|
||||
|
||||
#if PACKETBUF_WITH_PACKET_TYPE
|
||||
#define TCP_FIN 0x01
|
||||
#define TCP_ACK 0x10
|
||||
#define TCP_CTL 0x3f
|
||||
|
@ -1402,6 +1398,7 @@ output(const uip_lladdr_t *localdest)
|
|||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM_END);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The destination address will be tagged to each outbound
|
||||
|
|
|
@ -280,7 +280,7 @@ uip_ds6_route_add(uip_ipaddr_t *ipaddr, uint8_t length,
|
|||
if(r != NULL) {
|
||||
uip_ipaddr_t *current_nexthop;
|
||||
current_nexthop = uip_ds6_route_nexthop(r);
|
||||
if(uip_ipaddr_cmp(nexthop, current_nexthop)) {
|
||||
if(current_nexthop != NULL && uip_ipaddr_cmp(nexthop, current_nexthop)) {
|
||||
/* no need to update route - already correct! */
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -116,17 +116,20 @@ void uip_log(char *msg);
|
|||
#define UIP_ND6_OPT_RDNSS_BUF ((uip_nd6_opt_dns *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset])
|
||||
/** @} */
|
||||
|
||||
#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER
|
||||
static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/
|
||||
static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */
|
||||
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
|
||||
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
|
||||
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
|
||||
#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */
|
||||
|
||||
#if !UIP_CONF_ROUTER // TBD see if we move it to ra_input
|
||||
static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */
|
||||
static uip_ipaddr_t ipaddr;
|
||||
static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
|
||||
#endif
|
||||
static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/
|
||||
static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */
|
||||
static uip_ds6_addr_t *addr; /** Pointer to an interface address */
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* create a llao */
|
||||
static void
|
||||
|
@ -141,7 +144,7 @@ create_llao(uint8_t *llao, uint8_t type) {
|
|||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#if UIP_ND6_SEND_NA
|
||||
static void
|
||||
ns_input(void)
|
||||
{
|
||||
|
@ -321,7 +324,7 @@ discard:
|
|||
uip_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* UIP_ND6_SEND_NA */
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
@ -387,6 +390,7 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
|
|||
PRINTF("\n");
|
||||
return;
|
||||
}
|
||||
#if UIP_ND6_SEND_NA
|
||||
/*------------------------------------------------------------------*/
|
||||
/**
|
||||
* Neighbor Advertisement Processing
|
||||
|
@ -556,7 +560,7 @@ discard:
|
|||
uip_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* UIP_ND6_SEND_NA */
|
||||
|
||||
#if UIP_CONF_ROUTER
|
||||
#if UIP_ND6_SEND_RA
|
||||
|
@ -859,7 +863,7 @@ ra_input(void)
|
|||
(uip_lladdr_t *)&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
|
||||
1, NBR_STALE);
|
||||
} else {
|
||||
uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr);
|
||||
uip_lladdr_t *lladdr = (uip_lladdr_t *)uip_ds6_nbr_get_ll(nbr);
|
||||
if(nbr->state == NBR_INCOMPLETE) {
|
||||
nbr->state = NBR_STALE;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
* the packet back to the peer.
|
||||
*/
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include "net/ip/uip.h"
|
||||
#include "net/ip/uipopt.h"
|
||||
#include "net/ipv6/uip-icmp6.h"
|
||||
|
@ -459,7 +460,7 @@ uip_init(void)
|
|||
/*---------------------------------------------------------------------------*/
|
||||
#if UIP_TCP && UIP_ACTIVE_OPEN
|
||||
struct uip_conn *
|
||||
uip_connect(uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
uip_connect(const uip_ipaddr_t *ripaddr, uint16_t rport)
|
||||
{
|
||||
register struct uip_conn *conn, *cconn;
|
||||
|
||||
|
@ -2332,7 +2333,6 @@ void
|
|||
uip_send(const void *data, int len)
|
||||
{
|
||||
int copylen;
|
||||
#define MIN(a,b) ((a) < (b)? (a): (b))
|
||||
|
||||
if(uip_sappdata != NULL) {
|
||||
copylen = MIN(len, UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN -
|
||||
|
|
|
@ -229,10 +229,6 @@ static struct compower_activity current_packet;
|
|||
|
||||
#define DEFAULT_STREAM_TIME (4 * CYCLE_TIME)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
#if CONTIKIMAC_CONF_BROADCAST_RATE_LIMIT
|
||||
static struct timer broadcast_rate_timer;
|
||||
static int broadcast_rate_counter;
|
||||
|
@ -341,7 +337,6 @@ powercycle(struct rtimer *t, void *ptr)
|
|||
|
||||
while(1) {
|
||||
static uint8_t packet_seen;
|
||||
static rtimer_clock_t t0;
|
||||
static uint8_t count;
|
||||
|
||||
#if SYNC_CYCLE_STARTS
|
||||
|
@ -365,7 +360,6 @@ powercycle(struct rtimer *t, void *ptr)
|
|||
packet_seen = 0;
|
||||
|
||||
for(count = 0; count < CCA_COUNT_MAX; ++count) {
|
||||
t0 = RTIMER_NOW();
|
||||
if(we_are_sending == 0 && we_are_receiving_burst == 0) {
|
||||
powercycle_turn_radio_on();
|
||||
/* Check if a packet is seen in the air. If so, we keep the
|
||||
|
@ -499,7 +493,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
|
|||
uint8_t got_strobe_ack = 0;
|
||||
int len;
|
||||
uint8_t is_broadcast = 0;
|
||||
uint8_t is_reliable = 0;
|
||||
uint8_t is_known_receiver = 0;
|
||||
uint8_t collisions;
|
||||
int transmit_len;
|
||||
|
@ -546,11 +539,6 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
|
|||
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
|
||||
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
||||
}
|
||||
is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE)
|
||||
#if NETSTACK_CONF_WITH_RIME
|
||||
|| packetbuf_attr(PACKETBUF_ATTR_ERELIABLE)
|
||||
#endif /* NETSTACK_CONF_WITH_RIME */
|
||||
;
|
||||
|
||||
if(!packetbuf_attr(PACKETBUF_ATTR_IS_CREATED_AND_SECURED)) {
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1);
|
||||
|
@ -672,11 +660,12 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr,
|
|||
|
||||
{
|
||||
rtimer_clock_t wt;
|
||||
rtimer_clock_t txtime;
|
||||
int ret;
|
||||
|
||||
txtime = RTIMER_NOW();
|
||||
ret = NETSTACK_RADIO.transmit(transmit_len);
|
||||
rtimer_clock_t txtime = RTIMER_NOW();
|
||||
#if RDC_CONF_HARDWARE_ACK
|
||||
int ret = NETSTACK_RADIO.transmit(transmit_len);
|
||||
#else
|
||||
NETSTACK_RADIO.transmit(transmit_len);
|
||||
#endif
|
||||
|
||||
#if RDC_CONF_HARDWARE_ACK
|
||||
/* For radios that block in the transmit routine and detect the
|
||||
|
|
|
@ -373,11 +373,13 @@ send_packet(mac_callback_t sent, void *ptr)
|
|||
}
|
||||
metadata->sent = sent;
|
||||
metadata->cptr = ptr;
|
||||
|
||||
#if PACKETBUF_WITH_PACKET_TYPE
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
||||
PACKETBUF_ATTR_PACKET_TYPE_ACK) {
|
||||
list_push(n->queued_packet_list, q);
|
||||
} else {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
list_add(n->queued_packet_list, q);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "sys/rtimer.h"
|
||||
|
||||
#include "contiki-conf.h"
|
||||
#include "sys/cc.h"
|
||||
|
||||
#ifdef EXPERIMENT_SETUP
|
||||
#include "experiment-setup.h"
|
||||
|
@ -215,10 +216,6 @@ static linkaddr_t is_streaming_to, is_streaming_to_too;
|
|||
static rtimer_clock_t stream_until;
|
||||
#define DEFAULT_STREAM_TIME (RTIMER_ARCH_SECOND)
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
on(void)
|
||||
|
@ -453,8 +450,6 @@ send_packet(void)
|
|||
packetbuf_addr(PACKETBUF_ADDR_RECEIVER)->u8[1]);
|
||||
#endif /* NETSTACK_CONF_WITH_IPV6 */
|
||||
}
|
||||
/* is_reliable = packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE);*/
|
||||
len = NETSTACK_FRAMER.create();
|
||||
strobe_len = len + sizeof(struct cxmac_hdr);
|
||||
if(len < 0 || strobe_len > (int)sizeof(strobe)) {
|
||||
|
@ -475,7 +470,7 @@ send_packet(void)
|
|||
return MAC_TX_ERR;
|
||||
}
|
||||
|
||||
#if WITH_STREAMING
|
||||
#if WITH_STREAMING && PACKETBUF_WITH_PACKET_TYPE
|
||||
if(is_streaming == 1 &&
|
||||
(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER),
|
||||
&is_streaming_to) ||
|
||||
|
@ -519,7 +514,7 @@ send_packet(void)
|
|||
wait = ((rtimer_clock_t)(e->time - now)) % (DEFAULT_PERIOD);
|
||||
expected = now + wait - 2 * DEFAULT_ON_TIME;
|
||||
|
||||
#if WITH_ACK_OPTIMIZATION
|
||||
#if WITH_ACK_OPTIMIZATION && PACKETBUF_WITH_PACKET_TYPE
|
||||
/* Wait until the receiver is expected to be awake */
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) !=
|
||||
PACKETBUF_ATTR_PACKET_TYPE_ACK &&
|
||||
|
@ -624,12 +619,16 @@ send_packet(void)
|
|||
/* If we have received the strobe ACK, and we are sending a packet
|
||||
that will need an upper layer ACK (as signified by the
|
||||
PACKETBUF_ATTR_RELIABLE packet attribute), we keep the radio on. */
|
||||
if(got_strobe_ack && (packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
||||
if(got_strobe_ack && (
|
||||
#if NETSTACK_CONF_WITH_RIME
|
||||
packetbuf_attr(PACKETBUF_ATTR_RELIABLE) ||
|
||||
packetbuf_attr(PACKETBUF_ATTR_ERELIABLE) ||
|
||||
#endif /* NETSTACK_CONF_WITH_RIME */
|
||||
#if PACKETBUF_WITH_PACKET_TYPE
|
||||
packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) ==
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM)) {
|
||||
PACKETBUF_ATTR_PACKET_TYPE_STREAM ||
|
||||
#endif
|
||||
0)) {
|
||||
on(); /* Wait for ACK packet */
|
||||
waiting_for_packet = 1;
|
||||
} else {
|
||||
|
|
|
@ -242,8 +242,10 @@ parse(void)
|
|||
}
|
||||
packetbuf_set_addr(PACKETBUF_ADDR_SENDER, (linkaddr_t *)&frame.src_addr);
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PENDING, frame.fcf.frame_pending);
|
||||
/* packetbuf_set_attr(PACKETBUF_ATTR_RELIABLE, frame.fcf.ack_required);*/
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_MAC_SEQNO, frame.seq);
|
||||
#if NETSTACK_CONF_WITH_RIME
|
||||
packetbuf_set_attr(PACKETBUF_ATTR_PACKET_ID, frame.seq);
|
||||
#endif
|
||||
|
||||
#if LLSEC802154_SECURITY_LEVEL
|
||||
if(frame.fcf.security_enabled) {
|
||||
|
|
|
@ -74,7 +74,7 @@ mac_sequence_is_duplicate(void)
|
|||
for(i = 0; i < MAX_SEQNOS; ++i) {
|
||||
if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER),
|
||||
&received_seqnos[i].sender)) {
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_PACKET_ID) == received_seqnos[i].seqno) {
|
||||
if(packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) == received_seqnos[i].seqno) {
|
||||
/* Duplicate packet. */
|
||||
return 1;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ mac_sequence_register_seqno(void)
|
|||
for(j = i - 1; j > 0; --j) {
|
||||
memcpy(&received_seqnos[j], &received_seqnos[j - 1], sizeof(struct seqno));
|
||||
}
|
||||
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_PACKET_ID);
|
||||
received_seqnos[0].seqno = packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO);
|
||||
linkaddr_copy(&received_seqnos[0].sender,
|
||||
packetbuf_addr(PACKETBUF_ADDR_SENDER));
|
||||
}
|
||||
|
|
|
@ -264,11 +264,13 @@ send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list)
|
|||
static void
|
||||
packet_input(void)
|
||||
{
|
||||
#if NULLRDC_SEND_802154_ACK
|
||||
int original_datalen;
|
||||
uint8_t *original_dataptr;
|
||||
|
||||
original_datalen = packetbuf_datalen();
|
||||
original_dataptr = packetbuf_dataptr();
|
||||
#endif
|
||||
|
||||
#if NULLRDC_802154_AUTOACK
|
||||
if(packetbuf_datalen() == ACK_LEN) {
|
||||
|
@ -294,7 +296,7 @@ packet_input(void)
|
|||
if(duplicate) {
|
||||
/* Drop the packet. */
|
||||
PRINTF("nullrdc: drop duplicate link layer packet %u\n",
|
||||
packetbuf_attr(PACKETBUF_ATTR_PACKET_ID));
|
||||
packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO));
|
||||
} else {
|
||||
mac_sequence_register_seqno();
|
||||
}
|
||||
|
|
|
@ -106,7 +106,9 @@ send_packet(mac_callback_t sent, void *ptr)
|
|||
params.fcf.frame_type = FRAME802154_DATAFRAME;
|
||||
params.fcf.security_enabled = 0;
|
||||
params.fcf.frame_pending = 0;
|
||||
#if NETSTACK_CONF_WITH_RIME
|
||||
params.fcf.ack_required = packetbuf_attr(PACKETBUF_ATTR_RELIABLE);
|
||||
#endif
|
||||
params.fcf.panid_compression = 0;
|
||||
|
||||
/* Insert IEEE 802.15.4 (2003) version bit. */
|
||||
|
|
|
@ -106,10 +106,7 @@ packetbuf_compact(void)
|
|||
{
|
||||
int i, len;
|
||||
|
||||
if(packetbuf_is_reference()) {
|
||||
memcpy(&packetbuf[PACKETBUF_HDR_SIZE], packetbuf_reference_ptr(),
|
||||
packetbuf_datalen());
|
||||
} else if(bufptr > 0) {
|
||||
if(bufptr > 0) {
|
||||
len = packetbuf_datalen() + PACKETBUF_HDR_SIZE;
|
||||
for(i = PACKETBUF_HDR_SIZE; i < len; i++) {
|
||||
packetbuf[i] = packetbuf[bufptr + i];
|
||||
|
@ -215,26 +212,6 @@ packetbuf_hdrptr(void)
|
|||
return (void *)(&packetbuf[hdrptr]);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
packetbuf_reference(void *ptr, uint16_t len)
|
||||
{
|
||||
packetbuf_clear();
|
||||
packetbufptr = ptr;
|
||||
buflen = len;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
packetbuf_is_reference(void)
|
||||
{
|
||||
return packetbufptr != &packetbuf[PACKETBUF_HDR_SIZE];
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
packetbuf_reference_ptr(void)
|
||||
{
|
||||
return packetbufptr;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint16_t
|
||||
packetbuf_datalen(void)
|
||||
{
|
||||
|
|
|
@ -74,6 +74,12 @@
|
|||
#define PACKETBUF_HDR_SIZE 48
|
||||
#endif
|
||||
|
||||
#ifdef PACKETBUF_CONF_WITH_PACKET_TYPE
|
||||
#define PACKETBUF_WITH_PACKET_TYPE PACKETBUF_CONF_WITH_PACKET_TYPE
|
||||
#else
|
||||
#define PACKETBUF_WITH_PACKET_TYPE NETSTACK_CONF_WITH_RIME
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Clear and reset the packetbuf
|
||||
*
|
||||
|
@ -181,52 +187,12 @@ uint16_t packetbuf_totlen(void);
|
|||
*/
|
||||
void packetbuf_set_datalen(uint16_t len);
|
||||
|
||||
/**
|
||||
* \brief Point the packetbuf to external data
|
||||
* \param ptr A pointer to the external data
|
||||
* \param len The length of the external data
|
||||
*
|
||||
* For outbound packets, the packetbuf consists of two
|
||||
* parts: header and data. This function is used to make
|
||||
* the packetbuf point to external data. The function also
|
||||
* specifies the length of the external data that the
|
||||
* packetbuf references.
|
||||
*/
|
||||
void packetbuf_reference(void *ptr, uint16_t len);
|
||||
|
||||
/**
|
||||
* \brief Check if the packetbuf references external data
|
||||
* \retval Non-zero if the packetbuf references external data, zero otherwise.
|
||||
*
|
||||
* For outbound packets, the packetbuf consists of two
|
||||
* parts: header and data. This function is used to check
|
||||
* if the packetbuf points to external data that has
|
||||
* previously been referenced with packetbuf_reference().
|
||||
*
|
||||
*/
|
||||
int packetbuf_is_reference(void);
|
||||
|
||||
/**
|
||||
* \brief Get a pointer to external data referenced by the packetbuf
|
||||
* \retval A pointer to the external data
|
||||
*
|
||||
* For outbound packets, the packetbuf consists of two
|
||||
* parts: header and data. The data may point to external
|
||||
* data that has previously been referenced with
|
||||
* packetbuf_reference(). This function is used to get a
|
||||
* pointer to the external data.
|
||||
*
|
||||
*/
|
||||
void *packetbuf_reference_ptr(void);
|
||||
|
||||
/**
|
||||
* \brief Compact the packetbuf
|
||||
*
|
||||
* This function compacts the packetbuf by copying the data
|
||||
* portion of the packetbuf so that becomes consecutive to
|
||||
* the header. It also copies external data that has
|
||||
* previously been referenced with packetbuf_reference()
|
||||
* into the packetbuf.
|
||||
* the header.
|
||||
*
|
||||
* This function is called by the Rime code before a
|
||||
* packet is to be sent by a device driver. This assures
|
||||
|
@ -257,9 +223,7 @@ int packetbuf_copyfrom(const void *from, uint16_t len);
|
|||
*
|
||||
* This function copies the packetbuf to an external
|
||||
* buffer. Both the data portion and the header portion of
|
||||
* the packetbuf is copied. If the packetbuf referenced
|
||||
* external data (referenced with packetbuf_reference()) the
|
||||
* external data is copied.
|
||||
* the packetbuf is copied.
|
||||
*
|
||||
* The external buffer to which the packetbuf is to be
|
||||
* copied must be able to accomodate at least
|
||||
|
@ -351,10 +315,12 @@ enum {
|
|||
PACKETBUF_ATTR_IS_CREATED_AND_SECURED,
|
||||
|
||||
/* Scope 1 attributes: used between two neighbors only. */
|
||||
PACKETBUF_ATTR_RELIABLE,
|
||||
PACKETBUF_ATTR_PACKET_ID,
|
||||
#if PACKETBUF_WITH_PACKET_TYPE
|
||||
PACKETBUF_ATTR_PACKET_TYPE,
|
||||
#endif
|
||||
#if NETSTACK_CONF_WITH_RIME
|
||||
PACKETBUF_ATTR_PACKET_ID,
|
||||
PACKETBUF_ATTR_RELIABLE,
|
||||
PACKETBUF_ATTR_REXMIT,
|
||||
PACKETBUF_ATTR_MAX_REXMIT,
|
||||
PACKETBUF_ATTR_NUM_REXMIT,
|
||||
|
|
|
@ -43,18 +43,13 @@
|
|||
*/
|
||||
|
||||
#include "contiki-net.h"
|
||||
|
||||
#if WITH_SWAP
|
||||
#include "cfs/cfs.h"
|
||||
#endif
|
||||
|
||||
#include <string.h> /* for memcpy() */
|
||||
|
||||
#ifdef QUEUEBUF_CONF_REF_NUM
|
||||
#define QUEUEBUF_REF_NUM QUEUEBUF_CONF_REF_NUM
|
||||
#else
|
||||
#define QUEUEBUF_REF_NUM 2
|
||||
#endif
|
||||
|
||||
/* Structure pointing to a buffer either stored
|
||||
in RAM or swapped in CFS */
|
||||
struct queuebuf {
|
||||
|
@ -83,15 +78,7 @@ struct queuebuf_data {
|
|||
struct packetbuf_addr addrs[PACKETBUF_NUM_ADDRS];
|
||||
};
|
||||
|
||||
struct queuebuf_ref {
|
||||
uint16_t len;
|
||||
uint8_t *ref;
|
||||
uint8_t hdr[PACKETBUF_HDR_SIZE];
|
||||
uint8_t hdrlen;
|
||||
};
|
||||
|
||||
MEMB(bufmem, struct queuebuf, QUEUEBUF_NUM);
|
||||
MEMB(refbufmem, struct queuebuf_ref, QUEUEBUF_REF_NUM);
|
||||
MEMB(buframmem, struct queuebuf_data, QUEUEBUFRAM_NUM);
|
||||
|
||||
#if WITH_SWAP
|
||||
|
@ -144,7 +131,7 @@ LIST(queuebuf_list);
|
|||
#endif /* QUEUEBUF_CONF_STATS */
|
||||
|
||||
#if QUEUEBUF_STATS
|
||||
uint8_t queuebuf_len, queuebuf_ref_len, queuebuf_max_len;
|
||||
uint8_t queuebuf_len, queuebuf_max_len;
|
||||
#endif /* QUEUEBUF_STATS */
|
||||
|
||||
#if WITH_SWAP
|
||||
|
@ -301,20 +288,15 @@ queuebuf_init(void)
|
|||
#endif
|
||||
memb_init(&buframmem);
|
||||
memb_init(&bufmem);
|
||||
memb_init(&refbufmem);
|
||||
#if QUEUEBUF_STATS
|
||||
queuebuf_max_len = QUEUEBUF_NUM;
|
||||
queuebuf_max_len = 0;
|
||||
#endif /* QUEUEBUF_STATS */
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
queuebuf_numfree(void)
|
||||
{
|
||||
if(packetbuf_is_reference()) {
|
||||
return memb_numfree(&refbufmem);
|
||||
} else {
|
||||
return memb_numfree(&bufmem);
|
||||
}
|
||||
return memb_numfree(&bufmem);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#if QUEUEBUF_DEBUG
|
||||
|
@ -326,81 +308,62 @@ queuebuf_new_from_packetbuf(void)
|
|||
#endif /* QUEUEBUF_DEBUG */
|
||||
{
|
||||
struct queuebuf *buf;
|
||||
struct queuebuf_ref *rbuf;
|
||||
|
||||
if(packetbuf_is_reference()) {
|
||||
rbuf = memb_alloc(&refbufmem);
|
||||
if(rbuf != NULL) {
|
||||
#if QUEUEBUF_STATS
|
||||
++queuebuf_ref_len;
|
||||
#endif /* QUEUEBUF_STATS */
|
||||
rbuf->len = packetbuf_datalen();
|
||||
rbuf->ref = packetbuf_reference_ptr();
|
||||
rbuf->hdrlen = packetbuf_copyto_hdr(rbuf->hdr);
|
||||
} else {
|
||||
PRINTF("queuebuf_new_from_packetbuf: could not allocate a reference queuebuf\n");
|
||||
}
|
||||
return (struct queuebuf *)rbuf;
|
||||
} else {
|
||||
struct queuebuf_data *buframptr;
|
||||
buf = memb_alloc(&bufmem);
|
||||
if(buf != NULL) {
|
||||
struct queuebuf_data *buframptr;
|
||||
buf = memb_alloc(&bufmem);
|
||||
if(buf != NULL) {
|
||||
#if QUEUEBUF_DEBUG
|
||||
list_add(queuebuf_list, buf);
|
||||
buf->file = file;
|
||||
buf->line = line;
|
||||
buf->time = clock_time();
|
||||
list_add(queuebuf_list, buf);
|
||||
buf->file = file;
|
||||
buf->line = line;
|
||||
buf->time = clock_time();
|
||||
#endif /* QUEUEBUF_DEBUG */
|
||||
buf->ram_ptr = memb_alloc(&buframmem);
|
||||
buf->ram_ptr = memb_alloc(&buframmem);
|
||||
#if WITH_SWAP
|
||||
/* If the allocation failed, store the qbuf in swap files */
|
||||
if(buf->ram_ptr != NULL) {
|
||||
buf->location = IN_RAM;
|
||||
buframptr = buf->ram_ptr;
|
||||
} else {
|
||||
buf->location = IN_CFS;
|
||||
buf->swap_id = -1;
|
||||
tmpdata_qbuf = buf;
|
||||
buframptr = &tmpdata;
|
||||
}
|
||||
/* If the allocation failed, store the qbuf in swap files */
|
||||
if(buf->ram_ptr != NULL) {
|
||||
buf->location = IN_RAM;
|
||||
buframptr = buf->ram_ptr;
|
||||
} else {
|
||||
buf->location = IN_CFS;
|
||||
buf->swap_id = -1;
|
||||
tmpdata_qbuf = buf;
|
||||
buframptr = &tmpdata;
|
||||
}
|
||||
#else
|
||||
if(buf->ram_ptr == NULL) {
|
||||
PRINTF("queuebuf_new_from_packetbuf: could not queuebuf data\n");
|
||||
if(buf->ram_ptr == NULL) {
|
||||
PRINTF("queuebuf_new_from_packetbuf: could not queuebuf data\n");
|
||||
memb_free(&bufmem, buf);
|
||||
return NULL;
|
||||
}
|
||||
buframptr = buf->ram_ptr;
|
||||
#endif
|
||||
|
||||
buframptr->len = packetbuf_copyto(buframptr->data);
|
||||
packetbuf_attr_copyto(buframptr->attrs, buframptr->addrs);
|
||||
|
||||
#if WITH_SWAP
|
||||
if(buf->location == IN_CFS) {
|
||||
if(queuebuf_flush_tmpdata() == -1) {
|
||||
/* We were unable to write the data in the swap */
|
||||
memb_free(&bufmem, buf);
|
||||
return NULL;
|
||||
}
|
||||
buframptr = buf->ram_ptr;
|
||||
#endif
|
||||
|
||||
buframptr->len = packetbuf_copyto(buframptr->data);
|
||||
packetbuf_attr_copyto(buframptr->attrs, buframptr->addrs);
|
||||
|
||||
#if WITH_SWAP
|
||||
if(buf->location == IN_CFS) {
|
||||
if(queuebuf_flush_tmpdata() == -1) {
|
||||
/* We were unable to write the data in the swap */
|
||||
memb_free(&bufmem, buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QUEUEBUF_STATS
|
||||
++queuebuf_len;
|
||||
PRINTF("queuebuf len %d\n", queuebuf_len);
|
||||
printf("#A q=%d\n", queuebuf_len);
|
||||
if(queuebuf_len == queuebuf_max_len + 1) {
|
||||
queuebuf_free(buf);
|
||||
queuebuf_len--;
|
||||
return NULL;
|
||||
}
|
||||
++queuebuf_len;
|
||||
PRINTF("#A q=%d\n", queuebuf_len);
|
||||
if(queuebuf_len > queuebuf_max_len) {
|
||||
queuebuf_max_len = queuebuf_len;
|
||||
}
|
||||
#endif /* QUEUEBUF_STATS */
|
||||
|
||||
} else {
|
||||
PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n");
|
||||
}
|
||||
return buf;
|
||||
} else {
|
||||
PRINTF("queuebuf_new_from_packetbuf: could not allocate a queuebuf\n");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
|
@ -444,47 +407,30 @@ queuebuf_free(struct queuebuf *buf)
|
|||
memb_free(&bufmem, buf);
|
||||
#if QUEUEBUF_STATS
|
||||
--queuebuf_len;
|
||||
printf("#A q=%d\n", queuebuf_len);
|
||||
PRINTF("#A q=%d\n", queuebuf_len);
|
||||
#endif /* QUEUEBUF_STATS */
|
||||
#if QUEUEBUF_DEBUG
|
||||
list_remove(queuebuf_list, buf);
|
||||
#endif /* QUEUEBUF_DEBUG */
|
||||
} else if(memb_inmemb(&refbufmem, buf)) {
|
||||
memb_free(&refbufmem, buf);
|
||||
#if QUEUEBUF_STATS
|
||||
--queuebuf_ref_len;
|
||||
#endif /* QUEUEBUF_STATS */
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
queuebuf_to_packetbuf(struct queuebuf *b)
|
||||
{
|
||||
struct queuebuf_ref *r;
|
||||
if(memb_inmemb(&bufmem, b)) {
|
||||
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
|
||||
packetbuf_copyfrom(buframptr->data, buframptr->len);
|
||||
packetbuf_attr_copyfrom(buframptr->attrs, buframptr->addrs);
|
||||
} else if(memb_inmemb(&refbufmem, b)) {
|
||||
r = (struct queuebuf_ref *)b;
|
||||
packetbuf_clear();
|
||||
packetbuf_copyfrom(r->ref, r->len);
|
||||
packetbuf_hdralloc(r->hdrlen);
|
||||
memcpy(packetbuf_hdrptr(), r->hdr, r->hdrlen);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void *
|
||||
queuebuf_dataptr(struct queuebuf *b)
|
||||
{
|
||||
struct queuebuf_ref *r;
|
||||
|
||||
if(memb_inmemb(&bufmem, b)) {
|
||||
struct queuebuf_data *buframptr = queuebuf_load_to_ram(b);
|
||||
return buframptr->data;
|
||||
} else if(memb_inmemb(&refbufmem, b)) {
|
||||
r = (struct queuebuf_ref *)b;
|
||||
return r->ref;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -92,8 +92,6 @@ static struct broadcast_announcement_state {
|
|||
#define PRINTF(...)
|
||||
#endif
|
||||
|
||||
#define MIN(a, b) ((a)<(b)?(a):(b))
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
send_adv(void *ptr)
|
||||
|
|
|
@ -42,20 +42,13 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include "net/rime/rime.h"
|
||||
#include "net/rime/ipolite.h"
|
||||
#include "lib/random.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b)? (a) : (b))
|
||||
#endif /* MAX */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include "lib/list.h"
|
||||
#include "net/rime/rime.h"
|
||||
#include "net/rime/announcement.h"
|
||||
|
@ -90,8 +90,6 @@ static struct polite_announcement_state {
|
|||
#define PRINTF(...)
|
||||
#endif
|
||||
|
||||
#define MIN(a, b) ((a)<(b)?(a):(b))
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
send_adv(clock_time_t interval)
|
||||
|
|
|
@ -42,21 +42,13 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#include "sys/cc.h"
|
||||
#include "net/rime/rime.h"
|
||||
#include "net/rime/polite.h"
|
||||
#include "lib/random.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b)? (a) : (b))
|
||||
#endif /* MAX */
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b)? (a) : (b))
|
||||
#endif /* MIN */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
recv(struct abc_conn *abc)
|
||||
|
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Rudolph0: a simple block data flooding protocol
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup rudolph0
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <stddef.h> /* for offsetof */
|
||||
|
||||
#include "net/rime/rime.h"
|
||||
#include "net/rime/rudolph0.h"
|
||||
|
||||
#define STEADY_TIME CLOCK_SECOND * 2
|
||||
|
||||
#define DEFAULT_SEND_INTERVAL CLOCK_SECOND / 2
|
||||
enum {
|
||||
TYPE_DATA,
|
||||
TYPE_NACK,
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_RECEIVER,
|
||||
STATE_SENDER,
|
||||
};
|
||||
|
||||
#define VERSION_LT(a, b) ((signed char)((a) - (b)) < 0)
|
||||
|
||||
#define DEBUG 0
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
read_new_datapacket(struct rudolph0_conn *c)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if(c->cb->read_chunk) {
|
||||
len = c->cb->read_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
|
||||
c->current.data, RUDOLPH0_DATASIZE);
|
||||
}
|
||||
c->current.datalen = len;
|
||||
|
||||
PRINTF("read_new_datapacket len %d\n", len);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
send_nack(struct rudolph0_conn *c)
|
||||
{
|
||||
struct rudolph0_hdr *hdr;
|
||||
packetbuf_clear();
|
||||
packetbuf_hdralloc(sizeof(struct rudolph0_hdr));
|
||||
hdr = packetbuf_hdrptr();
|
||||
|
||||
hdr->type = TYPE_NACK;
|
||||
hdr->version = c->current.h.version;
|
||||
hdr->chunk = c->current.h.chunk;
|
||||
|
||||
PRINTF("Sending nack for %d:%d\n", hdr->version, hdr->chunk);
|
||||
polite_send(&c->nackc, c->send_interval / 2, sizeof(struct rudolph0_hdr));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
sent(struct stbroadcast_conn *stbroadcast)
|
||||
{
|
||||
struct rudolph0_conn *c = (struct rudolph0_conn *)stbroadcast;
|
||||
|
||||
if(c->current.datalen == RUDOLPH0_DATASIZE) {
|
||||
c->current.h.chunk++;
|
||||
PRINTF("Sending data chunk %d next time\n", c->current.h.chunk);
|
||||
read_new_datapacket(c);
|
||||
} else {
|
||||
stbroadcast_set_timer(&c->c, STEADY_TIME);
|
||||
PRINTF("Steady: Sending the same data chunk next time datalen %d, %d\n",
|
||||
c->current.datalen, RUDOLPH0_DATASIZE);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
recv(struct stbroadcast_conn *stbroadcast)
|
||||
{
|
||||
struct rudolph0_conn *c = (struct rudolph0_conn *)stbroadcast;
|
||||
struct rudolph0_datapacket *p = packetbuf_dataptr();
|
||||
|
||||
if(p->h.type == TYPE_DATA) {
|
||||
if(c->current.h.version != p->h.version) {
|
||||
PRINTF("rudolph0 new version %d\n", p->h.version);
|
||||
c->current.h.version = p->h.version;
|
||||
c->current.h.chunk = 0;
|
||||
c->cb->write_chunk(c, 0, RUDOLPH0_FLAG_NEWFILE, p->data, 0);
|
||||
if(p->h.chunk != 0) {
|
||||
send_nack(c);
|
||||
} else {
|
||||
c->cb->write_chunk(c, 0, RUDOLPH0_FLAG_NONE, p->data, p->datalen);
|
||||
c->current.h.chunk++;
|
||||
}
|
||||
} else if(p->h.version == c->current.h.version) {
|
||||
if(p->h.chunk == c->current.h.chunk) {
|
||||
PRINTF("received chunk %d\n", p->h.chunk);
|
||||
if(p->datalen < RUDOLPH0_DATASIZE) {
|
||||
c->cb->write_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
|
||||
RUDOLPH0_FLAG_LASTCHUNK, p->data, p->datalen);
|
||||
} else {
|
||||
c->cb->write_chunk(c, c->current.h.chunk * RUDOLPH0_DATASIZE,
|
||||
RUDOLPH0_FLAG_NONE, p->data, p->datalen);
|
||||
}
|
||||
c->current.h.chunk++;
|
||||
|
||||
} else if(p->h.chunk > c->current.h.chunk) {
|
||||
PRINTF("received chunk %d > %d, sending NACK\n", p->h.chunk, c->current.h.chunk);
|
||||
send_nack(c);
|
||||
}
|
||||
} else { /* p->h.version < c->current.h.version */
|
||||
/* Ignore packets with old version */
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
recv_nack(struct polite_conn *polite)
|
||||
{
|
||||
struct rudolph0_conn *c = (struct rudolph0_conn *)
|
||||
((char *)polite - offsetof(struct rudolph0_conn,
|
||||
nackc));
|
||||
struct rudolph0_datapacket *p = packetbuf_dataptr();
|
||||
|
||||
if(p->h.type == TYPE_NACK && c->state == STATE_SENDER) {
|
||||
if(p->h.version == c->current.h.version) {
|
||||
PRINTF("Reseting chunk to %d\n", p->h.chunk);
|
||||
c->current.h.chunk = p->h.chunk;
|
||||
} else {
|
||||
PRINTF("Wrong version, reseting chunk to 0\n");
|
||||
c->current.h.chunk = 0;
|
||||
}
|
||||
read_new_datapacket(c);
|
||||
stbroadcast_set_timer(&c->c, c->send_interval);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static const struct polite_callbacks polite = { recv_nack, 0, 0 };
|
||||
static const struct stbroadcast_callbacks stbroadcast = { recv, sent };
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rudolph0_open(struct rudolph0_conn *c, uint16_t channel,
|
||||
const struct rudolph0_callbacks *cb)
|
||||
{
|
||||
stbroadcast_open(&c->c, channel, &stbroadcast);
|
||||
polite_open(&c->nackc, channel + 1, &polite);
|
||||
c->cb = cb;
|
||||
c->current.h.version = 0;
|
||||
c->state = STATE_RECEIVER;
|
||||
c->send_interval = DEFAULT_SEND_INTERVAL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rudolph0_close(struct rudolph0_conn *c)
|
||||
{
|
||||
stbroadcast_close(&c->c);
|
||||
polite_close(&c->nackc);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rudolph0_send(struct rudolph0_conn *c, clock_time_t send_interval)
|
||||
{
|
||||
c->state = STATE_SENDER;
|
||||
c->current.h.version++;
|
||||
c->current.h.version++;
|
||||
c->current.h.chunk = 0;
|
||||
c->current.h.type = TYPE_DATA;
|
||||
read_new_datapacket(c);
|
||||
packetbuf_reference(&c->current, sizeof(struct rudolph0_datapacket));
|
||||
c->send_interval = send_interval;
|
||||
stbroadcast_send_stubborn(&c->c, c->send_interval);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rudolph0_force_restart(struct rudolph0_conn *c)
|
||||
{
|
||||
c->current.h.chunk = 0;
|
||||
send_nack(c);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rudolph0_stop(struct rudolph0_conn *c)
|
||||
{
|
||||
stbroadcast_cancel(&c->c);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rudolph0_version(struct rudolph0_conn *c)
|
||||
{
|
||||
return c->current.h.version;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rudolph0_set_version(struct rudolph0_conn *c, int version)
|
||||
{
|
||||
c->current.h.version = version;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @} */
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2007, 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.
|
||||
*
|
||||
* This file is part of the Contiki operating system.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Header file for the single-hop reliable bulk data transfer module
|
||||
* \author
|
||||
* Adam Dunkels <adam@sics.se>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup rime
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup rudolph0 Single-hop reliable bulk data transfer (rudolph0)
|
||||
* @{
|
||||
*
|
||||
* The rudolph0 module implements a single-hop reliable bulk data
|
||||
* transfer mechanism.
|
||||
*
|
||||
* \section rudolph0-channels Channels
|
||||
*
|
||||
* The rudolph0 module uses 2 channels; one for data packets and one
|
||||
* for NACK and repair packets.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RUDOLPH0_H_
|
||||
#define RUDOLPH0_H_
|
||||
|
||||
#include "net/rime/stbroadcast.h"
|
||||
#include "net/rime/polite.h"
|
||||
|
||||
struct rudolph0_conn;
|
||||
|
||||
enum {
|
||||
RUDOLPH0_FLAG_NONE,
|
||||
RUDOLPH0_FLAG_NEWFILE,
|
||||
RUDOLPH0_FLAG_LASTCHUNK,
|
||||
};
|
||||
|
||||
struct rudolph0_callbacks {
|
||||
void (* write_chunk)(struct rudolph0_conn *c, int offset, int flag,
|
||||
uint8_t *data, int len);
|
||||
int (* read_chunk)(struct rudolph0_conn *c, int offset, uint8_t *to,
|
||||
int maxsize);
|
||||
};
|
||||
|
||||
#ifdef RUDOLPH0_CONF_DATASIZE
|
||||
#define RUDOLPH0_DATASIZE RUDOLPH0_CONF_DATASIZE
|
||||
#else
|
||||
#define RUDOLPH0_DATASIZE 64
|
||||
#endif
|
||||
|
||||
struct rudolph0_hdr {
|
||||
uint8_t type;
|
||||
uint8_t version;
|
||||
uint16_t chunk;
|
||||
};
|
||||
|
||||
struct rudolph0_datapacket {
|
||||
struct rudolph0_hdr h;
|
||||
uint8_t datalen;
|
||||
uint8_t data[RUDOLPH0_DATASIZE];
|
||||
};
|
||||
|
||||
struct rudolph0_conn {
|
||||
struct stbroadcast_conn c;
|
||||
struct polite_conn nackc;
|
||||
const struct rudolph0_callbacks *cb;
|
||||
clock_time_t send_interval;
|
||||
uint8_t state;
|
||||
struct rudolph0_datapacket current;
|
||||
};
|
||||
|
||||
void rudolph0_open(struct rudolph0_conn *c, uint16_t channel,
|
||||
const struct rudolph0_callbacks *cb);
|
||||
void rudolph0_close(struct rudolph0_conn *c);
|
||||
void rudolph0_send(struct rudolph0_conn *c, clock_time_t interval);
|
||||
void rudolph0_stop(struct rudolph0_conn *c);
|
||||
|
||||
/* Force the sender to restart sending the file from the start. */
|
||||
void rudolph0_force_restart(struct rudolph0_conn *c);
|
||||
|
||||
void rudolph0_set_version(struct rudolph0_conn *c, int version);
|
||||
int rudolph0_version(struct rudolph0_conn *c);
|
||||
|
||||
#endif /* RUDOLPH0_H_ */
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
|
@ -105,6 +105,22 @@
|
|||
#define RPL_MAX_DAG_PER_INSTANCE 2
|
||||
#endif /* RPL_CONF_MAX_DAG_PER_INSTANCE */
|
||||
|
||||
/*
|
||||
* RPL Default route lifetime
|
||||
* The RPL route lifetime is used for the downward routes and for the default
|
||||
* route. In a high density network with DIO suppression activated it may happen
|
||||
* that a node will never send a DIO once the DIO interval becomes high as it
|
||||
* has heard DIO from many neighbors already. As the default route to the
|
||||
* preferred parent has a lifetime reset by receiving DIO from the parent, it
|
||||
* means that the default route can be destroyed after a while. Setting the
|
||||
* default route with infinite lifetime secures the upstream route.
|
||||
*/
|
||||
#ifdef RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME
|
||||
#define RPL_DEFAULT_ROUTE_INFINITE_LIFETIME RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME
|
||||
#else
|
||||
#define RPL_DEFAULT_ROUTE_INFINITE_LIFETIME 0
|
||||
#endif /* RPL_CONF_DEFAULT_ROUTE_INFINITE_LIFETIME */
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
@ -207,4 +223,65 @@
|
|||
#define RPL_INSERT_HBH_OPTION 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* RPL probing. When enabled, probes will be sent periodically to keep
|
||||
* parent link estimates up to date.
|
||||
* */
|
||||
#ifdef RPL_CONF_WITH_PROBING
|
||||
#define RPL_WITH_PROBING RPL_CONF_WITH_PROBING
|
||||
#else
|
||||
#define RPL_WITH_PROBING 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* RPL probing interval.
|
||||
* */
|
||||
#ifdef RPL_CONF_PROBING_INTERVAL
|
||||
#define RPL_PROBING_INTERVAL RPL_CONF_PROBING_INTERVAL
|
||||
#else
|
||||
#define RPL_PROBING_INTERVAL (120 * CLOCK_SECOND)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* RPL probing expiration time.
|
||||
* */
|
||||
#ifdef RPL_CONF_PROBING_EXPIRATION_TIME
|
||||
#define RPL_PROBING_EXPIRATION_TIME RPL_CONF_PROBING_EXPIRATION_TIME
|
||||
#else
|
||||
#define RPL_PROBING_EXPIRATION_TIME (10 * 60 * CLOCK_SECOND)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function used to select the next parent to be probed.
|
||||
* */
|
||||
#ifdef RPL_CONF_PROBING_SELECT_FUNC
|
||||
#define RPL_PROBING_SELECT_FUNC RPL_CONF_PROBING_SELECT_FUNC
|
||||
#else
|
||||
#define RPL_PROBING_SELECT_FUNC(dag) get_probing_target((dag))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function used to send RPL probes.
|
||||
* To probe with DIO, use:
|
||||
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) dio_output((instance), (addr))
|
||||
* To probe with DIS, use:
|
||||
* #define RPL_CONF_PROBING_SEND_FUNC(instance, addr) dis_output((addr))
|
||||
* Any other custom probing function is also acceptable.
|
||||
* */
|
||||
#ifdef RPL_CONF_PROBING_SEND_FUNC
|
||||
#define RPL_PROBING_SEND_FUNC RPL_CONF_PROBING_SEND_FUNC
|
||||
#else
|
||||
#define RPL_PROBING_SEND_FUNC(instance, addr) dio_output((instance), (addr))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function used to calculate next RPL probing interval
|
||||
* */
|
||||
#ifdef RPL_CONF_PROBING_DELAY_FUNC
|
||||
#define RPL_PROBING_DELAY_FUNC RPL_CONF_PROBING_DELAY_FUNC
|
||||
#else
|
||||
#define RPL_PROBING_DELAY_FUNC() ((RPL_PROBING_INTERVAL / 2) \
|
||||
+ random_rand() % (RPL_PROBING_INTERVAL))
|
||||
#endif
|
||||
|
||||
#endif /* RPL_CONF_H */
|
||||
|
|
260
core/net/rpl/rpl-dag-root.c
Normal file
260
core/net/rpl/rpl-dag-root.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
|
||||
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT HOLDER 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "contiki.h"
|
||||
#include "contiki-net.h"
|
||||
|
||||
#include "net/rpl/rpl.h"
|
||||
#include "net/rpl/rpl-private.h"
|
||||
#include "net/rpl/rpl-dag-root.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG DEBUG_NONE
|
||||
#include "net/ip/uip-debug.h"
|
||||
|
||||
#define RPL_DAG_GRACE_PERIOD (CLOCK_SECOND * 20 * 1)
|
||||
|
||||
static struct uip_ds6_notification n;
|
||||
static uint8_t to_become_root;
|
||||
static struct ctimer c;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static const uip_ipaddr_t *
|
||||
dag_root(void)
|
||||
{
|
||||
rpl_dag_t *dag;
|
||||
|
||||
dag = rpl_get_any_dag();
|
||||
if(dag != NULL) {
|
||||
return &dag->dag_id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static const uip_ipaddr_t *
|
||||
get_global_address(void)
|
||||
{
|
||||
int i;
|
||||
uint8_t state;
|
||||
uip_ipaddr_t *ipaddr = NULL;
|
||||
|
||||
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
|
||||
state = uip_ds6_if.addr_list[i].state;
|
||||
if(uip_ds6_if.addr_list[i].isused &&
|
||||
state == ADDR_PREFERRED &&
|
||||
!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
|
||||
ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
|
||||
}
|
||||
}
|
||||
return ipaddr;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
create_dag_callback(void *ptr)
|
||||
{
|
||||
const uip_ipaddr_t *root, *ipaddr;
|
||||
|
||||
root = dag_root();
|
||||
ipaddr = get_global_address();
|
||||
|
||||
if(root == NULL || uip_ipaddr_cmp(root, ipaddr)) {
|
||||
/* The RPL network we are joining is one that we created, so we
|
||||
become root. */
|
||||
if(to_become_root) {
|
||||
rpl_dag_root_init_dag_immediately();
|
||||
to_become_root = 0;
|
||||
}
|
||||
} else {
|
||||
rpl_dag_t *dag;
|
||||
|
||||
dag = rpl_get_any_dag();
|
||||
#if DEBUG
|
||||
printf("Found a network we did not create\n");
|
||||
printf("version %d grounded %d preference %d used %d joined %d rank %d\n",
|
||||
dag->version, dag->grounded,
|
||||
dag->preference, dag->used,
|
||||
dag->joined, dag->rank);
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* We found a RPL network that we did not create so we just join
|
||||
it without becoming root. But if the network has an infinite
|
||||
rank, we assume the network has broken, and we become the new
|
||||
root of the network. */
|
||||
|
||||
if(dag->rank == INFINITE_RANK) {
|
||||
if(to_become_root) {
|
||||
rpl_dag_root_init_dag_immediately();
|
||||
to_become_root = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try again after the grace period */
|
||||
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
route_callback(int event, uip_ipaddr_t *route, uip_ipaddr_t *ipaddr,
|
||||
int numroutes)
|
||||
{
|
||||
if(event == UIP_DS6_NOTIFICATION_DEFRT_ADD) {
|
||||
if(route != NULL && ipaddr != NULL &&
|
||||
!uip_is_addr_unspecified(route) &&
|
||||
!uip_is_addr_unspecified(ipaddr)) {
|
||||
if(to_become_root) {
|
||||
ctimer_set(&c, 0, create_dag_callback, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uip_ipaddr_t *
|
||||
set_global_address(void)
|
||||
{
|
||||
static uip_ipaddr_t ipaddr;
|
||||
int i;
|
||||
uint8_t state;
|
||||
|
||||
/* Assign a unique local address (RFC4193,
|
||||
http://tools.ietf.org/html/rfc4193). */
|
||||
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);
|
||||
|
||||
printf("IPv6 addresses: ");
|
||||
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
|
||||
state = uip_ds6_if.addr_list[i].state;
|
||||
if(uip_ds6_if.addr_list[i].isused &&
|
||||
(state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
|
||||
uip_debug_ipaddr_print(&uip_ds6_if.addr_list[i].ipaddr);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return &ipaddr;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_dag_root_init(void)
|
||||
{
|
||||
static uint8_t initialized = 0;
|
||||
|
||||
if(!initialized) {
|
||||
to_become_root = 0;
|
||||
set_global_address();
|
||||
uip_ds6_notification_add(&n, route_callback);
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_dag_root_init_dag_immediately(void)
|
||||
{
|
||||
struct uip_ds6_addr *root_if;
|
||||
int i;
|
||||
uint8_t state;
|
||||
uip_ipaddr_t *ipaddr = NULL;
|
||||
|
||||
rpl_dag_root_init();
|
||||
|
||||
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
|
||||
state = uip_ds6_if.addr_list[i].state;
|
||||
if(uip_ds6_if.addr_list[i].isused &&
|
||||
state == ADDR_PREFERRED &&
|
||||
!uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr)) {
|
||||
ipaddr = &uip_ds6_if.addr_list[i].ipaddr;
|
||||
}
|
||||
}
|
||||
|
||||
if(ipaddr != NULL) {
|
||||
root_if = uip_ds6_addr_lookup(ipaddr);
|
||||
if(root_if != NULL) {
|
||||
rpl_dag_t *dag;
|
||||
uip_ipaddr_t prefix;
|
||||
|
||||
rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr);
|
||||
dag = rpl_get_any_dag();
|
||||
|
||||
/* If there are routes in this dag, we remove them all as we are
|
||||
from now on the new dag root and the old routes are wrong */
|
||||
rpl_remove_routes(dag);
|
||||
if(dag->instance != NULL &&
|
||||
dag->instance->def_route != NULL) {
|
||||
uip_ds6_defrt_rm(dag->instance->def_route);
|
||||
dag->instance->def_route = NULL;
|
||||
}
|
||||
|
||||
uip_ip6addr(&prefix, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
|
||||
rpl_set_prefix(dag, &prefix, 64);
|
||||
PRINTF("rpl_dag_root_init_dag: created a new RPL dag\n");
|
||||
return 0;
|
||||
} else {
|
||||
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
PRINTF("rpl_dag_root_init_dag: failed to create a new RPL DAG, no preferred IP address found\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_dag_root_init_dag(void)
|
||||
{
|
||||
rpl_dag_root_init();
|
||||
|
||||
ctimer_set(&c, RPL_DAG_GRACE_PERIOD, create_dag_callback, NULL);
|
||||
to_become_root = 1;
|
||||
|
||||
/* Send a DIS packet to request RPL info from neighbors. */
|
||||
dis_output(NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
rpl_dag_root_is_root(void)
|
||||
{
|
||||
rpl_instance_t *instance;
|
||||
|
||||
instance = rpl_get_default_instance();
|
||||
|
||||
if(instance == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(instance->current_dag &&
|
||||
instance->current_dag->rank == ROOT_RANK(instance)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
41
core/net/rpl/rpl-dag-root.h
Normal file
41
core/net/rpl/rpl-dag-root.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
|
||||
* 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 copyright holder 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 COPYRIGHT HOLDERS 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
|
||||
* COPYRIGHT HOLDER 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 RPL_DAG_ROOT_H_
|
||||
#define RPL_DAG_ROOT_H_
|
||||
|
||||
void rpl_dag_root_init(void);
|
||||
void rpl_dag_root_init_dag(void);
|
||||
int rpl_dag_root_init_dag_immediately(void);
|
||||
|
||||
int rpl_dag_root_is_root(void);
|
||||
|
||||
#endif /* RPL_DAG_ROOT_H_ */
|
|
@ -75,12 +75,37 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF};
|
|||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Per-parent RPL information */
|
||||
NBR_TABLE(rpl_parent_t, rpl_parents);
|
||||
NBR_TABLE_GLOBAL(rpl_parent_t, rpl_parents);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Allocate instance table. */
|
||||
rpl_instance_t instance_table[RPL_MAX_INSTANCES];
|
||||
rpl_instance_t *default_instance;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_print_neighbor_list()
|
||||
{
|
||||
if(default_instance != NULL && default_instance->current_dag != NULL &&
|
||||
default_instance->of != NULL && default_instance->of->calculate_rank != NULL) {
|
||||
int curr_dio_interval = default_instance->dio_intcurrent;
|
||||
int curr_rank = default_instance->current_dag->rank;
|
||||
rpl_parent_t *p = nbr_table_head(rpl_parents);
|
||||
clock_time_t now = clock_time();
|
||||
|
||||
printf("RPL: rank %u dioint %u, %u nbr(s)\n", curr_rank, curr_dio_interval, uip_ds6_nbr_num());
|
||||
while(p != NULL) {
|
||||
uip_ds6_nbr_t *nbr = rpl_get_nbr(p);
|
||||
printf("RPL: nbr %3u %5u, %5u => %5u %c (last tx %u min ago)\n",
|
||||
nbr_table_get_lladdr(rpl_parents, p)->u8[7],
|
||||
p->rank, nbr ? nbr->link_metric : 0,
|
||||
default_instance->of->calculate_rank(p, 0),
|
||||
p == default_instance->current_dag->preferred_parent ? '*' : ' ',
|
||||
(unsigned)((now - p->last_tx_time) / (60 * CLOCK_SECOND)));
|
||||
p = nbr_table_next(rpl_parents, p);
|
||||
}
|
||||
printf("RPL: end of list\n");
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uip_ds6_nbr_t *
|
||||
rpl_get_nbr(rpl_parent_t *parent)
|
||||
|
@ -269,17 +294,27 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
|
|||
rpl_dag_t *dag;
|
||||
rpl_instance_t *instance;
|
||||
uint8_t version;
|
||||
int i;
|
||||
|
||||
version = RPL_LOLLIPOP_INIT;
|
||||
dag = get_dag(instance_id, dag_id);
|
||||
if(dag != NULL) {
|
||||
version = dag->version;
|
||||
RPL_LOLLIPOP_INCREMENT(version);
|
||||
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
|
||||
if(dag == dag->instance->current_dag) {
|
||||
dag->instance->current_dag = NULL;
|
||||
instance = rpl_get_instance(instance_id);
|
||||
if(instance != NULL) {
|
||||
for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) {
|
||||
dag = &instance->dag_table[i];
|
||||
if(dag->used) {
|
||||
if(uip_ipaddr_cmp(&dag->dag_id, dag_id)) {
|
||||
version = dag->version;
|
||||
RPL_LOLLIPOP_INCREMENT(version);
|
||||
}
|
||||
if(dag == dag->instance->current_dag) {
|
||||
PRINTF("RPL: Dropping a joined DAG when setting this node as root");
|
||||
dag->instance->current_dag = NULL;
|
||||
} else {
|
||||
PRINTF("RPL: Dropping a DAG when setting this node as root");
|
||||
}
|
||||
rpl_free_dag(dag);
|
||||
}
|
||||
}
|
||||
rpl_free_dag(dag);
|
||||
}
|
||||
|
||||
dag = rpl_alloc_dag(instance_id, dag_id);
|
||||
|
@ -446,8 +481,7 @@ rpl_set_default_route(rpl_instance_t *instance, uip_ipaddr_t *from)
|
|||
PRINT6ADDR(from);
|
||||
PRINTF("\n");
|
||||
instance->def_route = uip_ds6_defrt_add(from,
|
||||
RPL_LIFETIME(instance,
|
||||
instance->default_lifetime));
|
||||
RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime));
|
||||
if(instance->def_route == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -474,6 +508,9 @@ rpl_alloc_instance(uint8_t instance_id)
|
|||
instance->instance_id = instance_id;
|
||||
instance->def_route = NULL;
|
||||
instance->used = 1;
|
||||
#if RPL_WITH_PROBING
|
||||
rpl_schedule_probing(instance);
|
||||
#endif /* RPL_WITH_PROBING */
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
@ -507,7 +544,6 @@ rpl_alloc_dag(uint8_t instance_id, uip_ipaddr_t *dag_id)
|
|||
}
|
||||
|
||||
RPL_STAT(rpl_stats.mem_overflows++);
|
||||
rpl_free_instance(instance);
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -517,6 +553,12 @@ rpl_set_default_instance(rpl_instance_t *instance)
|
|||
default_instance = instance;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
rpl_instance_t *
|
||||
rpl_get_default_instance(void)
|
||||
{
|
||||
return default_instance;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
rpl_free_instance(rpl_instance_t *instance)
|
||||
{
|
||||
|
@ -534,6 +576,9 @@ rpl_free_instance(rpl_instance_t *instance)
|
|||
|
||||
rpl_set_default_route(instance, NULL);
|
||||
|
||||
#if RPL_WITH_PROBING
|
||||
ctimer_stop(&instance->probing_timer);
|
||||
#endif /* RPL_WITH_PROBING */
|
||||
ctimer_stop(&instance->dio_timer);
|
||||
ctimer_stop(&instance->dao_timer);
|
||||
ctimer_stop(&instance->dao_lifetime_timer);
|
||||
|
@ -729,6 +774,9 @@ rpl_select_dag(rpl_instance_t *instance, rpl_parent_t *p)
|
|||
rpl_schedule_dao(instance);
|
||||
}
|
||||
rpl_reset_dio_timer(instance);
|
||||
#if DEBUG
|
||||
rpl_print_neighbor_list();
|
||||
#endif
|
||||
} else if(best_dag->rank != old_rank) {
|
||||
PRINTF("RPL: Preferred parent update, rank changed from %u to %u\n",
|
||||
(unsigned)old_rank, best_dag->rank);
|
||||
|
@ -765,6 +813,9 @@ rpl_select_parent(rpl_dag_t *dag)
|
|||
|
||||
if(best != NULL) {
|
||||
rpl_set_preferred_parent(dag, best);
|
||||
dag->rank = dag->instance->of->calculate_rank(dag->preferred_parent, 0);
|
||||
} else {
|
||||
dag->rank = INFINITE_RANK;
|
||||
}
|
||||
|
||||
return best;
|
||||
|
@ -1324,12 +1375,15 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
}
|
||||
}
|
||||
|
||||
/* Parent info has been updated, trigger rank recalculation */
|
||||
p->flags |= RPL_PARENT_FLAG_UPDATED;
|
||||
|
||||
PRINTF("RPL: preferred DAG ");
|
||||
PRINT6ADDR(&instance->current_dag->dag_id);
|
||||
PRINTF(", rank %u, min_rank %u, ",
|
||||
instance->current_dag->rank, instance->current_dag->min_rank);
|
||||
PRINTF("parent rank %u, parent etx %u, link metric %u, instance etx %u\n",
|
||||
p->rank, -1/*p->mc.obj.etx*/, p->link_metric, instance->mc.obj.etx);
|
||||
p->rank, -1/*p->mc.obj.etx*/, rpl_get_nbr(p)->link_metric, instance->mc.obj.etx);
|
||||
|
||||
/* We have allocated a candidate parent; process the DIO further. */
|
||||
|
||||
|
@ -1349,7 +1403,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
|
|||
}
|
||||
/* We received a new DIO from our preferred parent.
|
||||
* Call uip_ds6_defrt_add to set a fresh value for the lifetime counter */
|
||||
uip_ds6_defrt_add(from, RPL_LIFETIME(instance, instance->default_lifetime));
|
||||
uip_ds6_defrt_add(from, RPL_DEFAULT_ROUTE_INFINITE_LIFETIME ? 0 : RPL_LIFETIME(instance, instance->default_lifetime));
|
||||
}
|
||||
p->dtsn = dio->dtsn;
|
||||
}
|
||||
|
|
|
@ -466,8 +466,12 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
|
|||
|
||||
buffer[pos++] = instance->dtsn_out;
|
||||
|
||||
/* always request new DAO to refresh route */
|
||||
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||
if(uc_addr == NULL) {
|
||||
/* Request new DAO to refresh route. We do not do this for unicast DIO
|
||||
* in order to avoid DAO messages after a DIS-DIO update,
|
||||
* or upon unicast DIO probing. */
|
||||
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
|
||||
}
|
||||
|
||||
/* reserved 2 bytes */
|
||||
buffer[pos++] = 0; /* flags */
|
||||
|
|
|
@ -313,6 +313,7 @@ rpl_of_t *rpl_find_of(rpl_ocp_t);
|
|||
void rpl_schedule_dao(rpl_instance_t *);
|
||||
void rpl_schedule_dao_immediately(rpl_instance_t *);
|
||||
void rpl_cancel_dao(rpl_instance_t *instance);
|
||||
void rpl_schedule_probing(rpl_instance_t *instance);
|
||||
|
||||
void rpl_reset_dio_timer(rpl_instance_t *);
|
||||
void rpl_reset_periodic_timer(void);
|
||||
|
@ -320,4 +321,7 @@ void rpl_reset_periodic_timer(void);
|
|||
/* Route poisoning. */
|
||||
void rpl_poison_routes(rpl_dag_t *, rpl_parent_t *);
|
||||
|
||||
|
||||
rpl_instance_t *rpl_get_default_instance(void);
|
||||
|
||||
#endif /* RPL_PRIVATE_H */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue