Merge pull request #1003 from adamdunkels/pr/http-socket-dns64-tcp-socket

New HTTP socket, DNS64, IP64 Cooja tests
This commit is contained in:
Nicolas Tsiftes 2015-05-10 17:14:31 +02:00
commit 44af0fa66b
60 changed files with 3826 additions and 89 deletions

View file

@ -110,6 +110,7 @@ env:
- 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

View 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;
}
/*---------------------------------------------------------------------------*/

View 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 */

View file

@ -41,6 +41,8 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static void relisten(struct tcp_socket *s);
LIST(socketlist);
/*---------------------------------------------------------------------------*/
PROCESS(tcp_socket_process, "TCP socket process");
@ -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,7 +70,7 @@ 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 */
@ -81,8 +83,14 @@ acked(struct tcp_socket *s)
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);
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,
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();
@ -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;
}
/*---------------------------------------------------------------------------*/

View file

@ -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 */

View file

@ -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;

View file

@ -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);
/**

View file

@ -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
/**

View file

@ -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.

View file

@ -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

View file

@ -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;

View file

@ -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
View 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;
}
/*---------------------------------------------------------------------------*/

View 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_ */

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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)
@ -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:

View file

@ -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.

View file

@ -386,7 +386,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;

View file

@ -459,7 +459,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;

260
core/net/rpl/rpl-dag-root.c Normal file
View 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;
}
/*---------------------------------------------------------------------------*/

View 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_ */

View file

