mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
Separate routing calculation from resulting rules, refactor more code to use subscriber structure
This commit is contained in:
parent
df0e20408c
commit
e05806f25e
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
35
constants.h
35
constants.h
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
34
keyring.c
34
keyring.c
@ -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
133
overlay.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
309
overlay_address.c
Normal 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
111
overlay_address.h
Normal 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
|
@ -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. */
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
328
overlay_mdp.c
328
overlay_mdp.c
@ -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
61
overlay_packet.h
Normal 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
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
311
overlay_route.c
311
overlay_route.c
@ -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 */
|
||||
|
@ -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); }
|
||||
|
95
serval.h
95
serval.h
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
129
subscribers.c
129
subscribers.c
@ -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);
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user