Separate routing calculation from resulting rules, refactor more code to use subscriber structure

This commit is contained in:
Jeremy Lakeman 2012-08-27 10:04:59 +09:30
parent df0e20408c
commit e05806f25e
24 changed files with 1209 additions and 1753 deletions

View File

@ -2,7 +2,6 @@
SERVALD_SRC_FILES = \
serval-dna/main.c \
serval-dna/overlay_abbreviations.c \
serval-dna/overlay_advertise.c \
serval-dna/overlay_buffer.c \
serval-dna/overlay_interface.c \
@ -24,7 +23,7 @@ SERVALD_SRC_FILES = \
serval-dna/strbuf_helpers.c \
serval-dna/gateway.c \
serval-dna/overlay.c \
serval-dna/overlay_broadcast.c \
serval-dna/overlay_address.c \
serval-dna/performance_timing.c \
serval-dna/packetformats.c \
serval-dna/peers.c \
@ -43,7 +42,6 @@ SERVALD_SRC_FILES = \
serval-dna/simulate.c \
serval-dna/srandomdev.c \
serval-dna/str.c \
serval-dna/subscribers.c \
serval-dna/keyring.c \
serval-dna/vomp.c \
serval-dna/lsif.c \

View File

@ -25,9 +25,8 @@ SRCS= \
monitor-cli.c \
net.c \
overlay.c \
overlay_abbreviations.c \
overlay_advertise.c \
overlay_broadcast.c \
overlay_address.c \
overlay_buffer.c \
overlay_interface.c \
overlay_mdp.c \
@ -57,7 +56,6 @@ SRCS= \
strbuf.c \
strbuf_helpers.c \
strlcpy.c \
subscribers.c \
vomp.c \
xprintf.c
@ -83,11 +81,12 @@ MONITORCLIENTOBJS= $(MONITORCLIENTSRCS:.c=.o)
HDRS= fifo.h \
Makefile \
overlay_buffer.h \
overlay_address.h \
overlay_packet.h \
rhizome.h \
serval.h \
strbuf.h \
strbuf_helpers.h \
subscribers.h \
sha2.h \
conf.h \
log.h \

View File