@ -516,6 +516,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)
{

View file

@ -320,4 +320,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 */

View file

@ -0,0 +1,7 @@
all: http-example
CONTIKI=../..
MODULES += core/net/http-socket
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,62 @@
#include "contiki-net.h"
#include "http-socket.h"
#include "ip64-addr.h"
#include <stdio.h>
static struct http_socket s;
static int bytes_received = 0;
/*---------------------------------------------------------------------------*/
PROCESS(http_example_process, "HTTP Example");
AUTOSTART_PROCESSES(&http_example_process);
/*---------------------------------------------------------------------------*/
static void
callback(struct http_socket *s, void *ptr,
http_socket_event_t e,
const uint8_t *data, uint16_t datalen)
{
if(e == HTTP_SOCKET_ERR) {
printf("HTTP socket error\n");
} else if(e == HTTP_SOCKET_TIMEDOUT) {
printf("HTTP socket error: timed out\n");
} else if(e == HTTP_SOCKET_ABORTED) {
printf("HTTP socket error: aborted\n");
} else if(e == HTTP_SOCKET_HOSTNAME_NOT_FOUND) {
printf("HTTP socket error: hostname not found\n");
} else if(e == HTTP_SOCKET_CLOSED) {
printf("HTTP socket closed, %d bytes received\n", bytes_received);
} else if(e == HTTP_SOCKET_DATA) {
bytes_received += datalen;
printf("HTTP socket received %d bytes of data\n", datalen);
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(http_example_process, ev, data)
{
static struct etimer et;
uip_ip4addr_t ip4addr;
uip_ip6addr_t ip6addr;
PROCESS_BEGIN();
uip_ipaddr(&ip4addr, 8,8,8,8);
ip64_addr_4to6(&ip4addr, &ip6addr);
uip_nameserver_update(&ip6addr, UIP_NAMESERVER_INFINITE_LIFETIME);
etimer_set(&et, CLOCK_SECOND * 60);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
http_socket_init(&s);
http_socket_get(&s, "http://www.contiki-os.org/", 0, 0,
callback, NULL);
etimer_set(&et, CLOCK_SECOND);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
etimer_reset(&et);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,5 @@
all: ip64-router
CONTIKI=../..
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1,27 @@
#include "contiki.h"
#include "contiki-net.h"
#include "ip64.h"
#include "net/netstack.h"
/*---------------------------------------------------------------------------*/
PROCESS(router_node_process, "Router node");
AUTOSTART_PROCESSES(&router_node_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(router_node_process, ev, data)
{
PROCESS_BEGIN();
/* Set us up as a RPL root node. */
rpl_dag_root_init_dag();
/* Initialize the IP64 module so we'll start translating packets */
ip64_init();
/* ... and do nothing more. */
while(1) {
PROCESS_WAIT_EVENT();
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View file

View file

@ -0,0 +1,15 @@
COOJAPLATFORMDIR=$(CONTIKI)/platform/cooja
MODULES += core/net/ip64
include $(COOJAPLATFORMDIR)/Makefile.cooja
vpath %.c $(COOJAPLATFORMDIR) $(COOJAPLATFORMDIR)/dev \
$(COOJAPLATFORMDIR)/net $(COOJAPLATFORMDIR)/lib \
$(COOJAPLATFORMDIR)/sys $(COOJAPLATFORMDIR)/cfs
CFLAGS += -I $(COOJAPLATFORMDIR)
CFLAGS += -DWITH_IP64=1 -DWITH_LARGE_BUFFER_SIZE=1
CFLAGS += -DINCLUDE_SUBPLATFORM_CONF=1
%.cooja: %.cooja-ip64
cp $< $@

View file

@ -0,0 +1,50 @@
### Define custom targets
REDEF_PRINTF=1 # Redefine functions to enable printf()s inside Cooja
# NB: Assumes ARCHIVE was not overridden and is in $(OBJECTDIR)
$(ARCHIVE): $(CONTIKI_OBJECTFILES) | $(OBJECTDIR)
${subst obj_cooja/,$(OBJECTDIR)/,$(AR_COMMAND_1)} $^ $(AR_COMMAND_2)
# NB: Assumes JNILIB was not overridden and is in $(OBJECTDIR)
$(JNILIB): $(CONTIKI_APP_OBJ) $(MAIN_OBJ) $(PROJECT_OBJECTFILES) $(ARCHIVE) | $(OBJECTDIR)
ifdef SYMBOLS
@echo Generating symbols
# Recreate symbols file and relink with final memory layout (twice)
${CONTIKI}/tools/make-symbols-nm $(JNILIB)
$(CC) $(CFLAGS) -c symbols.c -o $(OBJECTDIR)/symbols.o
$(LINK_COMMAND_1) $^ $(LINK_COMMAND_2)
${CONTIKI}/tools/make-symbols-nm $(JNILIB)
$(CC) $(CFLAGS) -c symbols.c -o $(OBJECTDIR)/symbols.o
endif ## SYMBOLS
ifdef REDEF_PRINTF
@echo Redefining printf
-$(foreach OBJ,$^, $(OBJCOPY) --redefine-sym printf=log_printf $(OBJ); )
-$(foreach OBJ,$^, $(OBJCOPY) --redefine-sym puts=log_puts $(OBJ); )
-$(foreach OBJ,$^, $(OBJCOPY) --redefine-sym putchar=log_putchar $(OBJ); )
endif ## REDEF_PRINTF
${subst .cooja,.$(TARGET),${subst obj_cooja/,$(OBJECTDIR)/,$(LINK_COMMAND_1)}} $^ $(LINK_COMMAND_2)
.PHONY: $(CONTIKI_APP).$(TARGET)
$(CONTIKI_APP).$(TARGET): $(JNILIB)
cp $(JNILIB) $@
rm $(CONTIKI_APP_OBJ)
mkdir -p obj_cooja
@-cp obj_cooja-ip64/$(LIBNAME).map obj_cooja/$(LIBNAME).map && echo Placed a copy of the map file at obj_cooja/$(LIBNAME).map
cp obj_cooja-ip64/$(LIBNAME).cooja-ip64 obj_cooja/$(LIBNAME).cooja
@echo Placed a copy of the shared library at obj_cooja/$(LIBNAME).cooja
cp $@ $(CONTIKI_APP).cooja
@echo Placed a copy of the shared library at $(CONTIKI_APP).cooja
# Trickiness: GNU make matches this against the file base name.
# Assume that the directory part is the standard location.
mtype%.o: contiki-cooja-ip64-main.o | $(OBJECTDIR)
mv contiki-cooja-ip64-main.o $@
symbols.c:
# Create initial symbol files if not existing
cp ${CONTIKI}/tools/empty-symbols.c symbols.c
cp ${CONTIKI}/tools/empty-symbols.h symbols.h

View file

@ -0,0 +1,425 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/**
* \file
* COOJA Contiki mote main file.
* \author
* Fredrik Osterlind <fros@sics.se>
*/
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include "contiki.h"
#include "sys/clock.h"
#include "sys/etimer.h"
#include "sys/cooja_mt.h"
#include "sys/autostart.h"
#include "lib/random.h"
#include "lib/simEnvChange.h"
#include "net/rime/rime.h"
#include "net/netstack.h"
#include "net/ip/uip-nameserver.h"
#include "dev/serial-line.h"
#include "dev/cooja-radio.h"
#include "dev/button-sensor.h"
#include "dev/pir-sensor.h"
#include "dev/vib-sensor.h"
#include "sys/node-id.h"
#include "ip64.h"
#include "dev/slip.h"
/* JNI-defined functions, depends on the environment variable CLASSNAME */
#ifndef CLASSNAME
#error CLASSNAME is undefined, required by contiki-cooja-main.c
#endif /* CLASSNAME */
#define COOJA__QUOTEME(a,b,c) COOJA_QUOTEME(a,b,c)
#define COOJA_QUOTEME(a,b,c) a##b##c
#define COOJA_JNI_PATH Java_org_contikios_cooja_corecomm_
#define Java_org_contikios_cooja_corecomm_CLASSNAME_init COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_init)
#define Java_org_contikios_cooja_corecomm_CLASSNAME_getMemory COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_getMemory)
#define Java_org_contikios_cooja_corecomm_CLASSNAME_setMemory COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_setMemory)
#define Java_org_contikios_cooja_corecomm_CLASSNAME_tick COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_tick)
#define Java_org_contikios_cooja_corecomm_CLASSNAME_setReferenceAddress COOJA__QUOTEME(COOJA_JNI_PATH,CLASSNAME,_setReferenceAddress)
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#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])
/* Simulation mote interfaces */
SIM_INTERFACE_NAME(moteid_interface);
SIM_INTERFACE_NAME(vib_interface);
SIM_INTERFACE_NAME(rs232_interface);
SIM_INTERFACE_NAME(simlog_interface);
SIM_INTERFACE_NAME(beep_interface);
SIM_INTERFACE_NAME(radio_interface);
SIM_INTERFACE_NAME(button_interface);
SIM_INTERFACE_NAME(pir_interface);
SIM_INTERFACE_NAME(clock_interface);
SIM_INTERFACE_NAME(leds_interface);
SIM_INTERFACE_NAME(cfs_interface);
SIM_INTERFACES(&vib_interface, &moteid_interface, &rs232_interface, &simlog_interface, &beep_interface, &radio_interface, &button_interface, &pir_interface, &clock_interface, &leds_interface, &cfs_interface);
/* Example: manually add mote interfaces */
//SIM_INTERFACE_NAME(dummy_interface);
//SIM_INTERFACES(..., &dummy_interface);
/* Sensors */
SENSORS(&button_sensor, &pir_sensor, &vib_sensor);
/*
* referenceVar is used for comparing absolute and process relative memory.
* (this must not be static due to memory locations)
*/
long referenceVar;
/*
* Contiki and rtimer threads.
*/
static struct cooja_mt_thread rtimer_thread;
static struct cooja_mt_thread process_run_thread;
#define MIN(a, b) ( (a)<(b) ? (a) : (b) )
/*---------------------------------------------------------------------------*/
static void
print_processes(struct process * const processes[])
{
/* const struct process * const * p = processes;*/
printf("Starting");
while(*processes != NULL) {
printf(" '%s'", (*processes)->name);
processes++;
}
putchar('\n');
}
/*---------------------------------------------------------------------------*/
static void
rtimer_thread_loop(void *data)
{
while(1)
{
rtimer_arch_check();
/* Return to COOJA */
cooja_mt_yield();
}
}
/*---------------------------------------------------------------------------*/
static void
set_mac_addr(void)
{
linkaddr_t addr;
int i;
memset(&addr, 0, sizeof(linkaddr_t));
for(i = 0; i < sizeof(uip_lladdr.addr); i += 2) {
addr.u8[i + 1] = node_id & 0xff;
addr.u8[i + 0] = node_id >> 8;
}
linkaddr_set_node_addr(&addr);
printf("MAC address ");
for(i = 0; i < sizeof(addr.u8) - 1; i++) {
printf("%d.", addr.u8[i]);
}
printf("%d\n", addr.u8[i]);
}
/*---------------------------------------------------------------------------*/
void
contiki_init(void)
{
int i;
uint8_t addr[sizeof(uip_lladdr.addr)];
uip_ipaddr_t ipaddr;
uip_ds6_addr_t *lladdr;
uip_ip4addr_t ipv4addr, netmask;
/* Start process handler */
process_init();
/* Start Contiki processes */
process_start(&etimer_process, NULL);
process_start(&sensors_process, NULL);
ctimer_init();
/* Print startup information */
printf(CONTIKI_VERSION_STRING " started. ");
if(node_id > 0) {
printf("Node id is set to %u.\n", node_id);
} else {
printf("Node id is not set.\n");
}
set_mac_addr();
queuebuf_init();
/* Initialize communication stack */
netstack_init();
printf("%s/%s/%s, channel check rate %lu Hz\n",
NETSTACK_NETWORK.name, NETSTACK_MAC.name, NETSTACK_RDC.name,
CLOCK_SECOND / (NETSTACK_RDC.channel_check_interval() == 0 ? 1:
NETSTACK_RDC.channel_check_interval()));
/* IPv6 CONFIGURATION */
for(i = 0; i < sizeof(uip_lladdr.addr); i += 2) {
addr[i + 1] = node_id & 0xff;
addr[i + 0] = node_id >> 8;
}
linkaddr_copy(addr, &linkaddr_node_addr);
memcpy(&uip_lladdr.addr, addr, sizeof(uip_lladdr.addr));
process_start(&tcpip_process, NULL);
printf("Tentative link-local IPv6 address ");
lladdr = uip_ds6_get_link_local(-1);
for(i = 0; i < 7; ++i) {
printf("%02x%02x:", lladdr->ipaddr.u8[i * 2],
lladdr->ipaddr.u8[i * 2 + 1]);
}
printf("%02x%02x\n", lladdr->ipaddr.u8[14],
lladdr->ipaddr.u8[15]);
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_TENTATIVE);
printf("Tentative global IPv6 address ");
for(i = 0; i < 7; ++i) {
printf("%02x%02x:",
ipaddr.u8[i * 2], ipaddr.u8[i * 2 + 1]);
}
printf("%02x%02x\n",
ipaddr.u8[7 * 2], ipaddr.u8[7 * 2 + 1]);
/* Start serial process */
serial_line_init();
/* Start autostart processes (defined in Contiki application) */
print_processes(autostart_processes);
autostart_start(autostart_processes);
/* Start the SLIP */
printf("Initiating SLIP with IP address is 172.16.0.2.\n");
uip_ipaddr(&ipv4addr, 172, 16, 0, 2);
uip_ipaddr(&netmask, 255, 255, 255, 0);
ip64_set_ipv4_address(&ipv4addr, &netmask);
rs232_set_input(slip_input_byte);
log_set_putchar_with_slip(1);
uip_ip4addr_t ip4addr;
uip_ip6addr_t ip6addr;
uip_ipaddr(&ip4addr, 8,8,8,8);
ip64_addr_4to6(&ip4addr, &ip6addr);
uip_nameserver_update((uip_ipaddr_t *)&ip6addr, UIP_NAMESERVER_INFINITE_LIFETIME);
}
/*---------------------------------------------------------------------------*/
static void
process_run_thread_loop(void *data)
{
/* Yield once during bootup */
simProcessRunValue = 1;
cooja_mt_yield();
contiki_init();
while(1) {
simProcessRunValue = process_run();
while(simProcessRunValue-- > 0) {
process_run();
}
simProcessRunValue = process_nevents();
/* Check if we must stay awake */
if(simDontFallAsleep) {
simDontFallAsleep = 0;
simProcessRunValue = 1;
}
/* Return to COOJA */
cooja_mt_yield();
}
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize a mote by starting processes etc.
*
* This function initializes a mote by starting certain
* processes and setting up the environment.
*
* This is a JNI function and should only be called via the
* responsible Java part (MoteType.java).
*/
JNIEXPORT void JNICALL
Java_org_contikios_cooja_corecomm_CLASSNAME_init(JNIEnv *env, jobject obj)
{
/* Create rtimers and Contiki threads */
cooja_mt_start(&rtimer_thread, &rtimer_thread_loop, NULL);
cooja_mt_start(&process_run_thread, &process_run_thread_loop, NULL);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Get a segment from the process memory.
* \param start Start address of segment
* \param length Size of memory segment
* \return Java byte array containing a copy of memory segment.
*
* Fetches a memory segment from the process memory starting at
* (start), with size (length). This function does not perform
* ANY error checking, and the process may crash if addresses are
* not available/readable.
*
* This is a JNI function and should only be called via the
* responsible Java part (MoteType.java).
*/
JNIEXPORT void JNICALL
Java_org_contikios_cooja_corecomm_CLASSNAME_getMemory(JNIEnv *env, jobject obj, jint rel_addr, jint length, jbyteArray mem_arr)
{
(*env)->SetByteArrayRegion(
env,
mem_arr,
0,
(size_t) length,
(jbyte *) (((long)rel_addr) + referenceVar)
);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Replace a segment of the process memory with given byte array.
* \param start Start address of segment
* \param length Size of memory segment
* \param mem_arr Byte array contaning new memory
*
* Replaces a process memory segment with given byte array.
* This function does not perform ANY error checking, and the
* process may crash if addresses are not available/writable.
*
* This is a JNI function and should only be called via the
* responsible Java part (MoteType.java).
*/
JNIEXPORT void JNICALL
Java_org_contikios_cooja_corecomm_CLASSNAME_setMemory(JNIEnv *env, jobject obj, jint rel_addr, jint length, jbyteArray mem_arr)
{
jbyte *mem = (*env)->GetByteArrayElements(env, mem_arr, 0);
memcpy((char *)(((long)rel_addr) + referenceVar),
mem,
length);
(*env)->ReleaseByteArrayElements(env, mem_arr, mem, 0);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Let mote execute one "block" of code (tick mote).
*
* Let mote defined by the active contiki processes and current
* process memory execute some program code. This code must not block
* or else this function will never return. A typical contiki
* process will return when it executes PROCESS_WAIT..() statements.
*
* Before the control is left to contiki processes, any messages
* from the Java part are handled. These may for example be
* incoming network data. After the contiki processes return control,
* messages to the Java part are also handled (those which may need
* special attention).
*
* This is a JNI function and should only be called via the
* responsible Java part (MoteType.java).
*/
JNIEXPORT void JNICALL
Java_org_contikios_cooja_corecomm_CLASSNAME_tick(JNIEnv *env, jobject obj)
{
clock_time_t nextEtimer;
rtimer_clock_t nextRtimer;
simProcessRunValue = 0;
/* Let all simulation interfaces act first */
doActionsBeforeTick();
/* Poll etimer process */
if(etimer_pending()) {
etimer_request_poll();
}
/* Let rtimers run.
* Sets simProcessRunValue */
cooja_mt_exec(&rtimer_thread);
if(simProcessRunValue == 0) {
/* Rtimers done: Let Contiki handle a few events.
* Sets simProcessRunValue */
cooja_mt_exec(&process_run_thread);
}
/* Let all simulation interfaces act before returning to java */
doActionsAfterTick();
/* Do we have any pending timers */
simEtimerPending = etimer_pending() || rtimer_arch_pending();
if(!simEtimerPending) {
return;
}
/* Save nearest expiration time */
nextEtimer = etimer_next_expiration_time() - (clock_time_t) simCurrentTime;
nextRtimer = rtimer_arch_next() - (rtimer_clock_t) simCurrentTime;
if(etimer_pending() && rtimer_arch_pending()) {
simNextExpirationTime = MIN(nextEtimer, nextRtimer);
} else if(etimer_pending()) {
simNextExpirationTime = nextEtimer;
} else if(rtimer_arch_pending()) {
simNextExpirationTime = nextRtimer;
}
}
/*---------------------------------------------------------------------------*/
/**
* \brief Set the relative memory address of the reference variable.
* \return Relative memory address.
*
* This is a JNI function and should only be called via the
* responsible Java part (MoteType.java).
*/
JNIEXPORT void JNICALL
Java_org_contikios_cooja_corecomm_CLASSNAME_setReferenceAddress(JNIEnv *env, jobject obj, jint addr)
{
referenceVar = (((long)&referenceVar) - ((long)addr));
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2012-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 IP64_CONF_H
#define IP64_CONF_H
#undef UIP_FALLBACK_INTERFACE
#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface
#include "ip64-slip-interface.h"
#include "ip64-null-driver.h"
#define IP64_CONF_UIP_FALLBACK_INTERFACE_SLIP 1
#define IP64_CONF_UIP_FALLBACK_INTERFACE ip64_slip_interface
#define IP64_CONF_INPUT ip64_slip_interface_input
#define IP64_CONF_ETH_DRIVER ip64_null_driver
#endif /* IP64_CONF_H */

View file

@ -0,0 +1,54 @@
/*
* 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 __PLATFORM_CONF_H__
#define __PLATFORM_CONF_H__
#if WITH_IP64
#define WITH_SLIP 1
#ifndef UIP_FALLBACK_INTERFACE
#define UIP_FALLBACK_INTERFACE ip64_uip_fallback_interface
#endif
#endif /* WITH_IP64 */
#ifndef UIP_CONF_ND6_RA_RDNSS
#define UIP_CONF_ND6_RA_RDNSS 1
#endif
#ifndef UIP_CONF_ND6_SEND_RA
#define UIP_CONF_ND6_SEND_RA 1
#endif
#ifndef UIP_CONF_ROUTER
#define UIP_CONF_ROUTER 1
#endif
#endif /* __PLATFORM_CONF_H__ */

View file

@ -37,7 +37,7 @@ endif ## QUICKSTART
#MAIN_SRC = $(OBJECTDIR)/$(LIBNAME).c
MAIN_OBJ = $(OBJECTDIR)/$(LIBNAME).o
ARCHIVE = $(OBJECTDIR)/$(LIBNAME).a
JNILIB = $(OBJECTDIR)/$(LIBNAME).cooja
JNILIB = $(OBJECTDIR)/$(LIBNAME).$(TARGET)
CONTIKI_APP_OBJ = $(CONTIKI_APP).co
### COOJA platform sources
@ -75,7 +75,7 @@ CFLAGSNO = $(EXTRA_CC_ARGS) -Wall -g -I/usr/local/include -DCLASSNAME=$(CLASSNAM
CFLAGS += $(CFLAGSNO)
MODULES += core/net core/net/mac \
core/net/llsec
core/net/llsec core/net/ip64-addr
## Copied from Makefile.include, since Cooja overrides CFLAGS et al
HAS_STACK = 0

View file

@ -33,6 +33,10 @@
#ifndef CONTIKI_CONF_H_
#define CONTIKI_CONF_H_
#ifdef INCLUDE_SUBPLATFORM_CONF
#include "subplatform-conf.h"
#endif /* INCLUDE_SUBPLATFORM_CONF */
#define PROFILE_CONF_ON 0
#define ENERGEST_CONF_ON 0
#define LOG_CONF_ENABLED 1
@ -135,9 +139,17 @@
#define TCPIP_CONF_ANNOTATE_TRANSMISSIONS 1
#ifndef UIP_CONF_ND6_SEND_RA
#define UIP_CONF_ND6_SEND_RA 0
#endif
#ifndef UIP_CONF_ND6_REACHABLE_TIME
#define UIP_CONF_ND6_REACHABLE_TIME 600000
#endif
#ifndef UIP_CONF_ND6_RETRANS_TIMER
#define UIP_CONF_ND6_RETRANS_TIMER 10000
#endif
#define LINKADDR_CONF_SIZE 8
#define UIP_CONF_NETIF_MAX_ADDRESSES 3
@ -149,9 +161,6 @@
#define UIP_CONF_IPV6_REASSEMBLY 0
#define UIP_CONF_NETIF_MAX_ADDRESSES 3
#define UIP_CONF_IP_FORWARD 0
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 240
#endif
#define SICSLOWPAN_CONF_COMPRESSION SICSLOWPAN_COMPRESSION_HC06
#ifndef SICSLOWPAN_CONF_FRAG
@ -168,7 +177,9 @@
#define PACKETBUF_CONF_ATTRS_INLINE 1
#ifndef QUEUEBUF_CONF_NUM
#define QUEUEBUF_CONF_NUM 16
#endif
#define CC_CONF_REGISTER_ARGS 1
#define CC_CONF_FUNCTION_POINTER_ARGS 1
@ -202,12 +213,6 @@ typedef unsigned long rtimer_clock_t;
#define UIP_CONF_DHCP_LIGHT
#define UIP_CONF_LLH_LEN 0
#ifndef UIP_CONF_RECEIVE_WINDOW
#define UIP_CONF_RECEIVE_WINDOW 48
#endif
#ifndef UIP_CONF_TCP_MSS
#define UIP_CONF_TCP_MSS 48
#endif
#define UIP_CONF_MAX_CONNECTIONS 4
#define UIP_CONF_MAX_LISTENPORTS 8
#define UIP_CONF_UDP_CONNS 12
@ -230,10 +235,27 @@ typedef unsigned long rtimer_clock_t;
#define CFS_CONF_OFFSET_TYPE long
#ifndef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 1600
#endif
#ifndef UIP_CONF_TCP_MSS
#define UIP_CONF_TCP_MSS (UIP_CONF_BUFFER_SIZE - 70)
#endif
#ifndef UIP_CONF_RECEIVE_WINDOW
#define UIP_CONF_RECEIVE_WINDOW (UIP_CONF_BUFFER_SIZE - 70)
#endif
#define RF_CHANNEL 26
#define IEEE802154_CONF_PANID 0xABCD
#define NETSTACK_RADIO_MAX_PAYLOAD_LEN 125
/* include the project config */
/* PROJECT_CONF_H might be defined in the project Makefile */
#ifdef PROJECT_CONF_H
#include PROJECT_CONF_H
#endif /* PROJECT_CONF_H */
#endif /* CONTIKI_CONF_H_ */

View file

@ -42,4 +42,4 @@ CURSES_LIBS ?= -lncurses
TARGET_LIBFILES += $(CURSES_LIBS)
MODULES+=core/net core/net/mac core/ctk core/net/llsec
MODULES+=core/net core/net/mac core/ctk core/net/llsec core/net/ip64-addr/

View file

@ -1 +1,2 @@
205
209

View file

@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>My simulation</title>
<speedlimit>1.0</speedlimit>
<randomseed>generated</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>100.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.contikimote.ContikiMoteType
<identifier>mtype503</identifier>
<description>ip64-router/ip64-router.c TARGET=cooja-ip64</description>
<source>[CONTIKI_DIR]/examples/ip64-router/ip64-router.c</source>
<commands>make ip64-router.cooja-ip64 TARGET=cooja-ip64</commands>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Battery</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiVib</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiMoteID</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRS232</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiBeeper</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiIPAddress</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRadio</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiButton</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiPIR</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiClock</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiLED</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiCFS</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<symbols>false</symbols>
</motetype>
<motetype>
org.contikios.cooja.contikimote.ContikiMoteType
<identifier>mtype555</identifier>
<description>examples/http-socket/http-example.c</description>
<source>[CONTIKI_DIR]/examples/http-socket/http-example.c</source>
<commands>make http-example.cooja TARGET=cooja</commands>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Battery</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiVib</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiMoteID</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRS232</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiBeeper</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiIPAddress</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiRadio</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiButton</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiPIR</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiClock</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiLED</moteinterface>
<moteinterface>org.contikios.cooja.contikimote.interfaces.ContikiCFS</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<symbols>false</symbols>
</motetype>
<mote>
<interface_config>
org.contikios.cooja.interfaces.Position
<x>55.719691912311305</x>
<y>37.8697579181178</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.contikimote.interfaces.ContikiMoteID
<id>1</id>
</interface_config>
<interface_config>
org.contikios.cooja.contikimote.interfaces.ContikiRadio
<bitrate>250.0</bitrate>
</interface_config>
<motetype_identifier>mtype503</motetype_identifier>
</mote>
<mote>
<interface_config>
org.contikios.cooja.interfaces.Position
<x>65.60514720922419</x>
<y>33.88871867406431</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.contikimote.interfaces.ContikiMoteID
<id>2</id>
</interface_config>
<interface_config>
org.contikios.cooja.contikimote.interfaces.ContikiRadio
<bitrate>250.0</bitrate>
</interface_config>
<motetype_identifier>mtype555</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>280</width>
<z>1</z>
<height>160</height>
<location_x>606</location_x>
<location_y>15</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Visualizer
<plugin_config>
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.LEDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
<viewport>8.230641272440463 0.0 0.0 8.230641272440463 -395.6087959411366 -239.69239249818943</viewport>
</plugin_config>
<width>219</width>
<z>3</z>
<height>171</height>
<location_x>29</location_x>
<location_y>27</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter />
<formatted_time />
<coloring />
</plugin_config>
<width>888</width>
<z>2</z>
<height>603</height>
<location_x>34</location_x>
<location_y>307</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.ScriptRunner
<plugin_config>
<script>/* conf */&#xD;
var travis = java.lang.System.getenv().get("TRAVIS");&#xD;
if (travis == null) {&#xD;
/* Instant Contiki */&#xD;
CMD_TUNNEL = "echo '-vj' &gt; ~/.slirprc &amp;&amp; make Connect.class &amp;&amp; java Connect 'nc localhost 60001' 'script -t -f -c slirp'";&#xD;
CMD_PING = "ping -c 5 8.8.8.8";&#xD;
CMD_DIR = "../../wpcapslip";&#xD;
} else {&#xD;
/* Travis */&#xD;
CMD_TUNNEL = "cd $TRAVIS_BUILD_DIR/tools/wpcapslip &amp;&amp; sudo apt-get install slirp &amp;&amp; echo '-vj' &gt; ~/.slirprc &amp;&amp; make Connect.class &amp;&amp; java Connect 'nc localhost 60001' 'script -t -f -c slirp'";&#xD;
CMD_PING = "ping -c 5 8.8.8.8";&#xD;
CMD_DIR = ".";&#xD;
}&#xD;
&#xD;
/* delay */&#xD;
GENERATE_MSG(1000, "continue");&#xD;
YIELD_THEN_WAIT_UNTIL(msg.equals("continue"));&#xD;
&#xD;
/* realtime speed */&#xD;
sim.setSpeedLimit(1.0);&#xD;
&#xD;
/* tunnel interface */&#xD;
log.log("opening tunnel interface: " + CMD_TUNNEL + "\n");&#xD;
launcher = new java.lang.ProcessBuilder["(java.lang.String[])"](['sh','-c',CMD_TUNNEL]);&#xD;
launcher.directory(new java.io.File(CMD_DIR));&#xD;
launcher.redirectErrorStream(true);&#xD;
tunProcess = launcher.start();&#xD;
tunRunnable = new Object();&#xD;
tunRunnable.run = function() {&#xD;
var stdIn = new java.io.BufferedReader(new java.io.InputStreamReader(tunProcess.getInputStream()));&#xD;
while ((line = stdIn.readLine()) != null) {&#xD;
if (line != null &amp;&amp; !line.trim().equals("")) {&#xD;
log.log("TUN&gt; " + line + "\n");&#xD;
}&#xD;
}&#xD;
tunProcess.destroy();&#xD;
}&#xD;
new java.lang.Thread(new java.lang.Runnable(tunRunnable)).start();&#xD;
&#xD;
GENERATE_MSG(2000, "continue");&#xD;
YIELD_THEN_WAIT_UNTIL(msg.equals("continue"));&#xD;
&#xD;
/* ping */&#xD;
log.log("pinging: " + CMD_PING + "\n");&#xD;
launcher = new java.lang.ProcessBuilder["(java.lang.String[])"](['sh','-c',CMD_PING]);&#xD;
launcher.directory(new java.io.File(CMD_DIR));&#xD;
launcher.redirectErrorStream(true);&#xD;
tunProcess = launcher.start();&#xD;
tunRunnable = new Object();&#xD;
tunRunnable.run = function() {&#xD;
var stdIn = new java.io.BufferedReader(new java.io.InputStreamReader(tunProcess.getInputStream()));&#xD;
while ((line = stdIn.readLine()) != null) {&#xD;
if (line != null &amp;&amp; !line.trim().equals("")) {&#xD;
log.log("PING&gt; " + line + "\n");&#xD;
}&#xD;
}&#xD;
tunProcess.destroy();&#xD;
}&#xD;
new java.lang.Thread(new java.lang.Runnable(tunRunnable)).start();&#xD;
&#xD;
GENERATE_MSG(2000000, "stop");&#xD;
while(!msg.equals("stop")) {&#xD;
if (!msg.startsWith("#L")) {&#xD;
log.log(mote + ": " + msg + "\n");&#xD;
}&#xD;
if (id == 2 &amp;&amp; msg.startsWith("HTTP socket closed")) {&#xD;
if (msg.split(' ')[3] &gt; 0) {&#xD;
log.testOK();&#xD;
} else {&#xD;
log.testFailed(); &#xD;
}&#xD;
}&#xD;
YIELD();&#xD;
}&#xD;
log.testFailed();</script>
<active>true</active>
</plugin_config>
<width>960</width>
<z>0</z>
<height>682</height>
<location_x>528</location_x>
<location_y>192</location_y>
</plugin>
<plugin>
org.contikios.cooja.serialsocket.SerialSocketServer
<mote_arg>0</mote_arg>
<plugin_config>
<port>60001</port>
<bound>true</bound>
</plugin_config>
<width>362</width>
<z>4</z>
<height>116</height>
<location_x>234</location_x>
<location_y>101</location_y>
</plugin>
</simconf>

View file

@ -0,0 +1 @@
include ../Makefile.simulation-test

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2012, 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.
*
*/
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
public class Connect {
private static Process cmd1Process;
private static Process cmd2Process;
private static BufferedOutputStream cmd1Out = null;
private static BufferedOutputStream cmd2Out = null;
private static final int BUFSIZE = 512;
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("Usage: " + Connect.class.getName() + " [cmd1] [cmd2]");
System.exit(1);
}
/* Command 1 */
String cmd1 = args[0];
System.out.println("> " + cmd1);
cmd1Process = Runtime.getRuntime().exec(cmd1, null, new File("."));
final DataInputStream cmd1Input = new DataInputStream(
cmd1Process.getInputStream());
final BufferedReader cmd1Err = new BufferedReader(
new InputStreamReader(cmd1Process.getErrorStream()));
cmd1Out = new BufferedOutputStream(cmd1Process.getOutputStream());
Thread readInput = new Thread(new Runnable() {
public void run() {
int numRead = 0;
byte[] buf = new byte[BUFSIZE];
try {
while (true) {
numRead = cmd1Input.read(buf, 0, BUFSIZE);
if (numRead > 0 && cmd2Out != null) {
/* System.err.println("1>2 " + numRead); */
cmd2Out.write(buf, 0, numRead);
cmd2Out.flush();
}
Thread.sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
}
String exitVal = "?";
try {
if (cmd1Process != null) {
exitVal = "" + cmd1Process.exitValue();
}
} catch (IllegalStateException e) {
e.printStackTrace();
exitVal = "!";
}
System.out.println("cmd1 terminated: " + exitVal);
exit();
}
}, "read stdout cmd1");
Thread readError = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = cmd1Err.readLine()) != null) {
System.err.println("cmd1 err: " + line);
}
cmd1Err.close();
} catch (IOException e) {
}
System.err.println("cmd1 terminated.");
exit();
}
}, "read error cmd1");
readInput.start();
readError.start();
/* Command 2 */
String cmd2 = args[1];
System.err.println("> " + cmd2);
cmd2Process = Runtime.getRuntime().exec(cmd2, null, new File("."));
final DataInputStream cmd2Input = new DataInputStream(
cmd2Process.getInputStream());
final BufferedReader cmd2Err = new BufferedReader(
new InputStreamReader(cmd2Process.getErrorStream()));
cmd2Out = new BufferedOutputStream(cmd2Process.getOutputStream());
readInput = new Thread(new Runnable() {
public void run() {
int numRead = 0;
byte[] buf = new byte[BUFSIZE];
try {
while (true) {
numRead = cmd2Input.read(buf, 0, BUFSIZE);
if (numRead > 0 && cmd1Out != null) {
/* System.err.println("2>1 " + numRead); */
cmd1Out.write(buf, 0, numRead);
cmd1Out.flush();
}
Thread.sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
}
String exitVal = "?";
try {
if (cmd2Process != null) {
exitVal = "" + cmd2Process.exitValue();
}
} catch (IllegalStateException e) {
e.printStackTrace();
exitVal = "!";
}
System.out.println("cmd2 terminated: " + exitVal);
exit();
}
}, "read stdout cmd2");
readError = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = cmd2Err.readLine()) != null) {
System.err.println("cmd2 err: " + line);
}
cmd2Err.close();
} catch (IOException e) {
}
System.err.println("cmd2 terminated.");
exit();
}
}, "read error cmd2");
readInput.start();
readError.start();
while (true) {
Thread.sleep(100);
}
}
private static void exit() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
try {
if (cmd1Process != null) {
cmd1Process.destroy();
}
} catch (Exception e) {
}
try {
if (cmd2Process != null) {
cmd2Process.destroy();
}
} catch (Exception e) {
}
System.err.flush();
System.exit(1);
}
}

