
27 changed files with 5414 additions and 0 deletions
@ -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
|
@ -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; |
||||