import ccn lite
This commit is contained in:
parent
a3854fd933
commit
8ae7750263
|
@ -88,6 +88,12 @@ endif
|
|||
ifneq (,$(findstring semaphore,$(USEMODULE)))
|
||||
DIRS += semaphore
|
||||
endif
|
||||
ifneq (,$(findstring ccn_lite,$(USEMODULE)))
|
||||
DIRS += net/ccn_lite
|
||||
endif
|
||||
ifneq (,$(findstring ccn_lite_client,$(USEMODULE)))
|
||||
DIRS += net/ccn_lite/util
|
||||
endif
|
||||
|
||||
all: $(BINDIR)$(MODULE).a
|
||||
@for i in $(DIRS) ; do "$(MAKE)" -C $$i ; done ;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
MODULE := ccn_lite
|
||||
INCLUDES = -I$(RIOTBASE) -I$(RIOTBASE)/sys/include -I$(RIOTBASE)/core/include -I$(RIOTBASE)/drivers/include -I$(RIOTBASE)/sys/net -I$(RIOTBASE)/cpu/arm_common/include/ -I$(RIOTBASE)/drivers/cc110x_ng/include/ -I$(RIOTBASE)/sys/net/ccn_lite/include/
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
|
@ -0,0 +1,50 @@
|
|||
CCN lite port of RIOT
|
||||
=====================
|
||||
|
||||
RIOT's support for CCN messages is based on the work of [Christian Tschudin from University of Basel](http://cn.cs.unibas.ch/people/cft/) [(CCN-lite code available here)](https://github.com/cn-uofbasel/ccn-lite).
|
||||
|
||||
The network stack can handle multiple faces based on the transceiver or from the local device via RIOT's message system.
|
||||
To communicate with the stack, one can send messages via RIOTs message system to the CCN-lite relay thread or via a physical network transceiver.
|
||||
|
||||
All incoming messages get processed in the main io loop which you can find [here](ccn-lite-relay.c#L283).
|
||||
|
||||
The public api on the ccn network stack one can find in ccn_lite/include (see in file "ccnl-riot.h").
|
||||
Client related functions are located in ccn_lite/include/util (see in file "ccn-riot-client.h").
|
||||
|
||||
To deal with the ccn lite network stack one only needs these two api declarations.
|
||||
|
||||
|
||||
Running Test Application
|
||||
------------------------
|
||||
|
||||
A test applications are provided in the projects repository.
|
||||
|
||||
### ccn-lite-client
|
||||
|
||||
It uses RIOTs shell for user interaction.
|
||||
The network stack is started on demand in it's own thread. You have to enter "ccn" in the shell.
|
||||
|
||||
A bunch of ccn user land code is provide to construct interests and content objects.
|
||||
To request a file e.g. */riot/text*, the user land code request the first segment (chunk): */riot/text/0* and stalls until its received.
|
||||
If this chunk has the default chunk size the next chunk is requested, ...
|
||||
If a smaller chunk arrives the user land code prints out the complete file which was requested.
|
||||
|
||||
You can test this functionality by typing "interest /riot/test" in the shell. *See HOWTO.md in the projects directory*.
|
||||
|
||||
### ccn-lite-relay
|
||||
|
||||
It's a stand alone ccn relay without interactive user control
|
||||
The network stack is started on boot up and is configured set the device address and to serve requests for "/riot/test".
|
||||
The ccn stack is ready to server requests coming over the transceiver.
|
||||
|
||||
Hardware support
|
||||
----------------
|
||||
|
||||
The CCN-lite stack is currently tested and proved to run on the native port of RIOT and the MSBA2 embedded hardware.
|
||||
On the MSBA2 platform (32 Bit) CCN-lite only needs a stack of 800 bytes.
|
||||
It uses the heap for the CS, FIB and PIT.
|
||||
|
||||
More
|
||||
----
|
||||
|
||||
This README is still under construction.
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* @f ccn-lite-relay.c
|
||||
* @b CCN relay
|
||||
*
|
||||
* Copyright (C) 2011-13, Christian Tschudin, University of Basel
|
||||
* Copyright (C) 2013, Christian Mehlis, Freie Universität Berlin
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* File history:
|
||||
* 2011-11-22 created
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define CCNL_RIOT
|
||||
|
||||
#define USE_CCNxDIGEST
|
||||
#define USE_RIOT_MSG
|
||||
#define USE_RIOT_TRANS
|
||||
#define USE_APPSERVER
|
||||
#define USE_MGMT
|
||||
#define RIOT_CCNL_POPULATE (1)
|
||||
|
||||
#include "ccnl-includes.h"
|
||||
|
||||
#include "ccnx.h"
|
||||
#include "ccnl.h"
|
||||
#include "ccnl-core.h"
|
||||
|
||||
#include "ccnl-ext.h"
|
||||
#include "ccnl-platform.h"
|
||||
|
||||
#include "ccnl-core.h"
|
||||
|
||||
#include "ccnl-pdu.h"
|
||||
|
||||
#include "msg.h"
|
||||
#include "thread.h"
|
||||
#include "transceiver.h"
|
||||
|
||||
#include "ccnl-riot-compat.h"
|
||||
#include "test_data/text.txt.ccnb.h"
|
||||
|
||||
/** The size of the message queue between router daemon and transceiver AND clients */
|
||||
#define RELAY_MSG_BUFFER_SIZE (64)
|
||||
|
||||
/** message buffer */
|
||||
msg_t msg_buffer_relay[RELAY_MSG_BUFFER_SIZE];
|
||||
|
||||
uint8_t packet_out[PAYLOAD_SIZE];
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
struct ccnl_relay_s theRelay;
|
||||
|
||||
struct timeval *
|
||||
ccnl_run_events(void)
|
||||
{
|
||||
static struct timeval now;
|
||||
long usec;
|
||||
|
||||
rtc_time(&now);
|
||||
|
||||
while (eventqueue) {
|
||||
struct ccnl_timer_s *t = eventqueue;
|
||||
usec = timevaldelta(&(t->timeout), &now);
|
||||
|
||||
if (usec >= 0) {
|
||||
now.tv_sec = usec / 1000000;
|
||||
now.tv_usec = usec % 1000000;
|
||||
return &now;
|
||||
}
|
||||
|
||||
if (t->fct) {
|
||||
(t->fct)(t->node, t->intarg);
|
||||
}
|
||||
else if (t->fct2) {
|
||||
(t->fct2)(t->aux1, t->aux2);
|
||||
}
|
||||
|
||||
eventqueue = t->next;
|
||||
ccnl_free(t);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ccnl_open_riotmsgdev(void)
|
||||
{
|
||||
/*
|
||||
* nothing to do here, msg system just needs a buffer, and this is
|
||||
* generated staticly
|
||||
*/
|
||||
return RIOT_MSG_DEV; /* sock id */
|
||||
}
|
||||
|
||||
int ccnl_open_riottransdev(void)
|
||||
{
|
||||
|
||||
transceiver_init(transceiver_ids);
|
||||
transceiver_start();
|
||||
|
||||
/** register for transceiver events */
|
||||
transceiver_register(transceiver_ids, thread_getpid());
|
||||
|
||||
return RIOT_TRANS_DEV; /* sock id */
|
||||
}
|
||||
|
||||
void ccnl_ll_TX(struct ccnl_relay_s *ccnl, struct ccnl_if_s *ifc,
|
||||
sockunion *dest, struct ccnl_buf_s *buf)
|
||||
{
|
||||
(void) ccnl; /* unused */
|
||||
|
||||
memcpy(&packet_out, &buf->data, buf->datalen);
|
||||
ifc->sendfunc(packet_out, (uint16_t) buf->datalen, (uint16_t) dest->id);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ccnl_ageing(void *relay, void *aux)
|
||||
{
|
||||
ccnl_do_ageing(relay, aux);
|
||||
ccnl_set_timer(1000000, ccnl_ageing, relay, 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void ccnl_relay_config(struct ccnl_relay_s *relay, int max_cache_entries)
|
||||
{
|
||||
struct ccnl_if_s *i;
|
||||
|
||||
DEBUGMSG(99, "ccnl_relay_config\n");
|
||||
|
||||
relay->max_cache_entries = max_cache_entries;
|
||||
|
||||
if (RIOT_MSG_IDX != relay->ifcount) {
|
||||
DEBUGMSG(1, "sorry, idx did not match: riot msg device\n");
|
||||
}
|
||||
|
||||
i = &relay->ifs[relay->ifcount];
|
||||
i->sock = ccnl_open_riotmsgdev();
|
||||
i->sendfunc = &riot_send_msg;
|
||||
i->mtu = 4000;
|
||||
i->reflect = 0;
|
||||
i->fwdalli = 0;
|
||||
|
||||
if (i->sock >= 0) {
|
||||
relay->ifcount++;
|
||||
|
||||
if (relay->defaultInterfaceScheduler) {
|
||||
i->sched = relay->defaultInterfaceScheduler(relay,
|
||||
ccnl_interface_CTS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUGMSG(1, "sorry, could not open riot msg device\n");
|
||||
}
|
||||
|
||||
if (RIOT_TRANS_IDX != relay->ifcount) {
|
||||
DEBUGMSG(1, "sorry, idx did not match: riot trans device\n");
|
||||
}
|
||||
|
||||
i = &relay->ifs[relay->ifcount];
|
||||
i->sock = ccnl_open_riottransdev();
|
||||
i->sendfunc = &riot_send_transceiver;
|
||||
#ifdef USE_FRAG
|
||||
i->mtu = 120;
|
||||
#else
|
||||
i->mtu = 1500;
|
||||
#endif
|
||||
i->reflect = 0;
|
||||
i->fwdalli = 0;
|
||||
|
||||
if (i->sock >= 0) {
|
||||
relay->ifcount++;
|
||||
|
||||
if (relay->defaultInterfaceScheduler) {
|
||||
i->sched = relay->defaultInterfaceScheduler(relay,
|
||||
ccnl_interface_CTS);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUGMSG(1, "sorry, could not open riot trans device\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if RIOT_CCNL_POPULATE
|
||||
|
||||
void ccnl_populate_cache(struct ccnl_relay_s *ccnl, unsigned char *buf, int datalen)
|
||||
{
|
||||
if (buf[0] == 0x04 && buf[1] == 0x82) {
|
||||
struct ccnl_prefix_s *prefix = 0;
|
||||
struct ccnl_content_s *c = 0;
|
||||
struct ccnl_buf_s *nonce = 0, *ppkd = 0, *pkt = 0;
|
||||
unsigned char *content, *data = buf + 2;
|
||||
int contlen;
|
||||
|
||||
datalen -= 2;
|
||||
|
||||
pkt = ccnl_extract_prefix_nonce_ppkd(&data, &datalen, 0, 0,
|
||||
0, 0, &prefix, &nonce, &ppkd, &content, &contlen);
|
||||
|
||||
if (!pkt) {
|
||||
DEBUGMSG(6, " parsing error\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (!prefix) {
|
||||
DEBUGMSG(6, " no prefix error\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
printf("populating: %s\n", ccnl_prefix_to_path(prefix));
|
||||
|
||||
c = ccnl_content_new(ccnl, &pkt, &prefix, &ppkd, content,
|
||||
contlen);
|
||||
|
||||
if (!c) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ccnl_content_add2cache(ccnl, c);
|
||||
c->flags |= CCNL_CONTENT_FLAGS_STATIC;
|
||||
Done:
|
||||
free_prefix(prefix);
|
||||
ccnl_free(pkt);
|
||||
ccnl_free(nonce);
|
||||
ccnl_free(ppkd);
|
||||
}
|
||||
else {
|
||||
DEBUGMSG(6, " not a content object\n");
|
||||
}
|
||||
}
|
||||
|
||||
void handle_populate_cache()
|
||||
{
|
||||
DEBUGMSG(1, "ccnl_populate_cache with: text_txt_ccnb\n");
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_0, (int) text_txt_ccnb_0_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_1, (int) text_txt_ccnb_1_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_2, (int) text_txt_ccnb_2_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_3, (int) text_txt_ccnb_3_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_4, (int) text_txt_ccnb_4_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_5, (int) text_txt_ccnb_5_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_6, (int) text_txt_ccnb_6_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_7, (int) text_txt_ccnb_7_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_8, (int) text_txt_ccnb_8_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_9, (int) text_txt_ccnb_9_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_10, (int) text_txt_ccnb_10_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_11, (int) text_txt_ccnb_11_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_12, (int) text_txt_ccnb_12_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_13, (int) text_txt_ccnb_13_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_14, (int) text_txt_ccnb_14_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_15, (int) text_txt_ccnb_15_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_16, (int) text_txt_ccnb_16_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_17, (int) text_txt_ccnb_17_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_18, (int) text_txt_ccnb_18_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_19, (int) text_txt_ccnb_19_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_20, (int) text_txt_ccnb_20_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_21, (int) text_txt_ccnb_21_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_22, (int) text_txt_ccnb_22_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_23, (int) text_txt_ccnb_23_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_24, (int) text_txt_ccnb_24_len);
|
||||
ccnl_populate_cache(&theRelay, (unsigned char *) text_txt_ccnb_25, (int) text_txt_ccnb_25_len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
int ccnl_io_loop(struct ccnl_relay_s *ccnl)
|
||||
{
|
||||
int i, maxfd = -1;
|
||||
|
||||
if (ccnl->ifcount == 0) {
|
||||
DEBUGMSG(1, "no socket to work with, not good, quitting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ccnl->ifcount; i++)
|
||||
if (ccnl->ifs[i].sock > maxfd) {
|
||||
maxfd = ccnl->ifs[i].sock;
|
||||
}
|
||||
|
||||
maxfd++;
|
||||
|
||||
DEBUGMSG(1, "starting main event and IO loop\n");
|
||||
|
||||
if (msg_init_queue(msg_buffer_relay, RELAY_MSG_BUFFER_SIZE) != 0) {
|
||||
DEBUGMSG(1, "msg init queue failed...abording\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg_t in;
|
||||
radio_packet_t *p;
|
||||
riot_ccnl_msg_t *m;
|
||||
|
||||
while (!ccnl->halt_flag) {
|
||||
// struct timeval *timeout = ccnl_run_events();
|
||||
DEBUGMSG(1, "waiting for incomming msg\n");
|
||||
msg_receive(&in);
|
||||
|
||||
switch (in.type) {
|
||||
case PKT_PENDING:
|
||||
p = (radio_packet_t *) in.content.ptr;
|
||||
DEBUGMSG(1, "%s Packet waiting\n", riot_ccnl_event_to_string(in.type));
|
||||
DEBUGMSG(1, "\tLength:\t%u\n", p->length);
|
||||
DEBUGMSG(1, "\tSrc:\t%u\n", p->src);
|
||||
DEBUGMSG(1, "\tDst:\t%u\n", p->dst);
|
||||
|
||||
// p->src must be > 0
|
||||
if (!p->src) {
|
||||
p->src = RIOT_BROADCAST;
|
||||
}
|
||||
|
||||
ccnl_core_RX(ccnl, RIOT_TRANS_IDX, (unsigned char *) p->data, (int) p->length, p->src);
|
||||
p->processing--;
|
||||
break;
|
||||
|
||||
case (CCNL_RIOT_MSG):
|
||||
m = (riot_ccnl_msg_t *) in.content.ptr;
|
||||
DEBUGMSG(1, "%s Packet waiting\n", riot_ccnl_event_to_string(in.type));
|
||||
DEBUGMSG(1, "\tLength:\t%u\n", m->size);
|
||||
DEBUGMSG(1, "\tSrc:\t%u\n", in.sender_pid);
|
||||
|
||||
ccnl_core_RX(ccnl, RIOT_MSG_IDX, (unsigned char *) m->payload, m->size,
|
||||
in.sender_pid);
|
||||
break;
|
||||
|
||||
case (CCNL_RIOT_HALT):
|
||||
DEBUGMSG(1, "%s Packet waiting\n", riot_ccnl_event_to_string(in.type));
|
||||
DEBUGMSG(1, "\tSrc:\t%u\n", in.sender_pid);
|
||||
DEBUGMSG(1, "\tNumb:\t%" PRIu32 "\n", in.content.value);
|
||||
|
||||
ccnl->halt_flag = 1;
|
||||
break;
|
||||
#if RIOT_CCNL_POPULATE
|
||||
case (CCNL_RIOT_POPULATE):
|
||||
DEBUGMSG(1, "%s Packet waiting\n", riot_ccnl_event_to_string(in.type));
|
||||
DEBUGMSG(1, "\tSrc:\t%u\n", in.sender_pid);
|
||||
DEBUGMSG(1, "\tNumb:\t%" PRIu32 "\n", in.content.value);
|
||||
|
||||
handle_populate_cache();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
DEBUGMSG(1, "%s Packet waiting\n", riot_ccnl_event_to_string(in.type));
|
||||
DEBUGMSG(1, "\tSrc:\t%u\n", in.sender_pid);
|
||||
DEBUGMSG(1, "\tdropping it...\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief initializing routing system
|
||||
* @param pointer to count transceiver pids
|
||||
*
|
||||
*/
|
||||
void ccnl_riot_relay_start(void)
|
||||
{
|
||||
int max_cache_entries = 20;
|
||||
|
||||
struct timeval now;
|
||||
theRelay.startup_time = rtc_time(&now);
|
||||
|
||||
DEBUGMSG(1, "This is ccn-lite-relay, starting at %lu:%lu\n", now.tv_sec, now.tv_usec);
|
||||
DEBUGMSG(1, " compile time: %s %s\n", __DATE__, __TIME__);
|
||||
DEBUGMSG(1, " compile options: %s\n", compile_string());
|
||||
|
||||
ccnl_relay_config(&theRelay, max_cache_entries);
|
||||
|
||||
ccnl_io_loop(&theRelay);
|
||||
DEBUGMSG(1, "ioloop stopped\n");
|
||||
|
||||
while (eventqueue) {
|
||||
ccnl_rem_timer(eventqueue);
|
||||
}
|
||||
|
||||
ccnl_core_cleanup(&theRelay);
|
||||
}
|
||||
|
||||
// eof
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* @f ccnl-core.h
|
||||
* @b CCN lite (CCNL), core header file (internal data structures)
|
||||
*
|
||||
* Copyright (C) 2011-13, Christian Tschudin, University of Basel
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* File history:
|
||||
* 2011-04-09 created
|
||||
* 2013-03-19 updated (ms): modified struct ccnl_relay_s for 'aux' field
|
||||
*/
|
||||
|
||||
#ifndef CCNL_CORE_H__
|
||||
#define CCNL_CORE_H__
|
||||
|
||||
//#define CCNL_UNIX
|
||||
|
||||
#define EXACT_MATCH 1
|
||||
#define PREFIX_MATCH 0
|
||||
|
||||
#define CMP_EXACT 0 // used to compare interests among themselves
|
||||
#define CMP_MATCH 1 // used to match interest and content
|
||||
#define CMP_LONGEST 2 // used to lookup the FIB
|
||||
|
||||
#define CCNL_FACE_FLAGS_STATIC 1
|
||||
#define CCNL_FACE_FLAGS_REFLECT 2
|
||||
#define CCNL_FACE_FLAGS_SERVED 4
|
||||
#define CCNL_FACE_FLAGS_FWDALLI 8 // forward all interests, also known ones
|
||||
|
||||
#define CCNL_FRAG_NONE 0
|
||||
#define CCNL_FRAG_SEQUENCED2012 1
|
||||
#define CCNL_FRAG_CCNx2013 2
|
||||
|
||||
#define CCNL_CONTENT_FLAGS_STATIC 0x01
|
||||
#define CCNL_CONTENT_FLAGS_STALE 0x02
|
||||
|
||||
enum {STAT_RCV_I, STAT_RCV_C, STAT_SND_I, STAT_SND_C, STAT_QLEN, STAT_EOP1};
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ccnl.h"
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
typedef union {
|
||||
uint16_t id;
|
||||
} sockunion;
|
||||
|
||||
struct ccnl_txrequest_s {
|
||||
struct ccnl_buf_s *buf;
|
||||
sockunion dst;
|
||||
void (*txdone)(void *, int, int);
|
||||
struct ccnl_face_s *txdone_face;
|
||||
};
|
||||
|
||||
struct ccnl_if_s { // interface for packet IO
|
||||
sockunion addr;
|
||||
int sock;
|
||||
int (*sendfunc)(uint8_t *, uint16_t, uint16_t);
|
||||
int reflect; // whether to reflect I packets on this interface
|
||||
int fwdalli; // whether to forward all I packets rcvd on this interface
|
||||
int mtu;
|
||||
|
||||
int qlen; // number of pending sends
|
||||
int qfront; // index of next packet to send
|
||||
struct ccnl_txrequest_s queue[CCNL_MAX_IF_QLEN];
|
||||
struct ccnl_sched_s *sched;
|
||||
};
|
||||
|
||||
struct ccnl_relay_s {
|
||||
time_t startup_time;
|
||||
int id;
|
||||
struct ccnl_face_s *faces;
|
||||
struct ccnl_forward_s *fib;
|
||||
struct ccnl_interest_s *pit;
|
||||
struct ccnl_content_s *contents; //, *contentsend;
|
||||
struct ccnl_buf_s *nonces;
|
||||
int contentcnt; // number of cached items
|
||||
int max_cache_entries; // -1: unlimited
|
||||
struct ccnl_if_s ifs[CCNL_MAX_INTERFACES];
|
||||
int ifcount; // number of active interfaces
|
||||
char halt_flag;
|
||||
struct ccnl_sched_s *(*defaultFaceScheduler)(struct ccnl_relay_s *,
|
||||
void(*cts_done)(void *, void *));
|
||||
struct ccnl_sched_s *(*defaultInterfaceScheduler)(struct ccnl_relay_s *,
|
||||
void(*cts_done)(void *, void *));
|
||||
struct ccnl_http_s *http;
|
||||
struct ccnl_stats_s *stats;
|
||||
void *aux;
|
||||
};
|
||||
|
||||
struct ccnl_buf_s {
|
||||
struct ccnl_buf_s *next;
|
||||
unsigned int datalen;
|
||||
unsigned char data[1];
|
||||
};
|
||||
|
||||
struct ccnl_prefix_s {
|
||||
unsigned char **comp;
|
||||
int *complen;
|
||||
int compcnt;
|
||||
unsigned char *path; // memory for name component copies
|
||||
};
|
||||
|
||||
struct ccnl_frag_s {
|
||||
int protocol; // (0=plain CCNx)
|
||||
int mtu;
|
||||
sockunion dest;
|
||||
struct ccnl_buf_s *bigpkt;
|
||||
unsigned int sendoffs;
|
||||
// transport state, if present:
|
||||
int ifndx;
|
||||
|
||||
struct ccnl_buf_s *defrag;
|
||||
|
||||
unsigned int sendseq;
|
||||
unsigned int losscount;
|
||||
unsigned int recvseq;
|
||||
unsigned char flagwidth;
|
||||
unsigned char sendseqwidth;
|
||||
unsigned char losscountwidth;
|
||||
unsigned char recvseqwidth;
|
||||
};
|
||||
|
||||
struct ccnl_face_s {
|
||||
struct ccnl_face_s *next, *prev;
|
||||
int faceid;
|
||||
int ifndx;
|
||||
sockunion peer;
|
||||
int flags;
|
||||
int last_used; // updated when we receive a packet
|
||||
struct ccnl_buf_s *outq, *outqend; // queue of packets to send
|
||||
struct ccnl_frag_s *frag; // which special datagram armoring
|
||||
struct ccnl_sched_s *sched;
|
||||
};
|
||||
|
||||
struct ccnl_forward_s {
|
||||
struct ccnl_forward_s *next;
|
||||
struct ccnl_prefix_s *prefix;
|
||||
struct ccnl_face_s *face;
|
||||
};
|
||||
|
||||
struct ccnl_interest_s {
|
||||
struct ccnl_interest_s *next, *prev;
|
||||
struct ccnl_face_s *from;
|
||||
struct ccnl_pendint_s *pending; // linked list of faces wanting that content
|
||||
struct ccnl_prefix_s *prefix;
|
||||
int minsuffix, maxsuffix;
|
||||
struct ccnl_buf_s *ppkd; // publisher public key digest
|
||||
struct ccnl_buf_s *pkt; // full datagram
|
||||
int last_used;
|
||||
int retries;
|
||||
};
|
||||
|
||||
struct ccnl_pendint_s { // pending interest
|
||||
struct ccnl_pendint_s *next; // , *prev;
|
||||
struct ccnl_face_s *face;
|
||||
int last_used;
|
||||
};
|
||||
|
||||
struct ccnl_content_s {
|
||||
struct ccnl_content_s *next, *prev;
|
||||
struct ccnl_prefix_s *name;
|
||||
struct ccnl_buf_s *ppkd; // publisher public key digest
|
||||
struct ccnl_buf_s *pkt; // full datagram
|
||||
int flags;
|
||||
unsigned char *content; // pointer into the data buffer
|
||||
int contentlen;
|
||||
// NON-CONFORM: "The [ContentSTore] MUST also implement the Staleness Bit."
|
||||
// >> CCNL: currently no stale bit, old content is fully removed <<
|
||||
int last_used;
|
||||
int served_cnt;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// macros for double linked lists (these double linked lists are not rings)
|
||||
|
||||
#define DBL_LINKED_LIST_ADD(l,e) \
|
||||
do { if ((l)) (l)->prev = (e); \
|
||||
(e)->next = (l); \
|
||||
(l) = (e); \
|
||||
} while(0)
|
||||
|
||||
#define DBL_LINKED_LIST_REMOVE(l,e) \
|
||||
do { if ((l) == (e)) (l) = (e)->next; \
|
||||
if ((e)->prev) (e)->prev->next = (e)->next; \
|
||||
if ((e)->next) (e)->next->prev = (e)->prev; \
|
||||
} while(0)
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// collect the USE_* macros in a string
|
||||
const char *compile_string(void);
|
||||
|
||||
int consume(int typ, int num, unsigned char **buf, int *len,
|
||||
unsigned char **valptr, int *vallen);
|
||||
|
||||
void
|
||||
ccnl_core_RX(struct ccnl_relay_s *relay, int ifndx, unsigned char *data,
|
||||
int datalen, uint16_t sender_id);
|
||||
|
||||
void ccnl_core_cleanup(struct ccnl_relay_s *ccnl);
|
||||
|
||||
struct ccnl_buf_s *
|
||||
ccnl_buf_new(void *data, int len);
|
||||
|
||||
struct ccnl_content_s *
|
||||
ccnl_content_new(struct ccnl_relay_s *ccnl, struct ccnl_buf_s **pkt,
|
||||
struct ccnl_prefix_s **prefix, struct ccnl_buf_s **ppkd,
|
||||
unsigned char *content, int contlen);
|
||||
|
||||
struct ccnl_content_s *
|
||||
ccnl_content_add2cache(struct ccnl_relay_s *ccnl, struct ccnl_content_s *c);
|
||||
|
||||
struct ccnl_face_s *
|
||||
ccnl_get_face_or_create(struct ccnl_relay_s *ccnl, int ifndx, uint16_t sender_id);
|
||||
|
||||
int ccnl_face_enqueue(struct ccnl_relay_s *ccnl, struct ccnl_face_s *to,
|
||||
struct ccnl_buf_s *buf);
|
||||
|
||||
struct ccnl_face_s *
|
||||
ccnl_face_remove(struct ccnl_relay_s *ccnl, struct ccnl_face_s *f);
|
||||
|
||||
struct ccnl_buf_s *
|
||||
ccnl_extract_prefix_nonce_ppkd(unsigned char **data, int *datalen, int *scope,
|
||||
int *aok, int *min, int *max, struct ccnl_prefix_s **prefix,
|
||||
struct ccnl_buf_s **nonce, struct ccnl_buf_s **ppkd,
|
||||
unsigned char **content, int *contlen);
|
||||
|
||||
void ccnl_do_ageing(void *ptr, void *dummy);
|
||||
|
||||
void ccnl_interface_CTS(void *aux1, void *aux2);
|
||||
|
||||
#define ccnl_app_RX(x,y) do{}while(0)
|
||||
#define ccnl_print_stats(x,y) do{}while(0)
|
||||
|
||||
#define ccnl_malloc(s) malloc(s)
|
||||
#define ccnl_calloc(n,s) calloc(n,s)
|
||||
#define ccnl_realloc(p,s) realloc(p,s)
|
||||
#define ccnl_free(p) free(p)
|
||||
|
||||
void free_2ptr_list(void *a, void *b);
|
||||
void free_3ptr_list(void *a, void *b, void *c);
|
||||
void free_4ptr_list(void *a, void *b, void *c, void *d);
|
||||
void free_prefix(struct ccnl_prefix_s *p);
|
||||
void free_content(struct ccnl_content_s *c);
|
||||
|
||||
#endif /*CCNL_CORE_H__*/
|
||||
// eof
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* @f ccnl-ext-appserver.c
|
||||
*
|
||||
* Copyright (C) 2013, Christian Mehlis, Freie Universität Berlin
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define RIOT_CCN_APPSERVER (1)
|
||||
|
||||
#if RIOT_CCN_APPSERVER
|
||||
|
||||
#include "msg.h"
|
||||
#include "thread.h"
|
||||
#include "util/ccnl-riot-client.h"
|
||||
#include "ccnl-riot-compat.h"
|
||||
|
||||
#include "ccnl-includes.h"
|
||||
#include "ccnl-core.h"
|
||||
#include "ccnl-ext.h"
|
||||
#include "ccnl-pdu.h"
|
||||
#include "ccnx.h"
|
||||
|
||||
static volatile int halt_flag;
|
||||
|
||||
/** The size of the message queue between router daemon and transceiver AND clients */
|
||||
#define APPSERVER_MSG_BUFFER_SIZE (64)
|
||||
|
||||
/** message buffer */
|
||||
msg_t msg_buffer_appserver[APPSERVER_MSG_BUFFER_SIZE];
|
||||
|
||||
unsigned char big_buf[2 * 1024];
|
||||
|
||||
int relay_pid;
|
||||
char prefix[] = "/riot/appserver/";
|
||||
|
||||
static int appserver_sent_content(uint8_t *buf, int len, uint16_t from)
|
||||
{
|
||||
static riot_ccnl_msg_t rmsg;
|
||||
rmsg.payload = buf;
|
||||
rmsg.size = len;
|
||||
DEBUGMSG(1, "datalen=%d\n", rmsg.size);
|
||||
|
||||
msg_t m;
|
||||
m.type = CCNL_RIOT_MSG;
|
||||
m.content.ptr = (char *) &rmsg;
|
||||
uint16_t dest_pid = from;
|
||||
DEBUGMSG(1, "sending msg to pid=%u\n", dest_pid);
|
||||
int ret = msg_send(&m, dest_pid, 1);
|
||||
DEBUGMSG(1, "msg_reply returned: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int appserver_create_content(char **prefix, uint8_t *out)
|
||||
{
|
||||
char buf[CCNL_RIOT_CHUNK_SIZE - 1];
|
||||
|
||||
for (int i = 0; i < CCNL_RIOT_CHUNK_SIZE - 1; i++) {
|
||||
buf[i] = 'a' + i%26;
|
||||
}
|
||||
|
||||
int len = mkContent(prefix, buf, CCNL_RIOT_CHUNK_SIZE - 1, out);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int appserver_create_prefix(char *name, char **prefix)
|
||||
{
|
||||
int i = 0;
|
||||
char *cp = strtok(name, "/");
|
||||
|
||||
while (i < (CCNL_MAX_NAME_COMP - 1) && cp) {
|
||||
prefix[i++] = cp;
|
||||
cp = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
prefix[i] = NULL;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int appserver_handle_interest(char *data, uint16_t datalen, uint16_t from)
|
||||
{
|
||||
(void) data;
|
||||
(void) datalen;
|
||||
|
||||
char *prefix[CCNL_MAX_NAME_COMP];
|
||||
//struct ccnl_interest_s *i = appserver_parse_interest(data, datalen);
|
||||
|
||||
char name[] = "/riot/appserver/test/0";
|
||||
appserver_create_prefix(name, prefix);
|
||||
|
||||
int len = appserver_create_content(prefix, big_buf);
|
||||
/*
|
||||
struct ccnl_prefix *myprefix = ccnl_path_to_prefix(name);
|
||||
|
||||
if (ccnl_prefix_cmp(myprefix, 0, i->prefix, CMP_EXACT) != CMP_EXACT) {
|
||||
DEBUGMSG(1, "APPSERVER: it's a match");
|
||||
}
|
||||
*/
|
||||
int ret = appserver_sent_content(big_buf, len, from);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void riot_ccnl_appserver_ioloop(void)
|
||||
{
|
||||
DEBUGMSG(1, "starting appserver main event and IO loop\n");
|
||||
|
||||
if (msg_init_queue(msg_buffer_appserver, APPSERVER_MSG_BUFFER_SIZE) != 0) {
|
||||
DEBUGMSG(1, "msg init queue failed...abording\n");
|
||||
}
|
||||
|
||||
msg_t in;
|
||||
riot_ccnl_msg_t *m;
|
||||
|
||||
while (!halt_flag) {
|
||||
DEBUGMSG(1, "appserver: waiting for incomming msg\n");
|
||||
msg_receive(&in);
|
||||
|
||||
switch (in.type) {
|
||||
case (CCNL_RIOT_MSG):
|
||||
m = (riot_ccnl_msg_t *) in.content.ptr;
|
||||
DEBUGMSG(1, "new msg: size=%" PRIu16 " sender_pid=%" PRIu16 "\n",
|
||||
m->size, in.sender_pid);
|
||||
appserver_handle_interest(m->payload, m->size, in.sender_pid);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGMSG(1,
|
||||
"received unknown msg type: '%" PRIu16 "' dropping it\n",
|
||||
in.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void riot_ccnl_appserver_register(void)
|
||||
{
|
||||
char faceid[10];
|
||||
snprintf(faceid, sizeof(faceid), "%d", thread_getpid());
|
||||
char *type = "newMSGface";
|
||||
|
||||
int content_len = ccnl_riot_client_publish(relay_pid, prefix, faceid, type, big_buf);
|
||||
DEBUG("received %d bytes.\n", content_len);
|
||||
DEBUG("appserver received: '%s'\n", big_buf);
|
||||
}
|
||||
|
||||
void ccnl_riot_appserver_start(int _relay_pid)
|
||||
{
|
||||
relay_pid = _relay_pid;
|
||||
riot_ccnl_appserver_register();
|
||||
riot_ccnl_appserver_ioloop();
|
||||
DEBUGMSG(1, "appserver terminated\n");
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* @f ccnl-ext-debug.c
|
||||
* @b CCNL debugging support, dumping routines, memory tracking, stats
|
||||
*
|
||||
* Copyright (C) 2011-13, Christian Tschudin, University of Basel
|
||||
* Copyright (C) 2013, Christian Mehlis, Freie Universität Berlin
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* File history:
|
||||
* 2011-04-19 created
|
||||
* 2013-03-18 updated (ms): removed omnet related code
|
||||
* 2013-03-31 merged with ccnl-debug.h and ccnl-debug-mem.c
|
||||
*/
|
||||
|
||||
#ifndef CCNL_EXT_DEBUG_H
|
||||
#define CCNL_EXT_DEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ccnl-core.h"
|
||||
|
||||
char *
|
||||
ccnl_prefix_to_path(struct ccnl_prefix_s *pr)
|
||||
{
|
||||
static char prefix_buf[256];
|
||||
int len, i, j;
|
||||
|
||||
if (!pr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (len = 0, i = 0; i < pr->compcnt; i++) {
|
||||
if ((len + 1 + 3 * pr->complen[i]) >= (int) sizeof(prefix_buf)) {
|
||||
return (char *) "(...prefix...)";
|
||||
}
|
||||
|
||||
prefix_buf[len++] = '/';
|
||||
|
||||
for (j = 0; j < pr->complen[i]; j++) {
|
||||
unsigned char c = pr->comp[i][j];
|
||||
len += sprintf(prefix_buf + len,
|
||||
!isprint(c) || isspace(c) || c == '/' ? "%%%02x" : "%c",
|
||||
c);
|
||||
}
|
||||
}
|
||||
|
||||
prefix_buf[len] = '\0';
|
||||
return prefix_buf;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// eof
|
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
* @f ccnl-ext-frag.c
|
||||
* @b CCN lite extension: fragmentation support (including scheduling interface)
|
||||
*
|
||||
* Copyright (C) 2011-13, Christian Tschudin, University of Basel
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* File history:
|
||||
* 2011-10-05 created
|
||||
* 2013-05-02 prototyped a new fragment format CCNL_FRAG_TYPE_CCNx2013
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
//#define USE_FRAG
|
||||
#ifdef USE_FRAG
|
||||
|
||||
#include "ccnl-includes.h"
|
||||
#include "ccnl-core.h"
|
||||
#include "ccnl-ext.h"
|
||||
#include "ccnx.h"
|
||||
|
||||
|
||||
|
||||
/* see ccnl-core.h for available fragmentation protocols.
|
||||
*
|
||||
* CCNL_FRAG_NONE
|
||||
* passthrough, i.e. no header is added at all
|
||||
*
|
||||
* CCNL_FRAG_SEQUENCED2012
|
||||
* - a ccnb encoded header is prepended,
|
||||
* - the driver is configurable for arbitrary MTU
|
||||
* - packets have sequence numbers (can detect lost packets)
|
||||
*
|
||||
* CCNL_FRAG_CCNx2013
|
||||
* - a ccnb encoded wire format as currently discussed with PARC.
|
||||
* It serves as a container for various wire format types,
|
||||
* including carrying fragments of bigger CCNX objects
|
||||
* - all attributes from SEQUENCED2012 are retained
|
||||
*
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
struct ccnl_frag_s *
|
||||
ccnl_frag_new(int protocol, int mtu)
|
||||
{
|
||||
struct ccnl_frag_s *e = NULL;
|
||||
|
||||
DEBUGMSG(8, "ccnl_frag_new proto=%d mtu=%d\n", protocol, mtu);
|
||||
|
||||
switch (protocol) {
|
||||
case CCNL_FRAG_SEQUENCED2012:
|
||||
case CCNL_FRAG_CCNx2013:
|
||||
e = (struct ccnl_frag_s *) ccnl_calloc(1, sizeof(struct ccnl_frag_s));
|
||||
|
||||
if (e) {
|
||||
e->protocol = protocol;
|
||||
e->mtu = mtu;
|
||||
e->flagwidth = 1;
|
||||
e->sendseqwidth = 4;
|
||||
e->losscountwidth = 2;
|
||||
e->recvseqwidth = 4;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CCNL_FRAG_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void ccnl_frag_reset(struct ccnl_frag_s *e, struct ccnl_buf_s *buf, int ifndx,
|
||||
sockunion *dst)
|
||||
{
|
||||
DEBUGMSG(99, "ccnl_frag_reset (%d bytes)\n", buf ? buf->datalen : -1);
|
||||
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
|
||||
e->ifndx = ifndx;
|
||||
memcpy(&e->dest, dst, sizeof(*dst));
|
||||
ccnl_free(e->bigpkt);
|
||||
e->bigpkt = buf;
|
||||
e->sendoffs = 0;
|
||||
}
|
||||
|
||||
int ccnl_frag_getfragcount(struct ccnl_frag_s *e, int origlen, int *totallen)
|
||||
{
|
||||
int cnt = 0, len = 0;
|
||||
unsigned char dummy[256];
|
||||
int hdrlen, blobtaglen, datalen;
|
||||
int offs = 0;
|
||||
|
||||
if (!e) {
|
||||
cnt = 1;
|
||||
}
|
||||
else if (e && e->protocol == CCNL_FRAG_SEQUENCED2012) {
|
||||
while (offs < origlen) { // we could do better than to simulate this:
|
||||
hdrlen = mkHeader(dummy, CCNL_DTAG_FRAGMENT2012, CCN_TT_DTAG);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_FLAGS, CCN_TT_DTAG, 0,
|
||||
e->flagwidth);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_SEQNR, CCN_TT_DTAG, 0,
|
||||
e->sendseqwidth);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_OLOSS, CCN_TT_DTAG, 0,
|
||||
e->losscountwidth);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_YSEQN, CCN_TT_DTAG, 0,
|
||||
e->recvseqwidth);
|
||||
|
||||
hdrlen += mkHeader(dummy, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
||||
blobtaglen = mkHeader(dummy, e->mtu - hdrlen - 1, CCN_TT_BLOB);
|
||||
datalen = e->mtu - hdrlen - blobtaglen - 1;
|
||||
|
||||
if (datalen > (origlen - offs)) {
|
||||
datalen = origlen - offs;
|
||||
}
|
||||
|
||||
hdrlen += mkHeader(dummy, datalen, CCN_TT_BLOB);
|
||||
len += hdrlen + datalen + 1;
|
||||
offs += datalen;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
else if (e && e->protocol == CCNL_FRAG_CCNx2013) {
|
||||
while (offs < origlen) { // we could do better than to simulate this:
|
||||
hdrlen = mkHeader(dummy, CCNL_DTAG_FRAGMENT, CCN_TT_DTAG);
|
||||
hdrlen += mkHeader(dummy, CCNL_DTAG_FRAG_TYPE, CCN_TT_DTAG);
|
||||
hdrlen += 4; // three BLOB bytes plus end-of-entry
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_SEQNR, CCN_TT_DTAG, 0,
|
||||
e->sendseqwidth);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_FLAGS, CCN_TT_DTAG, 0,
|
||||
e->flagwidth);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_OLOSS, CCN_TT_DTAG, 0,
|
||||
e->losscountwidth);
|
||||
hdrlen += mkBinaryInt(dummy, CCNL_DTAG_FRAG_YSEQN, CCN_TT_DTAG, 0,
|
||||
e->recvseqwidth);
|
||||
|
||||
hdrlen += mkHeader(dummy, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
||||
blobtaglen = mkHeader(dummy, e->mtu - hdrlen - 1, CCN_TT_BLOB);
|
||||
datalen = e->mtu - hdrlen - blobtaglen - 1;
|
||||
|
||||
if (datalen > (origlen - offs)) {
|
||||
datalen = origlen - offs;
|
||||
}
|
||||
|
||||
hdrlen += mkHeader(dummy, datalen, CCN_TT_BLOB);
|
||||
len += hdrlen + datalen + 1;
|
||||
offs += datalen;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (totallen) {
|
||||
*totallen = len;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
struct ccnl_buf_s *
|
||||
ccnl_frag_getnextSEQD2012(struct ccnl_frag_s *e, int *ifndx, sockunion *su)
|
||||
{
|
||||
struct ccnl_buf_s *buf = 0;
|
||||
unsigned char header[256];
|
||||
int hdrlen = 0, blobtaglen, flagoffs;
|
||||
unsigned int datalen;
|
||||
|
||||
DEBUGMSG(16, "ccnl_frag_getnextSEQD2012 e=%p, mtu=%d\n", (void *) e, e->mtu);
|
||||
DEBUGMSG(17, " %d bytes to fragment, offset=%d\n", e->bigpkt->datalen,
|
||||
e->sendoffs);
|
||||
|
||||
hdrlen = mkHeader(header, CCNL_DTAG_FRAGMENT2012, CCN_TT_DTAG);
|
||||
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_FLAGS,
|
||||
CCN_TT_DTAG, 0, e->flagwidth);
|
||||
flagoffs = hdrlen - 2;
|
||||
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_YSEQN,
|
||||
CCN_TT_DTAG, e->recvseq, e->recvseqwidth);
|
||||
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_OLOSS, CCN_TT_DTAG,
|
||||
e->losscount, e->losscountwidth);
|
||||
|
||||
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_SEQNR,
|
||||
CCN_TT_DTAG, e->sendseq, e->sendseqwidth);
|
||||
hdrlen += mkHeader(header + hdrlen, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
||||
blobtaglen = mkHeader(header + hdrlen, e->mtu - hdrlen - 2, CCN_TT_BLOB);
|
||||
|
||||
datalen = e->mtu - hdrlen - blobtaglen - 2;
|
||||
|
||||
if (datalen > (e->bigpkt->datalen - e->sendoffs)) {
|
||||
datalen = e->bigpkt->datalen - e->sendoffs;
|
||||
}
|
||||
|
||||
hdrlen += mkHeader(header + hdrlen, datalen, CCN_TT_BLOB);
|
||||
|
||||
buf = ccnl_buf_new(NULL, hdrlen + datalen + 2);
|
||||
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buf->data, header, hdrlen);
|
||||
memcpy(buf->data + hdrlen, e->bigpkt->data + e->sendoffs, datalen);
|
||||
buf->data[hdrlen + datalen] = '\0'; // end of content/any field
|
||||
buf->data[hdrlen + datalen + 1] = '\0'; // end of fragment/pdu
|
||||
|
||||
if (datalen >= e->bigpkt->datalen) { // fits in a single fragment
|
||||
buf->data[flagoffs + e->flagwidth - 1] =
|
||||
CCNL_DTAG_FRAG_FLAG_FIRST | CCNL_DTAG_FRAG_FLAG_LAST;
|
||||
ccnl_free(e->bigpkt);
|
||||
e->bigpkt = NULL;
|
||||
}
|
||||
else if (e->sendoffs == 0) { // this is the start fragment
|
||||
buf->data[flagoffs + e->flagwidth - 1] = CCNL_DTAG_FRAG_FLAG_FIRST;
|
||||
}
|
||||
else if (datalen >= (e->bigpkt->datalen - e->sendoffs)) { // the end
|
||||
buf->data[flagoffs + e->flagwidth - 1] = CCNL_DTAG_FRAG_FLAG_LAST;
|
||||
ccnl_free(e->bigpkt);
|
||||
e->bigpkt = NULL;
|
||||
}
|
||||
else
|
||||
// in the middle
|
||||
{
|
||||
buf->data[flagoffs + e->flagwidth - 1] = 0x00;
|
||||
}
|
||||
|
||||
e->sendoffs += datalen;
|
||||
e->sendseq++;
|
||||
|
||||
DEBUGMSG(17, " e->offset now %d\n", e->sendoffs);
|
||||
|
||||
if (ifndx) {
|
||||
*ifndx = e->ifndx;
|
||||
}
|
||||
|
||||
if (su) {
|
||||
memcpy(su, &e->dest, sizeof(*su));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ccnl_buf_s *
|
||||
ccnl_frag_getnextCCNx2013(struct ccnl_frag_s *fr, int *ifndx, sockunion *su)
|
||||
{
|
||||
struct ccnl_buf_s *buf = 0;
|
||||
unsigned char header[256];
|
||||
int hdrlen, blobtaglen, flagoffs;
|
||||
unsigned int datalen;
|
||||
|
||||
// switch among encodings of fragments here (ccnb, TLV, etc)
|
||||
|
||||
hdrlen = mkHeader(header, CCNL_DTAG_FRAGMENT, CCN_TT_DTAG); // fragment
|
||||
|
||||
hdrlen += mkHeader(header + hdrlen, CCNL_DTAG_FRAG_TYPE, CCN_TT_DTAG);
|
||||
hdrlen += mkHeader(header + hdrlen, 3, CCN_TT_BLOB);
|
||||
memcpy(header + hdrlen, CCNL_FRAG_TYPE_CCNx2013_VAL, 3); // "FHBH"
|
||||
header[hdrlen + 3] = '\0';
|
||||
hdrlen += 4;
|
||||
|
||||
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_SEQNR, CCN_TT_DTAG,
|
||||
fr->sendseq, fr->sendseqwidth);
|
||||
|
||||
hdrlen += mkBinaryInt(header + hdrlen, CCNL_DTAG_FRAG_FLAGS, CCN_TT_DTAG, 0,
|
||||
fr->flagwidth);
|
||||
flagoffs = hdrlen - 2; // most significant byte of flag element
|
||||
|
||||
// other optional fields would go here
|
||||
|
||||
hdrlen += mkHeader(header + hdrlen, CCN_DTAG_CONTENT, CCN_TT_DTAG);
|
||||
|
||||
blobtaglen = mkHeader(header + hdrlen, fr->mtu - hdrlen - 2, CCN_TT_BLOB);
|
||||
datalen = fr->mtu - hdrlen - blobtaglen - 2;
|
||||
|
||||
if (datalen > (fr->bigpkt->datalen - fr->sendoffs)) {
|
||||
datalen = fr->bigpkt->datalen - fr->sendoffs;
|
||||
}
|
||||
|
||||
hdrlen += mkHeader(header + hdrlen, datalen, CCN_TT_BLOB);
|
||||
|
||||
buf = ccnl_buf_new(NULL, hdrlen + datalen + 2);
|
||||
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buf->data, header, hdrlen);
|
||||
memcpy(buf->data + hdrlen, fr->bigpkt->data + fr->sendoffs, datalen);
|
||||
buf->data[hdrlen + datalen] = '\0'; // end of content field
|
||||
buf->data[hdrlen + datalen + 1] = '\0'; // end of fragment
|
||||
|
||||
// patch flag field:
|
||||
if (datalen >= fr->bigpkt->datalen) { // single
|
||||
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_SINGLE;
|
||||
ccnl_free(fr->bigpkt);
|
||||
fr->bigpkt = NULL;
|
||||
}
|
||||
else if (fr->sendoffs == 0) { // start
|
||||
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_FIRST;
|
||||
}
|
||||
else if (datalen >= (fr->bigpkt->datalen - fr->sendoffs)) { // end
|
||||
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_LAST;
|
||||
ccnl_free(fr->bigpkt);
|
||||
fr->bigpkt = NULL;
|
||||
}
|
||||
else {
|
||||
buf->data[flagoffs] = CCNL_DTAG_FRAG_FLAG_MID;
|
||||
}
|
||||
|
||||
fr->sendoffs += datalen;
|
||||
fr->sendseq++;
|
||||
|
||||
if (ifndx) {
|
||||
*ifndx = fr->ifndx;
|
||||
}
|
||||
|
||||
if (su) {
|
||||
memcpy(su, &fr->dest, sizeof(*su));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ccnl_buf_s *
|
||||
ccnl_frag_getnext(struct ccnl_frag_s *fr, int *ifndx, sockunion *su)
|
||||
{
|
||||
if (!fr->bigpkt) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUGMSG(99, "fragmenting %d bytes (@ %d)\n", fr->bigpkt->datalen,
|
||||
fr->sendoffs);
|
||||
|
||||
switch (fr->protocol) {
|
||||
case CCNL_FRAG_SEQUENCED2012:
|
||||
return ccnl_frag_getnextSEQD2012(fr, ifndx, su);
|
||||
|
||||
case CCNL_FRAG_CCNx2013:
|
||||
return ccnl_frag_getnextCCNx2013(fr, ifndx, su);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ccnl_frag_nomorefragments(struct ccnl_frag_s *e)
|
||||
{
|
||||
if (!e || !e->bigpkt) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return e->bigpkt->datalen <= e->sendoffs;
|
||||
}
|
||||
|
||||
void ccnl_frag_destroy(struct ccnl_frag_s *e)
|
||||
{
|
||||
if (e) {
|
||||
ccnl_free(e->bigpkt);
|
||||
ccnl_free(e->defrag);
|
||||
ccnl_free(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
struct serialFragPDU_s { // collect all fields of a numbered HBH fragment
|
||||
int contlen;
|
||||
unsigned char *content;
|
||||
unsigned int flags, ourseq, ourloss, yourseq, HAS;
|
||||
unsigned char flagwidth, ourseqwidth, ourlosswidth, yourseqwidth;
|
||||
};
|
||||
|
||||
void serialFragPDU_init(struct serialFragPDU_s *s)
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->contlen = -1;
|
||||
s->flagwidth = 1;
|
||||
s->ourseqwidth = s->ourlosswidth = s->yourseqwidth = sizeof(int);
|
||||
}
|
||||
|
||||
void ccnl_frag_RX_serialfragment(RX_datagram callback,
|
||||
struct ccnl_relay_s *relay, struct ccnl_face_s *from,
|
||||
struct serialFragPDU_s *s)
|
||||
{
|
||||
struct ccnl_buf_s *buf = NULL;
|
||||
struct ccnl_frag_s *e = from->frag;
|
||||
DEBUGMSG(8, " frag %p protocol=%d, flags=%04x, seq=%d (%d)\n", (void *) e,
|
||||
e->protocol, s->flags, s->ourseq, e->recvseq);
|
||||
|
||||
if (e->recvseq != s->ourseq) {
|
||||
// should increase error counter here
|
||||
if (e->defrag) {
|
||||
DEBUGMSG(17, " >> seqnum mismatch (%d/%d), dropped defrag buf\n",
|
||||
s->ourseq, e->recvseq);
|
||||
ccnl_free(e->defrag);
|
||||
e->defrag = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (s->flags & (CCNL_DTAG_FRAG_FLAG_FIRST | CCNL_DTAG_FRAG_FLAG_LAST)) {
|
||||
case CCNL_DTAG_FRAG_FLAG_SINGLE: // single packet
|
||||
DEBUGMSG(17, " >> single fragment\n");
|
||||
|
||||
if (e->defrag) {
|
||||
DEBUGMSG(18, " had to drop defrag buf\n");
|
||||
ccnl_free(e->defrag);
|
||||
e->defrag = NULL;
|
||||
}
|
||||
|
||||
// no need to copy the buffer:
|
||||
callback(relay, from, &s->content, &s->contlen);
|
||||
return;
|
||||
|
||||
case CCNL_DTAG_FRAG_FLAG_FIRST: // start of fragment sequence
|
||||
DEBUGMSG(17, " >> start of fragment series\n");
|
||||
|
||||
if (e->defrag) {
|
||||
DEBUGMSG(18, " had to drop defrag buf\n");
|
||||
ccnl_free(e->defrag);
|
||||
}
|
||||
|
||||
e->defrag = ccnl_buf_new(s->content, s->contlen);
|
||||
break;
|
||||
|
||||
case CCNL_DTAG_FRAG_FLAG_LAST: // end of fragment sequence
|
||||
DEBUGMSG(17, " >> last fragment of a series\n");
|
||||
|
||||
if (!e->defrag) {
|
||||
break;
|
||||
}
|
||||
|
||||
buf = ccnl_buf_new(NULL, e->defrag->datalen + s->contlen);
|
||||
|
||||
if (buf) {
|
||||
memcpy(buf->data, e->defrag->data, e->defrag->datalen);
|
||||
memcpy(buf->data + e->defrag->datalen, s->content, s->contlen);
|
||||
}
|
||||
|
||||
ccnl_free(e->defrag);
|
||||
e->defrag = NULL;
|
||||
break;
|
||||
|
||||
case CCNL_DTAG_FRAG_FLAG_MID: // fragment in the middle of a squence
|
||||
default:
|
||||
DEBUGMSG(17, " >> fragment in the middle of a series\n");
|
||||
|
||||
if (!e->defrag) {
|
||||
break;
|
||||
}
|
||||
|
||||
buf = ccnl_buf_new(NULL, e->defrag->datalen + s->contlen);
|
||||
|
||||
if (buf) {
|
||||
memcpy(buf->data, e->defrag->data, e->defrag->datalen);
|
||||
memcpy(buf->data + e->defrag->datalen, s->content, s->contlen);
|
||||
ccnl_free(e->defrag);
|
||||
e->defrag = buf;
|
||||
buf = NULL;
|
||||
}
|
||||
else {
|
||||
ccnl_free(e->defrag);
|
||||
e->defrag = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: we should only bump recvseq if s->ourseq is ahead, or 0
|
||||
e->recvseq = s->ourseq + 1;
|
||||
DEBUGMSG(1, ">>> seq from %d to %d (w=%d)\n", s->ourseq, e->recvseq,
|
||||
s->ourseqwidth);
|
||||
|
||||
if (buf) {
|
||||
unsigned char *frag = buf->data;
|
||||
int fraglen = buf->datalen;
|
||||
DEBUGMSG(1, " >> reassembled fragment is %d bytes\n", buf->datalen);
|
||||
callback(relay, from, &frag, &fraglen);
|
||||
ccnl_free(buf);
|
||||
}
|
||||
|
||||
DEBUGMSG(1, "leaving function\n");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
#define getNumField(var,len,flag,rem) \
|
||||
DEBUGMSG(19, " parsing " rem "\n"); \
|
||||
if (unmkBinaryInt(data, datalen, &var, &len) != 0) \
|
||||
goto Bail; \
|
||||
s.HAS |= flag
|
||||
#define HAS_FLAGS 0x01
|
||||
#define HAS_OSEQ 0x02
|
||||
#define HAS_OLOS 0x04
|
||||
#define HAS_YSEQ 0x08
|
||||
|
||||
int ccnl_frag_RX_frag2012(RX_datagram callback, struct ccnl_relay_s *relay,
|
||||
struct ccnl_face_s *from, unsigned char **data, int *datalen)
|
||||
{
|
||||
int num, typ;
|
||||
struct serialFragPDU_s s;
|
||||
DEBUGMSG(99, "ccnl_frag_RX_frag2012 (%d bytes)\n", *datalen);
|
||||
|
||||
serialFragPDU_init(&s);
|
||||
|
||||