View file

@ -0,0 +1,115 @@
/*
* 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.
*
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.net.Socket;
public class ConnectSocket {
private static BufferedOutputStream stdoutOutput = null;
private static BufferedOutputStream networkServerOutput = null;
private static final int BUFSIZE = 512;
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("Usage: " + ConnectSocket.class.getName() + " [server ip] [server port]");
System.exit(1);
}
/* Stdin */
final BufferedInputStream stdinInput = new BufferedInputStream(new DataInputStream(System.in));
stdoutOutput = new BufferedOutputStream(System.out);
Thread readInput = new Thread(new Runnable() {
public void run() {
int numRead = 0;
byte[] buf = new byte[BUFSIZE];
try {
while (true) {
numRead = stdinInput.read(buf, 0, BUFSIZE);
if (numRead > 0 && networkServerOutput != null) {
/* System.err.println("1>2 " + numRead); */
networkServerOutput.write(buf, 0, numRead);
networkServerOutput.flush();
}
Thread.sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
}
exit();
}
}, "read stdin");
readInput.start();
/* Network server */
Socket networkServer = new Socket(args[0], Integer.parseInt(args[1]));
final BufferedInputStream networkServerInput = new BufferedInputStream(new DataInputStream(networkServer.getInputStream()));
networkServerOutput = new BufferedOutputStream(networkServer.getOutputStream());
readInput = new Thread(new Runnable() {
public void run() {
int numRead = 0;
byte[] buf = new byte[BUFSIZE];
try {
while (true) {
numRead = networkServerInput.read(buf, 0, BUFSIZE);
if (numRead > 0 && stdoutOutput != null) {
/* System.err.println("2>1 " + numRead); */
stdoutOutput.write(buf, 0, numRead);
stdoutOutput.flush();
}
Thread.sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
}
exit();
}
}, "read network server");
readInput.start();
while (true) {
Thread.sleep(100);
}
}
private static void exit() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
System.err.flush();
System.exit(1);
}
}

