import ccn lite

This commit is contained in:
Christian Mehlis 2013-10-28 10:25:17 +01:00
parent a3854fd933
commit 8ae7750263
27 changed files with 5414 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

1306
sys/net/ccn_lite/ccnl-core.c Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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