@ -1622,9 +1622,11 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
/* Asked for DID resolution, but did not get it, so do a DNA lookup
here. We do this on the client side, so that we don't block the
single-threaded server. */
overlay_mdp_frame m2;
bzero(&m2,sizeof(m2));
overlay_mdp_frame mdp_resolve;
overlay_mdp_frame mdp_reply;
bzero(&mdp_resolve,sizeof(mdp_resolve));
int port=32768+(random()&0xffff);
unsigned char srcsid[SID_SIZE];
if (overlay_mdp_getmyaddr(0,srcsid)) port=0;
if (overlay_mdp_bind(srcsid,port)) port=0;
@ -1638,15 +1640,15 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
now=gettime_ms();
if (now >= next_send){
m2.packetTypeAndFlags=MDP_TX;
m2.out.src.port=port;
bcopy(&srcsid[0],&m2.out.src.sid[0],SID_SIZE);
bcopy(&mdp.nodeinfo.sid[0],&m2.out.dst.sid[0],SID_SIZE);
m2.out.dst.port=MDP_PORT_DNALOOKUP;
mdp_resolve.packetTypeAndFlags=MDP_TX;
mdp_resolve.out.src.port=port;
bcopy(&srcsid[0],&mdp_resolve.out.src.sid[0],SID_SIZE);
bcopy(&mdp.nodeinfo.sid[0],&mdp_resolve.out.dst.sid[0],SID_SIZE);
mdp_resolve.out.dst.port=MDP_PORT_DNALOOKUP;
/* search for any DID */
m2.out.payload[0]=0;
m2.out.payload_length=1;
overlay_mdp_send(&m2,0,0);
mdp_resolve.out.payload[0]=0;
mdp_resolve.out.payload_length=1;
overlay_mdp_send(&mdp_resolve,0,0);
next_send+=125;
continue;
}
@ -1656,27 +1658,27 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
continue;
int ttl=-1;
if (overlay_mdp_recv(&m2,&ttl))
if (overlay_mdp_recv(&mdp_reply,&ttl))
continue;
if ((m2.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR){
if ((mdp_reply.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR){
// TODO log error?
continue;
}
if (m2.packetTypeAndFlags!=MDP_TX) {
if (mdp_reply.packetTypeAndFlags!=MDP_TX) {
WHYF("MDP returned an unexpected message (type=0x%x)",
m2.packetTypeAndFlags);
mdp_reply.packetTypeAndFlags);
if (m2.packetTypeAndFlags==MDP_ERROR)
if (mdp_reply.packetTypeAndFlags==MDP_ERROR)
WHYF("MDP message is return/error: %d:%s",
m2.error.error,m2.error.message);
mdp_reply.error.error,mdp_reply.error.message);
continue;
}
// we might receive a late response from an ealier request, ignore it
if (memcmp(&m2.in.src.sid[0],&mdp.nodeinfo.sid[0],SID_SIZE)){
WHYF("Unexpected result from SID %s", alloca_tohex_sid(m2.in.src.sid));
if (memcmp(mdp_reply.in.src.sid, mdp.nodeinfo.sid, SID_SIZE)){
WHYF("Unexpected result from SID %s", alloca_tohex_sid(mdp_reply.in.src.sid));
continue;
}
@ -1685,12 +1687,13 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
char did[DID_MAXSIZE + 1];
char name[64];
char uri[512];
if ( !parseDnaReply((char *)m2.in.payload, m2.in.payload_length, sidhex, did, name, uri, NULL)
if ( !parseDnaReply((char *)mdp_reply.in.payload, mdp_reply.in.payload_length, sidhex, did, name, uri, NULL)
|| !str_is_subscriber_id(sidhex)
|| !str_is_did(did)
|| !str_is_uri(uri)
) {
WHYF("Received malformed DNA reply: %s", alloca_toprint(160, (const char *)m2.in.payload, m2.in.payload_length));
WHYF("Received malformed DNA reply: %s",
alloca_toprint(160, (const char *)mdp_reply.in.payload, mdp_reply.in.payload_length));
} else {
/* Got a good DNA reply, copy it into place */
bcopy(did,mdp.nodeinfo.did,32);

View File

@ -211,34 +211,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define OF_COMPRESS_BZIP2 0x02 /* bzip2 */
#define OF_COMPRESS_RESERVED 0x03 /* Reserved for another compression system */
#define OVERLAY_ADDRESS_CACHE_SIZE 1024
/* Return codes for resolution of abbreviated addressses */
#define OA_UNINITIALISED 0 /* Nothing has been written into the field */
#define OA_RESOLVED 1 /* We expanded the abbreviation successfully */
#define OA_PLEASEEXPLAIN 2 /* We need the sender to explain their abbreviation */
#define OA_UNSUPPORTED 3 /* We cannot expand the abbreviation as we do not understand this code */
/* Codes used to describe abbreviated addresses.
Values 0x10 - 0xff are the first byte of, and implicit indicators of addresses written in full */
#define OA_CODE_SELF 0x00
#define OA_CODE_INDEX 0x01
#define OA_CODE_02 0x02
#define OA_CODE_PREVIOUS 0x03
#define OA_CODE_04 0x04
#define OA_CODE_PREFIX3 0x05
#define OA_CODE_PREFIX7 0x06
#define OA_CODE_PREFIX11 0x07
#define OA_CODE_FULL_INDEX1 0x08
#define OA_CODE_PREFIX3_INDEX1 0x09
#define OA_CODE_PREFIX7_INDEX1 0x0a
#define OA_CODE_PREFIX11_INDEX1 0x0b
#define OA_CODE_0C 0x0c
#define OA_CODE_PREFIX11_INDEX2 0x0d
#define OA_CODE_FULL_INDEX2 0x0e
/* The TTL field in a frame is used to differentiate between link-local and wide-area broadcasts */
#define OA_CODE_BROADCAST 0x0f
#define RFS_PLUS250 0xfa
#define RFS_PLUS456 0xfb
#define RFS_PLUS762 0xfc
@ -342,4 +314,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define DEFAULT_MONITOR_SOCKET_NAME "org.servalproject.servald.monitor.socket"
#define DEFAULT_MDP_SOCKET_NAME "org.servalproject.servald.mdp.socket"
// flags for address types
#define TYPE_NONE 0
#define TYPE_BROADCAST 1
#define TYPE_SUBSCRIBER 2
#define TYPE_TOO_SHORT 3
#endif // __SERVALD_CONSTANTS_H

View File

@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include "overlay_address.h"
/*
The challenge with making an interface for calling an external program to
@ -566,10 +567,11 @@ dna_helper_enqueue(overlay_mdp_frame *mdp, const char *did, const unsigned char
dna_helper_pid = 0;
return 0;
}
unsigned char *mysid;
if ((mysid = overlay_get_my_sid()) == NULL)
if (!my_subscriber)
return WHY("Unable to lookup my SID");
if (dna_helper_start(dna_helper_executable, dna_helper_arg1, alloca_tohex_sid(mysid)) == -1) {
if (dna_helper_start(dna_helper_executable, dna_helper_arg1, alloca_tohex_sid(my_subscriber->sid)) == -1) {
/* Something broke, bail out */
return WHY("DNAHELPER start failed");
}

View File

@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "nacl.h"
#include "overlay_address.h"
static int urandomfd = -1;
@ -723,11 +724,25 @@ int keyring_decrypt_pkr(keyring_file *k,keyring_context *c,
dump("stored",&slot[32],crypto_hash_sha512_BYTES);
goto kdp_safeexit;
}
// add any unlocked subscribers to our memory table, flagged as local sid's
int i=0;
for (i=0;i<id->keypair_count;i++){
if (id->keypairs[i]->type == KEYTYPE_CRYPTOBOX){
struct subscriber *subscriber = find_subscriber(id->keypairs[i]->public_key, SID_SIZE, 1);
if (subscriber){
subscriber->reachable=REACHABLE_SELF;
if (!my_subscriber)
my_subscriber=subscriber;
}
}
}
/* Well, it's all fine, so add the id into the context and return */
c->identities[c->identity_count++]=id;
return 0;
WHY("Not implemented");
kdp_safeexit:
/* Clean up any potentially sensitive data before exiting */
bzero(slot,KEYRING_PAGE_SIZE);
@ -773,7 +788,9 @@ int keyring_enter_pin(keyring_file *k, const char *pin)
for(c=0;c<k->context_count;c++)
{
int result=keyring_decrypt_pkr(k,k->contexts[c],pin?pin:"",slot);
if (!result) identitiesFound++;
if (!result)
identitiesFound++;
}
}
}
@ -923,8 +940,17 @@ keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c, co
}
else
#endif
/* Everything went fine */
return id;
// add new identity to in memory table
struct subscriber *subscriber = find_subscriber(id->keypairs[1]->public_key, SID_SIZE, 1);
if (subscriber){
subscriber->reachable=REACHABLE_SELF;
if (!my_subscriber)
my_subscriber=subscriber;
}
/* Everything went fine */
return id;
kci_safeexit:
if (id) keyring_free_identity(id);

133
overlay.c
View File

@ -71,7 +71,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "rhizome.h"
#include "strbuf.h"
#include "overlay_buffer.h"
int overlayMode=0;
@ -174,135 +173,3 @@ schedule(&_sched_##X); }
return 0;
}
// a frame destined for one of our local addresses, or broadcast, has arrived. Process it.
int process_incoming_frame(time_ms_t now, struct overlay_interface *interface, overlay_frame *f){
int id = (interface - overlay_interfaces);
switch(f->type)
{
// route control frames
case OF_TYPE_SELFANNOUNCE:
overlay_route_saw_selfannounce(f,now);
break;
case OF_TYPE_SELFANNOUNCE_ACK:
overlay_route_saw_selfannounce_ack(f,now);
break;
case OF_TYPE_NODEANNOUNCE:
overlay_route_saw_advertisements(id,f,now);
break;
// data frames
case OF_TYPE_RHIZOME_ADVERT:
overlay_rhizome_saw_advertisements(id,f,now);
break;
case OF_TYPE_DATA:
case OF_TYPE_DATA_VOICE:
overlay_saw_mdp_containing_frame(f,now);
break;
default:
return WHYF("Support for f->type=0x%x not yet implemented",f->type);
break;
}
return 0;
}
int overlay_frame_process(struct overlay_interface *interface,overlay_frame *f)
{
IN();
if (!f) RETURN(WHY("f==NULL"));
time_ms_t now = gettime_ms();
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF(">>> Received frame (type=%02x, bytes=%d)",f->type,f->payload ? f->payload->sizeLimit:-1);
// only examine payloads that are broadcasts, or where I'm the next hop
if (overlay_address_is_broadcast(f->nexthop)) {
// Note we can only check for dropping once per payload, as a second test would return true.
if (overlay_broadcast_drop_check(f->nexthop)){
if (debug&(DEBUG_OVERLAYFRAMES|DEBUG_BROADCASTS))
DEBUGF("Dropping frame, duplicate broadcast %s", alloca_tohex_sid(f->nexthop));
RETURN(0);
}
}else if (!overlay_address_is_local(f->nexthop)){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF("Dropping frame, not addressed to me %s", alloca_tohex_sid(f->nexthop));
RETURN(0);
}
int broadcast=overlay_address_is_broadcast(f->destination);
int ultimatelyForMe=0;
if (broadcast){
ultimatelyForMe = 1;
// Note that we assume a broadcast destination address is the same as the broadcast nexthop address
// we should decide to drop the packet based on the nexthop address.
}else{
if (overlay_address_is_local(f->destination))
ultimatelyForMe = 1;
}
f->ttl--;
// Never ever forward these types
if ((f->type==OF_TYPE_SELFANNOUNCE)
||(f->type==OF_TYPE_RHIZOME_ADVERT))
f->ttl=0;
/* Is this a frame we have to forward on? */
if (((!ultimatelyForMe)||broadcast)&&(f->ttl>0))
{
/* Yes, it is. */
int forward=1;
if (!broadcast)
{
if (overlay_get_nexthop(f->destination,f->nexthop,&f->nexthop_interface))
INFOF("Could not find next hop for %s* - dropping frame",
alloca_tohex(f->destination, 7));
forward=0;
}
if (0)
DEBUGF("considering forwarding frame to %s (forme=%d, bcast=%d)",
alloca_tohex_sid(f->destination),ultimatelyForMe,broadcast);
if (forward) {
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Forwarding frame");
/* Queue frame for dispatch.
Don't forget to put packet in the correct queue based on type.
(e.g., mesh management, voice, video, ordinary or opportunistic).
But the really important bit is to clone the frame, since the
structure we are looking at here must be left as is and returned
to the caller to do as they please */
overlay_frame *qf=op_dup(f);
if (!qf) WHY("Could not clone frame for queuing");
else {
int qn=OQ_ORDINARY;
/* Make sure voice traffic gets priority */
if ((qf->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
qn=OQ_ISOCHRONOUS_VOICE;
rhizome_saw_voice_traffic();
}
if (0) WHY("queuing frame for forwarding");
if (overlay_payload_enqueue(qn,qf,0)) {
WHY("failed to enqueue forwarded payload");
op_free(qf);
}
}
}
}
// process payloads with broadcast or our sid as destination
if (ultimatelyForMe){
process_incoming_frame(now, interface, f);
}
RETURN(0);
}

View File

@ -1,539 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "overlay_buffer.h"
/*
We use 256bit Curve25519 addresses in the overlay mesh. This means we have very large
addresses to send around the place on a regular basis, which is bad.
We allow addresses to be shortened to save bandwidth, especially for low-bandwidth links.
For this purpose we have special address prefixes 0x00 - 0x0f which are not allowed to
occur in unabbreviated addresses.
0x00 = reserved
0x01-0x02 = one to two byte address by index.
0x03 = same as last address.
0x04 = address matches sender (not currently implemented).
0x05 = address by prefix of three bytes.
0x06 = address by prefix of seven bytes.
0x07 = address by prefix of eleven bytes.
0x08 = full address followed by one-byte index allocation.
0x09-0x0b = same as 0x05-0x07, but assign single byte index.
0x0c = reserved.
0x0d = same as 0x07, but assign two byte index.
0x0e = full address followed by two-byte index allocation.
0x0f = broadcast link-local.
However, in this implementation we not include support for the two-byte
index code, as it requires 64Kx32=2MB storage, which is too much to ask
of a mesh potato or a cheap smart phone.
All indexed abbreviations may reference a token which is used to keep
track of the epoch of the abbreviation table.
This allows us to maintain multiple abbreviation tables at the same time, so
that neighbours we have not spoken to for some time will not be so easily
confused, as any one epoch will remain valid for some time after it has
ceased to be ammended.
This also allows us to effectively have multiple 256-entry pages, which will
be more efficient than using a 16-bit index table in most instances, especially
since we have the flexibility to reorder frames in an ensemble to minimise the
total length.
One table is maintained for all interfaces, as we may have neighbours who are
reachable via multiple interfaces. It also helps to minimise memory usage.
A cache of recently seen addresses is also desirable for conclusively resolving
abbreviated addresses. Failure will allow the birthday paradox to cause us problems
and also allow an attack based on searching for private keys that yield colliding
public key prefixes. This would allow an attacker to mess with the routing and
divert the traffic of other nodes to themselves. Thus some cache or similar policy
is strongly recommended if a node is going to accept address prefixes, especially if
it accepts the shorter prefixes. Seven and eleven byte prefixes should be reasonably
resistant to this attack.
There is no reason why the address abbreviation table cannot be used as the cache,
excepting for the question of efficiency, as a naive implementation would require
a linear search. However, adding a simple index table can mitigate this, and thus
presents as a sensible solution.
If a node receives a packet with an abbreviation that it cannot resolve an
abbreviation can ask for clarification, including indicating if it does
not support the abbreviation mode specified.
Abbreviations are link-local, but clarifications will always be requested by
attempting to contact the abbreviator via normal mesh routing rules.
We need to take some care so as to allow other crypto-systems, and thus storing the
crypto-system ID byte, although we still limit addresses to 256 bits, so we always need
no more than 33 bytes. In any case, indicating the crypto system is not the problem of
this section, as we are just concerned with abbreviating and expanding the addresses.
(A simple solution to the multiple crypto-system problem is to have the receiver try each
known crypto system when decoding a frame, and remember which addresses use which system.
Probably a reasonable solution for now.)
To decode abbreviations supplied by other nodes we need to try to replicate a copy of
their abbreviation table. This is where things get memory intensive (about 8KB per node).
However, we only need the table of one-hop neighbours, and it is reasonable to have a
constrained set of such tables, with a random replacement algorithm. This allows the
structure to be scaled to accomodate varying memory sizes of devices.
Very memory constrained devices may elect to cache individual entries rather than tables
of individual nodes, but we haven't implemented that here.
If we send only a prefix, then we need to be careful to make sure that receivers
get some chance to learn the full address if they need it. The question is whether
abbreviation clarification is more or less efficient than sometimes sending the
full address. Given that we already have need for the clarification process, let's
go that way, and change the policy later if appropriate.
Having had said this, on mono-directional links there is a problem with using the
various abbreviation schemes that require state. And this is that the receiver has
no way to issue a please-explain. In these situations, we need to fall-back to at
most using the abbreviations only most of the time, and still sending the full-address
some of the time, so that even without a feedback look to ask for explanations the
receiver should synchronise with us fairly well.
Also, we haven't implemented index-based lookup on the receiver side, so we need to fix
that or disable it on the sender side.
*/
typedef struct overlay_address_table {
unsigned char epoch;
char sids[256][SID_SIZE];
/* 0x00 = not set, which thus limits us to using only 255 (0x01-0xff) of the indexes for
storing addresses.
By spending an extra 256 bytes we reduce, but not eliminate the problem of collisions.
Will think about a complete solution later.
*/
unsigned char byfirstbyte[256][2];
/* next free entry in sid[] */
unsigned char next_free;
} overlay_address_table;
typedef struct overlay_address_cache {
int size;
int shift; /* Used to calculat lookup function, which is (b[0].b[1].b[2]>>shift) */
sid *sids; /* one entry per bucket, to keep things simple. */
/* XXX Should have a means of changing the hash function so that naughty people can't try
to force our cache to flush with duplicate addresses?
But we must use only the first 24 bits of the address due to abbreviation policies,
so our options are limited.
For now the hash will be the first k bits.
*/
} overlay_address_cache;
overlay_address_table *abbrs=NULL;
overlay_address_cache *cache=NULL;
sid overlay_abbreviate_previous_address={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
/* The address of the sender of the current frame.
The ID is used to lookup the abbreviation indexes.
If the ID is -1, then this means that the sender SID has been set, but not looked up.
This just saves some time instead of doing the *_id determination each time, when we might not need
it on most occassions.
*/
sid overlay_abbreviate_current_sender={{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
int overlay_abbreviate_prepare_cache()
{
if (OVERLAY_ADDRESS_CACHE_SIZE>0x1000000)
exit(WHY("OVERLAY_ADDRESS_CACHE_SIZE must be no larger than 2^24."));
if (OVERLAY_ADDRESS_CACHE_SIZE<0)
exit(WHY("OVERLAY_ADDRESS_CACHE_SIZE must be larger than 0."));
/* Allocate cache */
cache=calloc(sizeof(overlay_address_cache),1);
if (!cache) return 0;
/* Allocate address cache */
cache->size=OVERLAY_ADDRESS_CACHE_SIZE;
cache->sids=calloc(sizeof(sid),cache->size);
if (!cache->sids) { free(cache); return 0; }
/* Work out the number of bits to shift */
cache->shift=0;
while(cache->size>>(cache->shift+1)) cache->shift++;
if ((1<<cache->shift)!=cache->size)
exit(WHYF("OVERLAY_ADDRESS_CACHE_SIZE must be a power of two: cache->size=%d, shift=%d", cache->size, cache->shift));
cache->shift=24-cache->shift;
return 0;
}
int overlay_abbreviate_cache_address(unsigned char *sid)
{
if ((!cache)&&OVERLAY_ADDRESS_CACHE_SIZE>0) overlay_abbreviate_prepare_cache();
if (!cache) return 0;
/* Work out the index in the cache where this address would go.
The XOR 1 is to make sure that all zeroes address doesn't live in index 0,
which would otherwise result in it being detected as already present. */
int index=(((sid[0]<<16)|(sid[1]<<8)|sid[2])>>cache->shift)^1;
/* Does the stored address match the one we have been passed? */
if (!memcmp(sid,&cache->sids[index].b[0],SID_SIZE))
/* Address is already in cache, so return and let the caller know. */
return 1;
/* Not yet in cache, so store it */
bcopy(sid,&cache->sids[index].b[0],SID_SIZE);
if (debug&DEBUG_OVERLAYABBREVIATIONS) {
DEBUGF("Cached address %s", alloca_tohex_sid(sid));
}
return 0;
}
int overlay_abbreviate_try_byindex(unsigned char *in,unsigned char *out,int *ofs,
int index)
{
if(!memcmp(in,abbrs->sids[index],SID_SIZE))
{
/* We can encode this address with one byte */
/* Don't always abbreviate as the receiver may not have the means to send us
please-explains, e.g., due to mono-directional links. Thus we want to resend
the whole address sometimes. */
if (random()&7) {
/* Do use abbreviation */
out[(*ofs)++]=0x01;
out[(*ofs)++]=index;
return 0;
} else {
/* Don't use the abbreviation this time, but rather repeat it again for the
receiving side to cache.
XXX - Should we use a prefix here instead of full length?
*/
out[(*ofs)++]=0x08;
bcopy(in,&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
out[(*ofs)++]=index;
return 0;
}
}
else
/* Cannot find index in our node list. */
return 1;
}
int overlay_abbreviate_append_address(struct overlay_buffer *b,unsigned char *a)
{
int count=0;
ob_makespace(b,SID_SIZE+3);
int r=overlay_abbreviate_address(a,&b->bytes[b->position],&count);
if (debug&DEBUG_PACKETCONSTRUCTION) {
DEBUGF("address %s abbreviates as shown in this", alloca_tohex_sid(a));
dump(NULL, &b->bytes[b->position], count);
}
if (r) return r;
b->position+=count;
overlay_abbreviate_set_most_recent_address(a);
return 0;
}
int overlay_abbreviate_address(unsigned char *in,unsigned char *out,int *ofs)
{
int i;
int wasInCachedP=overlay_abbreviate_cache_address(in);
if (!in) return WHY("in==NULL");
if (in[0]<0x10) return WHY("Invalid address - 0x00-0x0f are reserved prefixes.");
/* Is this the same as the current sender? */
for(i=0;i<SID_SIZE;i++)
if (in[i]!=overlay_abbreviate_current_sender.b[i])
break;
if (i==SID_SIZE) {
out[(*ofs)++]=OA_CODE_SELF;
return 0;
}
/* Try repeating previous address */
for(i=0;i<SID_SIZE;i++)
if (in[i]!=overlay_abbreviate_previous_address.b[i])
break;
if (i==SID_SIZE) {
out[(*ofs)++]=OA_CODE_PREVIOUS;
return 0;
}
/* Is it a broadcast address? */
if (overlay_address_is_broadcast(in)) {
/* write broadcast code followed by 64bit BPI tail */
out[(*ofs)++]=OA_CODE_BROADCAST;
for(i=0;i<8;i++) out[(*ofs)++]=in[24+i];
return 0;
}
if (!abbrs) {
// Abbreviation table not setup, so allocate it.
// Epoch starts at zero.
// XXX We have only one simultaneous epoch here, not that it is a problem.
abbrs=calloc(sizeof(overlay_address_table),1);
if (!abbrs)
{
// Could not allocate abbreviation table, so just output full-length address.
WHY("calloc() failed.");
bcopy(in,&out[*ofs],SID_SIZE);
(*ofs)+=SID_SIZE;
return 0;
}
abbrs->next_free=1;
}
/* Try abbreviating by index
XXX should search backwards through old epochs
XXX If we do, we need a way to indicate a reference to an old epoch */
for(i=0;i<2;i++)
if (abbrs->byfirstbyte[in[0]][i])
{
if (0) { if (!overlay_abbreviate_try_byindex(in,out,ofs,abbrs->byfirstbyte[in[0]][i])) return 0; }
else {
if (debug&DEBUG_OVERLAYABBREVIATIONS)
WHY("Abbreviation by index temporarily disabled to simplify development");
}
}
else break;
if (i<2&&abbrs->next_free) {
// There is a spare slot to abbreviate this address by storing it in an index if we
// wish. So let's store it, then send the full address along with the newly allocated
// index.
/* Remember this address */
bcopy(in,abbrs->sids[abbrs->next_free],SID_SIZE);
abbrs->byfirstbyte[in[0]][i]=abbrs->next_free;
/* Write address out with index code */
out[(*ofs)++]=OA_CODE_FULL_INDEX1;
bcopy(in,&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
out[(*ofs)++]=abbrs->next_free;
/* Tidy things up and return triumphant. */
abbrs->next_free++;
return 0;
}
/* No space in our table, so either send address verbatim, or send only a prefix.
Go for prefix. Next question is length of prefix. Seven bytes is probably about
right as an simple initial policy. */
if (wasInCachedP) {
/* Prefix addresses that have been seen recently */
out[(*ofs)++]=OA_CODE_PREFIX7;
bcopy(in,&out[(*ofs)],7);
(*ofs)+=7;
return 0;
} else {
/* But send full address for those we haven't seen before */
bcopy(in,&out[*ofs],SID_SIZE);
(*ofs)+=SID_SIZE;
return 0;
}
}
int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char *out,int *ofs)
{
int bytes=0,r;
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("Address first byte/abbreviation code=%02x (input offset=%d)\n",in[*inofs],*inofs);
switch(in[*inofs])
{
case OA_CODE_02: case OA_CODE_04: case OA_CODE_0C: case OA_CODE_INDEX:
/* Unsupported codes, so tell the sender
if the frame was addressed to us as next-hop */
(*inofs)++;
WHY("Reserved address abbreviation code");
return OA_UNSUPPORTED;
case OA_CODE_SELF: /* address matches the sender who produced the
selfannounce in this packet. Naturally it cannot be
used to encode the sender's address there ;) */
(*inofs)++;
if (debug&DEBUG_OVERLAYABBREVIATIONS) DEBUGF("Resolving OA_CODE_SELF.\n");
if (overlay_abbreviate_current_sender.b[0]) {
bcopy(overlay_abbreviate_current_sender.b,&out[*ofs],SID_SIZE);
overlay_abbreviate_set_most_recent_address(&out[*ofs]);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
} else {
WARN("Cannot resolve OA_CODE_SELF if the packet doesn't start with a self announcement.\n");
return OA_UNINITIALISED;
}
case OA_CODE_PREVIOUS: /* Same as last address */
(*inofs)++;
bcopy(&overlay_abbreviate_previous_address.b[0],&out[*ofs],SID_SIZE);
overlay_abbreviate_set_most_recent_address(&out[*ofs]);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
case OA_CODE_PREFIX3: case OA_CODE_PREFIX3_INDEX1: /* 3-byte prefix */
if (in[*inofs]==0x09) bytes=1;
r=overlay_abbreviate_cache_lookup(&in[(*inofs)+1],out,ofs,3,bytes);
(*inofs)+=1+3+bytes;
if (r==OA_RESOLVED)
overlay_abbreviate_set_most_recent_address(&out[(*ofs)-SID_SIZE]);
return r;
case OA_CODE_PREFIX7: case OA_CODE_PREFIX7_INDEX1: /* 7-byte prefix */
if (in[*inofs]==OA_CODE_PREFIX7_INDEX1) bytes=1;
r=overlay_abbreviate_cache_lookup(&in[(*inofs)+1],out,ofs,7,bytes);
(*inofs)+=1+7+bytes;
if (r==OA_RESOLVED)
overlay_abbreviate_set_most_recent_address(&out[(*ofs)-SID_SIZE]);
return r;
case OA_CODE_PREFIX11: case OA_CODE_PREFIX11_INDEX1: case OA_CODE_PREFIX11_INDEX2: /* 11-byte prefix */
bytes=0;
if (in[*inofs]==OA_CODE_PREFIX11_INDEX1) bytes=1;
if (in[*inofs]==OA_CODE_PREFIX11_INDEX2) bytes=2;
r=overlay_abbreviate_cache_lookup(&in[(*inofs)+1],out,ofs,11,bytes);
(*inofs)+=1+11+bytes;
if (r==OA_RESOLVED)
overlay_abbreviate_set_most_recent_address(&out[(*ofs)-SID_SIZE]);
return r;
case OA_CODE_BROADCAST: /* broadcast */
memset(&out[*ofs],0xff,SID_SIZE-8);
(*inofs)++;
/* Copy Broadcast Packet Identifier */
{ int i; for(i=0;i<8;i++) out[(*ofs)+24+i]=in[(*inofs)+i]; }
if (debug&DEBUG_BROADCASTS)
DEBUGF("Expanded broadcast address with "
"BPI=%02X%02X%02X%02X%02X%02X%02X%02X\n",
in[(*inofs)+0],in[(*inofs)+1],in[(*inofs)+2],in[(*inofs)+3],
in[(*inofs)+4],in[(*inofs)+5],in[(*inofs)+6],in[(*inofs)+7]);
(*inofs)+=8;
overlay_abbreviate_set_most_recent_address(&out[*ofs]);
return OA_RESOLVED;
case OA_CODE_FULL_INDEX1: case OA_CODE_FULL_INDEX2:
default: /* Full address, optionally followed by index for us to remember */
if (in[*inofs]==OA_CODE_FULL_INDEX1) bytes=1;
if (in[*inofs]==OA_CODE_FULL_INDEX2) bytes=2;
if (bytes) (*inofs)++; /* Skip leading control code if present */
bcopy(&in[*inofs],&out[*ofs],SID_SIZE);
overlay_abbreviate_cache_address(&in[*inofs]);
overlay_abbreviate_set_most_recent_address(&in[*inofs]);
(*inofs)+=SID_SIZE+bytes;
return OA_RESOLVED;
}
}
int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *ofs,
int prefix_bytes,int index_bytes)
{
/* Lookup this entry from the cache, and also assign it the specified prefix */
if ((!cache)&&OVERLAY_ADDRESS_CACHE_SIZE>0) overlay_abbreviate_prepare_cache();
if (!cache) return OA_PLEASEEXPLAIN; /* No cache? Then ask for address in full */
/* Work out the index in the cache where this address would live */
int index=(((in[0]<<16)|(in[1]<<8)|in[2])>>cache->shift)^1;
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("looking in cache slot #%d for: %s*", index, alloca_tohex(in, prefix_bytes));
if (in[0]<0x10) {
/* Illegal address */
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("Passed an illegal address (first byte <0x10)");
return OA_UNSUPPORTED;
}
/* So is it there? */
if (memcmp(in,&cache->sids[index].b[0],prefix_bytes))
{
/* No, it isn't in the cache, but it might be a local address. */
int cn=0,id=0,kp=0;
for(cn=0;cn<keyring->context_count;cn++)
for(id=0;id<keyring->contexts[cn]->identity_count;id++)
for(kp=0;kp<keyring->contexts[cn]->identities[id]->keypair_count;kp++)
if (keyring->contexts[cn]->identities[id]->keypairs[kp]->type
==KEYTYPE_CRYPTOBOX)
{
if (!memcmp(in,keyring->contexts[cn]->identities[id]
->keypairs[kp]->public_key,prefix_bytes))
{
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUG("Found reference to local address.");
bcopy(&keyring->contexts[cn]->identities[id]
->keypairs[kp]->public_key[0],&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
}
}
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUG("Encountered unresolvable address -- are we asking for explanation?");
return OA_PLEASEEXPLAIN;
}
/* XXX We should implement associativity in the address cache so that we can spot
colliding prefixes and ask the sender to resolve them for us, or better yet dynamically
size the prefix length based on whether any given short prefix has collided */
/* It is here, so let's return it */
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("I think I looked up the following sid=%s", alloca_tohex_sid(cache->sids[index].b));
bcopy(&cache->sids[index].b[0],&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
if (index_bytes) {
(*ofs)+=index_bytes;
}
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("OA_RESOLVED returned for sid=%s", alloca_tohex_sid(cache->sids[index].b));
return OA_RESOLVED;
}
int overlay_abbreviate_set_current_sender(unsigned char *in)
{
bcopy(in,&overlay_abbreviate_current_sender.b[0],SID_SIZE);
return 0;
}
int overlay_abbreviate_unset_current_sender()
{
overlay_abbreviate_current_sender.b[0]=0;
return 0;
}
int overlay_abbreviate_set_most_recent_address(unsigned char *in)
{
bcopy(in,&overlay_abbreviate_previous_address.b[0],SID_SIZE);
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUGF("Most recent address=%s", alloca_tohex_sid(in));
return 0;
}
int overlay_abbreviate_clear_most_recent_address()
{
/* make previous address invalid (first byte must be >0x0f to be valid) */
overlay_abbreviate_previous_address.b[0]=0x00;
if (debug&DEBUG_OVERLAYABBREVIATIONS)
DEBUG("Cleared most recent address");
return 0;
}

309
overlay_address.c Normal file
View File

@ -0,0 +1,309 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Smart-flooding of broadcast information is also a requirement. The long addresses help here, as we can make any address that begins
with the first 192 bits all ones be broadcast, and use the remaining 64 bits as a "broadcast packet identifier" (BPI).
Nodes can remember recently seen BPIs and not forward broadcast frames that have been seen recently. This should get us smart flooding
of the majority of a mesh (with some node mobility issues being a factor). We could refine this later, but it will do for now, especially
since for things like number resolution we are happy to send repeat requests.
*/
#include "serval.h"
#include "overlay_address.h"
#include "overlay_buffer.h"
#define MAX_BPIS 1024
#define BPI_MASK 0x3ff
static struct broadcast bpilist[MAX_BPIS];
// each node has 16 slots based on the next 4 bits of a subscriber id
// each slot either points to another tree node or a struct subscriber.
struct tree_node{
// bit flags for the type of object each element points to
int is_tree;
union{
struct tree_node *tree_nodes[16];
struct subscriber *subscribers[16];
};
};
static struct tree_node root;
static struct subscriber *previous=NULL;
static struct subscriber *sender=NULL;
static struct broadcast *previous_broadcast=NULL;
struct subscriber *my_subscriber=NULL;
static unsigned char get_nibble(const unsigned char *sid, int pos){
unsigned char byte = sid[pos>>1];
if (!(pos&1))
byte=byte>>4;
return byte&0xF;
}
// find a subscriber struct from a subscriber id
// TODO find abreviated sid's
struct subscriber *find_subscriber(const unsigned char *sid, int len, int create){
struct tree_node *ptr = &root;
int pos=0;
if (len!=SID_SIZE)
create =0;
do{
unsigned char nibble = get_nibble(sid, pos++);
if (ptr->is_tree & (1<<nibble)){
ptr = ptr->tree_nodes[nibble];
}else if(!ptr->subscribers[nibble]){
// subscriber is not yet known
if (create){
struct subscriber *ret=(struct subscriber *)malloc(sizeof(struct subscriber));
memset(ret,0,sizeof(struct subscriber));
ptr->subscribers[nibble]=ret;
bcopy(sid, ret->sid, SID_SIZE);
ret->abbreviate_len=pos;
}
return ptr->subscribers[nibble];
}else{
// there's a subscriber in this slot, does it match the rest of the sid we've been given?
struct subscriber *ret = ptr->subscribers[nibble];
if (memcmp(ret->sid,sid,len)==0){
return ret;
}
// if we need to insert this subscriber, we have to make a new tree node first
if (!create)
return NULL;
// create a new tree node and move the existing subscriber into it
struct tree_node *new=(struct tree_node *)malloc(sizeof(struct tree_node));
memset(new,0,sizeof(struct tree_node));
ptr->tree_nodes[nibble]=new;
ptr->is_tree |= (1<<nibble);
ptr=new;
nibble=get_nibble(ret->sid,pos);
ptr->subscribers[nibble]=ret;
ret->abbreviate_len=pos+1;
// then go around the loop again to compare the next nibble against the sid until we find an empty slot.
}
}while(pos < len*2);
// abbreviation is not unique
return NULL;
}
/*
Walk the subscriber tree, calling the callback function for each subscriber.
if start is a valid pointer, the first entry returned will be after this subscriber
if the callback returns non-zero, the process will stop.
*/
static int walk_tree(struct tree_node *node, int pos, struct subscriber *start,
int(*callback)(struct subscriber *, void *), void *context){
int i=0;
if (start){
i=get_nibble(start->sid,pos);
}
for (;i<16;i++){
if (node->is_tree & (1<<i)){
if (walk_tree(node->tree_nodes[i], pos+1, start, callback, context))
return 1;
}else if(node->subscribers[i] && node->subscribers[i] != start){
if (callback(node->subscribers[i], context))
return 1;
}
}
return 0;
}
/*
walk the tree, starting at start, calling the supplied callback function
*/
void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context){
walk_tree(&root, 0, start, callback, context);
}
// generate a new random broadcast address
int overlay_broadcast_generate_address(struct broadcast *addr)
{
int i;
for(i=0;i<BROADCAST_LEN;i++) addr->id[i]=random()&0xff;
return 0;
}
// test if the broadcast address has been seen
int overlay_broadcast_drop_check(struct broadcast *addr)
{
/* Hash the BPI and see if we have seen it recently.
If so, drop the frame.
The occassional failure to supress a broadcast frame is not
something we are going to worry about just yet. For byzantine
robustness it is however required. */
int bpi_index=0;
int i;
for(i=0;i<BROADCAST_LEN;i++)
{
bpi_index=((bpi_index<<3)&0xfff8)+((bpi_index>>13)&0x7);
bpi_index^=addr->id[i];
}
bpi_index&=BPI_MASK;
if (memcmp(bpilist[bpi_index].id, addr->id, BROADCAST_LEN)){
if (debug&DEBUG_BROADCASTS)
DEBUGF("BPI %s is new", alloca_tohex(addr->id, BROADCAST_LEN));
bcopy(addr->id, bpilist[bpi_index].id, BROADCAST_LEN);
return 0; /* don't drop */
}else{
if (debug&DEBUG_BROADCASTS)
DEBUGF("BPI %s is a duplicate", alloca_tohex(addr->id, BROADCAST_LEN));
return 1; /* drop frame because we have seen this BPI recently */
}
}
int overlay_broadcast_append(struct overlay_buffer *b, struct broadcast *broadcast)
{
if (ob_append_byte(b, OA_CODE_BROADCAST)) return -1;
if (ob_append_bytes(b, broadcast->id, BROADCAST_LEN)) return -1;
previous=NULL;
return 0;
}
// append an appropriate abbreviation into the address
int overlay_address_append(struct overlay_buffer *b, struct subscriber *subscriber)
{
if (subscriber==sender){
ob_append_byte(b, OA_CODE_SELF);
}else if(subscriber==previous){
ob_append_byte(b, OA_CODE_PREVIOUS);
}else if(subscriber->send_full || subscriber->abbreviate_len >= 24){
subscriber->send_full=0;
ob_append_bytes(b, subscriber->sid, SID_SIZE);
}else if(subscriber->abbreviate_len <= 4){
ob_append_byte(b, OA_CODE_PREFIX3);
ob_append_bytes(b, subscriber->sid, 3);
}else if(subscriber->abbreviate_len <= 12){
ob_append_byte(b, OA_CODE_PREFIX7);
ob_append_bytes(b, subscriber->sid, 7);
}else{
ob_append_byte(b, OA_CODE_PREFIX11);
ob_append_bytes(b, subscriber->sid, 11);
}
previous = subscriber;
return 0;
}
static struct subscriber * find_subscr_buffer(struct overlay_buffer *b, int len, int create){
unsigned char *id = ob_get_bytes_ptr(b, len);
if (!id)
return WHYNULL("Not enough space in buffer to parse address");
struct subscriber *ret=find_subscriber(id, len, create);
if (!ret)
return WHYFNULL("Abbreviation %s not found", alloca_tohex(id, len));
previous=ret;
previous_broadcast=NULL;
return ret;
}
int overlay_address_parse(struct overlay_buffer *b, struct broadcast *broadcast, struct subscriber **subscriber)
{
int code = ob_getbyte(b,b->position);
switch(code){
case OA_CODE_BROADCAST:
b->position++;
*subscriber=NULL;
if (!broadcast)
return WHY("No broadcast structure for receiving broadcast address");
ob_get_bytes(b, broadcast->id, BROADCAST_LEN);
previous=NULL;
previous_broadcast=broadcast;
return 0;
case OA_CODE_SELF:
b->position++;
if (!sender)
return WHY("Could not resolve address, sender has not been set");
*subscriber=sender;
previous=sender;
return 0;
case OA_CODE_PREVIOUS:
b->position++;
// previous may be null, if the previous address was a broadcast.
// In this case we want the subscriber to be null as well and not report an error,
if (previous)
*subscriber=previous;
// not an error if broadcast is NULL, as the previous OA_CODE_BROADCAST address must have been valid.
else if (previous_broadcast){
if (broadcast)
bcopy(previous_broadcast->id, broadcast->id, BROADCAST_LEN);
}else
return WHY("Unable to decode previous address");
return 0;
case OA_CODE_PREFIX3:
b->position++;
*subscriber=find_subscr_buffer(b,3,0);
if (!*subscriber) return -1;
return 0;
case OA_CODE_PREFIX7:
b->position++;
*subscriber=find_subscr_buffer(b,7,0);
if (!*subscriber) return -1;
return 0;
case OA_CODE_PREFIX11:
b->position++;
*subscriber=find_subscr_buffer(b,11,0);
if (!*subscriber) return -1;
return 0;
}
if (code<=0x0f)
return WHYF("Unsupported abbreviation code %d", code);
*subscriber=find_subscr_buffer(b,SID_SIZE,1);
if (!*subscriber) return -1;
return 0;
}
void overlay_address_clear(void){
sender=NULL;
previous=NULL;
previous_broadcast=NULL;
}
void overlay_address_set_sender(struct subscriber *subscriber){
sender = subscriber;
}

111
overlay_address.h Normal file
View File

@ -0,0 +1,111 @@
/*
Serval Daemon
Copyright (C) 2012 Serval Project Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _SERVALD_OVERLAY_ADDRESS_H
#define _SERVALD_OVERLAY_ADDRESS_H
#include "constants.h"
// not reachable
#define REACHABLE_NONE 0
// immediate neighbour
#define REACHABLE_DIRECT 1
// packets must be routed
#define REACHABLE_INDIRECT 2
// packets can probably be flooded to this peer with ttl=2
// (temporary state for new peers before path discovery has finished)
#define REACHABLE_BROADCAST 3
// this subscriber is in our keystore
#define REACHABLE_SELF 4
/* Codes used to describe abbreviated addresses.
Values 0x10 - 0xff are the first byte of, and implicit indicators of addresses written in full */
#define OA_CODE_SELF 0x00
#define OA_CODE_INDEX 0x01
#define OA_CODE_02 0x02
#define OA_CODE_PREVIOUS 0x03
#define OA_CODE_04 0x04
#define OA_CODE_PREFIX3 0x05
#define OA_CODE_PREFIX7 0x06
#define OA_CODE_PREFIX11 0x07
#define OA_CODE_FULL_INDEX1 0x08
#define OA_CODE_PREFIX3_INDEX1 0x09
#define OA_CODE_PREFIX7_INDEX1 0x0a
#define OA_CODE_PREFIX11_INDEX1 0x0b
#define OA_CODE_0C 0x0c
#define OA_CODE_PREFIX11_INDEX2 0x0d
#define OA_CODE_FULL_INDEX2 0x0e
/* The TTL field in a frame is used to differentiate between link-local and wide-area broadcasts */
#define OA_CODE_BROADCAST 0x0f
#define BROADCAST_LEN 8
// This structure supports both our own routing protocol which can store calculation details in *node
// or IP4 addresses reachable via any other kind of normal layer3 routing protocol, eg olsr
struct subscriber{
unsigned char sid[SID_SIZE];
// minimum abbreviation length, in 4bit nibbles.
int abbreviate_len;
// should we send the full address once?
int send_full;
// overlay routing information
struct overlay_node *node;
// result of routing calculations;
int reachable;
union{
// if indirect, who is the next hop?
struct subscriber *next_hop;
struct{
// if direct, where do we send packets?
struct overlay_interface *interface;
// if s_addr == INADDR_ANY, send to the interface broadcast address
struct sockaddr_in address;
};
};
};
struct broadcast{
unsigned char id[BROADCAST_LEN];
};
extern struct subscriber *my_subscriber;
struct subscriber *find_subscriber(const unsigned char *sid, int len, int create);
void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context);
int overlay_broadcast_drop_check(struct broadcast *addr);
int overlay_broadcast_generate_address(struct broadcast *addr);
int overlay_broadcast_append(struct overlay_buffer *b, struct broadcast *broadcast);
int overlay_address_append(struct overlay_buffer *b, struct subscriber *subscriber);
int overlay_address_parse(struct overlay_buffer *b, struct broadcast *broadcast, struct subscriber **subscriber);
void overlay_address_clear(void);
void overlay_address_set_sender(struct subscriber *subscriber);
#endif

View File

@ -18,8 +18,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
#include "subscribers.h"
#include "overlay_address.h"
#include "overlay_buffer.h"
#include "overlay_packet.h"
/* List of prioritised advertisements */
#define OVERLAY_MAX_ADVERTISEMENT_REQUESTS 16
@ -112,7 +113,9 @@ int overlay_route_add_advertisements(struct overlay_buffer *e)
Thus using a fixed 1-byte RFS field we are limited to RFS<0xfa,
which gives us 30 available advertisement slots per packet.
*/
int i;
if (!my_subscriber)
return WHY("Cannot advertise because I don't know who I am");
ob_checkpoint(e);
@ -123,13 +126,15 @@ int overlay_route_add_advertisements(struct overlay_buffer *e)
// assume we might fill the packet
ob_append_rfs(e, e->sizeLimit - e->position);
/* Stuff in dummy address fields */
ob_append_byte(e,OA_CODE_BROADCAST);
for(i=0;i<8;i++) ob_append_byte(e,random()&0xff); /* random BPI */
/* Add address fields */
struct broadcast broadcast;
overlay_broadcast_generate_address(&broadcast);
overlay_broadcast_append(e,&broadcast);
ob_append_byte(e,OA_CODE_PREVIOUS);
overlay_abbreviate_clear_most_recent_address();
overlay_abbreviate_append_address(e, overlay_get_my_sid());
overlay_address_append(e, my_subscriber);
overlay_address_set_sender(my_subscriber);
// TODO high priority advertisements first....
/*
@ -158,7 +163,7 @@ int overlay_route_add_advertisements(struct overlay_buffer *e)
if (e->position == start_pos){
// no advertisements? don't bother to send the payload at all.
ob_rewind(e);
overlay_abbreviate_clear_most_recent_address();
overlay_address_clear();
}else
ob_patch_rfs(e,COMPUTE_RFS_LENGTH);
@ -175,7 +180,7 @@ int overlay_route_add_advertisements(struct overlay_buffer *e)
of nodes from here to there. That seems silly, and is agains't the BATMAN
approach of each node just knowing single-hop information.
*/
int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now)
int overlay_route_saw_advertisements(int i, struct overlay_frame *f, long long now)
{
IN();
while(f->payload->position < f->payload->sizeLimit)
@ -192,27 +197,19 @@ int overlay_route_saw_advertisements(int i,overlay_frame *f, long long now)
subscriber = find_subscriber(sid, 6, 0);
if (!subscriber){
//WARN("Dispatch PLEASEEXPLAIN not implemented");
WARN("Dispatch PLEASEEXPLAIN not implemented");
continue;
}
/* Don't record routes to ourselves */
if (overlay_address_is_local(subscriber->sid)) {
if (subscriber->reachable==REACHABLE_SELF) {
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("Ignore announcement about me (%s)", alloca_tohex_sid(subscriber->sid));
continue;
}
/* Don't let nodes advertise paths to themselves!
(paths to self get detected through selfannouncements and selfannouncement acks) */
if (!memcmp(overlay_abbreviate_current_sender.b,subscriber->sid,SID_SIZE)){
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("Ignore announcement about neighbour (%s)", alloca_tohex_sid(subscriber->sid));
continue;
}
/* File it */
overlay_route_record_link(now,subscriber->sid,overlay_abbreviate_current_sender.b,
overlay_route_record_link(now, subscriber->sid, f->source->sid,
i,
/* time range that this advertisement covers.
XXX - Make it up for now. */

View File

@ -1,86 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Smart-flooding of broadcast information is also a requirement. The long addresses help here, as we can make any address that begins
with the first 192 bits all ones be broadcast, and use the remaining 64 bits as a "broadcast packet identifier" (BPI).
Nodes can remember recently seen BPIs and not forward broadcast frames that have been seen recently. This should get us smart flooding
of the majority of a mesh (with some node mobility issues being a factor). We could refine this later, but it will do for now, especially
since for things like number resolution we are happy to send repeat requests.
*/
#include "serval.h"
#define BROADCAST_LEN 8
struct broadcast{
unsigned char id[BROADCAST_LEN];
};
#define MAX_BPIS 1024
#define BPI_MASK 0x3ff
struct broadcast bpilist[MAX_BPIS];
/* Determine if an address is broadcast */
int overlay_address_is_broadcast(unsigned char *a)
{
int i;
for(i=0;i<(SID_SIZE - BROADCAST_LEN);i++)
if (a[i]!=0xff) return 0;
return 1;
}
int overlay_broadcast_generate_address(unsigned char *a)
{
int i;
for(i=0;i<(SID_SIZE - BROADCAST_LEN);i++) a[i]=0xff;
for(;i<SID_SIZE;i++) a[i]=random()&0xff;
return 0;
}
int overlay_broadcast_drop_check(unsigned char *a)
{
/* Don't drop frames to non-broadcast addresses */
if (!overlay_address_is_broadcast(a)) return 0;
/* Hash the BPI and see if we have seen it recently.
If so, drop the frame.
The occassional failure to supress a broadcast frame is not
something we are going to worry about just yet. For byzantine
robustness it is however required. */
int bpi_index=0;
int i;
for(i=0;i<BROADCAST_LEN;i++)
{
bpi_index=((bpi_index<<3)&0xfff8)+((bpi_index>>13)&0x7);
bpi_index^=a[SID_SIZE - BROADCAST_LEN + i];
}
bpi_index&=BPI_MASK;
if (memcmp(bpilist[bpi_index].id, a + SID_SIZE - BROADCAST_LEN, BROADCAST_LEN)){
if (debug&DEBUG_BROADCASTS)
DEBUGF("BPI %s is new", alloca_tohex(a + SID_SIZE - BROADCAST_LEN, BROADCAST_LEN));
bcopy(a + SID_SIZE - BROADCAST_LEN, bpilist[bpi_index].id, BROADCAST_LEN);
return 0; /* don't drop */
}else{
if (debug&DEBUG_BROADCASTS)
DEBUGF("BPI %s is a duplicate", alloca_tohex(a + SID_SIZE - BROADCAST_LEN, BROADCAST_LEN));
return 1; /* drop frame because we have seen this BPI recently */
}
}

View File

@ -57,9 +57,12 @@ struct overlay_buffer *ob_static(unsigned char *bytes, int size){
// Both buffers will point to the same memory region.
// It is up to the caller to ensure this buffer is not used after the parent buffer is freed.
struct overlay_buffer *ob_slice(struct overlay_buffer *b, int offset, int length){
if (offset+length > b->allocSize)
return WHYNULL("Buffer isn't long enough to slice");
struct overlay_buffer *ret=calloc(sizeof(struct overlay_buffer),1);
if (!ret) return NULL;
if (!ret)
return NULL;
ret->bytes = b->bytes+offset;
ret->allocSize = length;
ret->allocated = 0;
@ -74,8 +77,11 @@ struct overlay_buffer *ob_dup(struct overlay_buffer *b){
ret->position = b->position;
ret->checkpointLength = b->checkpointLength;
if (b->bytes){
if (b->bytes && b->allocSize){
// duplicate any bytes that might be relevant
int byteCount = b->sizeLimit;
if (byteCount < b->position)
byteCount = b->position;
if (byteCount > b->allocSize)
byteCount = b->allocSize;

View File

@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "strbuf.h"
#include "overlay_buffer.h"
#include "overlay_packet.h"
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
@ -53,6 +54,7 @@ struct profile_total sock_any_stats;
struct outgoing_packet{
overlay_interface *interface;
int i;
struct sockaddr_in dest;
struct overlay_buffer *buffer;
};
@ -262,7 +264,7 @@ overlay_interface_read_any(struct sched_ent *alarm){
overlay_interface *interface=NULL;
struct sockaddr src_addr;
socklen_t addrlen = sizeof(src_addr);
/* Read only one UDP packet per call to share resources more fairly, and also
enable stats to accurately count packets received */
plen = recvwithttl(alarm->poll.fd, packet, sizeof(packet), &recvttl, &src_addr, &addrlen);
@ -272,9 +274,9 @@ overlay_interface_read_any(struct sched_ent *alarm){
close(alarm->poll.fd);
return;
}
struct in_addr src = ((struct sockaddr_in *)&src_addr)->sin_addr;
/* Try to identify the real interface that the packet arrived on */
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state!=INTERFACE_STATE_UP)
@ -285,14 +287,14 @@ overlay_interface_read_any(struct sched_ent *alarm){
break;
}
}
/* Should we drop the packet if we don't find a match? */
if (!interface){
if (debug&DEBUG_OVERLAYINTERFACES)
DEBUGF("Could not find matching interface for packet received from %s", inet_ntoa(src));
return;
}
/* We have a frame from this interface */
if (debug&DEBUG_PACKETRX)
DEBUG_packet_visualise("Read from real interface", packet,plen);
@ -306,7 +308,7 @@ overlay_interface_read_any(struct sched_ent *alarm){
unwatch(alarm);
close(alarm->poll.fd);
alarm->poll.fd=-1;
}
}
}
// bind a socket to INADDR_ANY:port
@ -519,7 +521,7 @@ static void overlay_interface_poll(struct sched_ent *alarm)
overlay_interface_close(interface);
return;
}
/* We have a frame from this interface */
if (debug&DEBUG_PACKETRX)
DEBUG_packet_visualise("Read from real interface", packet,plen);
@ -533,7 +535,7 @@ static void overlay_interface_poll(struct sched_ent *alarm)
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
overlay_interface_close(interface);
}
}
}
void overlay_dummy_poll(struct sched_ent *alarm)
@ -865,11 +867,10 @@ void overlay_interface_discover(struct sched_ent *alarm){
}
/* remove and free a payload from the queue */
static overlay_frame *
overlay_queue_remove(overlay_txqueue *queue, overlay_frame *frame)
{
overlay_frame *prev = frame->prev;
overlay_frame *next = frame->next;
static struct overlay_frame *
overlay_queue_remove(overlay_txqueue *queue, struct overlay_frame *frame){
struct overlay_frame *prev = frame->prev;
struct overlay_frame *next = frame->next;
if (prev)
prev->next = next;
else if(frame == queue->first)
@ -921,44 +922,26 @@ overlay_queue_dump(overlay_txqueue *q)
return 0;
}
int overlay_resolve_next_hop(overlay_frame *frame){
IN();
if (frame->nexthop_address_status==OA_RESOLVED)
RETURN(0);
if (frame->isBroadcast)
bcopy(&frame->destination,&frame->nexthop,SID_SIZE);
else if (overlay_get_nexthop((unsigned char *)frame->destination,frame->nexthop,&frame->nexthop_interface)){
// TODO new code?
frame->nexthop_address_status=OA_UNSUPPORTED;
RETURN(-1);
}
frame->nexthop_address_status=OA_RESOLVED;
RETURN(0);
}
static void
overlay_init_packet(struct outgoing_packet *packet, int interface) {
packet->i = interface;
packet->interface = &overlay_interfaces[packet->i];
overlay_init_packet(struct outgoing_packet *packet, overlay_interface *interface, struct sockaddr_in addr){
packet->interface = interface;
packet->i = (interface - overlay_interfaces);
packet->dest=addr;
packet->buffer=ob_new();
ob_limitsize(packet->buffer, packet->interface->mtu);
ob_append_bytes(packet->buffer,magic_header,4);
overlay_abbreviate_clear_most_recent_address();
overlay_abbreviate_unset_current_sender();
overlay_address_clear();
}
// update the alarm time and return 1 if changed
static int
overlay_calc_queue_time(overlay_txqueue *queue, overlay_frame *frame) {
overlay_calc_queue_time(overlay_txqueue *queue, struct overlay_frame *frame){
int ret=0;
time_ms_t send_time;
if (frame->nexthop_address_status==OA_UNINITIALISED)
overlay_resolve_next_hop(frame);
if (frame->nexthop_address_status!=OA_RESOLVED)
// ignore packet if the destination is currently unreachable
if (frame->destination && frame->destination->reachable==REACHABLE_NONE)
return 0;
// when is the next packet from this queue due?
@ -983,16 +966,15 @@ overlay_calc_queue_time(overlay_txqueue *queue, overlay_frame *frame) {
}
static void
overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, time_ms_t now) {
overlay_frame *frame = queue->first;
overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, time_ms_t now){
struct overlay_frame *frame = queue->first;
// TODO stop when the packet is nearly full?
while(frame){
frame->isBroadcast = overlay_address_is_broadcast(frame->destination);
if (frame->enqueued_at + queue->latencyTarget < now){
DEBUG("Dropping frame due to expiry timeout");
DEBUGF("Dropping frame type %x for %s due to expiry timeout",
frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
frame = overlay_queue_remove(queue, frame);
continue;
}
@ -1000,19 +982,47 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
even if we hear it from somewhere else in the mean time
*/
if (overlay_resolve_next_hop(frame))
if (frame->destination && frame->destination->reachable==REACHABLE_NONE)
goto skip;
struct subscriber *next_hop = frame->destination;
if (next_hop){
switch(next_hop->reachable){
case REACHABLE_INDIRECT:
next_hop=next_hop->next_hop;
// make sure the routing table is consistent
if (next_hop->reachable!=REACHABLE_DIRECT)
goto skip;
// fall through
case REACHABLE_DIRECT:
frame->sendBroadcast=0;
break;
case REACHABLE_BROADCAST:
if (!frame->sendBroadcast){
frame->sendBroadcast=1;
overlay_broadcast_generate_address(&frame->broadcast_id);
int i;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
frame->broadcast_sent_via[i]=0;
}
break;
}
}
if (!packet->buffer){
// use the interface of the first payload we find
if (frame->isBroadcast){
if (frame->sendBroadcast){
// find an interface that we haven't broadcast on yet
int i;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
{
if (overlay_interfaces[i].state==INTERFACE_STATE_UP)
if (!frame->broadcast_sent_via[i]){
overlay_init_packet(packet, i);
overlay_init_packet(packet, &overlay_interfaces[i], overlay_interfaces[i].broadcast_address);
break;
}
}
@ -1023,28 +1033,34 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
continue;
}
}else{
overlay_init_packet(packet, frame->nexthop_interface);
overlay_init_packet(packet, next_hop->interface, next_hop->address);
}
}else{
// make sure this payload can be sent via this interface
if (frame->isBroadcast){
if (frame->sendBroadcast){
if (frame->broadcast_sent_via[packet->i]){
goto skip;
}
}else if(packet->i != frame->nexthop_interface){
}else if(packet->interface != next_hop->interface || packet->dest.sin_addr.s_addr != next_hop->address.sin_addr.s_addr){
goto skip;
}
}
if (overlay_frame_package_fmt1(frame, packet->buffer))
if (debug&DEBUG_OVERLAYFRAMES){
DEBUGF("Sending payload type %x len %d for %s via %s", frame->type, frame->payload->position,
frame->destination?alloca_tohex_sid(frame->destination->sid):"All",
frame->sendBroadcast?alloca_tohex(frame->broadcast_id.id, BROADCAST_LEN):alloca_tohex_sid(next_hop->sid));
}
if (overlay_frame_append_payload(frame, next_hop, packet->buffer))
// payload was not queued
goto skip;
// mark the payload as sent
int keep_payload = 0;
if (frame->isBroadcast){
if (frame->sendBroadcast){
int i;
frame->broadcast_sent_via[packet->i]=1;
@ -1102,7 +1118,7 @@ overlay_fill_send_packet(struct outgoing_packet *packet, time_ms_t now) {
overlay_broadcast_ensemble(packet->i,NULL,packet->buffer->bytes,packet->buffer->position);
}
ob_free(packet->buffer);
overlay_abbreviate_clear_most_recent_address();
overlay_address_clear();
RETURN(1);
}
RETURN(0);
@ -1117,7 +1133,7 @@ void overlay_send_packet(struct sched_ent *alarm){
}
// update time for next alarm and reschedule
void overlay_update_queue_schedule(overlay_txqueue *queue, overlay_frame *frame){
void overlay_update_queue_schedule(overlay_txqueue *queue, struct overlay_frame *frame){
if (overlay_calc_queue_time(queue, frame)){
unschedule(&next_packet);
schedule(&next_packet);
@ -1137,7 +1153,7 @@ overlay_tick_interface(int i, time_ms_t now) {
// initialise the packet buffer
bzero(&packet, sizeof(struct outgoing_packet));
overlay_init_packet(&packet, i);
overlay_init_packet(&packet, &overlay_interfaces[i], overlay_interfaces[i].broadcast_address);
if (debug&DEBUG_OVERLAYINTERFACES) DEBUGF("Ticking interface #%d",i);

View File

@ -19,8 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <sys/stat.h>
#include "serval.h"
#include "strbuf.h"
#include "subscribers.h"
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_packet.h"
struct profile_total mdp_stats={.name="overlay_mdp_poll"};
@ -34,6 +35,24 @@ struct sched_ent mdp_named={
.stats = &mdp_stats,
};
// is the SID entirely 0xFF?
static int is_broadcast(const unsigned char *sid){
int i;
for (i=0;i<SID_SIZE;i++)
if (sid[i]!=0xFF)
return 0;
return 1;
}
// is the SID entirely 0x00?
static int is_sid_any(unsigned char *sid){
int i;
for (i=0;i<SID_SIZE;i++)
if (sid[i])
return 0;
return 1;
}
int overlay_mdp_setup_sockets()
{
struct sockaddr_un name;
@ -134,10 +153,14 @@ int overlay_mdp_reply_error(int sock,
mdpreply.packetTypeAndFlags=MDP_ERROR;
mdpreply.error.error=error_number;
if (error_number)
WHYF("MDP error, code #%d %s",error_number, message);
if (error_number==0||message)
snprintf(&mdpreply.error.message[0],128,"%s",message?message:"Success");
else
else{
snprintf(&mdpreply.error.message[0],128,"Error code #%d",error_number);
}
mdpreply.error.message[127]=0;
return overlay_mdp_reply(sock,recvaddr,recvaddrlen,&mdpreply);
@ -199,12 +222,10 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
/* Make sure source address is either all zeros (listen on all), or a valid
local address */
for(i=0;i<SID_SIZE;i++) if (mdp->bind.sid[i]) break;
if (i<SID_SIZE) {
/* Not all zeroes, so make sure it is a valid SID */
int ok=0;
if (overlay_address_is_local(mdp->bind.sid)) ok=1;
if (!ok) {
if (!is_sid_any(mdp->bind.sid)){
struct subscriber *subscriber = find_subscriber(mdp->bind.sid, SID_SIZE, 0);
if (!subscriber || subscriber->reachable != REACHABLE_SELF){
WHYF("Invalid bind request for sid=%s", alloca_tohex_sid(mdp->bind.sid));
/* Source address is invalid */
return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,7,
"Bind address is not valid (must be a local MDP address, or all zeroes).");
@ -277,7 +298,7 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
return overlay_mdp_reply_ok(sock,recvaddr,recvaddrlen,"Port bound");
}
unsigned char *overlay_mdp_decrypt(overlay_frame *f, overlay_mdp_frame *mdp, int *len)
unsigned char *overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp, int *len)
{
IN();
@ -366,7 +387,7 @@ unsigned char *overlay_mdp_decrypt(overlay_frame *f, overlay_mdp_frame *mdp, int
RETURN(b);
}
int overlay_saw_mdp_containing_frame(overlay_frame *f, time_ms_t now)
int overlay_saw_mdp_containing_frame(struct overlay_frame *f, time_ms_t now)
{
IN();
/* Take frame source and destination and use them to populate mdp->in->{src,dst}
@ -378,8 +399,14 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f, time_ms_t now)
int len=f->payload->sizeLimit;
/* Get source and destination addresses */
bcopy(f->destination,mdp.in.dst.sid,SID_SIZE);
bcopy(f->source,mdp.in.src.sid,SID_SIZE);
if (f->destination)
bcopy(f->destination->sid,mdp.in.dst.sid,SID_SIZE);
else{
// pack the broadcast address into the mdp structure
memset(mdp.in.dst.sid, 0xFF, SID_SIZE - BROADCAST_LEN);
bcopy(f->broadcast_id.id, mdp.in.dst.sid + SID_SIZE - BROADCAST_LEN, BROADCAST_LEN);
}
bcopy(f->source->sid,mdp.in.src.sid,SID_SIZE);
if (len<10) RETURN(WHY("Invalid MDP frame"));
@ -433,13 +460,6 @@ int overlay_saw_mdp_frame(overlay_mdp_frame *mdp, time_ms_t now)
alloca_tohex(mdp->out.src.sid, 7),
mdp->out.src.port,mdp->out.dst.port);
if ((!overlay_address_is_local(mdp->out.dst.sid))
&&(!overlay_address_is_broadcast(mdp->out.dst.sid)))
{
RETURN(WHY("Asked to process an MDP packet that was not addressed to this node."));
}
for(i=0;i<MDP_MAX_BINDINGS;i++)
{
if (!memcmp(&mdp->out.dst,&mdp_bindings[i].addr,sizeof(sockaddr_mdp)))
@ -564,13 +584,10 @@ int overlay_saw_mdp_frame(overlay_mdp_frame *mdp, time_ms_t now)
}
/* If the packet was sent to broadcast, then replace broadcast address
with our local address. For now just responds with first local address */
if (overlay_address_is_broadcast(mdp->out.src.sid))
if (is_broadcast(mdp->out.src.sid))
{
if (keyring->contexts[0]->identity_count&&
keyring->contexts[0]->identities[0]->keypair_count&&
keyring->contexts[0]->identities[0]->keypairs[0]->type
==KEYTYPE_CRYPTOBOX)
bcopy(keyring->contexts[0]->identities[0]->keypairs[0]->public_key,
if (my_subscriber)
bcopy(my_subscriber->sid,
mdp->out.src.sid,SID_SIZE);
else
/* No local addresses, so put all zeroes */
@ -628,7 +645,7 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
struct sockaddr_un *recvaddr,
int recvaddrlen)
{
if (overlay_address_is_broadcast(src->sid))
if (is_broadcast(src->sid))
{
/* This is rather naughty if it happens, since broadcasting a
response can lead to all manner of nasty things.
@ -659,8 +676,9 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
}
}
struct subscriber *subscriber = find_subscriber(src->sid, SID_SIZE, 1);
/* Check for build-in port listeners */
if (overlay_address_is_local(src->sid)) {
if (subscriber && subscriber->reachable == REACHABLE_SELF) {
switch(src->port) {
case MDP_PORT_ECHO:
/* we don't allow user/network generated packets claiming to
@ -698,8 +716,6 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
{
IN();
/* Work out if destination is broadcast or not */
int broadcast=1;
if (overlay_mdp_sanitytest_sourceaddr(&mdp->out.src,userGeneratedFrameP,
recvaddr,recvaddrlen))
RETURN(overlay_mdp_reply_error
@ -709,41 +725,55 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
"Source address is invalid (you must bind to a source address before"
" you can send packets"));
if (!overlay_address_is_broadcast(mdp->out.dst.sid)) broadcast=0;
/* Prepare the overlay frame for dispatch */
struct overlay_frame *frame = calloc(1,sizeof(struct overlay_frame));
if (overlay_address_is_local(mdp->out.dst.sid)||broadcast)
if (is_broadcast(mdp->out.dst.sid)){
/* broadcast packets cannot be encrypted, so complain if MDP_NOCRYPT
flag is not set. Also, MDP_NOSIGN must also be applied, until
NaCl cryptobox keys can be used for signing. */
if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT))
RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,5,
"Broadcast packets cannot be encrypted "));
overlay_broadcast_generate_address(&frame->broadcast_id);
frame->destination = NULL;
}else{
frame->destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
}
frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */
if (is_sid_any(mdp->out.src.sid)){
/* set source to ourselves */
frame->source = my_subscriber;
bcopy(frame->source->sid, mdp->out.src.sid, SID_SIZE);
}else{
frame->source = find_subscriber(mdp->out.src.sid, SID_SIZE, 1);
}
if (!frame->destination || frame->destination->reachable == REACHABLE_SELF)
{
/* Packet is addressed such that we should process it. */
overlay_saw_mdp_frame(mdp,gettime_ms());
if (!broadcast) {
if (frame->destination) {
/* Is local, and is not broadcast, so shouldn't get sent out
on the wire. */
op_free(frame);
RETURN(0);
}
}
/* broadcast packets cannot be encrypted, so complain if MDP_NOCRYPT
flag is not set. Also, MDP_NOSIGN must also be applied, until
NaCl cryptobox keys can be used for signing. */
if (broadcast) {
if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT))
RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
recvaddr,recvaddrlen,5,
"Broadcast packets cannot be encrypted ")); }
/* Prepare the overlay frame for dispatch */
struct overlay_frame *frame;
frame=calloc(sizeof(overlay_frame),1);
if (!frame) RETURN(WHY_perror("calloc"));
/* give voice packets priority */
if (mdp->out.dst.port==MDP_PORT_VOMP) frame->type=OF_TYPE_DATA_VOICE;
else frame->type=OF_TYPE_DATA;
frame->prev=NULL;
frame->next=NULL;
frame->payload=ob_new();
int fe=0;
/* Work out the disposition of the frame. For now we are only worried
/* Work out the disposition of the frame-> For now we are only worried
about the crypto matters, and not compression that may be applied
before encryption (since applying it after is useless as ciphered
text should have maximum entropy). */
@ -751,15 +781,14 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
case 0: /* crypted and signed (using CryptoBox authcryption primitive) */
frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
/* Prepare payload */
frame->payload=ob_new();
/*length should be;
1 - frame type (MDP)
+1 - MDP version
+4 - dst port
+4 - src port
+crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
+crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
+mdp->out.payload_length*/
ob_makespace(frame->payload,
1 // frame type (MDP)
+1 // MDP version
+4 // dst port
+4 // src port
+crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
+crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
+mdp->out.payload_length);
{
/* write cryptobox nonce */
unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
@ -793,16 +822,23 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
/* get pre-computed PKxSK bytes (the slow part of auth-cryption that can be
retained and reused, and use that to do the encryption quickly. */
unsigned char *k=keyring_get_nm_bytes(&mdp->out.src,&mdp->out.dst);
if (!k) { op_free(frame); RETURN(WHY("could not compute Curve25519(NxM)")); }
if (!k) {
op_free(frame);
RETURN(WHY("could not compute Curve25519(NxM)"));
}
/* Get pointer to place in frame where the ciphered text needs to go */
int cipher_offset=frame->payload->position;
unsigned char *cipher_text=ob_append_space(frame->payload,cipher_len);
if (fe||(!cipher_text))
{ op_free(frame); RETURN(WHY("could not make space for ciphered text")); }
if (fe||(!cipher_text)){
op_free(frame);
RETURN(WHY("could not make space for ciphered text"));
}
/* Actually authcrypt the payload */
if (crypto_box_curve25519xsalsa20poly1305_afternm
(cipher_text,plain,cipher_len,nonce,k))
{ op_free(frame); RETURN(WHY("crypto_box_afternm() failed")); }
(cipher_text,plain,cipher_len,nonce,k)){
op_free(frame);
RETURN(WHY("crypto_box_afternm() failed"));
}
/* now shuffle down 16 bytes to get rid of the temporary space that crypto_box
uses. */
bcopy(&cipher_text[16],&cipher_text[0],cipher_len-16);
@ -819,15 +855,6 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
}
}
break;
case MDP_NOSIGN:
/* ciphered, but not signed.
This means we don't use CryptoBox, but rather a more compact means
of representing the ciphered stream segment.
*/
frame->modifiers=OF_CRYPTO_CIPHERED;
op_free(frame);
RETURN(WHY("ciphered MDP packets not implemented"));
break;
case MDP_NOCRYPT:
/* Payload is sent unencrypted, but signed.
@ -841,18 +868,19 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
*/
frame->modifiers=OF_CRYPTO_SIGNED;
/* Prepare payload */
frame->payload=ob_new();
/* Length should be;
1 - frame type (MDP)
+1 - MDP version
+4 - dst port
+4 - src port
ob_makespace(frame->payload,
1 // frame type (MDP)
+1 // MDP version
+4 // dst port
+4 // src port
+crypto_sign_edwards25519sha512batch_BYTES
+mdp->out.payload_length
*/
+mdp->out.payload_length);
{
unsigned char *key=keyring_find_sas_private(keyring,mdp->out.src.sid,NULL);
if (!key) { op_free(frame); RETURN(WHY("could not find signing key")); }
unsigned char *key=keyring_find_sas_private(keyring, frame->source->sid, NULL);
if (!key) {
op_free(frame);
RETURN(WHY("could not find signing key"));
}
/* Build plain-text that includes header and hash it so that
we can sign that hash. */
@ -882,7 +910,10 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
crypto_sign_edwards25519sha512batch(signature,&sig_len,
hash,crypto_hash_sha512_BYTES,
key);
if (!sig_len) { op_free(frame); RETURN(WHY("Signing MDP frame failed")); }
if (!sig_len) {
op_free(frame);
RETURN(WHY("Signing MDP frame failed"));
}
/* chop hash out of middle of signature since it has to be recomputed
at the far end, anyway, as described above. */
bcopy(&signature[32+64],&signature[32],32);
@ -899,14 +930,12 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
frame->modifiers=0;
/* Copy payload body in */
frame->payload=ob_new();
/* Length should be;
1 - frame type (MDP)
+1 - MDP version
+4 - dst port
+4 - src port
+mdp->out.payload_length
*/
ob_makespace(frame->payload,
1 // frame type (MDP)
+1 // MDP version
+4 // dst port
+4 // src port
+mdp->out.payload_length);
/* MDP version 1 */
ob_append_byte(frame->payload,0x01);
ob_append_byte(frame->payload,0x01);
@ -915,36 +944,28 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
ob_append_ui32(frame->payload,mdp->out.dst.port);
ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
break;
}
frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */
/* set source to ourselves
XXX should eventually honour binding, which should allow choosing which
local identity. This will be required for openbts integration/SIP:MSIP
gateways etc. */
overlay_frame_set_me_as_source(frame);
/* Set destination address */
if (broadcast)
overlay_frame_set_broadcast_as_destination(frame);
else{
bcopy(&mdp->out.dst.sid[0],frame->destination,SID_SIZE);
case MDP_NOSIGN:
default:
/* ciphered, but not signed.
This means we don't use CryptoBox, but rather a more compact means
of representing the ciphered stream segment.
*/
op_free(frame);
RETURN(WHY("Not implemented"));
break;
}
int q=OQ_ORDINARY;
if (mdp->out.src.port==MDP_PORT_VOMP) {
q=OQ_ISOCHRONOUS_VOICE;
// TODO include priority in packet header
int qn=OQ_ORDINARY;
/* Make sure voice traffic gets priority */
if ((frame->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
qn=OQ_ISOCHRONOUS_VOICE;
rhizome_saw_voice_traffic();
}
if (overlay_payload_enqueue(q,frame,0))
{
if (frame) op_free(frame);
RETURN(WHY("Error enqueuing frame"));
}
else {
if (debug&DEBUG_OVERLAYINTERFACES)
DEBUGF("queued frame type=%#x modifiers=%#x ttl=%u", frame->type, frame->modifiers, frame->ttl);
RETURN(0);
}
if (overlay_payload_enqueue(qn, frame))
op_free(frame);
RETURN(0);
}
struct search_state{
@ -956,17 +977,27 @@ struct search_state{
int count;
};
int search_subscribers(struct subscriber *subscriber, void *context){
static int search_subscribers(struct subscriber *subscriber, void *context){
struct search_state *state = context;
if (!subscriber->node)
return 0;
int score = subscriber->node->best_link_score;
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_ALL_PEERS || score >= 1) {
if (state->count++ >= state->first && state->index < state->max) {
memcpy(state->mdpreply->addrlist.sids[state->index++], subscriber->sid, SID_SIZE);
}
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_SELF && subscriber->reachable != REACHABLE_SELF){
return 0;
}
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_ROUTABLE_PEERS &&
(subscriber->reachable != REACHABLE_DIRECT && subscriber->reachable != REACHABLE_INDIRECT)){
return 0;
}
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_ALL_PEERS &&
subscriber->reachable == REACHABLE_SELF){
return 0;
}
if (state->count++ >= state->first && state->index < state->max) {
memcpy(state->mdpreply->addrlist.sids[state->index++], subscriber->sid, SID_SIZE);
}
return 0;
}
@ -982,7 +1013,7 @@ void overlay_mdp_poll(struct sched_ent *alarm)
ttl=-1;
bzero((void *)recvaddrbuffer,sizeof(recvaddrbuffer));
ssize_t len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl, recvaddr, &recvaddrlen);
recvaddr_un=(struct sockaddr_un *)recvaddr;
@ -1028,42 +1059,18 @@ void overlay_mdp_poll(struct sched_ent *alarm)
mdpreply.addrlist.frame_sid_count = max_sids;
/* Populate with SIDs */
int i=0;
int count=0;
switch (mdp->addrlist.mode) {
case MDP_ADDRLIST_MODE_SELF: {
int cn=0,in=0,kp=0;
while(keyring_next_identity(keyring,&cn,&in,&kp)) {
if (count>=sid_num&&(i<max_sids))
bcopy(keyring->contexts[cn]->identities[in]
->keypairs[kp]->public_key,
mdpreply.addrlist.sids[i++],SID_SIZE);
in++; kp=0;
count++;
if (i>=max_sids)
break;
}
}
break;
case MDP_ADDRLIST_MODE_ROUTABLE_PEERS:
case MDP_ADDRLIST_MODE_ALL_PEERS: {
/* from peer list */
struct search_state state={
.mdp=mdp,
.mdpreply=&mdpreply,
.first=sid_num,
.max=max_sid,
};
enum_subscribers(NULL, search_subscribers, &state);
i=state.index;
count=state.count;
}
break;
}
mdpreply.addrlist.frame_sid_count = i;
mdpreply.addrlist.last_sid = sid_num + i - 1;
mdpreply.addrlist.server_sid_count = count;
struct search_state state={
.mdp=mdp,
.mdpreply=&mdpreply,
.first=sid_num,
.max=max_sid,
};
enum_subscribers(NULL, search_subscribers, &state);
mdpreply.addrlist.frame_sid_count = state.index;
mdpreply.addrlist.last_sid = sid_num + state.index - 1;
mdpreply.addrlist.server_sid_count = state.count;
if (debug & DEBUG_MDPREQUESTS)
DEBUGF("reply MDP_ADDRLIST first_sid=%u last_sid=%u frame_sid_count=%u server_sid_count=%u",
@ -1367,7 +1374,8 @@ int overlay_mdp_bind(unsigned char *localaddr,int port)
int overlay_mdp_getmyaddr(int index,unsigned char *sid)
{
overlay_mdp_frame a;
memset(&a, 0, sizeof(a));
a.packetTypeAndFlags=MDP_GETADDRS;
a.addrlist.mode = MDP_ADDRLIST_MODE_SELF;
a.addrlist.first_sid=index;

61
overlay_packet.h Normal file
View File

@ -0,0 +1,61 @@
/*
Serval Daemon
Copyright (C) 2012 Serval Project Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _SERVALD_OVERLAY_PACKET_H
#define _SERVALD_OVERLAY_PACKET_H
#include "overlay_address.h"
#include "serval.h"
struct overlay_frame {
struct overlay_frame *prev;
struct overlay_frame *next;
unsigned int type;
unsigned int modifiers;
unsigned char ttl;
/* Mark which interfaces the frame has been sent on,
so that we can ensure that broadcast frames get sent
exactly once on each interface */
int sendBroadcast;
unsigned char broadcast_sent_via[OVERLAY_MAX_INTERFACES];
struct broadcast broadcast_id;
// null if destination is broadcast
struct subscriber *destination;
struct subscriber *source;
/* IPv4 node frame was received from (if applicable) */
struct sockaddr *recvaddr;
/* Actual payload */
struct overlay_buffer *payload;
time_ms_t enqueued_at;
};
int op_free(struct overlay_frame *p);
struct overlay_frame *op_dup(struct overlay_frame *f);
#endif

View File

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "strbuf.h"
#include "overlay_buffer.h"
#include "overlay_packet.h"
struct sockaddr_in loopback = {
.sin_family=0,
@ -27,6 +28,73 @@ struct sockaddr_in loopback = {
.sin_addr.s_addr=0x0100007f
};
// a frame destined for one of our local addresses, or broadcast, has arrived. Process it.
int process_incoming_frame(time_ms_t now, struct overlay_interface *interface, struct overlay_frame *f){
int id = (interface - overlay_interfaces);
switch(f->type)
{
// route control frames
case OF_TYPE_SELFANNOUNCE:
overlay_route_saw_selfannounce(f,now);
break;
case OF_TYPE_SELFANNOUNCE_ACK:
overlay_route_saw_selfannounce_ack(f,now);
break;
case OF_TYPE_NODEANNOUNCE:
overlay_route_saw_advertisements(id,f,now);
break;
// data frames
case OF_TYPE_RHIZOME_ADVERT:
overlay_rhizome_saw_advertisements(id,f,now);
break;
case OF_TYPE_DATA:
case OF_TYPE_DATA_VOICE:
overlay_saw_mdp_containing_frame(f,now);
break;
default:
return WHYF("Support for f->type=0x%x not yet implemented",f->type);
break;
}
return 0;
}
// duplicate the frame and queue it
int overlay_forward_payload(struct overlay_frame *f){
f->ttl--;
if (f->ttl<=0)
return 0;
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Forwarding frame");
/* Queue frame for dispatch.
Don't forget to put packet in the correct queue based on type.
(e.g., mesh management, voice, video, ordinary or opportunistic).
But the really important bit is to clone the frame, since the
structure we are looking at here must be left as is and returned
to the caller to do as they please */
struct overlay_frame *qf=op_dup(f);
if (!qf)
return WHY("Could not clone frame for queuing");
// TODO include priority in packet header
int qn=OQ_ORDINARY;
/* Make sure voice traffic gets priority */
if ((qf->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
qn=OQ_ISOCHRONOUS_VOICE;
rhizome_saw_voice_traffic();
}
if (overlay_payload_enqueue(qn,qf)) {
op_free(qf);
return WHY("failed to enqueue forwarded payload");
}
return 0;
}
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr, size_t recvaddrlen, int parseP)
@ -82,10 +150,14 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
the source having received the frame from elsewhere.
*/
int ofs;
overlay_frame f;
bzero(&f,sizeof(overlay_frame));
struct overlay_frame f;
time_ms_t now = gettime_ms();
struct overlay_buffer *b = ob_static(packet, len);
ob_limitsize(b, len);
// skip magic bytes and version as they have already been parsed
b->position=4;
bzero(&f,sizeof(struct overlay_frame));
if (recvaddr->sa_family==AF_INET){
f.recvaddr=recvaddr;
@ -101,7 +173,7 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
f.recvaddr=NULL;
}
overlay_abbreviate_unset_current_sender();
overlay_address_clear();
// TODO put sender of packet and sequence number in envelope header
// Then we can quickly drop reflected broadcast packets
@ -109,150 +181,126 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
// plus with a sequence number we can detect dropped packets and nack them for retransmission
/* Skip magic bytes and version */
for(ofs=4;ofs<len;)
{
/* Get normal form of packet type and modifiers */
f.type=packet[ofs]&OF_TYPE_BITS;
f.modifiers=packet[ofs]&OF_MODIFIER_BITS;
while(b->position < b->sizeLimit){
int flags = ob_get(b);
/* Get normal form of packet type and modifiers */
f.type=flags&OF_TYPE_BITS;
f.modifiers=flags&OF_MODIFIER_BITS;
switch(packet[ofs]&OF_TYPE_BITS)
{
case OF_TYPE_EXTENDED20:
/* Eat the next two bytes and then skip over this reserved frame type */
f.type=OF_TYPE_FLAG_E20|(packet[ofs]&OF_MODIFIER_BITS)|(packet[ofs+2]<<12)|(packet[ofs+1]<<4);
f.modifiers=0;
ofs+=3;
break;
case OF_TYPE_EXTENDED12:
/* Eat the next byte and then skip over this reserved frame type */
f.type=OF_TYPE_FLAG_E12|(packet[ofs]&OF_MODIFIER_BITS)|(packet[ofs+1]<<4);
f.modifiers=0;
ofs+=2;
break;
default:
/* No extra bytes to deal with here */
ofs++;
break;
}
/* Get time to live */
f.ttl=packet[ofs++];
/* Decode length of remainder of frame */
f.rfs=rfs_decode(packet,&ofs);
if (debug&DEBUG_PACKETFORMATS) DEBUGF("f.rfs=%d, ofs=%d", f.rfs, ofs);
if (!f.rfs) {
/* Zero length -- assume we fell off the end of the packet */
switch(f.type){
case OF_TYPE_EXTENDED20:
/* Eat the next two bytes */
f.type=OF_TYPE_FLAG_E20|flags|(ob_get(b)<<4)|(ob_get(b)<<12);
f.modifiers=0;
break;
}
int nextPayload = ofs+f.rfs;
if (nextPayload > len){
WHYF("Payload length %d is too long for the remaining packet buffer %d", f.rfs, len - ofs);
case OF_TYPE_EXTENDED12:
/* Eat the next byte */
f.type=OF_TYPE_FLAG_E12|flags|(ob_get(b)<<4);
f.modifiers=0;
break;
}
/* Always attempt to resolve all of the addresses in a packet, or we could fail to understand an important payload
eg, peer sends two payloads travelling in opposite directions;
[Next, Dest, Sender] forwarding a payload we just send, so Sender == Me
[Next, Dest, Sender] delivering a payload to us so Next == Me
But Next would be encoded as OA_CODE_PREVIOUS, so we must parse all three addresses,
even if Next is obviously not intended for us
*/
/* Now extract the next hop address */
int alen=0;
int nexthop_address_status=overlay_abbreviate_expand_address(packet,&ofs,f.nexthop,&alen);
if (ofs>nextPayload){
WARN("Next hop address didn't fit in payload");
break;
}
alen=0;
int destination_address_status=overlay_abbreviate_expand_address(packet,&ofs,f.destination,&alen);
if (ofs>nextPayload){
WARN("Destination address didn't fit in payload");
break;
}
alen=0;
int source_address_status=overlay_abbreviate_expand_address(packet,&ofs,f.source,&alen);
if (ofs>nextPayload){
WARN("Source address didn't fit in payload");
break;
}
// TODO respond with OA_PLEASEEXPLAIN's?
if (debug&DEBUG_OVERLAYFRAMES) {
DEBUGF("Type=0x%02x", f.type);
strbuf b = strbuf_alloca(1024);
strbuf_sprintf(b, "Next Hop for this frame is (resolve code=%d): ", nexthop_address_status);
if (nexthop_address_status==OA_RESOLVED)
strbuf_sprintf(b, "%s", alloca_tohex_sid(f.nexthop));
else
strbuf_puts(b, "???");
DEBUG(strbuf_str(b));
strbuf_reset(b);
strbuf_sprintf(b, "Destination for this frame is (resolve code=%d): ", destination_address_status);
if (destination_address_status==OA_RESOLVED)
strbuf_sprintf(b, "%s", alloca_tohex_sid(f.destination));
else
strbuf_puts(b, "???");
DEBUG(strbuf_str(b));
strbuf_reset(b);
strbuf_sprintf(b, "Source for this frame is (resolve code=%d): ", source_address_status);
if (source_address_status==OA_RESOLVED)
strbuf_sprintf(b, "%s", alloca_tohex_sid(f.source));
else
strbuf_puts(b, "???");
DEBUG(strbuf_str(b));
}
if (f.nexthop[0]==0 || f.destination[0]==0 || f.source[0]==0)
break;
if (nexthop_address_status!=OA_RESOLVED
|| destination_address_status!=OA_RESOLVED
|| source_address_status!=OA_RESOLVED){
WARN("Unable to resolve all payload addresses");
// we have to stop now as we can't be certain about the destination of any other payloads in this packet.
break;
}
/* not that noteworthy, as when listening to a broadcast socket
you hear everything you send. */
if (overlay_address_is_local(f.source)){
// skip the remainder of any packet that we know we sent
// TODO add our id to the header
if (f.type==OF_TYPE_SELFANNOUNCE)
break;
}else{
/* Record current sender for reference by addresses in subsequent frames in the
ensemble */
if (f.type==OF_TYPE_SELFANNOUNCE)
overlay_abbreviate_set_current_sender(f.source);
/* Create an overlay buffer, wrapping around this static packet */
f.payload = ob_static(&packet[ofs], nextPayload - ofs);
ob_limitsize(f.payload, nextPayload - ofs);
/* Finally process the frame */
overlay_frame_process(interface,&f);
ob_free(f.payload);
}
/* Jump to the next payload offset */
ofs = nextPayload;
}
if (0) INFOF("Finished processing overlay packet");
/* Get time to live */
f.ttl=ob_get(b);
/* Decode length of remainder of frame */
int payload_len=rfs_decode(b->bytes, &b->position);
if (payload_len <=0) {
/* assume we fell off the end of the packet */
break;
}
int payload_start=b->position;
int next_payload = b->position + payload_len;
/* Always attempt to resolve all of the addresses in a packet, or we could fail to understand an important payload
eg, peer sends two payloads travelling in opposite directions;
[Next, Dest, Sender] forwarding a payload we just send, so Sender == Me
[Next, Dest, Sender] delivering a payload to us so Next == Me
But Next would be encoded as OA_CODE_PREVIOUS, so we must parse all three addresses,
even if Next is obviously not intended for us
*/
struct subscriber *nexthop=NULL;
// if we can't parse one of the addresses, skip processing the payload
if (overlay_address_parse(b, &f.broadcast_id, &nexthop)
|| overlay_address_parse(b, NULL, &f.destination)
|| overlay_address_parse(b, NULL, &f.source)){
WHYF("Parsing failed for type %x", f.type);
dump(NULL, b->bytes + payload_start, payload_len);
goto next;
}
if (debug&DEBUG_OVERLAYFRAMES){
DEBUGF("Received payload type %x, len %d", f.type, next_payload - b->position);
DEBUGF("Payload from %s", alloca_tohex_sid(f.source->sid));
DEBUGF("Payload to %s", (f.destination?alloca_tohex_sid(f.destination->sid):alloca_tohex(f.broadcast_id.id, BROADCAST_LEN)));
if (nexthop)
DEBUGF("Next hop %s", alloca_tohex_sid(nexthop->sid));
}
if (f.type==OF_TYPE_SELFANNOUNCE){
overlay_address_set_sender(f.source);
}
// ignore any payload we sent
if (f.source->reachable==REACHABLE_SELF){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF("Ignoring payload from myself (%s)", alloca_tohex_sid(f.source->sid));
goto next;
}
// skip unicast payloads that aren't for me
if (nexthop && nexthop->reachable!=REACHABLE_SELF){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF("Ignoring payload that is not meant for me (%s)", alloca_tohex_sid(nexthop->sid));
goto next;
}
// skip broadcast payloads we've already seen
if ((!nexthop) && overlay_broadcast_drop_check(&f.broadcast_id)){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF("Ignoring duplicate broadcast (%s)", alloca_tohex(f.broadcast_id.id, BROADCAST_LEN));
goto next;
}
f.payload = ob_slice(b, b->position, next_payload - b->position);
if (!f.payload){
WHY("Payload length is longer than remaining packet size");
break;
}
// mark the entire payload as having valid data
ob_limitsize(f.payload, next_payload - b->position);
// forward payloads that are for someone else or everyone
if ((!f.destination) ||
(f.destination->reachable != REACHABLE_SELF && f.destination->reachable != REACHABLE_NONE)){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Forwarding payload");
overlay_forward_payload(&f);
}
// process payloads that are for me or everyone
if ((!f.destination) || f.destination->reachable==REACHABLE_SELF){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Processing payload");
process_incoming_frame(now, interface, &f);
}
next:
if (f.payload){
ob_free(f.payload);
f.payload=NULL;
}
b->position=next_payload;
}
ob_free(b);
return 0;
}
@ -278,7 +326,6 @@ int overlay_add_selfannouncement(int interface,struct overlay_buffer *b)
XXX - But this functionality really needs to move up a level to whole frame composition.
*/
unsigned char *sid=overlay_get_my_sid();
time_ms_t now = gettime_ms();
/* Header byte */
@ -309,18 +356,12 @@ int overlay_add_selfannouncement(int interface,struct overlay_buffer *b)
return WHY("Could not add RFS for self-announcement frame");
/* Add next-hop address. Always link-local broadcast for self-announcements */
if (ob_append_byte(b,OA_CODE_BROADCAST))
return WHY("Could not add self-announcement header");
/* BPI for broadcast */
{
int i;
for(i=0;i<8;i++)
if (ob_append_byte(b,random()&0xff))
return WHYF("Could not add next-hop address byte %d", i);
}
struct broadcast broadcast_id;
overlay_broadcast_generate_address(&broadcast_id);
if (overlay_broadcast_append(b, &broadcast_id))
return WHY("Could not write broadcast address to self-announcement");
/* Add final destination. Always broadcast for self-announcments.
As we have just referenced the broadcast address, we can encode it in a single byte */
/* Add final destination. Always broadcast for self-announcments. */
if (ob_append_byte(b, OA_CODE_PREVIOUS))
return WHY("Could not add self-announcement header");
@ -332,17 +373,14 @@ int overlay_add_selfannouncement(int interface,struct overlay_buffer *b)
a uselessly short address. So instead we will use a simple scheme where we will send our
address in full an arbitrary 1 in 4 times.
*/
if (send_prefix) {
if (ob_append_byte(b, OA_CODE_PREFIX7)) return WHY("Could not add address format code.");
if (ob_append_bytes(b,sid,7)) return WHY("Could not append SID prefix to self-announcement");
}
else {
if (ob_append_bytes(b,sid,SID_SIZE)) return WHY("Could not append SID to self-announcement");
}
/* Make note that this is the most recent address we have set */
overlay_abbreviate_set_most_recent_address(sid);
/* And the sender for any other addresses in this packet */
overlay_abbreviate_set_current_sender(sid);
if (!send_prefix)
my_subscriber->send_full=1;
if (overlay_address_append(b, my_subscriber))
return WHY("Could not append SID to self-announcement");
overlay_address_set_sender(my_subscriber);
/* Sequence number range. Based on one tick per millisecond. */
time_ms_t last_ms = overlay_interfaces[interface].last_tick_ms;

View File

@ -19,16 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "overlay_buffer.h"
#include "overlay_packet.h"
int overlay_payload_verify(overlay_frame *p)
{
/* Make sure that an incoming payload has a valid signature from the sender.
This is used to prevent spoofing */
return WHY("function not implemented");
}
int op_append_type(struct overlay_buffer *headers,overlay_frame *p)
static int op_append_type(struct overlay_buffer *headers, struct overlay_frame *p)
{
unsigned char c[3];
switch(p->type&OF_TYPE_FLAG_BITS)
@ -60,7 +53,7 @@ int op_append_type(struct overlay_buffer *headers,overlay_frame *p)
}
int overlay_frame_package_fmt1(overlay_frame *p, struct overlay_buffer *b)
int overlay_frame_append_payload(struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b)
{
/* Convert a payload (frame) structure into a series of bytes.
Assumes that any encryption etc has already been done.
@ -76,26 +69,10 @@ int overlay_frame_package_fmt1(overlay_frame *p, struct overlay_buffer *b)
ob_checkpoint(b);
if (debug&DEBUG_PACKETCONSTRUCTION)
dump_payload(p,"package_fmt1 stuffing into packet");
dump_payload(p,"append_payload stuffing into packet");
/* Build header */
if (p->source[0]<0x10) {
// Make sure that addresses do not overload the special address spaces of 0x00*-0x0f*
WHY("packet source address begins with reserved value 0x00-0x0f");
goto cleanup;
}
if (p->destination[0]<0x10) {
// Make sure that addresses do not overload the special address spaces of 0x00*-0x0f*
WHY("packet destination address begins with reserved value 0x00-0x0f");
goto cleanup;
}
if (p->nexthop[0]<0x10) {
// Make sure that addresses do not overload the special address spaces of 0x00*-0x0f*
WHY("packet nexthop address begins with reserved value 0x00-0x0f");
goto cleanup;
}
/* Write fields into binary structure in correct order */
/* Write out type field byte(s) */
@ -120,9 +97,16 @@ int overlay_frame_package_fmt1(overlay_frame *p, struct overlay_buffer *b)
int addrs_start=headers->position;
/* Write out addresses as abbreviated as possible */
overlay_abbreviate_append_address(headers,p->nexthop);
overlay_abbreviate_append_address(headers,p->destination);
overlay_abbreviate_append_address(headers,p->source);
if (p->sendBroadcast){
overlay_broadcast_append(headers, &p->broadcast_id);
}else{
overlay_address_append(headers, next_hop);
}
if (p->destination)
overlay_address_append(headers,p->destination);
else
ob_append_byte(headers, OA_CODE_PREVIOUS);
overlay_address_append(headers,p->source);
int addrs_len=headers->position-addrs_start;
int actual_len=addrs_len+p->payload->position;
@ -177,19 +161,18 @@ int dump_queue(char *msg,int q)
return 0;
}
int dump_payload(overlay_frame *p,char *message)
int dump_payload(struct overlay_frame *p, char *message)
{
DEBUGF( "+++++\nFrame from %s to %s of type 0x%02x %s:",
alloca_tohex_sid(p->source),
alloca_tohex_sid(p->destination),p->type,
alloca_tohex_sid(p->source->sid),
alloca_tohex_sid(p->destination->sid),p->type,
message?message:"");
DEBUGF(" next hop is %s",alloca_tohex_sid(p->nexthop));
if (p->payload)
dump("payload contents", &p->payload->bytes[0],p->payload->position);
return 0;
}
int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
int overlay_payload_enqueue(int q, struct overlay_frame *p)
{
/* Add payload p to queue q.
@ -198,14 +181,27 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
Complain if there are too many frames in the queue.
*/
if (!p) return WHY("Cannot queue NULL");
if (p->destination &&
(p->destination->reachable == REACHABLE_NONE || p->destination->reachable == REACHABLE_SELF))
return WHYF("Destination %s is unreachable (%d)", alloca_tohex_sid(p->destination->sid), p->destination->reachable);
if (debug&DEBUG_PACKETTX)
DEBUGF("Enqueuing packet for %s* (q[%d]length = %d)",
alloca_tohex(p->destination, 7),
alloca_tohex(p->destination->sid, 7),
q,overlay_tx[q].length);
if (q<0||q>=OQ_MAX) return WHY("Invalid queue specified");
if (!p) return WHY("Cannot queue NULL");
if (p->payload && p->payload->position > p->payload->sizeLimit){
// HACK, maybe should be done in each caller
// set the size of the payload based on the position written
p->payload->sizeLimit=p->payload->position;
}
if (0) dump_payload(p,"queued for delivery");
if (overlay_tx[q].length>=overlay_tx[q].maxLength)
@ -213,17 +209,14 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
if (0) dump_queue("before",q);
/* If the frame is broadcast, then mark it correctly so that it can be sent
via all interfaces. */
if (overlay_address_is_broadcast(p->destination)||forceBroadcastP)
{
p->isBroadcast=1;
int i;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++) p->broadcast_sent_via[i]=0;
}
else p->isBroadcast=0;
overlay_frame *l=overlay_tx[q].last;
if (!p->destination){
int i;
p->sendBroadcast=1;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
p->broadcast_sent_via[i]=0;
}
struct overlay_frame *l=overlay_tx[q].last;
if (l) l->next=p;
p->prev=l;
p->next=NULL;
@ -237,7 +230,7 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
if (0) dump_queue("after",q);
if (q==OQ_ISOCHRONOUS_VOICE&&(!forceBroadcastP)) {
if (q==OQ_ISOCHRONOUS_VOICE) {
// Send a packet now
overlay_send_packet(NULL);
}
@ -245,7 +238,7 @@ int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP)
return 0;
}
int op_free(overlay_frame *p)
int op_free(struct overlay_frame *p)
{
if (!p) return WHY("Asked to free NULL");
if (p->prev&&p->prev->next==p) return WHY("p->prev->next still points here");
@ -258,53 +251,29 @@ int op_free(overlay_frame *p)
return 0;
}
overlay_frame *op_dup(overlay_frame *in)
struct overlay_frame *op_dup(struct overlay_frame *in)
{
if (!in) return NULL;
/* clone the frame */
overlay_frame *out=malloc(sizeof(overlay_frame));
struct overlay_frame *out=malloc(sizeof(struct overlay_frame));
if (!out) return WHYNULL("malloc() failed");
/* copy main data structure */
bcopy(in,out,sizeof(overlay_frame));
bcopy(in,out,sizeof(struct overlay_frame));
out->payload=ob_dup(in->payload);
if (in->payload)
out->payload=ob_dup(in->payload);
return out;
}
int overlay_frame_set_broadcast_as_destination(overlay_frame *f)
int overlay_frame_set_broadcast_as_destination(struct overlay_frame *f)
{
overlay_broadcast_generate_address(f->destination);
// remember the broadcast address we are about to send so we don't sent the packet twice
overlay_broadcast_drop_check(f->destination);
f->isBroadcast=1;
overlay_broadcast_generate_address(&f->broadcast_id);
// remember the broadcast address we are about to send so we don't sent the packet if we receive it again
overlay_broadcast_drop_check(&f->broadcast_id);
f->destination=NULL;
f->sendBroadcast=1;
return 0;
}
unsigned char *overlay_get_my_sid()
{
/* Make sure we can find our SID */
int kp;
if (!keyring)
{ WHY("keyring is null"); return NULL; }
if (!keyring->context_count)
{ WHY("No context zero in keyring"); return NULL; }
if (!keyring->contexts[0]->identity_count)
{ WHY("No identity in keyring context zero"); return NULL; }
for(kp=0;kp<keyring->contexts[0]->identities[0]->keypair_count;kp++)
if (keyring->contexts[0]->identities[0]->keypairs[kp]->type==KEYTYPE_CRYPTOBOX)
return keyring->contexts[0]->identities[0]->keypairs[kp]->public_key;
WHY("Could not find first entry in HLR"); return NULL;
}
int overlay_frame_set_me_as_source(overlay_frame *f)
{
unsigned char *sid=overlay_get_my_sid();
if (!sid) return WHY("overlay_get_my_sid() failed.");
bcopy(sid,f->source,SID_SIZE);
return 0;
}

View File

@ -19,8 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "strbuf.h"
#include "subscribers.h"
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_packet.h"
/*
Here we implement the actual routing algorithm which is heavily based on BATMAN.
@ -170,110 +171,24 @@ int overlay_route_recalc_neighbour_metrics(struct overlay_neighbour *n, time_ms_
struct overlay_neighbour *overlay_route_get_neighbour_structure(overlay_node *node, int createP);
/* Select a next hop to get to a node.
Frist, let us consider neighbours. These are on a local link to us, and do not require any
intermediate nodes to transmit to us. However, assymetric packet loss is common, so we may
not be able to transmit back to the neighbour. We know if we can because we will have
received acks to our self announcements. However, to send an ack to a self announcement we
need a fall-back option. This fall-back should be by sending to the broadcast address.
The complication comes when we have multiple interfaces available. If we send to all, then
we need a way of keeping track which interfaces we have sent it on so far, which is a bit
icky, and more to the point requires some revamping of code. A bigger problem is that we might
have cheap and expensive interfaces, and we don't want to go blabbing about our wifi or ethernet
based peers over a $10/MB BGAN link, when we can reasonably know that it shouldn't be necessary.
The trouble is that sometimes it might just be necessary. We then have two options, send traffic
over multiple interfaces to try to discover such one-way links, even if internet back-haul is
required in between. This is nice in the long-term. Or, we be more conservative with the traffic
and require that a resolution to the route be discoverable via the interface that the frame
arrived on.
In any case, we need to tag the nexthop address with the interface(s) on which to send it.
Once we have this working and neighbours can communicate, then we can move on to addressing
nodes that are only indirectly connected. Indeed, the two are somewhat interconnected as
an indirect route may be required to get a self-announce ack back to the sender.
*/
int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface)
{
int i;
overlay_node *get_node(struct subscriber *subscriber, int create){
if (!subscriber)
return NULL;
if (*d==0){
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("No open path to %s, invalid sid",alloca_tohex_sid(d));
return -1;
}
// Note, broadcast address handling is already done by this point
// we don't want to track routing info for ourselves.
if (subscriber->reachable==REACHABLE_SELF)
return NULL;
overlay_node *n=overlay_route_find_node(d,SID_SIZE,0 /* don't create if missing */ );
if (!n){
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("No open path to %s, unknown peer",alloca_tohex_sid(d));
return -1;
if ((!subscriber->node) && create){
subscriber->node = (overlay_node *)malloc(sizeof(overlay_node));
memset(subscriber->node,0,sizeof(overlay_node));
subscriber->node->subscriber = subscriber;
// This info message is used by tests; don't alter or remove it.
INFOF("ADD OVERLAY NODE sid=%s", alloca_tohex_sid(subscriber->sid));
}
time_ms_t now = gettime_ms();
struct overlay_neighbour *direct_neighbour=NULL;
if (n->neighbour_id) {
direct_neighbour = &overlay_neighbours[n->neighbour_id];
overlay_route_recalc_neighbour_metrics(direct_neighbour, now);
/* Is a direct neighbour.
So in the absence of any better indirect route, we pick the interface that
we can hear this neighbour on the most reliably, and then send the frame
via that interface and directly addressed to the recipient. */
int ifn = -1;
for (i = 0; i < overlay_interface_count; ++i) {
if ( overlay_interfaces[i].state == INTERFACE_STATE_UP
&& (ifn == -1 || direct_neighbour->scores[i] > direct_neighbour->scores[ifn]))
ifn = i;
}
if (ifn != -1 && direct_neighbour->scores[ifn] > 0) {
*interface = ifn;
bcopy(d, nexthop, SID_SIZE);
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("nexthop is %s", alloca_tohex_sid(nexthop));
return 0;
}
}
/* Is not a direct neighbour.
XXX - Very simplistic for now. */
int o;
int best_score=0;
int best_o=-1;
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++) {
int score=n->observations[o].observed_score;
if (!score)
continue;
struct overlay_neighbour *neighbour
=overlay_route_get_neighbour_structure
(n->observations[o].sender->node,0);
if (neighbour && neighbour!=direct_neighbour) {
overlay_route_recalc_neighbour_metrics(neighbour, now);
for(i=1;i<OVERLAY_MAX_INTERFACES;i++) {
if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
neighbour->scores[i]*score>best_score) {
bcopy(neighbour->node->subscriber->sid,nexthop,SID_SIZE);
*interface=i;
best_o=o;
best_score=score;
}
}
}
}
if (best_o>-1) {
return 0;
} else {
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("No open path to %s, no good neighbour observations",alloca_tohex_sid(d));
return -1;
}
return subscriber->node;
}
overlay_node *overlay_route_find_node(const unsigned char *sid, int prefixLen, int createP)
@ -283,23 +198,10 @@ overlay_node *overlay_route_find_node(const unsigned char *sid, int prefixLen, i
return NULL;
}
struct subscriber *subscriber = find_subscriber(sid, prefixLen, createP);
if (!subscriber)
return NULL;
if ((!subscriber->node) && createP){
subscriber->node = (overlay_node *)malloc(sizeof(overlay_node));
memset(subscriber->node,0,sizeof(overlay_node));
subscriber->node->subscriber = subscriber;
// This info message is used by tests; don't alter or remove it.
INFOF("ADD OVERLAY NODE sid=%s", alloca_tohex_sid(sid));
}
return subscriber->node;
return get_node(find_subscriber(sid, prefixLen, createP), createP);
}
int overlay_route_ack_selfannounce(overlay_frame *f,
int overlay_route_ack_selfannounce(struct overlay_frame *f,
unsigned int s1,unsigned int s2,
int interface,
struct overlay_neighbour *n)
@ -327,8 +229,8 @@ int overlay_route_ack_selfannounce(overlay_frame *f,
*/
/* XXX Allocate overlay_frame structure and populate it */
overlay_frame *out=NULL;
out=calloc(sizeof(overlay_frame),1);
struct overlay_frame *out=NULL;
out=calloc(sizeof(struct overlay_frame),1);
if (!out) return WHY("calloc() failed to allocate an overlay frame");
out->type=OF_TYPE_SELFANNOUNCE_ACK;
@ -339,24 +241,14 @@ int overlay_route_ack_selfannounce(overlay_frame *f,
XXX 6 is quite an arbitrary selection however. */
/* Set destination of ack to source of observed frame */
bcopy(n->node->subscriber->sid, out->destination, SID_SIZE);
out->destination = n->node->subscriber;
/* set source to ourselves */
overlay_frame_set_me_as_source(out);
/* Next-hop will get set at TX time, so no need to set it here.
However, if there is no known next-hop for this node (because the return path
has not yet begun to be built), then we need to set the nexthop to broadcast. */
out->nexthop_address_status=OA_UNINITIALISED;
if (overlay_resolve_next_hop(out)) {
/* no open path, so convert to broadcast */
overlay_frame_set_broadcast_as_destination(out);
out->isBroadcast = 1;
out->ttl=2;
if (debug&DEBUG_OVERLAYROUTING)
DEBUG("Broadcasting ack to selfannounce for hithero unroutable node");
} else
out->isBroadcast = 0;
out->source = my_subscriber;
/* Try to use broadcast if we don't have a route yet */
if (out->destination->reachable == REACHABLE_NONE)
out->destination->reachable = REACHABLE_BROADCAST;
/* Set the time in the ack. Use the last sequence number we have seen
from this neighbour, as that may be helpful information for that neighbour
down the track. My policy is to communicate that information which should
@ -410,7 +302,7 @@ int overlay_route_ack_selfannounce(overlay_frame *f,
/* Add to queue. Keep broadcast status that we have assigned here if required to
get ack back to sender before we have a route. */
if (overlay_payload_enqueue(OQ_MESH_MANAGEMENT,out,out->isBroadcast))
if (overlay_payload_enqueue(OQ_MESH_MANAGEMENT,out))
{
op_free(out);
return WHY("overlay_payload_enqueue(self-announce ack) failed");
@ -429,9 +321,6 @@ int overlay_route_make_neighbour(overlay_node *n)
/* If it is already a neighbour, then return */
if (n->neighbour_id) return 0;
/* If address is local don't both making it a neighbour */
if (overlay_address_is_local(n->subscriber->sid)) return 0;
/* It isn't yet a neighbour, so find or free a neighbour slot */
/* slot 0 is reserved, so skip it */
if (!overlay_neighbour_count) overlay_neighbour_count=1;
@ -446,7 +335,7 @@ int overlay_route_make_neighbour(overlay_node *n)
}
bzero(&overlay_neighbours[n->neighbour_id],sizeof(struct overlay_neighbour));
overlay_neighbours[n->neighbour_id].node=n;
return 0;
}
@ -468,17 +357,7 @@ struct overlay_neighbour *overlay_route_get_neighbour_structure(overlay_node *no
return &overlay_neighbours[node->neighbour_id];
}
int overlay_route_i_can_hear_node(unsigned char *who,int sender_interface,
unsigned int s1,unsigned int s2,
time_ms_t now)
{
if (0) DEBUGF("I can hear node %s (but I really only care who can hear me)",
alloca_tohex_sid(who));
return 0;
}
int overlay_route_node_can_hear_me(unsigned char *who,int sender_interface,
int overlay_route_node_can_hear_me(struct subscriber *subscriber, int sender_interface,
unsigned int s1,unsigned int s2,
time_ms_t now)
{
@ -487,7 +366,6 @@ int overlay_route_node_can_hear_me(unsigned char *who,int sender_interface,
3. Update score of how reliably we can hear this node */
/* Get neighbour structure */
struct subscriber *subscriber = find_subscriber(who, SID_SIZE, 1);
struct overlay_neighbour *neh=overlay_route_get_neighbour_structure(subscriber->node,1 /* create if necessary */);
if (!neh)
return -1;
@ -537,13 +415,13 @@ int overlay_route_node_can_hear_me(unsigned char *who,int sender_interface,
return 0;
}
int overlay_route_saw_selfannounce(overlay_frame *f, time_ms_t now)
int overlay_route_saw_selfannounce(struct overlay_frame *f, time_ms_t now)
{
IN();
unsigned int s1,s2;
unsigned char sender_interface;
overlay_node *node = overlay_route_find_node(f->source, SID_SIZE, 1);
overlay_node *node = get_node(f->source, 1);
if (!node)
RETURN(-1);
@ -559,8 +437,6 @@ int overlay_route_saw_selfannounce(overlay_frame *f, time_ms_t now)
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("Received self-announcement for sequence range [%08x,%08x] from interface %d",s1,s2,sender_interface);
overlay_route_i_can_hear_node(f->source,sender_interface,s1,s2,now);
overlay_route_ack_selfannounce(f,s1,s2,sender_interface,n);
RETURN(0);
@ -572,53 +448,96 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
int o;
int best_score=0;
int best_observation=-1;
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++)
{
if (n->observations[o].observed_score)
{
int discounted_score=n->observations[o].observed_score;
discounted_score-=(now-n->observations[o].rx_time)/1000;
if (discounted_score<0) discounted_score=0;
n->observations[o].corrected_score=discounted_score;
if (discounted_score>best_score) {
best_score=discounted_score;
best_observation=o;
}
}
}
int reachable = REACHABLE_NONE;
// TODO expiry timer since last self announce
if (n->subscriber->reachable==REACHABLE_BROADCAST)
reachable = REACHABLE_BROADCAST;
overlay_interface *interface=NULL;
struct subscriber *next_hop=NULL;
if (n->neighbour_id)
{
/* Node is also a direct neighbour, so check score that way */
if (n->neighbour_id>overlay_max_neighbours||n->neighbour_id<0)
return WHY("n->neighbour_id is invalid.");
struct overlay_neighbour *neighbour=&overlay_neighbours[n->neighbour_id];
int i;
for(i=0;i<overlay_interface_count;i++)
{
/* Node is also a direct neighbour, so check score that way */
if (n->neighbour_id>overlay_max_neighbours||n->neighbour_id<0)
return WHY("n->neighbour_id is invalid.");
struct overlay_neighbour *neighbour=&overlay_neighbours[n->neighbour_id];
int i;
for(i=0;i<overlay_interface_count;i++)
{
if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
neighbour->scores[i]>best_score)
{
best_score=neighbour->scores[i];
best_observation=-1;
}
}
if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
neighbour->scores[i]>best_score)
{
best_score=neighbour->scores[i];
best_observation=-1;
reachable=REACHABLE_DIRECT;
interface = &overlay_interfaces[i];
}
}
}
if (best_score<=0){
for(o=0;o<OVERLAY_MAX_OBSERVATIONS;o++)
{
if (n->observations[o].observed_score && n->observations[o].sender->reachable==REACHABLE_DIRECT)
{
int discounted_score=n->observations[o].observed_score;
discounted_score-=(now-n->observations[o].rx_time)/1000;
if (discounted_score<0) discounted_score=0;
n->observations[o].corrected_score=discounted_score;
if (discounted_score>best_score) {
best_score=discounted_score;
best_observation=o;
reachable=REACHABLE_INDIRECT;
next_hop=n->observations[o].sender;
}
}
}
}
/* Think about scheduling this node's score for readvertising if its score
has changed a lot?
Really what we probably want is to advertise when the score goes up, since
if it goes down, we probably don't need to say anything at all.
*/
int diff=best_score-n->best_link_score;
if (diff>0) {
overlay_route_please_advertise(n);
if (debug&DEBUG_OVERLAYROUTEMONITOR) overlay_route_dump();
}
/* Remember new reachability information */
if (n->subscriber->reachable!=reachable){
switch (reachable){
case REACHABLE_DIRECT:
DEBUGF("%s is now reachable directly", alloca_tohex_sid(n->subscriber->sid));
break;
case REACHABLE_INDIRECT:
DEBUGF("%s is now reachable indirectly", alloca_tohex_sid(n->subscriber->sid));
break;
case REACHABLE_NONE:
DEBUGF("%s is not reachable", alloca_tohex_sid(n->subscriber->sid));
break;
case REACHABLE_BROADCAST:
DEBUGF("%s is now reachable via broadcast", alloca_tohex_sid(n->subscriber->sid));
break;
}
}
n->subscriber->reachable=reachable;
switch (reachable){
case REACHABLE_INDIRECT:
n->subscriber->next_hop = next_hop;
break;
case REACHABLE_DIRECT:
n->subscriber->interface = interface;
n->subscriber->address = interface->broadcast_address;
break;
}
if (n->best_link_score && !best_score){
INFOF("PEER UNREACHABLE, sid=%s", alloca_tohex_sid(n->subscriber->sid));
monitor_announce_unreachable_peer(n->subscriber->sid);
@ -632,7 +551,6 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
keyring_find_sas_public(keyring, n->subscriber->sid);
}
/* Remember new reachability information */
n->best_link_score=best_score;
n->best_observation=best_observation;
@ -800,14 +718,14 @@ int overlay_route_recalc_neighbour_metrics(struct overlay_neighbour *n, time_ms_
These link scores should get stored in our node list as compared to our neighbour list,
with the node itself listed as the nexthop that the score is associated with.
*/
int overlay_route_saw_selfannounce_ack(overlay_frame *f,long long now)
int overlay_route_saw_selfannounce_ack(struct overlay_frame *f,long long now)
{
IN();
if (debug&DEBUG_OVERLAYROUTING)
DEBUGF("processing selfannounce ack (payload length=%d)",f->payload->sizeLimit);
if (f->payload->sizeLimit<9)
RETURN(WHY("FOO! selfannounce ack packet too short"));
RETURN(WHY("selfannounce ack packet too short"));
unsigned int s1=ob_get_ui32(f->payload);
unsigned int s2=ob_get_ui32(f->payload);
@ -906,14 +824,6 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
RETURN(0);
}
int overlay_address_is_local(unsigned char *s)
{
int cn=0,in=0,kp=0;
int found=keyring_find_sid(keyring,&cn,&in,&kp,s);
return found;
}
int node_dump(struct subscriber *subscriber, void *context){
strbuf *b=context;
overlay_node *node = subscriber->node;
@ -985,11 +895,6 @@ int overlay_route_dump()
return 0;
}
int max(int a,int b)
{
if (a>b) return a; else return b;
}
/* Ticking neighbours is easy; we just pretend we have heard from them again,
and recalculate the score that way, which already includes a mechanism for
taking into account the age of the most recent observation */

View File

@ -21,6 +21,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "rhizome.h"
#include <assert.h>
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_packet.h"
#include <stdlib.h>
int rhizome_manifest_to_bar(rhizome_manifest *m,unsigned char *bar)
@ -111,11 +113,11 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
ob_append_rfs(e,1+11+1+2+RHIZOME_BAR_BYTES/* RFS */);
/* Stuff in dummy address fields (11 bytes) */
ob_append_byte(e,OA_CODE_BROADCAST);
{ int i; for(i=0;i<8;i++) ob_append_byte(e,random()&0xff); } /* BPI for broadcast */
ob_append_byte(e,OA_CODE_PREVIOUS);
overlay_abbreviate_clear_most_recent_address();
overlay_abbreviate_append_address(e, overlay_get_my_sid());
struct broadcast broadcast_id;
overlay_broadcast_generate_address(&broadcast_id);
overlay_broadcast_append(e, &broadcast_id);
ob_append_byte(e, OA_CODE_PREVIOUS);
overlay_address_append(e, my_subscriber);
/* Randomly choose whether to advertise manifests or BARs first. */
int skipmanifests=random()&1;
@ -267,7 +269,7 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
RETURN(0);
}
int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
int overlay_rhizome_saw_advertisements(int i, struct overlay_frame *f, long long now)
{
IN();
if (!f) { RETURN(-1); }

View File

@ -285,47 +285,6 @@ void keyring_identity_extract(const keyring_identity *id, const unsigned char **
extern int sock;
typedef struct sid {
unsigned char b[SID_SIZE];
} sid;
extern sid overlay_abbreviate_current_sender;
typedef struct overlay_frame {
struct overlay_frame *prev;
struct overlay_frame *next;
unsigned int type;
unsigned int modifiers;
unsigned char ttl;
/* Mark which interfaces the frame has been sent on,
so that we can ensure that broadcast frames get sent
exactly once on each interface */
int isBroadcast;
unsigned char broadcast_sent_via[OVERLAY_MAX_INTERFACES];
unsigned char nexthop[32];
int nexthop_address_status;
int nexthop_interface; /* which interface the next hop should be attempted on */
unsigned char destination[32];
unsigned char source[32];
/* IPv4 node frame was received from (if applicable) */
struct sockaddr *recvaddr;
/* Actual payload */
// TODO refactor *all* packet parsing so that the payload is not copied or allocated unless it must be forwarded.
struct overlay_buffer *payload;
int rfs; /* remainder of frame size */
time_ms_t enqueued_at;
} overlay_frame;
struct profile_total {
struct profile_total *_next;
int _initialised;
@ -362,6 +321,9 @@ struct sched_ent{
int _poll_index;
};
struct overlay_buffer;
struct subscriber;
#define STRUCT_SCHED_ENT_UNUSED ((struct sched_ent){NULL, NULL, NULL, NULL, {-1, 0, 0}, 0LL, 0LL, NULL, -1})
extern int overlayMode;
@ -595,6 +557,7 @@ int getBatmanPeerList(char *socket_path,struct in_addr peers[],int *peer_count,i
int asteriskObtainGateway(char *requestor_sid,char *did,char *uri_out);
int packetOkDNA(unsigned char *packet,int len,unsigned char *transaction_id,
int recvttl,struct sockaddr *recvaddr, size_t recvaddrlen,int parseP);
int overlay_forward_payload(struct overlay_frame *f);
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr, size_t recvaddrlen,int parseP);
@ -604,50 +567,32 @@ int packetSendRequest(int method,unsigned char *packet,int packet_len,int batchP
struct response_set *responses);
int readArpTable(struct in_addr peers[],int *peer_count,int peer_max);
int overlay_frame_process(struct overlay_interface *interface,overlay_frame *f);
int overlay_frame_resolve_addresses(overlay_frame *f);
int overlay_frame_process(struct overlay_interface *interface, struct overlay_frame *f);
int overlay_frame_resolve_addresses(struct overlay_frame *f);
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
#define alloca_tohex_sid(sid) alloca_tohex((sid), SID_SIZE)
#define alloca_tohex_sas(sas) alloca_tohex((sas), SAS_SIZE)
int op_free(overlay_frame *p);
overlay_frame *op_dup(overlay_frame *f);
time_ms_t overlay_time_until_next_tick();
int overlay_rx_messages();
#define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __HERE__, (M), (P), (N))
int overlay_add_selfannouncement();
int overlay_frame_package_fmt1(overlay_frame *p, struct overlay_buffer *b);
int overlay_frame_append_payload(struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b);
int overlay_interface_args(const char *arg);
int overlay_get_nexthop(unsigned char *d,unsigned char *nexthop,int *interface);
int overlay_sendto(struct sockaddr_in *recipientaddr,unsigned char *bytes,int len);
int overlay_rhizome_add_advertisements(int interface_number,struct overlay_buffer *e);
int overlay_add_local_identity(unsigned char *s);
int overlay_address_is_local(unsigned char *s);
void overlay_update_queue_schedule(overlay_txqueue *queue, overlay_frame *frame);
void overlay_update_queue_schedule(overlay_txqueue *queue, struct overlay_frame *frame);
void overlay_send_packet(struct sched_ent *alarm);
int overlay_resolve_next_hop(overlay_frame *frame);
extern int overlay_interface_count;
extern int overlay_local_identity_count;
extern unsigned char *overlay_local_identities[OVERLAY_MAX_LOCAL_IDENTITIES];
int overlay_abbreviate_address(unsigned char *in,unsigned char *out,int *ofs);
int overlay_abbreviate_append_address(struct overlay_buffer *b,unsigned char *a);
int overlay_abbreviate_expand_address(unsigned char *in,int *inofs,unsigned char *out,int *ofs);
int overlay_abbreviate_cache_address(unsigned char *sid);
int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *ofs,
int prefix_bytes,int index_bytes);
int overlay_abbreviate_remember_index(int index_byte_count,unsigned char *in,unsigned char *index_bytes);
extern int overlay_abbreviate_repeat_policy;
int overlay_abbreviate_set_most_recent_address(unsigned char *in);
int overlay_abbreviate_clear_most_recent_address();
int rfs_length(int l);
int rfs_encode(int l,unsigned char *b);
int rfs_decode(unsigned char *b,int *offset);
@ -678,41 +623,33 @@ typedef struct overlay_node {
overlay_node_observation observations[OVERLAY_MAX_OBSERVATIONS];
} overlay_node;
int overlay_route_saw_selfannounce_ack(overlay_frame *f, time_ms_t now);
int overlay_route_saw_selfannounce(overlay_frame *f, time_ms_t now);
int overlay_route_saw_selfannounce_ack(struct overlay_frame *f, time_ms_t now);
int overlay_route_saw_selfannounce(struct overlay_frame *f, time_ms_t now);
overlay_node *overlay_route_find_node(const unsigned char *sid,int prefixLen,int createP);
unsigned int overlay_route_hash_sid(const unsigned char *sid);
unsigned char *overlay_get_my_sid();
int overlay_frame_set_me_as_source(overlay_frame *f);
int overlay_frame_set_broadcast_as_destination(overlay_frame *f);
int overlay_frame_set_broadcast_as_destination(struct overlay_frame *f);
int packetEncipher(unsigned char *packet,int maxlen,int *len,int cryptoflags);
int overlayServerMode();
int overlay_payload_enqueue(int q,overlay_frame *p,int forceBroadcastP);
int overlay_abbreviate_lookup_sender_id();
int overlay_payload_enqueue(int q, struct overlay_frame *p);
int overlay_route_record_link( time_ms_t now,unsigned char *to,
unsigned char *via,int sender_interface,
unsigned int s1,unsigned int s2,int score,int gateways_en_route);
int overlay_route_dump();
int overlay_route_add_advertisements(struct overlay_buffer *e);
int ovleray_route_please_advertise(overlay_node *n);
int overlay_abbreviate_set_current_sender(unsigned char *in);
int overlay_route_saw_advertisements(int i,overlay_frame *f, time_ms_t now);
int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, time_ms_t now);
int overlay_route_saw_advertisements(int i, struct overlay_frame *f, time_ms_t now);
int overlay_rhizome_saw_advertisements(int i, struct overlay_frame *f, time_ms_t now);
int overlay_route_please_advertise(overlay_node *n);
int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_saw_voice_traffic();
int overlay_saw_mdp_containing_frame(overlay_frame *f, time_ms_t now);
int overlay_saw_mdp_containing_frame(struct overlay_frame *f, time_ms_t now);
#include "nacl.h"
int serval_packetvisualise(XPRINTF xpf, const char *message, const unsigned char *packet, size_t len);
int overlay_broadcast_drop_check(unsigned char *a);
int overlay_address_is_broadcast(unsigned char *a);
int overlay_broadcast_generate_address(unsigned char *a);
int overlay_abbreviate_unset_current_sender();
int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_opendb();
@ -880,7 +817,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
struct sockaddr_un *recvaddr,int recvaddlen);
int overlay_mdp_dnalookup_reply(const sockaddr_mdp *dstaddr, const unsigned char *resolved_sid, const char *uri, const char *did, const char *name);
int dump_payload(overlay_frame *p,char *message);
int dump_payload(struct overlay_frame *p, char *message);
int urandombytes(unsigned char *x,unsigned long long xlen);

View File

@ -171,7 +171,8 @@ int isOverlayPacket(XPRINTF xpf, const unsigned char *packet, size_t *ofs, size_
xprintf(xpf,"%sServal Overlay Mesh Packet version %d (0x%04x)\n",
indent(4),version,version);
if (version>0x001) {
xprintf(xpf,"%s WARNING: Packet version is newer than I know about.\n",indent(4));
xprintf(xpf,"%s ERROR: Packet version is newer than I know about.\n",indent(4));
return 0;
}
(*ofs)+=4;

View File

@ -1,129 +0,0 @@
//
// subscribers.c
//
//
// Created by Jeremy Lakeman on 11/08/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#include <stdlib.h>
#include "constants.h"
#include "log.h"
#include "serval.h"
#include "subscribers.h"
// each node has 16 slots based on the next 4 bits of a subscriber id
// each slot either points to another tree node or a struct subscriber.
struct tree_node{
// bit flags for the type of object each element points to
int is_tree;
union{
struct tree_node *tree_nodes[16];
struct subscriber *subscribers[16];
};
};
struct tree_node root;
int isSame(const unsigned char *ptr1, const unsigned char *ptr2, int len){
int i;
for (i=0;i<len;i++)
if (ptr1[i]!=ptr2[i])
return 0;
return 1;
}
unsigned char get_nibble(const unsigned char *sid, int pos){
unsigned char byte = sid[pos>>1];
if (!(pos&1))
byte=byte>>4;
return byte&0xF;
}
// find a subscriber struct from a subscriber id
// TODO find abreviated sid's
struct subscriber *find_subscriber(const unsigned char *sid, int len, int create){
struct tree_node *ptr = &root;
int pos=0;
if (len!=SID_SIZE)
create =0;
do{
unsigned char nibble = get_nibble(sid, pos++);
if (ptr->is_tree & (1<<nibble)){
ptr = ptr->tree_nodes[nibble];
}else if(!ptr->subscribers[nibble]){
// subscriber is not yet known
if (create){
struct subscriber *ret=(struct subscriber *)malloc(sizeof(struct subscriber));
memset(ret,0,sizeof(struct subscriber));
ptr->subscribers[nibble]=ret;
bcopy(sid, ret->sid, SID_SIZE);
ret->abbreviate_len=pos;
}
return ptr->subscribers[nibble];
}else{
// there's a subscriber in this slot, does it match the rest of the sid we've been given?
struct subscriber *ret = ptr->subscribers[nibble];
if (isSame(ret->sid,sid,len)){
return ret;
}
// if we need to insert this subscriber, we have to make a new tree node first
if (!create)
return NULL;
// create a new tree node and move the existing subscriber into it
struct tree_node *new=(struct tree_node *)malloc(sizeof(struct tree_node));
memset(new,0,sizeof(struct tree_node));
ptr->tree_nodes[nibble]=new;
ptr->is_tree |= (1<<nibble);
ptr=new;
nibble=get_nibble(ret->sid,pos);
ptr->subscribers[nibble]=ret;
ret->abbreviate_len=pos+1;
// then go around the loop again to compare the next nibble against the sid until we find an empty slot.
}
}while(pos < len*2);
// abbreviation is not unique
return NULL;
}
/*
Walk the subscriber tree, calling the callback function for each subscriber.
if start is a valid pointer, the first entry returned will be after this subscriber
if the callback returns non-zero, the process will stop.
*/
int walk_tree(struct tree_node *node, int pos, struct subscriber *start,
int(*callback)(struct subscriber *, void *), void *context){
int i=0;
if (start){
i=get_nibble(start->sid,pos);
}
for (;i<16;i++){
if (node->is_tree & (1<<i)){
if (walk_tree(node->tree_nodes[i], pos+1, start, callback, context))
return 1;
}else if(node->subscribers[i] && node->subscribers[i] != start){
if (callback(node->subscribers[i], context))
return 1;
}
}
return 0;
}
/*
walk the tree, starting at start, calling the callback function
*/
void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context){
walk_tree(&root, 0, start, callback, context);
}

View File

@ -1,24 +0,0 @@
//
// subscribers.h
//
//
// Created by Jeremy Lakeman on 11/08/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#ifndef _subscribers_h
#define _subscribers_h
#include "constants.h"
struct subscriber{
unsigned char sid[SID_SIZE];
// minimum abbreviation length, in 4bit nibbles.
int abbreviate_len;
overlay_node *node;
};
struct subscriber *find_subscriber(const unsigned char *sid, int len, int create);
void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context);
#endif