View file

@ -1,12 +1,21 @@
CONTIKI=../..
CFLAGS=-Wall -Werror -I$(CONTIKI)/core -I.
CC=gcc
CFLAGS=-Wall -I$(CONTIKI)/core -I.
all: wpcapslip
all: wpcapslip wpcapstdio Connect.class ConnectSocket.class
%.class: %.java
javac $*.java
vpath %.c $(CONTIKI)/core/net
wpcapslip: wpcapslip.o wpcap.o tcpdump.o
wpcapstdio: wpcapstdio.o wpcap.o tcpdump.o
%: %.o
$(CC) $(LDFLAGS) $^ /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a -o $@
clean:
rm -f *.class *.exe *.o

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2005, 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.
*
*/
#ifndef __TCPDUMP_H__
#define __TCPDUMP_H__
#include "net/ip/uip.h"
int tcpdump_format(uint8_t *packet, uint16_t packetlen,
char *printbuf, uint16_t printbuflen);
#endif /* __TCPDUMP_H__ */

289
tools/wpcapslip/tcpdump.c Normal file
View file

@ -0,0 +1,289 @@
/*
* Copyright (c) 2005, 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.
*
*/
#include "contiki-net.h"
#include <string.h>
#include <stdio.h>
struct ip_hdr {
/* IP header. */
uint8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
uint16_t ipchksum;
uint8_t srcipaddr[4],
destipaddr[4];
};
#define TCP_FIN 0x01
#define TCP_SYN 0x02
#define TCP_RST 0x04
#define TCP_PSH 0x08
#define TCP_ACK 0x10
#define TCP_URG 0x20
#define TCP_CTL 0x3f
struct tcpip_hdr {
/* IP header. */
uint8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
uint16_t ipchksum;
uint8_t srcipaddr[4],
destipaddr[4];
/* TCP header. */
uint16_t srcport,
destport;
uint8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
uint16_t tcpchksum;
uint8_t urgp[2];
uint8_t optdata[4];
};
#define ICMP_ECHO_REPLY 0
#define ICMP_ECHO 8
struct icmpip_hdr {
/* IP header. */
uint8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
uint16_t ipchksum;
uint8_t srcipaddr[4],
destipaddr[4];
/* The ICMP and IP headers. */
/* ICMP (echo) header. */
uint8_t type, icode;
uint16_t icmpchksum;
uint16_t id, seqno;
};
/* The UDP and IP headers. */
struct udpip_hdr {
/* IP header. */
uint8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
uint16_t ipchksum;
uint8_t srcipaddr[4],
destipaddr[4];
/* UDP header. */
uint16_t srcport,
destport;
uint16_t udplen;
uint16_t udpchksum;
};
#define ETHBUF ((struct eth_hdr *)&packet[0])
#define IPBUF ((struct ip_hdr *)&packet[0])
#define UDPBUF ((struct udpip_hdr *)&packet[0])
#define ICMPBUF ((struct icmpip_hdr *)&packet[0])
#define TCPBUF ((struct tcpip_hdr *)&packet[0])
/*---------------------------------------------------------------------------*/
static void
tcpflags(unsigned char flags, char *flagsstr)
{
if(flags & TCP_FIN) {
*flagsstr++ = 'F';
}
if(flags & TCP_SYN) {
*flagsstr++ = 'S';
}
if(flags & TCP_RST) {
*flagsstr++ = 'R';
}
if(flags & TCP_ACK) {
*flagsstr++ = 'A';
}
if(flags & TCP_URG) {
*flagsstr++ = 'U';
}
*flagsstr = 0;
}
/*---------------------------------------------------------------------------*/
static char * CC_FASTCALL
n(uint16_t num, char *ptr)
{
uint16_t d;
uint8_t a, f;
if(num == 0) {
*ptr = '0';
return ptr + 1;
} else {
f = 0;
for(d = 10000; d >= 1; d /= 10) {
a = (num / d) % 10;
if(f == 1 || a > 0) {
*ptr = a + '0';
++ptr;
f = 1;
}
}
}
return ptr;
}
/*---------------------------------------------------------------------------*/
static char * CC_FASTCALL
d(char *ptr)
{
*ptr = '.';
return ptr + 1;
}
/*---------------------------------------------------------------------------*/
static char * CC_FASTCALL
s(char *str, char *ptr)
{
strcpy(ptr, str);
return ptr + strlen(str);
}
/*---------------------------------------------------------------------------*/
int
tcpdump_format(uint8_t *packet, uint16_t packetlen,
char *buf, uint16_t buflen)
{
char flags[8];
if(IPBUF->proto == UIP_PROTO_ICMP) {
if(ICMPBUF->type == ICMP_ECHO) {
return s(" ping",
n(IPBUF->destipaddr[3], d(
n(IPBUF->destipaddr[2], d(
n(IPBUF->destipaddr[1], d(
n(IPBUF->destipaddr[0],
s(" ",
n(IPBUF->srcipaddr[3], d(
n(IPBUF->srcipaddr[2], d(
n(IPBUF->srcipaddr[1], d(
n(IPBUF->srcipaddr[0],
buf)))))))))))))))) - buf;
/* return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d ping",
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/
} else if(ICMPBUF->type == ICMP_ECHO_REPLY) {
return s(" pong",
n(IPBUF->destipaddr[3], d(
n(IPBUF->destipaddr[2], d(
n(IPBUF->destipaddr[1], d(
n(IPBUF->destipaddr[0],
s(" ",
n(IPBUF->srcipaddr[3], d(
n(IPBUF->srcipaddr[2], d(
n(IPBUF->srcipaddr[1], d(
n(IPBUF->srcipaddr[0],
buf)))))))))))))))) - buf;
/* return sprintf(buf, "%d.%d.%d.%d %d.%d.%d.%d pong",
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
IPBUF->destipaddr[2], IPBUF->destipaddr[3]);*/
}
} else if(IPBUF->proto == UIP_PROTO_UDP) {
return s(" UDP",
n(uip_htons(UDPBUF->destport), d(
n(IPBUF->destipaddr[3], d(
n(IPBUF->destipaddr[2], d(
n(IPBUF->destipaddr[1], d(
n(IPBUF->destipaddr[0],
s(" ",
n(uip_htons(UDPBUF->srcport), d(
n(IPBUF->srcipaddr[3], d(
n(IPBUF->srcipaddr[2], d(
n(IPBUF->srcipaddr[1], d(
n(IPBUF->srcipaddr[0],
buf)))))))))))))))))))) - buf;
/* return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d UDP",
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
uip_htons(UDPBUF->srcport),
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
IPBUF->destipaddr[2], IPBUF->destipaddr[3],
uip_htons(UDPBUF->destport));*/
} else if(IPBUF->proto == UIP_PROTO_TCP) {
tcpflags(TCPBUF->flags, flags);
return s(flags,
s(" ",
n(uip_htons(TCPBUF->destport), d(
n(IPBUF->destipaddr[3], d(
n(IPBUF->destipaddr[2], d(
n(IPBUF->destipaddr[1], d(
n(IPBUF->destipaddr[0],
s(" ",
n(uip_htons(TCPBUF->srcport), d(
n(IPBUF->srcipaddr[3], d(
n(IPBUF->srcipaddr[2], d(
n(IPBUF->srcipaddr[1], d(
n(IPBUF->srcipaddr[0],
buf))))))))))))))))))))) - buf;
/* return sprintf(buf, "%d.%d.%d.%d.%d %d.%d.%d.%d.%d %s",
IPBUF->srcipaddr[0], IPBUF->srcipaddr[1],
IPBUF->srcipaddr[2], IPBUF->srcipaddr[3],
uip_htons(TCPBUF->srcport),
IPBUF->destipaddr[0], IPBUF->destipaddr[1],
IPBUF->destipaddr[2], IPBUF->destipaddr[3],
uip_htons(TCPBUF->destport),
flags); */
} else {
strcpy(buf, "Unrecognized protocol");
}
return 0;
}
/*---------------------------------------------------------------------------*/

View file

@ -58,7 +58,6 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
@ -69,7 +68,7 @@
#define PROGRESS(x)
static void raw_send(void *buf, int len);
void raw_send(void *buf, int len);
struct pcap;
@ -150,7 +149,7 @@ struct arp_entry {
struct uip_eth_addr ethaddr;
uint8_t time;
};
static struct uip_eth_addr uip_lladdr = {{0,0,0,0,0,0}};
struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}};
static const uip_ipaddr_t all_zeroes_addr = { { 0x0, /* rest is 0 */ } };
static const struct uip_eth_addr broadcast_ethaddr =
{{0xff,0xff,0xff,0xff,0xff,0xff}};
@ -164,18 +163,20 @@ static int arptime;
static int logging;
uip_lladdr_t uip_lladdr;
static void
log_message(char *msg1, char *msg2)
{
if(logging) {
printf("Log: %s %s\n", msg1, msg2);
fprintf(stderr, "Log: %s %s\n", msg1, msg2);
}
}
/*---------------------------------------------------------------------------*/
static void
error_exit(char *msg1)
{
printf("error_exit: %s", msg1);
fprintf(stderr, "error_exit: %s", msg1);
exit(EXIT_FAILURE);
}
/*---------------------------------------------------------------------------*/
@ -263,7 +264,7 @@ set_ethaddr(struct in_addr addr)
log_message("set_ethaddr: with address: ", inet_ntoa(adapter_addr));
if(adapter_addr.s_addr == addr.s_addr) {
printf("Using local network interface with address %s\n",
fprintf(stderr, "Using local network interface with address %s\n",
inet_ntoa(adapter_addr));
if(adapters->PhysicalAddressLength != 6) {
error_exit("ip addr specified on cmdline does not belong to an ethernet card\n");
@ -292,12 +293,12 @@ print_packet(unsigned char *buf, int len)
int i;
for(i = 0; i < len; ++i) {
printf("0x%02x, ", buf[i]);
fprintf(stderr, "0x%02x, ", buf[i]);
if(i % 8 == 7) {
printf("\n");
fprintf(stderr, "\n");
}
}
printf("\n\n");
fprintf(stderr, "\n\n");
}
/*---------------------------------------------------------------------------*/
static void
@ -399,7 +400,7 @@ arp_out(struct ethip_hdr *iphdr, int len)
int i;
#endif
#if 1
#if 0
/* Find the destination IP address in the ARP table and construct
the Ethernet header. If the destination IP addres isn't on the
local network, we use the default router's IP address instead.
@ -439,8 +440,8 @@ arp_out(struct ethip_hdr *iphdr, int len)
memset(arphdr->ethhdr.dest.addr, 0xff, 6);
memset(arphdr->dhwaddr.addr, 0x00, 6);
memcpy(arphdr->ethhdr.src.addr, uip_lladdr.addr, 6);
memcpy(arphdr->shwaddr.addr, uip_lladdr.addr, 6);
memcpy(arphdr->ethhdr.src.addr, uip_ethaddr.addr, 6);
memcpy(arphdr->shwaddr.addr, uip_ethaddr.addr, 6);
uip_ipaddr_copy(&arphdr->dipaddr, &ipaddr);
uip_ipaddr_copy(&arphdr->sipaddr, &netaddr);
@ -476,14 +477,14 @@ do_arp(void *buf, int len)
if(hdr->ethhdr.type == UIP_HTONS(UIP_ETHTYPE_ARP)) {
if(hdr->opcode == UIP_HTONS(ARP_REQUEST)) {
/* Check if the ARP is for our network */
/* printf("ARP for %d.%d.%d.%d we are %d.%d.%d.%d/%d.%d.%d.%d\n",
/* fprintf(stderr, "ARP for %d.%d.%d.%d we are %d.%d.%d.%d/%d.%d.%d.%d\n",
uip_ipaddr_to_quad(&hdr->dipaddr),
uip_ipaddr_to_quad(&netaddr),
uip_ipaddr_to_quad(&netmask));*/
if(uip_ipaddr_maskcmp(&hdr->dipaddr, &netaddr, &netmask)) {
uip_ipaddr_t tmpaddr;
/* printf("ARP for us.\n");*/
/* fprintf(stderr, "ARP for us.\n");*/
uip_arp_update(&hdr->sipaddr, &hdr->shwaddr);
hdr->opcode = UIP_HTONS(ARP_REPLY);
@ -521,8 +522,8 @@ cleanup(void)
char buf[1024];
snprintf(buf, sizeof(buf), "route delete %d.%d.%d.%d",
uip_ipaddr_to_quad(&ifaddr));
printf("%s\n", buf);
uip_ipaddr_to_quad(&netaddr));
fprintf(stderr, "%s\n", buf);
system(buf);
}
@ -551,7 +552,7 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
tmpaddr = inet_addr(slipnetmask);
memcpy(&netmask.u16[0], &tmpaddr, sizeof(tmpaddr));
printf("Network address %d.%d.%d.%d/%d.%d.%d.%d\n",
fprintf(stderr, "Network address %d.%d.%d.%d/%d.%d.%d.%d\n",
uip_ipaddr_to_quad(&netaddr),
uip_ipaddr_to_quad(&netmask));
@ -559,7 +560,7 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
uip_ipaddr_to_quad(&netaddr),
uip_ipaddr_to_quad(&netmask),
uip_ipaddr_to_quad(&ifaddr));
printf("%s\n", buf);
fprintf(stderr, "%s\n", buf);
system(buf);
signal(SIGTERM, remove_route);
@ -593,7 +594,7 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
if(ret > 0) {
/* print_packet(buf, ret);*/
if(do_arp(buf, ret)) {
printf("IP packet\n");
fprintf(stderr, "IP packet\n");
}
}
sleep(1);
@ -602,17 +603,16 @@ wpcap_start(char *ethcardaddr, char *slipnetaddr, char *slipnetmask, int log)
}
/*---------------------------------------------------------------------------*/
uint16_t
wpcap_poll(char **buf)
wpcap_poll(char **buf, int eth)
{
struct pcap_pkthdr *packet_header;
unsigned char *packet;
int len;
int ret;
char *buf2;
switch(pcap_next_ex(pcap, &packet_header, &packet)) {
case -1:
error_exit("error on poll\n");
case 0:
ret = pcap_next_ex(pcap, &packet_header, &packet);
if (ret != 1) {
return 0;
}
@ -622,13 +622,20 @@ wpcap_poll(char **buf)
CopyMemory(*buf, packet, packet_header->caplen);
len = packet_header->caplen;
/* printf("len %d\n", len);*/
if(eth) {
/* poll requested us to return the raw ethernet packet */
return len;
}
buf2 = do_arp(*buf, len);
if(buf2 == NULL) {
return 0;
} else {
len = len - (buf2 - *buf);
*buf = buf2;
/*fprintf(stderr, "wpcap_poll() %d\n", len);*/
return len;
}
}
@ -644,7 +651,7 @@ wpcap_send(void *buf, int len)
raw_send(buf2, len);
}
/*---------------------------------------------------------------------------*/
static void
void
raw_send(void *buf, int len)
{
/* printf("sending len %d\n", len);*/

View file

@ -47,8 +47,6 @@
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
@ -75,6 +73,18 @@ static int should_print = 0;
#define IP_HLEN 20
/*---------------------------------------------------------------------------*/
uint16_t
uip_htons(uint16_t val)
{
return UIP_HTONS(val);
}
/*---------------------------------------------------------------------------*/
uint32_t
uip_htonl(uint32_t val)
{
return UIP_HTONL(val);
}
/*---------------------------------------------------------------------------*/
static void
print_packet(uint8_t *packet, int len)
@ -289,8 +299,9 @@ serial_to_wpcap(FILE *inslip)
*/
#define DEBUG_LINE_MARKER '\r'
int ecode;
ecode = check_ip(&uip.iphdr, inbufptr);
if(ecode < 0 && inbufptr == 8 && strncmp(uip.inbuf, "=IPA", 4) == 0) {
if(ecode < 0 && inbufptr == 8 && strncmp((const char*)uip.inbuf, "=IPA", 4) == 0) {
static struct in_addr ipa;
inbufptr = 0;
@ -902,7 +913,7 @@ main(int argc, char **argv)
if(iphdr->ip_id != last_id) {
last_id = iphdr->ip_id;
/* printf("------ wpcap_poll ret %d\n", ret);*/
print_packet(pbuf, ret);
print_packet((uint8_t*)pbuf, ret);
write_to_serial(slipfd, pbuf, ret);
slip_flushbuf(slipfd);
sigalarm_reset();

View file

@ -0,0 +1,597 @@
/*
* Copyright (c) 2012, Thingsquare, 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 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.
*
* Author: Fredrik Osterlind <fredrik@thingsquare.com>
* Based on wpcapslip.c by : Oliver Schmidt <ol.sc@web.de>
*/
/* This is a stripped-down version of wpcapslip: Instead of reading from and writing
* to a serial port, this program just reads and writes to stdin/stdout. To
* achieve the same functionality as wpcapslip, this program can hence be connected
* to serialdump. But, in contrast to wpcapslip, this program can easily be connected
* to networked or simulated serial ports. -- Fredrik, 2012 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __CYGWIN__
#include <alloca.h>
#else /* __CYGWIN__ */
#include <malloc.h>
#endif /* __CYGWIN__ */
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <err.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PROGRESS(x)
void wpcap_start(char *ethifaddr, char *netaddr, char *netmask, int logging);
void wpcap_send(void *buf, int len);
void raw_send(void *buf, int len);
uint16_t wpcap_poll(char **buf, int eth);
#include "net/tcpdump.h"
static int should_print = 0;
static int send_eth = 0; /* Sends ethernet frames or IP packets */
#define IP_HLEN 20
/*---------------------------------------------------------------------------*/
uint16_t
uip_htons(uint16_t val)
{
return UIP_HTONS(val);
}
/*---------------------------------------------------------------------------*/
uint32_t
uip_htonl(uint32_t val)
{
return UIP_HTONL(val);
}
/*---------------------------------------------------------------------------*/
static void
print_packet(char* prefix, uint8_t *packet, int len)
{
char buf[2000];
if(should_print) {
tcpdump_format(packet, len, buf, sizeof(buf));
fprintf(stderr, "%s: %s\n", prefix, buf);
}
}
/*---------------------------------------------------------------------------*/
void cleanup(void);
/*---------------------------------------------------------------------------*/
void
sigcleanup(int signo)
{
fprintf(stderr, "signal %d\n", signo);
exit(0); /* exit(0) will call cleanup() */
}
/*---------------------------------------------------------------------------*/
#define SLIP_END 0300
#define SLIP_ESC 0333
#define SLIP_ESC_END 0334
#define SLIP_ESC_ESC 0335
struct ip {
u_int8_t ip_vhl; /* version and header length */
#define IP_V4 0x40
#define IP_V 0xf0
#define IP_HL 0x0f
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
u_int32_t ip_src, ip_dst; /* source and dest address */
u_int16_t uh_sport; /* source port */
u_int16_t uh_dport; /* destination port */
u_int16_t uh_ulen; /* udp length */
u_int16_t uh_sum; /* udp checksum */
};
static int ip_id, last_id;
int
ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
int
ssystem(const char *fmt, ...)
{
char cmd[128];
va_list ap;
va_start(ap, fmt);
vsnprintf(cmd, sizeof(cmd), fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", cmd);
fflush(stderr);
return system(cmd);
}
/*---------------------------------------------------------------------------*/
int
is_sensible_string(const unsigned char *s, int len)
{
int i;
for(i = 1; i < len; i++) {
if(s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') {
continue;
} else if(s[i] < ' ' || '~' < s[i]) {
return 0;
}
}
return 1;
}
/*---------------------------------------------------------------------------*/
u_int16_t
ip4sum(u_int16_t sum, const void *_p, u_int16_t len)
{
u_int16_t t;
const u_int8_t *p = _p;
const u_int8_t *end = p + len;
while(p < (end - 1)) {
t = (p[0] << 8) + p[1];
sum += t;
if(sum < t)
sum++;
p += 2;
}
if(p < end) {
t = (p[0] << 8) + 0;
sum += t;
if(sum < t)
sum++;
}
return sum;
}
/*---------------------------------------------------------------------------*/
static uint16_t
chksum(const void *p, uint16_t len)
{
uint16_t sum = ip4sum(0, p, len);
return (sum == 0) ? 0xffff : uip_htons(sum);
}
/*---------------------------------------------------------------------------*/
int
check_ip(const struct ip *ip, unsigned ip_len)
{
u_int16_t sum, ip_hl;
if(send_eth) {
return 0;
}
/* Check IP version and length. */
if((ip->ip_vhl & IP_V) != IP_V4) {
return -1;
}
if(uip_ntohs(ip->ip_len) > ip_len) {
return -2;
}
if(uip_ntohs(ip->ip_len) < ip_len) {
return -3;
}
/* Check IP header. */
ip_hl = 4 * (ip->ip_vhl & IP_HL);
sum = ip4sum(0, ip, ip_hl);
if(sum != 0xffff && sum != 0x0) {
return -4;
}
if(ip->ip_p == 6 || ip->ip_p == 17) { /* Check TCP or UDP header. */
u_int16_t tcp_len = ip_len - ip_hl;
/* Sum pseudoheader. */
sum = ip->ip_p + tcp_len; /* proto and len, no carry */
sum = ip4sum(sum, &ip->ip_src, 8); /* src and dst */
/* Sum TCP/UDP header and data. */
sum = ip4sum(sum, (u_int8_t*)ip + ip_hl, tcp_len);
/* Failed checksum test? */
if(sum != 0xffff && sum != 0x0) {
if(ip->ip_p == 6) { /* TCP == 6 */
return -5;
} else { /* UDP */
/* Deal with disabled UDP checksums. */
if(ip->uh_sum != 0) {
return -6;
}
}
}
} else if(ip->ip_p == 1) { /* ICMP */
u_int16_t icmp_len = ip_len - ip_hl;
sum = ip4sum(0, (u_int8_t*)ip + ip_hl, icmp_len);
if(sum != 0xffff && sum != 0x0) {
return -7;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
/*
* Read a single character from stdin. When we have a full packet, write it to
* the network interface.
*/
void
serial_to_wpcap(void)
{
static union {
unsigned char inbuf[2000];
struct ip iphdr;
} uip;
static int inbufptr = 0;
int ret;
unsigned char c;
if(inbufptr >= sizeof(uip.inbuf)) {
inbufptr = 0;
return;
}
ret = read(STDIN_FILENO, &c, 1);
if(ret <= 0) {
err(1, "serial_to_wpcap: read");
inbufptr = 0;
return;
}
switch (c) {
case SLIP_END:
if(inbufptr > 0) {
/*
* Sanity checks.
*/
#define DEBUG_LINE_MARKER '\r'
int ecode;
ecode = check_ip(&uip.iphdr, inbufptr);
if(ecode < 0 && inbufptr == 8
&& strncmp((const char*)uip.inbuf, "=IPA", 4) == 0) {
static struct in_addr ipa;
inbufptr = 0;
if(memcmp(&ipa, &uip.inbuf[4], sizeof(ipa)) == 0) {
break;
}
memcpy(&ipa, &uip.inbuf[4], sizeof(ipa));
break;
} else if(ecode < 0) {
/*
* If sensible ASCII string, print it as debug info!
*/
/* printf("----------------------------------\n");*/
if(uip.inbuf[0] == DEBUG_LINE_MARKER) {
fwrite(uip.inbuf + 1, inbufptr - 1, 1, stderr);
} else if(is_sensible_string(uip.inbuf, inbufptr)) {
fwrite(uip.inbuf, inbufptr, 1, stderr);
} else {
fprintf(stderr, "serial_to_wpcap: drop packet len=%d ecode=%d\n",
inbufptr, ecode);
}
inbufptr = 0;
break;
}
PROGRESS("s");
if(send_eth) {
raw_send(uip.inbuf, inbufptr);
} else {
/* printf("Sending to wpcap\n");*/
if(uip.iphdr.ip_id != last_id) {
last_id = uip.iphdr.ip_id;
print_packet("to wpcap: ", uip.inbuf, inbufptr);
wpcap_send(uip.inbuf, inbufptr);
} else {
/*print_packet("IGNORED to wpcap: ", uip.inbuf, inbufptr);*/
}
}
/* printf("After sending to wpcap\n");*/
inbufptr = 0;
}
break;
case SLIP_ESC:
/* TODO We do not actually check that we have another byte incoming, so
* we may block here */
read(STDIN_FILENO, &c, 1);
switch (c) {
case SLIP_ESC_END:
c = SLIP_END;
break;
case SLIP_ESC_ESC:
c = SLIP_ESC;
break;
}
/* FALLTHROUGH */
default:
uip.inbuf[inbufptr++] = c;
break;
}
}
/*---------------------------------------------------------------------------*/
unsigned char stdout_buf[2000];
int stdout_buf_cnt;
/*---------------------------------------------------------------------------*/
void
stdout_write(unsigned char c)
{
if(stdout_buf_cnt >= sizeof(stdout_buf)) {
err(1, "stdout_write overflow");
}
stdout_buf[stdout_buf_cnt] = c;
stdout_buf_cnt++;
}
/*---------------------------------------------------------------------------*/
int
stdout_buf_empty(void)
{
return stdout_buf_cnt == 0;
}
/*---------------------------------------------------------------------------*/
void
stdout_flushbuf(void)
{
if(stdout_buf_empty()) {
return;
}
fwrite(stdout_buf, stdout_buf_cnt, 1, stdout);
stdout_buf_cnt = 0;
fflush(stdout);
}
/*---------------------------------------------------------------------------*/
void
write_slip_stdout(void *inbuf, int len)
{
u_int8_t *p = inbuf;
int i, ecode;
struct ip *iphdr = inbuf;
if(!send_eth) {
/*
* Sanity checks.
*/
/*fprintf(stderr, "write_slip_stdout: %d\n", len);*/
ecode = check_ip(inbuf, len);
if(ecode < 0) {
fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode);
return;
}
if(iphdr->ip_id == 0 && iphdr->ip_off & IP_DF) {
uint16_t nid = uip_htons(ip_id++);
iphdr->ip_id = nid;
nid = ~nid; /* negate */
iphdr->ip_sum += nid; /* add */
if(iphdr->ip_sum < nid) { /* 1-complement overflow? */
iphdr->ip_sum++;
}
ecode = check_ip(inbuf, len);
if(ecode < 0) {
fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode);
return;
}
}
iphdr->ip_ttl = uip_htons(uip_htons(iphdr->ip_ttl) + 1);
if(iphdr->ip_ttl == 0) {
fprintf(stderr, "Packet with ttl %d dropped\n", iphdr->ip_ttl);
return;
}
iphdr->ip_sum = 0;
iphdr->ip_sum = ~chksum(iphdr, 4 * (iphdr->ip_vhl & IP_HL));
ecode = check_ip(inbuf, len);
if(ecode < 0) {
fprintf(stderr, "write_slip_stdout: drop packet %d\n", ecode);
return;
}
}
for(i = 0; i < len; i++) {
switch (p[i]) {
case SLIP_END:
stdout_write(SLIP_ESC);
stdout_write(SLIP_ESC_END);
break;
case SLIP_ESC:
stdout_write(SLIP_ESC);
stdout_write(SLIP_ESC_ESC);
break;
default:
stdout_write(p[i]);
break;
}
}
stdout_write(SLIP_END);
/* printf("slip end\n");*/
PROGRESS("t");
}
/*---------------------------------------------------------------------------*/
/*const char *ipaddr;*/
/*const char *netmask;*/
static int got_sigalarm;
void
sigalarm(int signo)
{
got_sigalarm = 1;
return;
}
/*---------------------------------------------------------------------------*/
void
sigalarm_reset(void)
{
#ifdef linux
#define TIMEOUT (997*1000)
#else
#define TIMEOUT (2451*1000)
#endif
ualarm(TIMEOUT, TIMEOUT);
got_sigalarm = 0;
}
/*---------------------------------------------------------------------------*/
int
main(int argc, char **argv)
{
int c;
int ret;
char buf[4000];
int logging = 0;
ip_id = getpid() * time(NULL);
while((c = getopt(argc, argv, "E:D:hl:t:T")) != -1) {
switch (c) {
case 'E':
send_eth = 1;
break;
case 'T':
should_print = 1;
break;
case 'l':
logging = 1;
break;
case '?':
case 'h':
default:
err(1,
"usage: wpcapstdio [-E] [-l] [-T] <IP address of local Ethernet card> <IP address of SLIP network> <netmask of SLIP network>");
break;
}
}
argc -= (optind - 1);
argv += (optind - 1);
if(argc != 4) {
err(1, "usage: wpcapstdio [-E] [-T] <IP address of local Ethernet card> <IP address of SLIP network> <netmask of SLIP network>");
}
wpcap_start(argv[1], argv[2], argv[3], logging);
stdout_write(SLIP_END);
atexit(cleanup);
signal(SIGHUP, sigcleanup);
signal(SIGTERM, sigcleanup);
signal(SIGINT, sigcleanup);
signal(SIGALRM, sigalarm);
while(1) {
if(got_sigalarm) {
/* Send "?IPA". */
stdout_write('?');
stdout_write('I');
stdout_write('P');
stdout_write('A');
stdout_write(SLIP_END);
got_sigalarm = 0;
}
if(stdout_buf_empty()) {
char *pbuf = buf;
ret = wpcap_poll(&pbuf, send_eth);
if(ret > 0) {
if(send_eth) {
write_slip_stdout(pbuf, ret);
stdout_flushbuf();
} else {
struct ip *iphdr = (struct ip *)pbuf;
if(iphdr->ip_id != last_id) {
/*last_id = iphdr->ip_id;*/
print_packet("to stdout: ", (uint8_t*)pbuf, ret);
write_slip_stdout(pbuf, ret);
stdout_flushbuf();
} else {
/*print_packet("IGNORED to stdout: ", (uint8_t*)pbuf, ret);*/
}
}
}
}
if(!stdout_buf_empty()) {
stdout_flushbuf();
}
{
fd_set s_rd;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100;
do {
FD_ZERO(&s_rd);
FD_SET(fileno(stdin), &s_rd);
select(fileno(stdin) + 1, &s_rd, NULL, NULL, &tv);
if(FD_ISSET(fileno(stdin), &s_rd)) {
serial_to_wpcap();
}
} while(FD_ISSET(fileno(stdin), &s_rd));
}
}
}
/*---------------------------------------------------------------------------*/