Merge remote-tracking branch 'origin/master' into rhizomeovermdp

Conflicts:
	rhizome_fetch.c
This commit is contained in:
Jeremy Lakeman 2012-12-06 12:55:27 +10:30
commit 4b73e42bed
34 changed files with 1669 additions and 1766 deletions

@ -1,52 +0,0 @@
/*
Copyright (C) 2012 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"
int encodeAndDispatchRecordedAudio(int fd,int callSessionToken,
int recordCodec,
unsigned char *sampleData,
int sampleBytes)
{
switch (recordCodec) {
case VOMP_CODEC_PCM:
/* leave data raw, so need to rewrite sampleData or sampleBytes */
break;
default:
WHYF("Codec not yet supported");
return -1;
}
char msg[128+MAX_AUDIO_BYTES];
snprintf(msg,128,"\n*%d:AUDIO:%x:%d\n",sampleBytes,callSessionToken,recordCodec);
int len=strlen(msg);
bcopy(&sampleData[0],&msg[len],sampleBytes);
len+=sampleBytes;
write(fd,msg,len);
return 0;
}
int bufferAudioForPlayback(int codec, time_ms_t start_time, time_ms_t end_time, unsigned char *data,int dataLen)
{
/* XXX We need to buffer and reorder out-of-order sample blocks and
decode codecs etc here. */
/* send audio to device */
// int bytesWritten=audev->write(&data[0],dataLen);
return 0;
}

@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "str.h"
#include "mdp_client.h"
#include "cli.h"
#include "overlay_address.h"
extern struct command_line_option command_line_options[];
@ -1525,22 +1526,6 @@ int app_count_peers(int argc, const char *const *argv, struct command_line_optio
return 0;
}
int app_test_rfs(int argc, const char *const *argv, struct command_line_option *o, void *context)
{
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
printf("Testing that RFS coder works properly.\n");
int i;
for(i=0;i<65536;i++) {
unsigned char bytes[8];
rfs_encode(i, &bytes[0]);
int zero=0;
int r=rfs_decode(&bytes[0],&zero);
if (i != r)
printf("RFS encoding of %d decodes to %d: %s\n", i, r, alloca_tohex(bytes, sizeof bytes));
}
return 0;
}
int app_crypt_test(int argc, const char *const *argv, struct command_line_option *o, void *context)
{
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
@ -1751,6 +1736,48 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
return 0;
}
int app_route_print(int argc, const char *const *argv, struct command_line_option *o, void *context)
{
overlay_mdp_frame mdp;
bzero(&mdp,sizeof(mdp));
mdp.packetTypeAndFlags=MDP_ROUTING_TABLE;
overlay_mdp_send(&mdp,0,0);
while(overlay_mdp_client_poll(200)){
overlay_mdp_frame rx;
int ttl;
if (overlay_mdp_recv(&rx, 0, &ttl))
continue;
int ofs=0;
while(ofs + sizeof(struct overlay_route_record) <= rx.out.payload_length){
struct overlay_route_record *p=(struct overlay_route_record *)&rx.out.payload[ofs];
ofs+=sizeof(struct overlay_route_record);
cli_printf(alloca_tohex_sid(p->sid));
cli_delim(":");
if (p->reachable==REACHABLE_NONE)
cli_printf("NONE");
if (p->reachable & REACHABLE_SELF)
cli_printf("SELF ");
if (p->reachable & REACHABLE_ASSUMED)
cli_printf("ASSUMED ");
if (p->reachable & REACHABLE_BROADCAST)
cli_printf("BROADCAST ");
if (p->reachable & REACHABLE_UNICAST)
cli_printf("UNICAST ");
if (p->reachable & REACHABLE_INDIRECT)
cli_printf("INDIRECT ");
cli_delim(":");
cli_printf(alloca_tohex_sid(p->neighbour));
cli_delim("\n");
}
}
return 0;
}
int app_reverse_lookup(int argc, const char *const *argv, struct command_line_option *o, void *context)
{
const char *sid, *delay;
@ -1847,6 +1874,33 @@ int app_reverse_lookup(int argc, const char *const *argv, struct command_line_op
return 0;
}
int app_network_scan(int argc, const char *const *argv, struct command_line_option *o, void *context)
{
overlay_mdp_frame mdp;
bzero(&mdp,sizeof(mdp));
mdp.packetTypeAndFlags=MDP_SCAN;
struct overlay_mdp_scan *scan = (struct overlay_mdp_scan *)&mdp.raw;
const char *address;
if (cli_arg(argc, argv, o, "address", &address, NULL, NULL) == -1)
return -1;
if (address){
DEBUGF("Parsing arg %s", address);
if (!inet_aton(address, &scan->addr))
return WHY("Unable to parse the address");
}else
DEBUGF("Scanning local networks");
overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000);
if (mdp.packetTypeAndFlags!=MDP_ERROR)
return -1;
cli_puts(mdp.error.message);
cli_delim("\n");
return mdp.error.error;
}
/* NULL marks ends of command structure.
"<anystring>" marks an arg that can take any value.
"[<anystring>]" marks an optional arg that can take any value.
@ -1934,14 +1988,16 @@ struct command_line_option command_line_options[]={
"Return identity of known routable peers as URIs"},
{app_id_self,{"id","allpeers",NULL},0,
"Return identity of all known peers as URIs"},
{app_route_print, {"route","print",NULL},0,
"Print the routing table"},
{app_network_scan, {"scan","[<address>]",NULL},0,
"Scan the network for serval peers. If no argument is supplied, all local addresses will be scanned."},
{app_node_info,{"node","info","<sid>",NULL},0,
"Return routing information about a SID"},
{app_count_peers,{"peer","count",NULL},0,
"Return a count of routable peers on the network"},
{app_reverse_lookup, {"reverse", "lookup", "<sid>", "[<timeout>]", NULL}, 0,
"Lookup the phone number and name of a given subscriber"},
{app_test_rfs,{"test","rfs",NULL},0,
"Test RFS field calculation"},
{app_monitor_cli,{"monitor",NULL},0,
"Interactive servald monitor interface."},
{app_crypt_test,{"crypt","test",NULL},0,

@ -54,62 +54,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define SAS_SIZE 32 // == crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES
#define DID_MINSIZE 5
#define DID_MAXSIZE 32
#define SIDDIDFIELD_LEN (SID_SIZE+1)
#define PINFIELD_LEN 32
#define HEADERFIELDS_LEN (2+2+2+2+8+1)
#define OFS_TRANSIDFIELD (2+2+2+2)
#define TRANSID_SIZE 8
#define OFS_ROTATIONFIELD (OFS_TRANSIDFIELD+TRANSID_SIZE)
#define OFS_SIDDIDFIELD HEADERFIELDS_LEN
#define OFS_PINFIELD (OFS_SIDDIDFIELD+SIDDIDFIELD_LEN)
#define OFS_PAYLOAD (OFS_PINFIELD+16+16)
#define SID_STRLEN (SID_SIZE*2)
/* Array of variables that can be placed in an MPHLR */
#define VAR_EOR 0x00
#define VAR_CREATETIME 0x01
#define VAR_CREATOR 0x02
#define VAR_REVISION 0x03
#define VAR_REVISOR 0x04
#define VAR_PIN 0x05
#define VAR_VOICESIG 0x08
#define VAR_HLRMASTER 0x0f
#define VAR_NAME 0x10
#define VAR_DIDS 0x80
#define VAR_LOCATIONS 0x81
#define VAR_IEMIS 0x82
#define VAR_TEMIS 0x83
#define VAR_CALLS_IN 0x90
#define VAR_CALLS_MISSED 0x91
#define VAR_CALLS_OUT 0x92
#define VAR_SMESSAGES 0xa0
#define VAR_DID2SUBSCRIBER 0xb0
#define VAR_HLRBACKUPS 0xf0
#define VAR_NOTE 0xff
#define ACTION_GET 0x00
#define ACTION_SET 0x01
#define ACTION_DEL 0x02
#define ACTION_INSERT 0x03
#define ACTION_DIGITALTELEGRAM 0x04
#define ACTION_CREATEHLR 0x0f
#define ACTION_STATS 0x40
#define ACTION_DONE 0x7e
#define ACTION_ERROR 0x7f
#define ACTION_DECLINED 0x80
#define ACTION_OKAY 0x81
#define ACTION_DATA 0x82
#define ACTION_WROTE 0x83
#define ACTION_XFER 0xf0
#define ACTION_RECVTTL 0xfd
#define ACTION_PAD 0xfe
#define ACTION_EOT 0xff
#define OVERLAY_MAX_INTERFACES 16
#define CRYPT_CIPHERED 1
@ -130,8 +77,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define OVERLAY_MAX_LOCAL_IDENTITIES 256
/* All of these types should be considered deprecated. Processing code should migrate to well known MDP port numbers */
/* Overlay mesh packet codes */
#define OF_TYPE_BITS 0xf0
#define OF_TYPE_SELFANNOUNCE 0x10 /* BATMAN style announcement frames */
#define OF_TYPE_SELFANNOUNCE_ACK 0x20 /* BATMAN style "I saw your announcment" frames */
#define OF_TYPE_DATA 0x30 /* Ordinary data frame.
@ -144,45 +91,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define OF_TYPE_RHIZOME_ADVERT 0x50 /* Advertisment of file availability via Rhizome */
#define OF_TYPE_PLEASEEXPLAIN 0x60 /* Request for resolution of an abbreviated address */
#define OF_TYPE_NODEANNOUNCE 0x70
#define OF_TYPE_IDENTITYENQUIRY 0x80
#define OF_TYPE_RESERVED_09 0x90
#define OF_TYPE_RESERVED_0a 0xa0
#define OF_TYPE_RESERVED_0b 0xb0
#define OF_TYPE_RESERVED_0c 0xc0
#define OF_TYPE_RESERVED_0d 0xd0
#define OF_TYPE_EXTENDED12 0xe0 /* modifier bits and next byte provide 12 bits extended format
(for future expansion, just allows us to skip the frame) */
#define OF_TYPE_EXTENDED20 0xf0 /* modifier bits and next 2 bytes provide 20 bits extended format
(for future expansion, just allows us to skip the frame) */
/* Flags used to control the interpretation of the resolved type field */
#define OF_TYPE_FLAG_BITS 0xf0000000
#define OF_TYPE_FLAG_NORMAL 0x0
#define OF_TYPE_FLAG_E12 0x10000000
#define OF_TYPE_FLAG_E20 0x20000000
/* Modifiers that indicate the disposition of the frame */
#define OF_MODIFIER_BITS 0x0f
#define PAYLOAD_FLAG_SENDER_SAME (1<<0)
#define PAYLOAD_FLAG_TO_BROADCAST (1<<1)
#define PAYLOAD_FLAG_ONE_HOP (1<<2)
#define PAYLOAD_FLAG_LONG_PAYLOAD (1<<3)
#define PAYLOAD_FLAG_CIPHERED (1<<4)
#define PAYLOAD_FLAG_SIGNED (1<<5)
// this can be removed once all overlay messages have been turned into mdp payloads
#define PAYLOAD_FLAG_LEGACY_TYPE (1<<7)
/* Crypto/security options */
#define OF_CRYPTO_BITS 0x0c
#define OF_CRYPTO_NONE 0x00
#define OF_CRYPTO_CIPHERED 0x04 /* Encrypted frame */
#define OF_CRYPTO_SIGNED 0x08 /* signed frame */
/* The following was previously considered, but is not being implemented at this
time.
#define OF_CRYPTO_PARANOID 0x0c Encrypted and digitally signed frame, with final destination address also encrypted. */
/* QOS packet queue bits */
#define OF_QUEUE_BITS 0x03
#define RFS_PLUS250 0xfa
#define RFS_PLUS456 0xfb
#define RFS_PLUS762 0xfc
#define RFS_PLUS1018 0xfd
#define RFS_PLUS1274 0xfe
#define RFS_3BYTE 0xff
#define COMPUTE_RFS_LENGTH -1
#define OF_CRYPTO_CIPHERED PAYLOAD_FLAG_CIPHERED /* Encrypted frame */
#define OF_CRYPTO_SIGNED PAYLOAD_FLAG_SIGNED /* signed frame */
/* Keep track of last 32 observations of a node.
Hopefully this is enough, if not, we will increase.
@ -199,33 +122,32 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define MAX_SIGNATURES 16
#define IDENTITY_VERIFIED (1<<0)
#define IDENTITY_VERIFIEDBYME (1<<1)
#define IDENTITY_NOTVERIFIED (1<<2)
/* The value below is for caching negative results */
#define IDENTITY_UNKNOWN (1<<3)
#define MDP_PORT_ECHO 0x00000007
#define MDP_PORT_KEYMAPREQUEST 0x10000001
#define MDP_PORT_VOMP 0x10000002
#define MDP_PORT_DNALOOKUP 0x10000003
#define MDP_PORT_NOREPLY 0x10000000
#define MDP_PORT_RHIZOME_REQUEST 0x10000004
#define MDP_PORT_RHIZOME_RESPONSE 0x10000005
#define MDP_PORT_DIRECTORY 10
#define MDP_PORT_KEYMAPREQUEST 1
#define MDP_PORT_PROBE 6
#define MDP_PORT_ECHO 7
#define MDP_PORT_DNALOOKUP 10
#define MDP_PORT_VOMP 12
#define MDP_PORT_RHIZOME_REQUEST 13
#define MDP_PORT_RHIZOME_RESPONSE 14
#define MDP_PORT_DIRECTORY 15
#define MDP_PORT_NOREPLY 0x3f
#define MDP_TYPE_MASK 0xff
#define MDP_FLAG_MASK 0xff00
#define MDP_FORCE 0x0100
#define MDP_NOCRYPT 0x0200
#define MDP_NOSIGN 0x0400
#define MDP_MTU 2000
#define MDP_MTU 1200
#define MDP_TX 1
#define MDP_BIND 3
#define MDP_ERROR 4
#define MDP_GETADDRS 5
#define MDP_ADDRLIST 6
#define MDP_ROUTING_TABLE 7
#define MDP_NODEINFO 8
#define MDP_GOODBYE 9
#define MDP_SCAN 10
// These are back-compatible with the old values of 'mode' when it was 'selfP'
#define MDP_ADDRLIST_MODE_ROUTABLE_PEERS 0
@ -243,26 +165,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define VOMP_STUFF_BYTES 800
#define MAX_AUDIO_BYTES 1024
#define MDP_NODEINFO 8
#define MDP_GOODBYE 9
#define MDP_AWAITREPLY 9999
/* max number of recent samples to cram into a VoMP frame as well as the current
frame of audio (preemptive audio retransmission) */
#define VOMP_MAX_RECENT_SAMPLES 2
#define VOMP_CODEC_NONE 0x00
#define VOMP_CODEC_CODEC2_2400 0x01
#define VOMP_CODEC_CODEC2_1400 0x02
#define VOMP_CODEC_GSMHALF 0x03
#define VOMP_CODEC_GSMFULL 0x04
#define VOMP_CODEC_16SIGNED 0x05
#define VOMP_CODEC_8ULAW 0x06
#define VOMP_CODEC_8ALAW 0x07
#define VOMP_CODEC_PCM 0x08
#define VOMP_CODEC_DTMF 0x80
#define VOMP_CODEC_ENGAGED 0x81
#define VOMP_CODEC_ONHOLD 0x82
// codec's with well defined parameters
#define VOMP_CODEC_16SIGNED 0x01
#define VOMP_CODEC_ULAW 0x02
#define VOMP_CODEC_ALAW 0x03
#define VOMP_CODEC_GSM 0x04
// other out of band signals, probably shouldn't be codecs
#define VOMP_CODEC_DTMF 0x20
#define VOMP_CODEC_TEXT 0x21
// Note, Don't add codec's we aren't using yet
#define CODEC_FLAGS_LENGTH 32
@ -279,11 +198,4 @@ 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

@ -113,7 +113,7 @@ int extractDid(unsigned char *packet,int *ofs,char *did)
int nybl;
nybl=0;
while(nybl!=0xf&&(*ofs<(OFS_SIDDIDFIELD+SIDDIDFIELD_LEN))&&(d<64))
while(nybl!=0xf&&(d<64))
{
if (highP) nybl=packet[*ofs]>>4; else nybl=packet[*ofs]&0xf;
if (nybl<0xa) did[d++]='0'+nybl;
@ -194,81 +194,6 @@ int stowSid(unsigned char *packet, int ofs, const char *sid)
return 0;
}
int packetGetID(unsigned char *packet,int len,char *did,char *sid)
{
int ofs=HEADERFIELDS_LEN;
switch(packet[ofs])
{
case 0: /* DID */
ofs++;
if (extractDid(packet,&ofs,did)) return WHY("Could not decode DID");
if (debug&DEBUG_PACKETFORMATS) DEBUGF("Decoded DID as %s", did);
return 0;
break;
case 1: /* SID */
ofs++;
if (len<(OFS_SIDDIDFIELD+SID_SIZE)) return WHY("Packet too short");
if (extractSid(packet,&ofs,sid)) return WHY("Could not decode SID");
return 0;
break;
default: /* no idea */
return WHY("Unknown ID key");
break;
}
return WHY("Impossible event #1 just occurred");
}
/*
One of the goals of our packet format is to make it very difficult to mount a known plain-text
attack against the ciphered part of the packet.
One defence is to make sure that no fixed fields are actually left zero.
We accomplish this by filling "zero" fields with randomised data that meets a simple test condition.
We have chosen to use the condition that if the modulo 256 sum of the bytes equals zero, then the packet
is assumed to be zero/empty.
The following two functions allow us to test this, and also to fill a field with safe "zero" data.
*/
int isFieldZeroP(unsigned char *packet,int start,int count)
{
int mod=0;
int i;
for(i=start;i<start+count;i++)
{
mod+=packet[i];
mod&=0xff;
}
if (debug&DEBUG_PACKETFORMATS) {
if (mod) DEBUGF("Field [%d,%d) is non-zero (mod=0x%02x)",start,start+count,mod);
else DEBUGF("Field [%d,%d) is zero",start,start+count);
}
if (mod) return 0; else return 1;
}
int safeZeroField(unsigned char *packet,int start,int count)
{
int mod=0;
int i;
if (debug&DEBUG_PACKETFORMATS)
DEBUGF("Known plain-text counter-measure: safe-zeroing [%d,%d)", start,start+count);
for(i=start;i<(start+count-1);i++)
{
packet[i]=random()&0xff;
mod+=packet[i];
mod&=0xff;
}
/* set final byte so that modulo sum is zero */
packet[i]=(0x100-mod)&0xff;
return 0;
}
int is_uri_char_scheme(char c)
{
return isalpha(c) || isdigit(c) || c == '+' || c == '-' || c == '.';
@ -311,3 +236,48 @@ int str_is_uri(const char *uri)
++p;
return p != q && *p == '\0';
}
void write_uint64(unsigned char *o,uint64_t v)
{
int i;
for(i=0;i<8;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
void write_uint32(unsigned char *o,uint32_t v)
{
int i;
for(i=0;i<4;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
void write_uint16(unsigned char *o,uint16_t v)
{
int i;
for(i=0;i<2;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
uint64_t read_uint64(unsigned char *o)
{
int i;
uint64_t v=0;
for(i=0;i<8;i++) v=(v<<8)|o[8-1-i];
return v;
}
uint32_t read_uint32(unsigned char *o)
{
int i;
uint32_t v=0;
for(i=0;i<4;i++) v=(v<<8)|o[4-1-i];
return v;
}
uint16_t read_uint16(unsigned char *o)
{
int i;
uint16_t v=0;
for(i=0;i<2;i++) v=(v<<8)|o[2-1-i];
return v;
}

@ -100,7 +100,7 @@ static void directory_update(struct sched_ent *alarm){
load_directory_config();
if (directory_service){
if (subscriber_is_reachable(directory_service) != REACHABLE_NONE){
if (subscriber_is_reachable(directory_service) & REACHABLE){
directory_send_keyring(directory_service);
unschedule(alarm);

@ -1269,9 +1269,6 @@ int keyring_send_sas_request(struct subscriber *subscriber){
if (debug & DEBUG_KEYRING)
DEBUGF("Requesting SAS mapping for SID=%s", alloca_tohex_sid(subscriber->sid));
// always send our sid in full, it's likely this is a new peer
my_subscriber->send_full = 1;
/* request mapping (send request auth-crypted). */
overlay_mdp_frame mdp;
memset(&mdp,0,sizeof(overlay_mdp_frame));

@ -60,9 +60,11 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
}
}
int port=mdp->out.dst.port;
int port=0;
if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK) == MDP_TX)
port = mdp->out.dst.port;
time_ms_t started = gettime_ms();
while(timeout_ms>=0 && overlay_mdp_client_poll(timeout_ms)>0){
int ttl=-1;
if (!overlay_mdp_recv(mdp, port, &ttl)) {
@ -209,8 +211,10 @@ int overlay_mdp_recv(overlay_mdp_frame *mdp, int port, int *ttl)
}
// silently drop incoming packets for the wrong port number
if (port>0 && port != mdp->in.dst.port)
if (port>0 && port != mdp->in.dst.port){
WARNF("Ignoring packet for port %d",mdp->in.dst.port);
return -1;
}
int expected_len = overlay_mdp_relevant_bytes(mdp);
@ -273,6 +277,7 @@ int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
int len;
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK)
{
case MDP_ROUTING_TABLE:
case MDP_GOODBYE:
/* no arguments for saying goodbye */
len=&mdp->raw[0]-(char *)mdp;
@ -289,6 +294,9 @@ int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
case MDP_BIND:
len=(&mdp->raw[0] - (char *)mdp) + sizeof(sockaddr_mdp);
break;
case MDP_SCAN:
len=(&mdp->raw[0] - (char *)mdp) + sizeof(struct overlay_mdp_scan);
break;
case MDP_ERROR:
/* This formulation is used so that we don't copy any bytes after the
end of the string, to avoid information leaks */

@ -21,6 +21,16 @@
#include "serval.h"
struct overlay_route_record{
unsigned char sid[SID_SIZE];
int reachable;
unsigned char neighbour[SID_SIZE];
};
struct overlay_mdp_scan{
struct in_addr addr;
};
/* Client-side MDP function */
extern int mdp_client_socket;
int overlay_mdp_client_init();

@ -487,10 +487,17 @@ static int monitor_call_pickup(int argc, const char *const *argv, struct command
static int monitor_call_audio(int argc, const char *const *argv, struct command_line_option *o, void *context){
struct monitor_context *c=context;
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
if (!call)
if (!call){
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", argv[1]);
else
vomp_received_audio(call, atoi(argv[2]), c->buffer, c->data_expected);
return 0;
}
int codec_type = atoi(argv[2]);
int time = argc>=4?atoi(argv[3]):-1;
int sequence = argc>=5?atoi(argv[4]):-1;
vomp_received_audio(call, codec_type, time, sequence, c->buffer, c->data_expected);
return 0;
}
@ -520,7 +527,7 @@ static int monitor_call_dtmf(int argc, const char *const *argv, struct command_l
of the majority of codec time units (70ms is the nominal
DTMF tone length for most systems). */
unsigned char code = digit <<4;
vomp_received_audio(call, VOMP_CODEC_DTMF, &code, 1);
vomp_received_audio(call, VOMP_CODEC_DTMF, -1, -1, &code, 1);
}
}
return 0;
@ -534,7 +541,7 @@ struct command_line_option monitor_options[]={
{monitor_call, {"call","<sid>","<local_did>","<remote_did>",NULL},0,""},
{monitor_call_ring, {"ringing","<token>",NULL},0,""},
{monitor_call_pickup, {"pickup","<token>",NULL},0,""},
{monitor_call_audio,{"audio","<token>","<type>","[<offset>]",NULL},0,""},
{monitor_call_audio,{"audio","<token>","<type>","[<time>]","[<sequence>]",NULL},0,""},
{monitor_call_hangup, {"hangup","<token>",NULL},0,""},
{monitor_call_dtmf, {"dtmf","<token>","<digits>",NULL},0,""},
{NULL},

@ -153,10 +153,8 @@ schedule(&_sched_##X); }
#undef SCHEDULE
while(1) {
/* Check for activitiy and respond to it */
fd_poll();
}
/* Check for activitiy and respond to it */
while(fd_poll());
return 0;
}

@ -36,6 +36,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define BPI_MASK 0x3ff
static struct broadcast bpilist[MAX_BPIS];
#define OA_CODE_SELF 0xff
#define OA_CODE_PREVIOUS 0xfe
// 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{
@ -50,9 +53,6 @@ struct tree_node{
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){
@ -85,12 +85,6 @@ struct subscriber *find_subscriber(const unsigned char *sid, int len, int create
ptr->subscribers[nibble]=ret;
bcopy(sid, ret->sid, SID_SIZE);
ret->abbreviate_len=pos;
// always send the full sid on first use
ret->send_full=1;
// always send my full sid when we hear about someone new
if (my_subscriber)
my_subscriber->send_full = 1;
}
return ptr->subscribers[nibble];
@ -175,18 +169,18 @@ int subscriber_is_reachable(struct subscriber *subscriber){
ret = REACHABLE_NONE;
// avoid infinite recursion...
else if (subscriber->next_hop->reachable!=REACHABLE_DIRECT &&
subscriber->next_hop->reachable!=REACHABLE_UNICAST)
else if (!(subscriber->next_hop->reachable & REACHABLE_DIRECT))
ret = REACHABLE_NONE;
else{
int r = subscriber_is_reachable(subscriber->next_hop);
if (r!=REACHABLE_DIRECT && r!= REACHABLE_UNICAST)
if (r&REACHABLE_ASSUMED)
ret = REACHABLE_NONE;
else if (!(r & REACHABLE_DIRECT))
ret = REACHABLE_NONE;
}
}
if (ret==REACHABLE_DIRECT ||
ret==REACHABLE_UNICAST){
if (ret & REACHABLE_DIRECT){
// make sure the interface is still up
if (!subscriber->interface)
ret=REACHABLE_NONE;
@ -194,22 +188,12 @@ int subscriber_is_reachable(struct subscriber *subscriber){
ret=REACHABLE_NONE;
}
// after all of that, should we use a default route?
if (ret==REACHABLE_NONE &&
directory_service &&
subscriber!=directory_service &&
subscriber_is_reachable(directory_service)!=REACHABLE_NONE){
ret = REACHABLE_DEFAULT_ROUTE;
}
return ret;
}
int set_reachable(struct subscriber *subscriber, int reachable){
if (subscriber->reachable==reachable)
return 0;
int old_value=subscriber->reachable;
subscriber->reachable=reachable;
// These log messages are for use in tests. Changing them may break test scripts.
@ -220,11 +204,10 @@ int set_reachable(struct subscriber *subscriber, int reachable){
break;
case REACHABLE_SELF:
break;
case REACHABLE_DIRECT:
DEBUGF("REACHABLE DIRECTLY sid=%s", alloca_tohex_sid(subscriber->sid));
break;
case REACHABLE_INDIRECT:
DEBUGF("REACHABLE INDIRECTLY sid=%s", alloca_tohex_sid(subscriber->sid));
DEBUGF("(via %s, %d)",subscriber->next_hop?alloca_tohex_sid(subscriber->next_hop->sid):"NOONE!"
,subscriber->next_hop?subscriber->next_hop->reachable:0);
break;
case REACHABLE_UNICAST:
DEBUGF("REACHABLE VIA UNICAST sid=%s", alloca_tohex_sid(subscriber->sid));
@ -232,18 +215,21 @@ int set_reachable(struct subscriber *subscriber, int reachable){
case REACHABLE_BROADCAST:
DEBUGF("REACHABLE VIA BROADCAST sid=%s", alloca_tohex_sid(subscriber->sid));
break;
case REACHABLE_UNICAST|REACHABLE_ASSUMED:
DEBUGF("ASSUMED REACHABLE VIA UNICAST sid=%s", alloca_tohex_sid(subscriber->sid));
break;
case REACHABLE_BROADCAST|REACHABLE_ASSUMED:
DEBUGF("ASSUMED REACHABLE VIA BROADCAST sid=%s", alloca_tohex_sid(subscriber->sid));
break;
}
}
/* Pre-emptively send a sas request */
if (!subscriber->sas_valid && reachable!=REACHABLE_SELF && reachable!=REACHABLE_NONE && reachable!=REACHABLE_BROADCAST)
if (!subscriber->sas_valid && reachable&REACHABLE)
keyring_send_sas_request(subscriber);
// Hacky layering violation... send our identity to a directory service
if (subscriber==directory_service &&
(old_value==REACHABLE_NONE||old_value==REACHABLE_BROADCAST) &&
(reachable!=REACHABLE_NONE&&reachable!=REACHABLE_BROADCAST)
)
if (subscriber==directory_service)
directory_registration();
return 0;
@ -251,7 +237,7 @@ int set_reachable(struct subscriber *subscriber, int reachable){
// mark the subscriber as reachable via reply unicast packet
int reachable_unicast(struct subscriber *subscriber, overlay_interface *interface, struct in_addr addr, int port){
if (subscriber->reachable!=REACHABLE_NONE && subscriber->reachable!=REACHABLE_UNICAST)
if (subscriber->reachable&REACHABLE)
return WHYF("Subscriber %s is already reachable", alloca_tohex_sid(subscriber->sid));
if (subscriber->node)
@ -266,37 +252,41 @@ int reachable_unicast(struct subscriber *subscriber, overlay_interface *interfac
return 0;
}
// load a unicast address from configuration, replace with database??
// load a unicast address from configuration
int load_subscriber_address(struct subscriber *subscriber){
if (subscriber_is_reachable(subscriber)&REACHABLE)
return 0;
char buff[80];
const char *sid_hex = alloca_tohex_sid(subscriber->sid);
snprintf(buff, sizeof(buff), "%s.interface", sid_hex);
const char *interface_name = confValueGet(buff, NULL);
// no unicast configuration? just return.
if (!interface_name)
return 1;
overlay_interface *interface=NULL;
snprintf(buff, sizeof(buff), "%s.address", sid_hex);
const char *address = confValueGet(buff, NULL);
// no address configuration? just return.
if (!address)
return 1;
snprintf(buff, sizeof(buff), "%s.port", sid_hex);
int port = confValueGetInt64Range(buff, PORT_DNA, 1, 65535);
overlay_interface *interface = overlay_interface_find_name(interface_name);
if (!interface){
WARNF("Interface %s is not UP", interface_name);
return -1;
snprintf(buff, sizeof(buff), "%s.interface", sid_hex);
const char *interface_name = confValueGet(buff, NULL);
if (interface_name){
interface = overlay_interface_find_name(interface_name);
// explicity defined interface isn't up? just return.
if (!interface)
return 1;
}
struct in_addr addr;
if (!inet_aton(address, &addr)){
struct sockaddr_in addr;
addr.sin_family=AF_INET;
if (!inet_aton(address, &addr.sin_addr)){
return WHYF("%s doesn't look like an IP address", address);
}
return reachable_unicast(subscriber, interface, addr, port);
snprintf(buff, sizeof(buff), "%s.port", sid_hex);
addr.sin_port = htons(confValueGetInt64Range(buff, PORT_DNA, 1, 65535));
return overlay_send_probe(subscriber, addr, interface);
}
// generate a new random broadcast address
@ -338,60 +328,41 @@ int overlay_broadcast_drop_check(struct broadcast *addr)
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;
return ob_append_bytes(b, broadcast->id, BROADCAST_LEN);
}
// append an appropriate abbreviation into the address
int overlay_address_append(struct overlay_buffer *b, struct subscriber *subscriber)
int overlay_address_append(struct decode_context *context, struct overlay_buffer *b, struct subscriber *subscriber)
{
if (subscriber==sender){
ob_append_byte(b, OA_CODE_SELF);
if (!subscriber)
return WHY("No address supplied");
if (context && subscriber==context->sender){
if (ob_append_byte(b, OA_CODE_SELF))
return -1;
}else if(subscriber==previous){
ob_append_byte(b, OA_CODE_PREVIOUS);
}else if(subscriber->send_full || subscriber->abbreviate_len >= 20){
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 if(context && subscriber==context->previous){
if (ob_append_byte(b, OA_CODE_PREVIOUS))
return -1;
}else{
ob_append_byte(b, OA_CODE_PREFIX11);
ob_append_bytes(b, subscriber->sid, 11);
int len=SID_SIZE;
if (subscriber->send_full){
subscriber->send_full=0;
}else{
len=(subscriber->abbreviate_len+2)/2;
if (subscriber->reachable==REACHABLE_SELF)
len++;
if (len>SID_SIZE)
len=SID_SIZE;
}
if (ob_append_byte(b, len))
return -1;
if (ob_append_bytes(b, subscriber->sid, len))
return -1;
}
previous = subscriber;
return 0;
}
int overlay_address_append_self(overlay_interface *interface, struct overlay_buffer *b){
static int ticks_per_full_address = -1;
if (ticks_per_full_address == -1) {
ticks_per_full_address = confValueGetInt64Range("mdp.selfannounce.ticks_per_full_address", 4LL, 1LL, 1000000LL);
INFOF("ticks_per_full_address = %d", ticks_per_full_address);
}
if (!my_subscriber)
return WHY("I don't know who I am yet");
if (++interface->ticks_since_sent_full_address > ticks_per_full_address){
interface->ticks_since_sent_full_address = 0;
my_subscriber->send_full=1;
}
if (overlay_address_append(b, my_subscriber))
return WHY("Could not append my sid");
if (context)
context->previous = subscriber;
return 0;
}
@ -410,15 +381,24 @@ static int add_explain_response(struct subscriber *subscriber, void *context){
// add the whole subscriber id to the payload, stop if we run out of space
DEBUGF("Adding full sid by way of explanation %s", alloca_tohex_sid(subscriber->sid));
if (ob_append_byte(response->please_explain->payload, SID_SIZE))
return 1;
if (ob_append_bytes(response->please_explain->payload, subscriber->sid, SID_SIZE))
return 1;
return 0;
}
int find_subscr_buffer(struct decode_context *context, struct overlay_buffer *b, int code, int len, int create, struct subscriber **subscriber){
static int find_subscr_buffer(struct decode_context *context, struct overlay_buffer *b, int len, struct subscriber **subscriber){
if (len<=0 || len>SID_SIZE){
dump_stack();
return WHY("Invalid abbreviation length");
}
unsigned char *id = ob_get_bytes_ptr(b, len);
if (!id)
if (!id){
dump_stack();
return WHY("Not enough space in buffer to parse address");
}
if (!subscriber){
WARN("Could not resolve address, no buffer supplied");
@ -426,7 +406,7 @@ int find_subscr_buffer(struct decode_context *context, struct overlay_buffer *b,
return 0;
}
*subscriber=find_subscriber(id, len, create);
*subscriber=find_subscriber(id, len, 1);
if (!*subscriber){
context->invalid_addresses=1;
@ -445,160 +425,104 @@ int find_subscr_buffer(struct decode_context *context, struct overlay_buffer *b,
walk_tree(&root, 0, id, len, id, len, add_explain_response, context);
INFOF("Asking for explanation of %s", alloca_tohex(id, len));
if (code>=0)
ob_append_byte(context->please_explain->payload, code);
ob_append_byte(context->please_explain->payload, len);
ob_append_bytes(context->please_explain->payload, id, len);
}else{
previous=*subscriber;
previous_broadcast=NULL;
context->previous=*subscriber;
}
return 0;
}
// returns 0 = success, -1 = fatal parsing error, 1 = unable to identify address
int overlay_address_parse(struct decode_context *context, struct overlay_buffer *b, struct broadcast *broadcast, struct subscriber **subscriber)
int overlay_broadcast_parse(struct overlay_buffer *b, struct broadcast *broadcast)
{
int code = ob_getbyte(b,b->position);
if (code<0)
return -1;
return ob_get_bytes(b, broadcast->id, BROADCAST_LEN);
}
// returns 0 = success, -1 = fatal parsing error, 1 = unable to identify address
int overlay_address_parse(struct decode_context *context, struct overlay_buffer *b, struct subscriber **subscriber)
{
int len = ob_get(b);
switch(code){
case OA_CODE_BROADCAST:
b->position++;
if (subscriber)
*subscriber=NULL;
if (!broadcast){
context->invalid_addresses=1;
}else{
ob_get_bytes(b, broadcast->id, BROADCAST_LEN);
}
previous_broadcast=broadcast;
previous=NULL;
return 0;
switch(len){
case OA_CODE_SELF:
b->position++;
if (!subscriber){
WARN("Could not resolve address, no buffer supplied");
context->invalid_addresses=1;
}else if (!sender){
if (!context->sender){
INFO("Could not resolve address, sender has not been set");
context->invalid_addresses=1;
}else{
*subscriber=sender;
previous=sender;
*subscriber=context->sender;
context->previous=context->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 (!subscriber){
WARN("Could not resolve address, no buffer supplied");
context->invalid_addresses=1;
}else if (previous){
*subscriber=previous;
}else if (previous_broadcast){
*subscriber=NULL;
// not an error if broadcast is NULL, as the previous OA_CODE_BROADCAST address must have been valid.
if (broadcast)
bcopy(previous_broadcast->id, broadcast->id, BROADCAST_LEN);
}else{
if (!context->previous){
INFO("Unable to decode previous address");
context->invalid_addresses=1;
}else{
*subscriber=context->previous;
}
return 0;
case OA_CODE_PREFIX3:
b->position++;
return find_subscr_buffer(context, b, code, 3,0,subscriber);
case OA_CODE_PREFIX7:
b->position++;
return find_subscr_buffer(context, b, code, 7,0,subscriber);
case OA_CODE_PREFIX11:
b->position++;
return find_subscr_buffer(context, b, code, 11,0,subscriber);
}
// we must assume that we wont be able to understand the rest of the packet
if (code<=0x0f || context->abbreviations_only)
return WHYF("Unsupported abbreviation code %d", code);
return find_subscr_buffer(context, b, -1, SID_SIZE,1,subscriber);
return find_subscr_buffer(context, b, len, subscriber);
}
// once we've finished parsing a packet, complete and send a please explain if required.
int send_please_explain(struct decode_context *context, struct subscriber *source, struct subscriber *destination){
if (!context->please_explain)
return 0;
context->please_explain->type = OF_TYPE_PLEASEEXPLAIN;
IN();
struct overlay_frame *frame=context->please_explain;
if (!frame)
RETURN(0);
frame->type = OF_TYPE_PLEASEEXPLAIN;
if (source)
context->please_explain->source = source;
frame->source = source;
else
context->please_explain->source = my_subscriber;
frame->source = my_subscriber;
if (destination){
context->please_explain->destination = destination;
context->please_explain->ttl=64;
frame->source->send_full=1;
frame->destination = destination;
if (destination && (destination->reachable & REACHABLE)){
frame->ttl=64;
}else{
context->please_explain->ttl=2;// how will this work with olsr??
overlay_broadcast_generate_address(&context->please_explain->broadcast_id);
frame->ttl=1;// how will this work with olsr??
overlay_broadcast_generate_address(&frame->broadcast_id);
if (context->interface){
frame->destination_resolved=1;
frame->next_hop = destination;
frame->recvaddr=context->addr;
frame->interface=context->interface;
}
}
DEBUGF("Queued please explain");
context->please_explain->queue=OQ_MESH_MANAGEMENT;
if (!overlay_payload_enqueue(context->please_explain))
return 0;
op_free(context->please_explain);
return 0;
frame->queue=OQ_MESH_MANAGEMENT;
if (!overlay_payload_enqueue(frame))
RETURN(0);
op_free(frame);
RETURN(-1);
}
// process an incoming request for explanation of subscriber abbreviations
int process_explain(struct overlay_frame *frame){
struct overlay_buffer *b=frame->payload;
struct decode_context context={
.please_explain=NULL,
};
struct decode_context context;
bzero(&context, sizeof context);
while(b->position < b->sizeLimit){
int code = ob_getbyte(b,b->position);
int len=SID_SIZE;
switch(code){
case OA_CODE_PREFIX3:
len=3;
b->position++;
break;
case OA_CODE_PREFIX7:
len=7;
b->position++;
break;
case OA_CODE_PREFIX11:
len=11;
b->position++;
break;
}
if (len==SID_SIZE && code<=0x0f)
return WHYF("Unsupported abbreviation code %d", code);
while(ob_remaining(b)>0){
int len = ob_get(b);
if (len<=0 || len>SID_SIZE)
return WHY("Badly formatted explain message");
unsigned char *sid = ob_get_bytes_ptr(b, len);
if (!sid)
return WHY("Ran past end of buffer");
if (len==SID_SIZE){
// This message is also used to inform people of previously unknown subscribers
// make sure we know this one
find_subscriber(sid,len,1);
INFOF("Now know about %s", alloca_tohex(sid, len));
}else{
// reply to the sender with all subscribers that match this abbreviation
INFOF("Sending responses for %s", alloca_tohex(sid, len));
@ -609,13 +533,3 @@ int process_explain(struct overlay_frame *frame){
send_please_explain(&context, frame->destination, frame->source);
return 0;
}
void overlay_address_clear(void){
sender=NULL;
previous=NULL;
previous_broadcast=NULL;
}
void overlay_address_set_sender(struct subscriber *subscriber){
sender = subscriber;
}

@ -25,43 +25,22 @@
// not reachable
#define REACHABLE_NONE 0
// immediate neighbour
#define REACHABLE_DIRECT 1
// reachable via unicast packet
#define REACHABLE_UNICAST 2
// packets must be routed
#define REACHABLE_INDIRECT 3
// packets can probably be flooded to this peer with ttl=2
// (temporary state for new peers before path discovery has finished)
#define REACHABLE_BROADCAST 4
// this subscriber is in our keystore
#define REACHABLE_SELF 5
#define REACHABLE_SELF (1<<0)
#define REACHABLE_DEFAULT_ROUTE 6
// immediate neighbour broadcast packet
#define REACHABLE_BROADCAST (1<<1)
/* 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
// reachable directly via unicast packet
#define REACHABLE_UNICAST (1<<2)
// packets must be routed via next_hop
#define REACHABLE_INDIRECT (1<<3)
#define REACHABLE_ASSUMED (1<<4)
#define REACHABLE_DIRECT (REACHABLE_BROADCAST|REACHABLE_UNICAST)
#define REACHABLE (REACHABLE_DIRECT|REACHABLE_INDIRECT)
#define BROADCAST_LEN 8
@ -75,7 +54,8 @@ struct subscriber{
// should we send the full address once?
int send_full;
// sequence number for this unicast or broadcast destination
int sequence;
// overlay routing information
struct overlay_node *node;
@ -88,8 +68,11 @@ struct subscriber{
// if direct, or unicast, where do we send packets?
struct overlay_interface *interface;
// if reachable==REACHABLE_UNICAST send packets to this address, else use the interface broadcast address
// if reachable&REACHABLE_UNICAST send packets to this address, else use the interface broadcast address
struct sockaddr_in address;
time_ms_t last_probe;
time_ms_t last_rx;
time_ms_t last_tx;
// public signing key details for remote peers
unsigned char sas_public[SAS_SIZE];
@ -105,9 +88,12 @@ struct broadcast{
};
struct decode_context{
int abbreviations_only;
struct overlay_interface *interface;
struct sockaddr_in addr;
int invalid_addresses;
struct overlay_frame *please_explain;
struct subscriber *sender;
struct subscriber *previous;
};
extern struct subscriber *my_subscriber;
@ -125,14 +111,10 @@ 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_append_self(overlay_interface *interface, struct overlay_buffer *b);
int overlay_address_append(struct decode_context *context, struct overlay_buffer *b, struct subscriber *subscriber);
int overlay_address_parse(struct decode_context *context, struct overlay_buffer *b, struct broadcast *broadcast, struct subscriber **subscriber);
int overlay_broadcast_parse(struct overlay_buffer *b, struct broadcast *broadcast);
int overlay_address_parse(struct decode_context *context, struct overlay_buffer *b, struct subscriber **subscriber);
int send_please_explain(struct decode_context *context, struct subscriber *source, struct subscriber *destination);
void overlay_address_clear(void);
void overlay_address_set_sender(struct subscriber *subscriber);
#endif

@ -67,11 +67,12 @@ int add_advertisement(struct subscriber *subscriber, void *context){
if (subscriber->node){
overlay_node *n=subscriber->node;
if (n->best_link_score>0 && n->observations[n->best_observation].gateways_en_route < 64){
if ((subscriber->reachable&REACHABLE) && (!(subscriber->reachable&REACHABLE_ASSUMED))
&& n->best_link_score>0 && n->observations[n->best_observation].gateways_en_route < 64){
// never send the full sid in an advertisement
subscriber->send_full=0;
if (overlay_address_append(e,subscriber) ||
if (overlay_address_append(NULL,e,subscriber) ||
ob_append_byte(e,n->best_link_score -1) ||
ob_append_byte(e,n->observations[n->best_observation].gateways_en_route +1)){
@ -80,7 +81,6 @@ int add_advertisement(struct subscriber *subscriber, void *context){
ob_rewind(e);
return 1;
}
ob_checkpoint(e);
}
}
@ -88,7 +88,8 @@ int add_advertisement(struct subscriber *subscriber, void *context){
return 0;
}
int overlay_route_add_advertisements(overlay_interface *interface, struct overlay_buffer *e)
int overlay_route_add_advertisements(struct decode_context *context, overlay_interface *interface,
struct overlay_buffer *e)
{
/* Construct a route advertisement frame and append it to e.
@ -121,22 +122,11 @@ int overlay_route_add_advertisements(overlay_interface *interface, struct overla
ob_checkpoint(e);
if (ob_append_byte(e,OF_TYPE_NODEANNOUNCE))
return WHY("could not add node advertisement header");
ob_append_byte(e,1); /* TTL */
// assume we might fill the packet
ob_append_rfs(e, e->sizeLimit - e->position);
/* Add address fields */
struct broadcast broadcast;
overlay_broadcast_generate_address(&broadcast);
overlay_broadcast_append(e,&broadcast);
ob_append_byte(e,OA_CODE_PREVIOUS);
overlay_address_append_self(interface,e);
overlay_address_set_sender(my_subscriber);
if (overlay_frame_build_header(context, e,
0, OF_TYPE_NODEANNOUNCE, 0, 1,
NULL, NULL,
NULL, my_subscriber))
return -1;
// TODO high priority advertisements first....
/*
@ -154,22 +144,21 @@ int overlay_route_add_advertisements(overlay_interface *interface, struct overla
struct subscriber *start = next_advertisement;
next_advertisement=NULL;
int start_pos = e->position;
int start_pos = ob_position(e);
// append announcements starting from the last node we couldn't advertise last time
enum_subscribers(start, add_advertisement, e);
// if we didn't start at the beginning and still have space, start again from the beginning
if (start && !next_advertisement && e->sizeLimit - e->position > 0){
if (start && !next_advertisement && ob_limit(e) - ob_position(e) > 0){
enum_subscribers(NULL, add_advertisement, e);
}
if (e->position == start_pos){
if (ob_position(e) == start_pos){
// no advertisements? don't bother to send the payload at all.
ob_rewind(e);
overlay_address_clear();
}else
ob_patch_rfs(e,COMPUTE_RFS_LENGTH);
ob_patch_rfs(e);
return 0;
}
@ -187,22 +176,26 @@ int overlay_route_add_advertisements(overlay_interface *interface, struct overla
int overlay_route_saw_advertisements(int i, struct overlay_frame *f, struct decode_context *context, time_ms_t now)
{
IN();
context->abbreviations_only=1;
struct subscriber *previous=context->previous;
// minimum record length is (address code, 3 byte sid, score, gateways)
while(f->payload->position +6 <= f->payload->sizeLimit)
while(ob_remaining(f->payload)>0)
{
struct subscriber *subscriber;
context->invalid_addresses=0;
if (overlay_address_parse(context, f->payload, NULL, &subscriber))
if (overlay_address_parse(context, f->payload, &subscriber)){
WHY("Failed to parse address");
break;
}
int score=ob_get(f->payload);
int gateways_en_route=ob_get(f->payload);
// stop if hit end of payload
if (score<0 || gateways_en_route<0)
if (score<0 || gateways_en_route<0){
WHY("Unexpected end of payload");
break;
}
// skip if we can't parse the subscriber id
if (context->invalid_addresses || !subscriber)
@ -216,7 +209,7 @@ int overlay_route_saw_advertisements(int i, struct overlay_frame *f, struct deco
}
/* File it */
overlay_route_record_link(now, subscriber->sid, f->source->sid,
overlay_route_record_link(now, subscriber, f->source,
i,
/* time range that this advertisement covers.
XXX - Make it up for now. */
@ -224,6 +217,7 @@ int overlay_route_saw_advertisements(int i, struct overlay_frame *f, struct deco
score,gateways_en_route);
}
context->abbreviations_only=0;
// restore the previous subscriber id for parsing the next header
context->previous=previous;
RETURN(0);
}

@ -47,7 +47,7 @@ struct overlay_buffer *ob_static(unsigned char *bytes, int size){
if (!ret) return NULL;
ret->bytes = bytes;
ret->allocSize = size;
ret->allocated = 0;
ret->allocated = NULL;
ob_unlimitsize(ret);
return ret;
@ -67,7 +67,7 @@ struct overlay_buffer *ob_slice(struct overlay_buffer *b, int offset, int length
return NULL;
ret->bytes = b->bytes+offset;
ret->allocSize = length;
ret->allocated = 0;
ret->allocated = NULL;
ob_unlimitsize(ret);
return ret;
@ -95,8 +95,10 @@ struct overlay_buffer *ob_dup(struct overlay_buffer *b){
int ob_free(struct overlay_buffer *b)
{
if (!b) return WHY("Asked to free NULL");
if (b->bytes && b->allocated) free(b->bytes);
if (b->bytes && b->allocated) free(b->allocated);
// we're about to free this anyway, why are we clearing it?
b->bytes=NULL;
b->allocated=NULL;
b->allocSize=0;
b->sizeLimit=0;
free(b);
@ -164,7 +166,7 @@ int ob_makespace(struct overlay_buffer *b,int bytes)
}
if (0) DEBUGF("realloc(b->bytes=%p,newSize=%d)", b->bytes,newSize);
/* XXX OSX realloc() seems to be able to corrupt things if the heap is not happy when calling realloc(), making debugging memory corruption much harder.
So will do a three-stage malloc,bcopy,free to see if we can tease the bug out that way. */
So will do a three-stage malloc,bcopy,free to see if we can tease bugs out that way. */
/*
unsigned char *r=realloc(b->bytes,newSize);
if (!r) return WHY("realloc() failed");
@ -192,9 +194,9 @@ int ob_makespace(struct overlay_buffer *b,int bytes)
unsigned char *new=malloc(newSize);
#endif
bcopy(b->bytes,new,b->position);
if (b->bytes) free(b->bytes);
if (b->allocated) free(b->allocated);
b->bytes=new;
b->allocated=1;
b->allocated=new;
b->allocSize=newSize;
return 0;
}
@ -253,26 +255,24 @@ int ob_append_ui32(struct overlay_buffer *b, uint32_t v)
return 0;
}
int ob_append_packed_ui32(struct overlay_buffer *b, uint32_t v)
{
do{
if (ob_append_byte(b, (v&0x7f) | (v>0x7f?0x80:0)))
return -1;
v = v>>7;
}while(v!=0);
return 0;
}
int ob_append_rfs(struct overlay_buffer *b,int l)
{
/* Encode the specified length and append it to the buffer */
if (l<0||l>0xffff) return -1;
/* First work out how long the field needs to be, then write dummy bytes
and use ob_patch_rfs to set the value. That way we have only one
lot of code that does the encoding. */
b->var_length_offset=b->position;
b->var_length_bytes=rfs_length(l);
unsigned char c[3]={0,0,0};
if (ob_append_bytes(b,c,b->var_length_bytes)) {
b->var_length_offset=0;
return -1;
}
return ob_patch_rfs(b,l);
return ob_append_ui16(b,l);
}
@ -341,6 +341,21 @@ uint16_t ob_get_ui16(struct overlay_buffer *b)
return ret;
}
uint32_t ob_get_packed_ui32(struct overlay_buffer *b)
{
uint32_t ret=0;
int shift=0;
int byte;
do{
byte = ob_get(b);
if (byte<0)
return WHY("Failed to unpack integer");
ret |= (byte&0x7f)<<shift;
shift+=7;
}while(byte & 0x80);
return ret;
}
int ob_get(struct overlay_buffer *b){
if (test_offset(b, b->position, 1))
return -1;
@ -348,96 +363,32 @@ int ob_get(struct overlay_buffer *b){
return b->bytes[b->position++];
}
int rfs_length(int l)
int ob_set_ui16(struct overlay_buffer *b, int offset, uint16_t v)
{
if (l<0) return -1;
if (l<250) return 1;
else if (l<(255+250+(256*4))) return 2;
else if (l<=0xffff) return 3;
else return -1;
}
int rfs_encode(int l, unsigned char *b)
{
if (l<250) { b[0]=l; }
else if (l<(255+250+(256*4))) {
l-=250;
int page=(l>>8);
l&=0xff;
b[0]=RFS_PLUS250+page;
b[1]=l;
} else {
b[0]=RFS_3BYTE;
b[1]=l>>8;
b[2]=l&0xff;
}
return 0;
}
int rfs_decode(unsigned char *b,int *ofs)
{
int rfs=b[*ofs];
switch(rfs) {
case RFS_PLUS250: case RFS_PLUS456: case RFS_PLUS762: case RFS_PLUS1018: case RFS_PLUS1274:
rfs=250+256*(rfs-RFS_PLUS250)+b[++(*ofs)];
break;
case RFS_3BYTE: rfs=(b[(*ofs)+1]<<8)+b[(*ofs)+2]; (*ofs)+=2;
default: /* Length is natural value of field, so nothing to do */
break;
}
(*ofs)++;
return rfs;
}
// move the data at offset, by shift bytes
int ob_indel_space(struct overlay_buffer *b,int offset,int shift)
{
if (offset>=b->position) return -1;
if (shift>0 && ob_makespace(b, shift)) return -1;
bcopy(&b->bytes[offset],&b->bytes[offset+shift],b->position-offset);
b->position+=shift;
return 0;
}
int ob_patch_rfs(struct overlay_buffer *b,int l)
{
if (l==COMPUTE_RFS_LENGTH){
// assume the payload has been written, we can now calculate the actual length
l = b->position - (b->var_length_offset + b->var_length_bytes);
}
if (l<0||l>0xffff) return -1;
/* Adjust size of field */
int new_size=rfs_length(l);
int shift=new_size - b->var_length_bytes;
if (shift) {
if (debug&DEBUG_PACKETCONSTRUCTION) {
DEBUGF("Patching RFS for rfs_size=%d (was %d), so indel %d btyes",
new_size,b->var_length_bytes,shift);
dump("before indel",
&b->bytes[b->var_length_offset],
b->position-b->var_length_offset);
}
if (ob_indel_space(b, b->var_length_offset + b->var_length_bytes, shift)) return -1;
if (debug&DEBUG_PACKETCONSTRUCTION) {
dump("after indel",
&b->bytes[b->var_length_offset],
b->position-b->var_length_offset);
}
}
if (test_offset(b, offset, 2))
return -1;
if (rfs_encode(l,&b->bytes[b->var_length_offset])) return -1;
if (debug&DEBUG_PACKETCONSTRUCTION) {
dump("after patch",
&b->bytes[b->var_length_offset],
b->position-b->var_length_offset);
}
b->bytes[offset] = (v >> 8) & 0xFF;
b->bytes[offset+1] = v & 0xFF;
return 0;
}
int ob_patch_rfs(struct overlay_buffer *b){
return ob_set_ui16(b,b->var_length_offset,b->position - (b->var_length_offset + 2));
}
int ob_position(struct overlay_buffer *b){
return b->position;
}
int ob_limit(struct overlay_buffer *b){
return b->sizeLimit;
}
int ob_remaining(struct overlay_buffer *b){
return b->sizeLimit - b->position;
}
unsigned char *ob_ptr(struct overlay_buffer *b){
return b->bytes;
}
int asprintable(int c)
@ -449,8 +400,8 @@ int asprintable(int c)
int ob_dump(struct overlay_buffer *b,char *desc)
{
DEBUGF("overlay_buffer '%s' at %p : length=%d", desc, b, b->position);
dump(NULL, b->bytes, b->position);
DEBUGF("overlay_buffer '%s' at %p : position=%d, size=%d", desc, b, b->position, b->sizeLimit);
dump(NULL, b->bytes, b->sizeLimit>b->position?b->sizeLimit:b->position);
return 0;
}

@ -36,11 +36,10 @@ struct overlay_buffer {
int allocSize;
// is this an allocated buffer? can it be resized? Should it be freed?
int allocated;
unsigned char * allocated;
// length position and size for later patching
// length position for later patching
int var_length_offset;
int var_length_bytes;
};
struct overlay_buffer *ob_new(void);
@ -58,7 +57,8 @@ int ob_append_bytes(struct overlay_buffer *b,unsigned char *bytes,int count);
unsigned char *ob_append_space(struct overlay_buffer *b,int count);
int ob_append_ui16(struct overlay_buffer *b, uint16_t v);
int ob_append_ui32(struct overlay_buffer *b, uint32_t v);
int ob_patch_rfs(struct overlay_buffer *b,int l);
int ob_append_packed_ui32(struct overlay_buffer *b, uint32_t v);
int ob_patch_rfs(struct overlay_buffer *b);
int ob_append_rfs(struct overlay_buffer *b,int l);
// get one byte, -ve number indicates failure
int ob_getbyte(struct overlay_buffer *b,int ofs);
@ -69,6 +69,13 @@ unsigned char * ob_get_bytes_ptr(struct overlay_buffer *b, int len);
uint32_t ob_get_ui32(struct overlay_buffer *b);
uint16_t ob_get_ui16(struct overlay_buffer *b);
int ob_dump(struct overlay_buffer *b,char *desc);
int ob_set_ui16(struct overlay_buffer *b, int offset, uint16_t v);
uint32_t ob_get_packed_ui32(struct overlay_buffer *b);
// information routines
int ob_position(struct overlay_buffer *b);
int ob_limit(struct overlay_buffer *b);
int ob_remaining(struct overlay_buffer *b);
unsigned char* ob_ptr(struct overlay_buffer *b);
#endif

@ -265,15 +265,21 @@ error:
overlay_interface * overlay_interface_find(struct in_addr addr){
int i;
overlay_interface *ret = NULL;
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state!=INTERFACE_STATE_UP)
continue;
if ((overlay_interfaces[i].netmask.s_addr & addr.s_addr) == (overlay_interfaces[i].netmask.s_addr & overlay_interfaces[i].address.sin_addr.s_addr)){
return &overlay_interfaces[i];
}
// check if this is a default interface
if (overlay_interfaces[i].default_route)
ret=&overlay_interfaces[i];
}
return NULL;
return ret;
}
overlay_interface * overlay_interface_find_name(const char *name){
@ -331,7 +337,8 @@ overlay_interface_read_any(struct sched_ent *alarm){
DEBUGF("Received %d bytes from %s on interface %s (ANY)",plen,
inet_ntoa(src),
interface->name);
if (packetOk(interface,packet,plen,NULL,recvttl,&src_addr,addrlen,1)) {
if (packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen)) {
WHY("Malformed packet");
}
}
@ -427,9 +434,6 @@ overlay_interface_init_socket(int interface_index)
INFOF("Interface %s addr %s, is up",interface->name, inet_ntoa(interface->broadcast_address.sin_addr));
// mark our sid to be sent in full
if (my_subscriber)
my_subscriber->send_full = 1;
directory_registration();
return 0;
@ -480,6 +484,9 @@ overlay_interface_init(char *name, struct in_addr src_addr, struct in_addr netma
char option_name[64];
snprintf(option_name, sizeof(option_name), "mdp.%s.tick_ms", (*name=='>'?name+1:name));
interface->tick_ms = confValueGetInt64Range(option_name, interface->tick_ms, 1LL, 3600000LL);
snprintf(option_name, sizeof(option_name), "interface.%s.default_route", (*name=='>'?name+1:name));
interface->default_route=confValueGetBoolean(option_name,0);
}
// disable announcements and other broadcasts if tick_ms=0.
@ -505,6 +512,16 @@ overlay_interface_init(char *name, struct in_addr src_addr, struct in_addr netma
return WHYF("could not open dummy interface file %s for append", dummyfile);
}
interface->address.sin_family=AF_INET;
interface->address.sin_port = 0;
interface->address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
interface->netmask.s_addr=0xFFFFFF00;
interface->broadcast_address.sin_family=AF_INET;
interface->broadcast_address.sin_port = 0;
interface->broadcast_address.sin_addr.s_addr = interface->address.sin_addr.s_addr | ~interface->netmask.s_addr;
/* Seek to end of file as initial reading point */
interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END);
/* XXX later add pretend location information so that we can decide which "packets" to receive
@ -521,10 +538,6 @@ overlay_interface_init(char *name, struct in_addr src_addr, struct in_addr netma
interface->state=INTERFACE_STATE_UP;
INFOF("Dummy interface %s is up",interface->name);
// mark our sid to be sent in full
if (my_subscriber)
my_subscriber->send_full = 1;
directory_registration();
} else {
@ -593,7 +606,7 @@ static void overlay_interface_poll(struct sched_ent *alarm)
inet_ntoa(src),
interface->name);
}
if (packetOk(interface,packet,plen,NULL,recvttl,&src_addr,addrlen,1)) {
if (packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen)) {
WHY("Malformed packet");
// Do we really want to attempt to parse it again?
//DEBUG_packet_visualise("Malformed packet", packet,plen);
@ -614,9 +627,12 @@ void overlay_dummy_poll(struct sched_ent *alarm)
*/
unsigned char packet[2048];
int plen=0;
struct sockaddr src_addr;
struct sockaddr_in src_addr={
.sin_family = AF_INET,
.sin_port = 0,
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
};
size_t addrlen = sizeof(src_addr);
unsigned char transaction_id[8];
time_ms_t now = gettime_ms();
/* Read from dummy interface file */
@ -651,17 +667,9 @@ void overlay_dummy_poll(struct sched_ent *alarm)
plen = -1;
if (debug&DEBUG_PACKETRX)
DEBUG_packet_visualise("Read from dummy interface", &packet[128], plen);
bzero(&transaction_id[0],8);
bzero(&src_addr,sizeof(src_addr));
if (plen >= 4) {
if (packet[0] == 0x01 && packet[1] == 0 && packet[2] == 0 && packet[3] == 0) {
if (packetOk(interface,&packet[128],plen,transaction_id, -1 /* fake TTL */, &src_addr,addrlen,1) == -1)
WARN("Unsupported packet from dummy interface");
} else {
WARNF("Unsupported packet version from dummy interface: %02x %02x %02x %02x", packet[0], packet[1], packet[2], packet[3]);
}
} else {
WARNF("Invalid packet from dummy interface: plen=%lld", (long long) plen);
if (packetOkOverlay(interface, &packet[128], plen, -1, (struct sockaddr*)&src_addr, addrlen)) {
WARN("Unsupported packet from dummy interface");
}
}
else

@ -158,7 +158,7 @@ int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
{
int replylen;
if (!recvaddr) return 0;
if (!recvaddr) return WHY("No reply address");
replylen=overlay_mdp_relevant_bytes(mdpreply);
if (replylen<0) return WHY("Invalid MDP frame (could not compute length)");
@ -260,77 +260,105 @@ int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, in
return 0;
}
static int overlay_mdp_decode_header(struct overlay_buffer *buff, overlay_mdp_frame *mdp)
{
/* extract MDP port numbers */
int port = ob_get_packed_ui32(buff);
int same = port&1;
port >>=1;
mdp->in.dst.port = port;
if (!same){
port = ob_get_packed_ui32(buff);
}
mdp->in.src.port = port;
int len=ob_remaining(buff);
if (len<0)
return WHY("MDP payload is too short");
mdp->in.payload_length=len;
return ob_get_bytes(buff, &mdp->in.payload[0], len);
}
int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
{
IN();
int len=f->payload->sizeLimit - f->payload->position;
unsigned char *b = &f->payload->bytes[f->payload->position];
unsigned char plain_block[len+16];
/* Indicate MDP message type */
mdp->packetTypeAndFlags=MDP_TX;
switch(f->modifiers&OF_CRYPTO_BITS) {
switch(f->modifiers&(OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED)) {
case 0:
/* nothing to do, b already points to the plain text */
mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN;
break;
RETURN(overlay_mdp_decode_header(f->payload, mdp));
case OF_CRYPTO_CIPHERED:
RETURN(WHY("decryption not implemented"));
case OF_CRYPTO_SIGNED:
if (crypto_verify_message(f->source, b, &len))
RETURN(-1);
{
int len = ob_remaining(f->payload);
if (crypto_verify_message(f->source, ob_ptr(f->payload), &len))
RETURN(-1);
mdp->packetTypeAndFlags|=MDP_NOCRYPT;
break;
mdp->packetTypeAndFlags|=MDP_NOCRYPT;
ob_limitsize(f->payload, len + ob_position(f->payload));
RETURN(overlay_mdp_decode_header(f->payload, mdp));
}
case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED:
{
if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(f->destination->sid));
unsigned char *k=keyring_get_nm_bytes(f->destination->sid, f->source->sid);
unsigned char *nonce=&f->payload->bytes[f->payload->position];
int nm=crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES;
int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
int cz=crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES;
unsigned char *k=keyring_get_nm_bytes(f->destination->sid, f->source->sid);
if (!k)
RETURN(WHY("I don't have the private key required to decrypt that"));
bzero(&plain_block[0],crypto_box_curve25519xsalsa20poly1305_ZEROBYTES-16);
int cipher_len=f->payload->sizeLimit - f->payload->position - nb;
bcopy(&f->payload->bytes[nb + f->payload->position],&plain_block[16],cipher_len);
if (0){
dump("frame",&f->payload->bytes[f->payload->position],
ob_remaining(f->payload));
}
unsigned char *nonce=ob_get_bytes_ptr(f->payload, nb);
int cipher_len=ob_remaining(f->payload);
unsigned char *cipher_text=ob_get_bytes_ptr(f->payload, cipher_len);
unsigned char plain_block[cipher_len+cz];
bzero(&plain_block[0],cz);
bcopy(cipher_text,&plain_block[cz],cipher_len);
if (0) {
dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES);
dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
dump("cipher block",&plain_block[16],cipher_len);
dump("nm bytes",k,nm);
dump("nonce",nonce,nb);
dump("cipher block",plain_block,sizeof(plain_block));
}
cipher_len+=cz;
if (crypto_box_curve25519xsalsa20poly1305_open_afternm
(plain_block,plain_block,cipher_len+16,nonce,k)) {
RETURN(WHYF("crypto_box_open_afternm() failed (forged or corrupted packet of %d bytes)",cipher_len+16));
(plain_block,plain_block,cipher_len,nonce,k)) {
RETURN(WHYF("crypto_box_open_afternm() failed (from %s, to %s, len %d)",
alloca_tohex_sid(f->source->sid), alloca_tohex_sid(f->destination->sid), cipher_len));
}
if (0) dump("plain block",&plain_block[zb],cipher_len-16);
b=&plain_block[zb];
len=cipher_len-16;
break;
if (0) dump("plain block",plain_block,sizeof(plain_block));
cipher_len -= zb;
struct overlay_buffer *plaintext = ob_static(&plain_block[zb], cipher_len);
ob_limitsize(plaintext,cipher_len);
int ret=overlay_mdp_decode_header(plaintext, mdp);
ob_free(plaintext);
RETURN(ret);
}
}
if (!b)
RETURN(WHY("Failed to decode mdp payload"));
int version=(b[0]<<8)+b[1];
if (version!=0x0101) RETURN(WHY("Saw unsupported MDP frame version"));
/* extract MDP port numbers */
mdp->in.src.port=(b[2]<<24)+(b[3]<<16)+(b[4]<<8)+b[5];
mdp->in.dst.port=(b[6]<<24)+(b[7]<<16)+(b[8]<<8)+b[9];
if (0) DEBUGF("RX mdp dst.port=%d, src.port=%d", mdp->in.dst.port, mdp->in.src.port);
mdp->in.payload_length=len-10;
bcopy(&b[10],&mdp->in.payload[0],mdp->in.payload_length);
RETURN(0);
RETURN(WHY("Failed to decode mdp payload"));
}
int overlay_saw_mdp_containing_frame(struct overlay_frame *f, time_ms_t now)
@ -498,6 +526,7 @@ int overlay_mdp_check_binding(struct subscriber *subscriber, int port, int userG
case MDP_PORT_DNALOOKUP:
case MDP_PORT_RHIZOME_RESPONSE:
case MDP_PORT_RHIZOME_REQUEST:
case MDP_PORT_PROBE:
return 0;
}
}
@ -510,6 +539,20 @@ int overlay_mdp_check_binding(struct subscriber *subscriber, int port, int userG
);
}
int overlay_mdp_encode_ports(struct overlay_buffer *plaintext, int dst_port, int src_port){
int port=dst_port << 1;
if (dst_port==src_port)
port |= 1;
if (ob_append_packed_ui32(plaintext, port))
return -1;
if (dst_port!=src_port){
if (ob_append_packed_ui32(plaintext, src_port))
return -1;
}
return 0;
}
/* Construct MDP packet frame from overlay_mdp_frame structure
(need to add return address from bindings list, and copy
payload etc).
@ -606,10 +649,18 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
else frame->type=OF_TYPE_DATA;
frame->prev=NULL;
frame->next=NULL;
frame->payload=ob_new();
struct overlay_buffer *plaintext=ob_new();
if (overlay_mdp_encode_ports(plaintext, mdp->out.dst.port, mdp->out.src.port)){
ob_free(plaintext);
RETURN (-1);
}
if (ob_append_bytes(plaintext, mdp->out.payload, mdp->out.payload_length)){
ob_free(plaintext);
RETURN(-1);
}
int fe=0;
/* 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
@ -617,44 +668,38 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) {
case 0: /* crypted and signed (using CryptoBox authcryption primitive) */
frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
/* Prepare payload */
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];
if (urandombytes(nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)) {
int nm=crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES;
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
int cz=crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES;
/* generate plain message with zero bytes and get ready to cipher it */
int cipher_len=ob_position(plaintext);
// TODO, add support for leading zero's in overlay_buffer's, then we don't need to copy the plain text again.
unsigned char plain[zb+cipher_len];
/* zero bytes */
bzero(&plain[0],zb);
bcopy(ob_ptr(plaintext),&plain[zb],cipher_len);
cipher_len+=zb;
ob_free(plaintext);
frame->payload = ob_new();
ob_makespace(frame->payload, nb+cipher_len);
unsigned char *nonce = ob_append_space(frame->payload, nb);
if (!nonce)
RETURN(-1);
if (urandombytes(nonce,nb)) {
op_free(frame);
RETURN(WHY("urandombytes() failed to generate nonce"));
}
fe|= ob_append_bytes(frame->payload,nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
/* generate plain message with zero bytes and get ready to cipher it */
unsigned char plain[crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
+10+mdp->out.payload_length];
/* zero bytes */
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
bzero(&plain[0],zb);
/* MDP version 1 */
plain[zb+0]=0x01;
plain[zb+1]=0x01;
/* Ports */
plain[zb+2]=(mdp->out.src.port>>24)&0xff;
plain[zb+3]=(mdp->out.src.port>>16)&0xff;
plain[zb+4]=(mdp->out.src.port>>8)&0xff;
plain[zb+5]=(mdp->out.src.port>>0)&0xff;
plain[zb+6]=(mdp->out.dst.port>>24)&0xff;
plain[zb+7]=(mdp->out.dst.port>>16)&0xff;
plain[zb+8]=(mdp->out.dst.port>>8)&0xff;
plain[zb+9]=(mdp->out.dst.port>>0)&0xff;
/* payload */
bcopy(&mdp->out.payload,&plain[zb+10],mdp->out.payload_length);
int cipher_len=zb+10+mdp->out.payload_length;
// reserve the high bit of the nonce as a flag for transmitting a shorter nonce.
nonce[0]&=0x7f;
/* 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. */
@ -664,9 +709,8 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
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)){
if ((!cipher_text)){
op_free(frame);
RETURN(WHY("could not make space for ciphered text"));
}
@ -676,17 +720,20 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
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);
frame->payload->position-=16;
if (0) {
DEBUG("authcrypted mdp frame");
dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES);
dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
dump("plain text",&plain[16],cipher_len-16);
dump("cipher text",cipher_text,cipher_len-16);
DEBUGF("frame->payload->length=%d,cipher_len-16=%d,cipher_offset=%d", frame->payload->position,cipher_len-16,cipher_offset);
dump("nm",k,nm);
dump("plain text",plain,sizeof(plain));
dump("nonce",nonce,nb);
dump("cipher text",cipher_text,cipher_len);
}
/* now shuffle down to get rid of the temporary space that crypto_box
uses.
TODO extend overlay buffer so we don't need this.
*/
bcopy(&cipher_text[cz],&cipher_text[0],cipher_len-cz);
frame->payload->position-=cz;
if (0){
dump("frame",&frame->payload->bytes[0],
frame->payload->position);
}
@ -695,17 +742,9 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
case MDP_NOCRYPT:
/* Payload is sent unencrypted, but signed. */
frame->modifiers=OF_CRYPTO_SIGNED;
/* Prepare payload */
/* MDP version 1 */
ob_append_byte(frame->payload,0x01);
ob_append_byte(frame->payload,0x01);
/* Destination port */
ob_append_ui32(frame->payload,mdp->out.src.port);
ob_append_ui32(frame->payload,mdp->out.dst.port);
ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
frame->modifiers=OF_CRYPTO_SIGNED;
frame->payload = plaintext;
ob_makespace(frame->payload,SIGNATURE_BYTES);
if (crypto_sign_message(frame->source, frame->payload->bytes, frame->payload->allocSize, &frame->payload->position)){
op_free(frame);
RETURN(-1);
@ -714,20 +753,7 @@ 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 */
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);
/* Destination port */
ob_append_ui32(frame->payload,mdp->out.src.port);
ob_append_ui32(frame->payload,mdp->out.dst.port);
ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
frame->payload = plaintext;
break;
case MDP_NOSIGN:
default:
@ -737,7 +763,6 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
*/
op_free(frame);
RETURN(WHY("Not implemented"));
break;
}
frame->queue=mdp->out.queue;
@ -745,7 +770,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
frame->queue = OQ_ORDINARY;
/* Make sure only voice traffic gets priority */
if ((frame->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
if (frame->type==OF_TYPE_DATA_VOICE) {
frame->queue=OQ_ISOCHRONOUS_VOICE;
rhizome_saw_voice_traffic();
}
@ -765,9 +790,7 @@ static int search_subscribers(struct subscriber *subscriber, void *context){
}
if (response->mode == MDP_ADDRLIST_MODE_ROUTABLE_PEERS &&
(subscriber->reachable != REACHABLE_DIRECT &&
subscriber->reachable != REACHABLE_INDIRECT &&
subscriber->reachable != REACHABLE_UNICAST)){
(!(subscriber->reachable &REACHABLE))){
return 0;
}
@ -814,6 +837,61 @@ int overlay_mdp_address_list(overlay_mdp_addrlist *request, overlay_mdp_addrlist
return 0;
}
struct routing_state{
struct sockaddr_un *recvaddr_un;
socklen_t recvaddrlen;
int fd;
};
static int routing_table(struct subscriber *subscriber, void *context){
struct routing_state *state = (struct routing_state *)context;
overlay_mdp_frame reply;
bzero(&reply, sizeof(overlay_mdp_frame));
struct overlay_route_record *r=(struct overlay_route_record *)&reply.out.payload;
reply.packetTypeAndFlags=MDP_TX;
reply.out.payload_length=sizeof(struct overlay_route_record);
memcpy(r->sid, subscriber->sid, SID_SIZE);
r->reachable = subscriber->reachable;
if (subscriber->reachable==REACHABLE_INDIRECT && subscriber->next_hop)
memcpy(r->neighbour, subscriber->next_hop->sid, SID_SIZE);
overlay_mdp_reply(mdp_named.poll.fd, state->recvaddr_un, state->recvaddrlen, &reply);
return 0;
}
struct scan_state{
struct sched_ent alarm;
overlay_interface *interface;
uint32_t current;
uint32_t last;
};
struct scan_state scans[OVERLAY_MAX_INTERFACES];
static void overlay_mdp_scan(struct sched_ent *alarm)
{
struct sockaddr_in addr={
.sin_family=AF_INET,
.sin_port=htons(PORT_DNA),
};
struct scan_state *state = (struct scan_state *)alarm;
while(state->current <= state->last){
addr.sin_addr.s_addr=htonl(state->current);
if (overlay_send_probe(NULL, addr, state->interface))
break;
state->current++;
}
if (state->current <= state->last){
alarm->alarm=gettime_ms()+500;
schedule(alarm);
}else{
state->interface=NULL;
state->current=0;
state->last=0;
}
}
void overlay_mdp_poll(struct sched_ent *alarm)
{
if (alarm->poll.revents & POLLIN) {
@ -849,6 +927,18 @@ void overlay_mdp_poll(struct sched_ent *alarm)
overlay_mdp_reply(mdp_named.poll.fd,recvaddr_un,recvaddrlen,mdp);
return;
case MDP_ROUTING_TABLE:
{
struct routing_state state={
.recvaddr_un=recvaddr_un,
.recvaddrlen=recvaddrlen,
};
enum_subscribers(NULL, routing_table, &state);
}
return;
case MDP_GETADDRS:
{
overlay_mdp_frame mdpreply;
@ -898,6 +988,56 @@ void overlay_mdp_poll(struct sched_ent *alarm)
}
break;
case MDP_SCAN:
{
struct overlay_mdp_scan *scan = (struct overlay_mdp_scan *)&mdp->raw;
time_ms_t start=gettime_ms();
if (scan->addr.s_addr==0){
int i=0;
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
// skip any interface that is already being scanned
if (scans[i].interface)
continue;
struct overlay_interface *interface = &overlay_interfaces[i];
if (interface->state!=INTERFACE_STATE_UP)
continue;
scans[i].interface = interface;
scans[i].current = ntohl(interface->address.sin_addr.s_addr & interface->netmask.s_addr)+1;
scans[i].last = ntohl(interface->broadcast_address.sin_addr.s_addr)-1;
if (scans[i].last - scans[i].current>0x10000){
INFOF("Skipping scan on interface %s as the address space is too large",interface->name);
continue;
}
scans[i].alarm.alarm=start;
scans[i].alarm.function=overlay_mdp_scan;
start+=100;
schedule(&scans[i].alarm);
}
}else{
struct overlay_interface *interface = overlay_interface_find(scan->addr);
if (!interface){
overlay_mdp_reply_error(alarm->poll.fd,recvaddr_un,recvaddrlen, 1, "Unable to find matching interface");
return;
}
int i = interface - overlay_interfaces;
if (!scans[i].interface){
scans[i].interface = interface;
scans[i].current = ntohl(scan->addr.s_addr);
scans[i].last = ntohl(scan->addr.s_addr);
scans[i].alarm.alarm=start;
scans[i].alarm.function=overlay_mdp_scan;
schedule(&scans[i].alarm);
}
}
overlay_mdp_reply_ok(alarm->poll.fd,recvaddr_un,recvaddrlen,"Scan initiated");
}
break;
default:
/* Client is not allowed to send any other frame type */
WARNF("Unsupported MDP frame type: %d", mdp_type);

@ -40,6 +40,8 @@ int overlay_mdp_service_rhizomerequest(overlay_mdp_frame *mdp)
read_uint16(&mdp->out.payload[RHIZOME_MANIFEST_ID_BYTES+8+8+4]);
if (blockLength>1024) RETURN(-1);
struct subscriber *source = find_subscriber(mdp->out.src.sid, SID_SIZE, 0);
if(0) {
DEBUGF("Someone sent me a rhizome request via MDP");
DEBUGF("requestor sid = %s",alloca_tohex_sid(mdp->out.src.sid));
@ -96,10 +98,15 @@ int overlay_mdp_service_rhizomerequest(overlay_mdp_frame *mdp)
reply.packetTypeAndFlags=MDP_TX|MDP_NOCRYPT|MDP_NOSIGN;
reply.out.ttl=1;
bcopy(my_subscriber->sid,reply.out.src.sid,SID_SIZE);
// send replies to broadcast so that others can hear blocks and record them
// (not that preemptive listening is implemented yet).
reply.out.src.port=MDP_PORT_RHIZOME_RESPONSE;
memset(reply.out.dst.sid,0xff,SID_SIZE);
if (source && source->reachable&REACHABLE_UNICAST){
// if we get a request from a peer that we can only talk to via unicast, send data via unicast too.
bcopy(mdp->out.src.sid,reply.out.dst.sid,SID_SIZE);
}else{
// send replies to broadcast so that others can hear blocks and record them
// (not that preemptive listening is implemented yet).
memset(reply.out.dst.sid,0xff,SID_SIZE);
}
reply.out.dst.port=MDP_PORT_RHIZOME_RESPONSE;
reply.out.queue=OQ_ORDINARY;
reply.out.payload[0]='B'; // reply contains blocks
@ -278,6 +285,88 @@ int overlay_mdp_service_echo(overlay_mdp_frame *mdp)
RETURN(0);
}
struct probe_contents{
struct sockaddr_in addr;
unsigned char interface;
};
/* Collection of unicast echo responses to detect working links */
static int
overlay_mdp_service_probe(overlay_mdp_frame *mdp)
{
IN();
if (mdp->out.src.port!=MDP_PORT_ECHO || mdp->out.payload_length != sizeof(struct probe_contents)){
WARN("Probe packets should be returned from remote echo port");
RETURN(-1);
}
struct subscriber *peer = find_subscriber(mdp->out.src.sid, SID_SIZE, 0);
struct probe_contents probe;
bcopy(&mdp->out.payload, &probe, sizeof(struct probe_contents));
if (probe.addr.sin_family!=AF_INET)
RETURN(WHY("Unsupported address family"));
if (peer->reachable == REACHABLE_NONE || peer->reachable == REACHABLE_INDIRECT || (peer->reachable & REACHABLE_ASSUMED)){
reachable_unicast(peer, &overlay_interfaces[probe.interface], probe.addr.sin_addr, probe.addr.sin_port);
}
RETURN(0);
}
int overlay_send_probe(struct subscriber *peer, struct sockaddr_in addr, overlay_interface *interface){
if (interface==NULL)
interface = overlay_interface_find(addr.sin_addr);
if (!interface)
return WHY("I don't know which interface to use");
time_ms_t now = gettime_ms();
if (peer && peer->last_probe+1000>now)
return -1;
struct overlay_frame *frame=malloc(sizeof(struct overlay_frame));
bzero(frame,sizeof(struct overlay_frame));
frame->type=OF_TYPE_DATA;
frame->source = my_subscriber;
frame->next_hop = frame->destination = peer;
frame->ttl=1;
frame->queue=OQ_MESH_MANAGEMENT;
frame->destination_resolved=1;
frame->recvaddr=addr;
frame->flags=PACKET_UNICAST;
frame->interface=interface;
frame->payload = ob_new();
frame->send_copies=3;
if ((!peer) || !(peer->reachable&REACHABLE))
my_subscriber->send_full=1;
if (peer)
peer->last_probe=gettime_ms();
if (overlay_mdp_encode_ports(frame->payload, MDP_PORT_ECHO, MDP_PORT_PROBE)){
op_free(frame);
return -1;
}
// not worried about byte order here as we are the only node that should be parsing the contents.
unsigned char *dst=ob_append_space(frame->payload, sizeof(struct probe_contents));
if (!dst){
op_free(frame);
return -1;
}
struct probe_contents probe;
probe.addr=addr;
// get interface number
probe.interface = interface - overlay_interfaces;
bcopy(&probe, dst, sizeof(struct probe_contents));
if (overlay_payload_enqueue(frame)){
op_free(frame);
return -1;
}
DEBUGF("Queued probe packet on interface %s to %s", interface->name, inet_ntoa(addr.sin_addr));
return 0;
}
int overlay_mdp_try_interal_services(overlay_mdp_frame *mdp)
{
IN();
@ -286,6 +375,7 @@ int overlay_mdp_try_interal_services(overlay_mdp_frame *mdp)
case MDP_PORT_KEYMAPREQUEST: RETURN(keyring_mapping_request(keyring,mdp));
case MDP_PORT_DNALOOKUP: RETURN(overlay_mdp_service_dnalookup(mdp));
case MDP_PORT_ECHO: RETURN(overlay_mdp_service_echo(mdp));
case MDP_PORT_PROBE: RETURN(overlay_mdp_service_probe(mdp));
case MDP_PORT_RHIZOME_REQUEST:
if (is_rhizome_mdp_server_running()) {
RETURN(overlay_mdp_service_rhizomerequest(mdp));

@ -130,7 +130,6 @@ static void parse_frame(struct overlay_buffer *buff){
WHYF("Unexpected magic number %d", magic);
return;
}
overlay_address_clear();
frame.ttl = ob_get(buff);
addr_len = ob_get(buff);
@ -142,31 +141,28 @@ static void parse_frame(struct overlay_buffer *buff){
addr = (struct in_addr *)ob_get_bytes_ptr(buff, addr_len);
// read subscriber id of transmitter
struct subscriber *sender;
if (overlay_address_parse(&context, buff, NULL, &sender))
if (overlay_address_parse(&context, buff, &context.sender))
goto end;
if (context.invalid_addresses)
goto end;
overlay_address_set_sender(sender);
// locate the interface we should send outgoing unicast packets to
overlay_interface *interface = overlay_interface_find(*addr);
if (interface){
// always update the IP address we heard them from, even if we don't need to use it right now
sender->address.sin_family = AF_INET;
sender->address.sin_addr = *addr;
context.sender->address.sin_family = AF_INET;
context.sender->address.sin_addr = *addr;
// assume the port number of the other servald matches our local port number configuration
sender->address.sin_port = htons(interface->port);
context.sender->address.sin_port = htons(interface->port);
if (sender->reachable==REACHABLE_NONE){
reachable_unicast(sender, interface, *addr, interface->port);
if (context.sender->reachable==REACHABLE_NONE){
reachable_unicast(context.sender, interface, *addr, interface->port);
}
}
// read subscriber id of payload origin
if (overlay_address_parse(&context, buff, NULL, &frame.source))
if (overlay_address_parse(&context, buff, &frame.source))
goto end;
if (context.invalid_addresses)
@ -174,7 +170,7 @@ static void parse_frame(struct overlay_buffer *buff){
// read source broadcast id
// assume each packet may arrive multiple times due to routing loops between servald overlay and olsr.
if (overlay_address_parse(&context, buff, &frame.broadcast_id, NULL))
if (overlay_broadcast_parse(buff, &frame.broadcast_id))
goto end;
if (context.invalid_addresses)
@ -194,7 +190,7 @@ static void parse_frame(struct overlay_buffer *buff){
end:
// if we didn't understand one of the address abreviations, ask for explanation
send_please_explain(&context, my_subscriber, sender);
send_please_explain(&context, my_subscriber, context.sender);
}
static void olsr_read(struct sched_ent *alarm){
@ -266,18 +262,18 @@ int olsr_send(struct overlay_frame *frame){
if (frame->destination)
return 0;
struct decode_context context;
bzero(&context, sizeof context);
struct overlay_buffer *b=ob_new();
overlay_address_clear();
// build olsr specific frame header
ob_append_byte(b, PACKET_FORMAT_NUMBER);
ob_append_byte(b, frame->ttl);
// address the packet as transmitted by me
overlay_address_append(b, my_subscriber);
overlay_address_set_sender(my_subscriber);
overlay_address_append(&context, b, my_subscriber);
overlay_address_append(b, frame->source);
overlay_address_append(&context, b, frame->source);
overlay_broadcast_append(b, &frame->broadcast_id);
ob_append_byte(b, frame->modifiers);

@ -23,6 +23,8 @@
#include "overlay_address.h"
#include "serval.h"
#define PACKET_UNICAST (1<<0)
struct overlay_frame {
struct overlay_frame *prev;
struct overlay_frame *next;
@ -38,17 +40,20 @@ struct overlay_frame {
/* 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 *next_hop;
struct subscriber *source;
/* IPv4 node frame was received from (if applicable) */
struct sockaddr *recvaddr;
/* IPv4 address the frame was received from, or should be sent to */
int destination_resolved;
struct sockaddr_in recvaddr;
overlay_interface *interface;
int flags;
/* Actual payload */
struct overlay_buffer *payload;

@ -25,8 +25,23 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
struct sockaddr_in loopback;
unsigned char magic_header[]={0x00, 0x01};
int overlay_packet_init_header(struct decode_context *context, struct overlay_buffer *buff,
struct subscriber *destination, int flags){
if (ob_append_bytes(buff,magic_header,sizeof magic_header))
return -1;
if (overlay_address_append(context, buff, my_subscriber))
return -1;
context->sender = my_subscriber;
ob_append_byte(buff,0);
ob_append_byte(buff,flags);
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, struct overlay_frame *f, struct decode_context *context){
IN();
int id = (interface - overlay_interfaces);
switch(f->type)
{
@ -65,16 +80,16 @@ int process_incoming_frame(time_ms_t now, struct overlay_interface *interface, s
process_explain(f);
break;
default:
return WHYF("Support for f->type=0x%x not yet implemented",f->type);
break;
RETURN(WHYF("Support for f->type=0x%x not yet implemented",f->type));
}
return 0;
RETURN(0);
}
// duplicate the frame and queue it
int overlay_forward_payload(struct overlay_frame *f){
IN();
if (f->ttl<=0)
return 0;
RETURN(0);
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF("Forwarding payload for %s, ttl=%d",
@ -90,26 +105,26 @@ int overlay_forward_payload(struct overlay_frame *f){
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");
RETURN(WHY("Could not clone frame for queuing"));
/* Make sure voice traffic gets priority */
if ((qf->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
if (qf->type==OF_TYPE_DATA_VOICE) {
qf->queue=OQ_ISOCHRONOUS_VOICE;
rhizome_saw_voice_traffic();
}
if (overlay_payload_enqueue(qf)) {
op_free(qf);
return WHY("failed to enqueue forwarded payload");
RETURN(WHY("failed to enqueue forwarded payload"));
}
return 0;
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)
int recvttl, struct sockaddr *recvaddr, size_t recvaddrlen)
{
IN();
/*
This function decodes overlay packets which have been assembled for delivery overy IP networks.
IP based wireless networks have a high, but limited rate of packets that can be sent. In order
@ -161,105 +176,169 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
the source having received the frame from elsewhere.
*/
if (recvaddr->sa_family!=AF_INET)
RETURN(WHYF("Unexpected protocol family %d",recvaddr->sa_family));
struct overlay_frame f;
struct subscriber *sender=NULL;
struct decode_context context={
.please_explain=NULL,
};
struct decode_context context;
bzero(&context, sizeof context);
bzero(&f,sizeof 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;
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Received overlay packet");
} else {
if (interface->fileP) {
/* dummy interface, so tell to use localhost */
loopback.sin_family = AF_INET;
loopback.sin_port = 0;
loopback.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
f.recvaddr=(struct sockaddr *)&loopback;
} else
/* some other sort of interface, so we can't offer any help here */
f.recvaddr=NULL;
if (ob_get(b)!=magic_header[0] || ob_get(b)!=magic_header[1]){
ob_free(b);
RETURN(WHY("Packet type not recognised."));
}
overlay_address_clear();
// TODO put sender of packet and sequence number in envelope header
// Then we can quickly drop reflected broadcast packets
// currently we see annoying errors as we attempt to parse each payload
// plus with a sequence number we can detect dropped packets and nack them for retransmission
/* Skip magic bytes and version */
context.interface = f.interface = interface;
f.recvaddr = *((struct sockaddr_in *)recvaddr);
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Received overlay packet");
if (overlay_address_parse(&context, b, &context.sender)){
WHY("Unable to parse sender");
}
ob_get(b); // sequence number, not implemented yet
int packet_flags = ob_get(b);
if (context.sender){
if (context.sender->reachable==REACHABLE_SELF){
ob_free(b);
RETURN(0);
}
// always update the IP address we heard them from, even if we don't need to use it right now
context.sender->address = f.recvaddr;
context.sender->last_rx = now;
// if this is a dummy announcement for a node that isn't in our routing table
if (context.sender->reachable == REACHABLE_NONE &&
(!context.sender->node) &&
packet_flags&PACKET_UNICAST){
// mark this subscriber as reachable directly via unicast.
context.sender->interface = interface;
set_reachable(context.sender, REACHABLE_UNICAST|REACHABLE_ASSUMED);
}
}
if (packet_flags & PACKET_UNICAST)
context.addr=f.recvaddr;
else
context.addr=interface->broadcast_address;
while(b->position < b->sizeLimit){
context.invalid_addresses=0;
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(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;
case OF_TYPE_EXTENDED12:
/* Eat the next byte */
f.type=OF_TYPE_FLAG_E12|flags|(ob_get(b)<<4);
f.modifiers=0;
break;
}
f.queue = (f.modifiers & OF_QUEUE_BITS) +1;
/* Get time to live */
f.ttl=ob_get(b);
f.ttl--;
/* 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 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;
bzero(f.broadcast_id.id, BROADCAST_LEN);
// if the structure of the addresses looks wrong, stop immediately
if (overlay_address_parse(&context, b, &f.broadcast_id, &nexthop)
|| overlay_address_parse(&context, b, NULL, &f.destination)
|| overlay_address_parse(&context, b, NULL, &f.source)){
goto next;
int process=1;
int forward=1;
int flags = ob_get(b);
if (flags<0){
WHY("Unable to parse payload flags");
break;
}
if (flags & PAYLOAD_FLAG_SENDER_SAME){
if (!context.sender)
context.invalid_addresses=1;
f.source = context.sender;
}else{
if (overlay_address_parse(&context, b, &f.source)){
WHY("Unable to parse payload source");
break;
}
if (!f.source || f.source->reachable==REACHABLE_SELF)
process=forward=0;
}
if (flags & PAYLOAD_FLAG_TO_BROADCAST){
if (!(flags & PAYLOAD_FLAG_ONE_HOP)){
if (overlay_broadcast_parse(b, &f.broadcast_id)){
WHY("Unable to parse payload broadcast id");
break;
}
if (overlay_broadcast_drop_check(&f.broadcast_id)){
process=forward=0;
if (debug&DEBUG_OVERLAYFRAMES)
DEBUGF("Ignoring duplicate broadcast (%s)", alloca_tohex(f.broadcast_id.id, BROADCAST_LEN));
}
}
f.destination=NULL;
}else{
if (overlay_address_parse(&context, b, &f.destination)){
WHY("Unable to parse payload destination");
break;
}
if (!f.destination || f.destination->reachable!=REACHABLE_SELF){
process=0;
}
if (!(flags & PAYLOAD_FLAG_ONE_HOP)){
if (overlay_address_parse(&context, b, &nexthop)){
WHY("Unable to parse payload nexthop");
break;
}
if (!nexthop || nexthop->reachable!=REACHABLE_SELF){
forward=0;
}
}
}
if (flags & PAYLOAD_FLAG_ONE_HOP){
f.ttl=1;
}else{
int ttl_qos = ob_get(b);
if (ttl_qos<0){
WHY("Unable to parse ttl/qos");
break;
}
f.ttl = ttl_qos & 0x1F;
f.queue = (ttl_qos >> 5) & 3;
}
f.ttl--;
if (f.ttl<=0)
forward=0;
if (flags & PAYLOAD_FLAG_LEGACY_TYPE){
f.type=ob_get(b);
if (f.type<0){
WHY("Unable to parse payload type");
break;
}
}else
f.type=OF_TYPE_DATA;
f.modifiers=flags;
// TODO allow for one byte length
int payload_len = ob_get_ui16(b);
if (payload_len <=0){
WHY("Unable to parse payload length");
break;
}
int next_payload = b->position + payload_len;
if (f.source)
f.source->last_rx = now;
// if we can't understand one of the addresses, skip processing the payload
if (context.invalid_addresses)
if (context.invalid_addresses){
if (debug&DEBUG_OVERLAYFRAMES)
DEBUG("Skipping payload due to unknown addresses");
goto next;
}
if (debug&DEBUG_OVERLAYFRAMES){
DEBUGF("Received payload type %x, len %d", f.type, next_payload - b->position);
@ -271,50 +350,8 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
DEBUGF("Next hop %s", alloca_tohex_sid(nexthop->sid));
}
if (f.type==OF_TYPE_SELFANNOUNCE){
sender = f.source;
// skip the entire packet if it came from me
if (sender->reachable==REACHABLE_SELF)
break;
overlay_address_set_sender(f.source);
struct sockaddr_in *addr=(struct sockaddr_in *)recvaddr;
// always update the IP address we heard them from, even if we don't need to use it right now
f.source->address = *addr;
// if this is a dummy announcement for a node that isn't in our routing table
if (f.destination &&
(f.source->reachable == REACHABLE_NONE || f.source->reachable == REACHABLE_UNICAST) &&
(!f.source->node) &&
(interface->fileP || recvaddr->sa_family==AF_INET)){
// mark this subscriber as reachable directly via unicast.
reachable_unicast(f.source, interface, addr->sin_addr, ntohs(addr->sin_port));
}
}
// 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));
if (!process && !forward)
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){
@ -325,13 +362,12 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
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 (forward){
overlay_forward_payload(&f);
}
// process payloads that are for me or everyone
if ((!f.destination) || f.destination->reachable==REACHABLE_SELF){
if (process){
process_incoming_frame(now, interface, &f, &context);
}
@ -343,13 +379,14 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
b->position=next_payload;
}
send_please_explain(&context, my_subscriber, context.sender);
ob_free(b);
send_please_explain(&context, my_subscriber, sender);
return 0;
RETURN(0);
}
int overlay_add_selfannouncement(int interface,struct overlay_buffer *b)
int overlay_add_selfannouncement(struct decode_context *context, int interface,struct overlay_buffer *b)
{
/* Pull the first record from the HLR database and turn it into a
@ -373,40 +410,12 @@ int overlay_add_selfannouncement(int interface,struct overlay_buffer *b)
time_ms_t now = gettime_ms();
/* Header byte */
if (ob_append_byte(b, OF_TYPE_SELFANNOUNCE))
return WHY("Could not add self-announcement header");
/* A TTL for this frame.
XXX - BATMAN uses various TTLs, but I think that it may just be better to have all TTL=1,
and have the onward nodes selectively choose which nodes to on-announce. If we prioritise
newly arrived nodes somewhat (or at least reserve some slots for them), then we can still
get the good news travels fast property of BATMAN, but without having to flood in the formal
sense. */
if (ob_append_byte(b,1))
return WHY("Could not add TTL to self-announcement");
/* Add space for Remaining Frame Size field. This will always be a single byte
for self-announcments as they are always <256 bytes. */
if (ob_append_rfs(b,1+8+1+SID_SIZE+4+4+1))
return WHY("Could not add RFS for self-announcement frame");
/* Add next-hop address. Always link-local broadcast for self-announcements */
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. */
if (ob_append_byte(b, OA_CODE_PREVIOUS))
return WHY("Could not add self-announcement header");
/* Add our SID to the announcement as sender */
if (overlay_address_append_self(&overlay_interfaces[interface], b))
if (overlay_frame_build_header(context, b,
0, OF_TYPE_SELFANNOUNCE, 0, 1,
NULL, NULL,
NULL, my_subscriber))
return -1;
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;
// If this interface has not been ticked yet (no selfannounce sent) then invent the prior sequence
@ -430,7 +439,7 @@ int overlay_add_selfannouncement(int interface,struct overlay_buffer *b)
if (ob_append_byte(b,interface))
return WHY("Could not add interface number to self-announcement");
ob_patch_rfs(b, COMPUTE_RFS_LENGTH);
ob_patch_rfs(b);
return 0;
}

@ -22,46 +22,59 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "overlay_buffer.h"
#include "overlay_packet.h"
static int op_append_type(struct overlay_buffer *headers, struct overlay_frame *p)
{
unsigned char c[3];
// pack the QOS queue into the modifiers
int q_bits = p->queue;
if (q_bits>0) q_bits--;
if (q_bits>3) q_bits=3;
int overlay_frame_build_header(struct decode_context *context, struct overlay_buffer *buff,
int queue, int type, int modifiers, int ttl,
struct broadcast *broadcast, struct subscriber *next_hop,
struct subscriber *destination, struct subscriber *source){
p->modifiers = (p->modifiers & ~OF_QUEUE_BITS)|q_bits;
int flags = modifiers & (PAYLOAD_FLAG_CIPHERED | PAYLOAD_FLAG_SIGNED);
switch(p->type&OF_TYPE_FLAG_BITS)
{
case OF_TYPE_FLAG_NORMAL:
c[0]=p->type|p->modifiers;
if (debug&DEBUG_PACKETFORMATS) DEBUGF("type resolves to %02x",c[0]);
if (ob_append_bytes(headers,c,1)) return -1;
break;
case OF_TYPE_FLAG_E12:
c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED12;
c[1]=(p->type>>4)&0xff;
if (debug&DEBUG_PACKETFORMATS) DEBUGF("type resolves to %02x%02x",c[0],c[1]);
if (ob_append_bytes(headers,c,2)) return -1;
break;
case OF_TYPE_FLAG_E20:
c[0]=(p->type&OF_MODIFIER_BITS)|OF_TYPE_EXTENDED20;
c[1]=(p->type>>4)&0xff;
c[2]=(p->type>>12)&0xff;
if (debug&DEBUG_PACKETFORMATS) DEBUGF("type resolves to %02x%02x%02x",c[0],c[1],c[2]);
if (ob_append_bytes(headers,c,3)) return -1;
break;
default:
/* Don't know this type of frame */
WHY("Asked for format frame with unknown TYPE_FLAG bits");
return -1;
if (ttl==1 && !broadcast)
flags |= PAYLOAD_FLAG_ONE_HOP;
if (destination && destination==next_hop)
flags |= PAYLOAD_FLAG_ONE_HOP;
if (source == context->sender)
flags |= PAYLOAD_FLAG_SENDER_SAME;
if (!destination)
flags |= PAYLOAD_FLAG_TO_BROADCAST;
if (type!=OF_TYPE_DATA)
flags |= PAYLOAD_FLAG_LEGACY_TYPE;
if (ob_append_byte(buff, flags)) return -1;
if (!(flags & PAYLOAD_FLAG_SENDER_SAME)){
if (overlay_address_append(context, buff, source)) return -1;
}
if (flags & PAYLOAD_FLAG_TO_BROADCAST){
if (!(flags & PAYLOAD_FLAG_ONE_HOP)){
if (overlay_broadcast_append(buff, broadcast)) return -1;
}
}else{
if (overlay_address_append(context, buff, destination)) return -1;
if (!(flags & PAYLOAD_FLAG_ONE_HOP)){
if (overlay_address_append(context, buff, next_hop)) return -1;
}
}
if (!(flags & PAYLOAD_FLAG_ONE_HOP)){
if (ob_append_byte(buff, ttl | ((queue&3)<<5))) return -1;
}
if (flags & PAYLOAD_FLAG_LEGACY_TYPE){
if (ob_append_byte(buff, type)) return -1;
}
if (ob_append_rfs(buff, 2)) return -1;
return 0;
}
int overlay_frame_append_payload(overlay_interface *interface, struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b)
int overlay_frame_append_payload(struct decode_context *context, overlay_interface *interface,
struct overlay_frame *p, struct overlay_buffer *b)
{
/* Convert a payload (frame) structure into a series of bytes.
Assumes that any encryption etc has already been done.
@ -76,58 +89,26 @@ int overlay_frame_append_payload(overlay_interface *interface, struct overlay_fr
ob_checkpoint(b);
if (debug&DEBUG_PACKETCONSTRUCTION)
dump_payload(p,"append_payload stuffing into packet");
/* Build header */
/* Write fields into binary structure in correct order */
/* Write out type field byte(s) */
if (op_append_type(headers,p))
goto cleanup;
/* Write out TTL */
if (p->ttl>64)
p->ttl=64;
if (ob_append_byte(headers,p->ttl))
if (debug&DEBUG_PACKETCONSTRUCTION){
DEBUGF( "+++++\nFrame from %s to %s of type 0x%02x %s:",
alloca_tohex_sid(p->source->sid),
alloca_tohex_sid(p->destination->sid),p->type,
"append_payload stuffing into packet");
if (p->payload)
dump("payload contents", &p->payload->bytes[0],p->payload->position);
}
if (overlay_frame_build_header(context, headers,
p->queue, p->type, p->modifiers, p->ttl,
(p->destination?NULL:&p->broadcast_id), p->next_hop,
p->destination, p->source))
goto cleanup;
/* Length. This is the fun part, because we cannot calculate how many bytes we need until
we have abbreviated the addresses, and the length encoding we use varies according to the
length encoded. The simple option of running the abbreviations twice won't work because
we rely on context for abbreviating the addresses. So we write it initially and then patch it
after.
*/
int max_len=((SID_SIZE+3)*3+headers->position+p->payload->position);
int hdr_len=headers->position - (headers->var_length_offset +2);
if (debug&DEBUG_PACKETCONSTRUCTION)
DEBUGF("Appending RFS for max_len=%d\n",max_len);
ob_append_rfs(headers,max_len);
DEBUGF("Patching RFS for actual_len=%d\n",hdr_len + p->payload->position);
int addrs_start=headers->position;
/* Write out addresses as abbreviated as possible */
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);
if (p->source==my_subscriber){
overlay_address_append_self(interface, headers);
}else{
overlay_address_append(headers,p->source);
}
int addrs_len=headers->position-addrs_start;
int actual_len=addrs_len+p->payload->position;
if (debug&DEBUG_PACKETCONSTRUCTION)
DEBUGF("Patching RFS for actual_len=%d\n",actual_len);
ob_patch_rfs(headers,actual_len);
ob_set_ui16(headers,headers->var_length_offset,hdr_len + p->payload->position);
/* Write payload format plus total length of header bits */
if (ob_makespace(b,2+headers->position+p->payload->position)) {
@ -156,17 +137,6 @@ cleanup:
return -1;
}
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->sid),
alloca_tohex_sid(p->destination->sid),p->type,
message?message:"");
if (p->payload)
dump("payload contents", &p->payload->bytes[0],p->payload->position);
return 0;
}
int op_free(struct overlay_frame *p)
{
if (!p) return WHY("Asked to free NULL");

@ -1,3 +1,22 @@
/*
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.
*/
#include "serval.h"
#include "overlay_buffer.h"
#include "overlay_packet.h"
@ -32,17 +51,15 @@ typedef struct overlay_txqueue {
overlay_txqueue overlay_tx[OQ_MAX];
unsigned char magic_header[]={/* Magic */ 'O',0x10,
/* Version */ 0x00,0x01};
struct outgoing_packet{
overlay_interface *interface;
int i;
struct subscriber *unicast_subscriber;
int unicast;
int add_advertisements;
struct sockaddr_in dest;
int header_length;
struct overlay_buffer *buffer;
struct decode_context context;
};
struct sched_ent next_packet;
@ -144,11 +161,23 @@ int overlay_payload_enqueue(struct overlay_frame *p)
if (!p) return WHY("Cannot queue NULL");
if (p->destination){
do{
if (p->destination_resolved)
break;
if (!p->destination)
break;
int r = subscriber_is_reachable(p->destination);
if (r == REACHABLE_SELF || r == REACHABLE_NONE)
return WHYF("Destination %s is unreachable (%d)", alloca_tohex_sid(p->destination->sid), r);
}
if (r&REACHABLE)
break;
if (directory_service){
r = subscriber_is_reachable(directory_service);
if (r&REACHABLE)
break;
}
return WHYF("Cannot send %x packet, destination %s is %s", p->type, alloca_tohex_sid(p->destination->sid), r==REACHABLE_SELF?"myself":"unreachable");
} while(0);
if (p->queue>=OQ_MAX)
return WHY("Invalid queue specified");
@ -160,10 +189,10 @@ int overlay_payload_enqueue(struct overlay_frame *p)
p->destination?alloca_tohex(p->destination->sid, 7): alloca_tohex(p->broadcast_id.id,BROADCAST_LEN),
p->queue, queue->length);
if (p->payload && p->payload->position > p->payload->sizeLimit){
if (p->payload && ob_remaining(p->payload)<0){
// 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;
ob_limitsize(p->payload,ob_position(p->payload));
}
if (queue->length>=queue->maxLength)
@ -174,28 +203,30 @@ int overlay_payload_enqueue(struct overlay_frame *p)
else if(p->send_copies>5)
return WHY("Too many copies requested");
if (!p->destination){
int i;
int drop=1;
// hook to allow for flooding via olsr
olsr_send(p);
// make sure there is an interface up that allows broadcasts
for(i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state==INTERFACE_STATE_UP
&& overlay_interfaces[i].send_broadcasts){
p->broadcast_sent_via[i]=0;
drop=0;
}else
p->broadcast_sent_via[i]=1;
if (!p->destination_resolved){
if (!p->destination){
int i;
int drop=1;
// hook to allow for flooding via olsr
olsr_send(p);
// make sure there is an interface up that allows broadcasts
for(i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state==INTERFACE_STATE_UP
&& overlay_interfaces[i].send_broadcasts){
p->broadcast_sent_via[i]=0;
drop=0;
}else
p->broadcast_sent_via[i]=1;
}
// just drop it now
if (drop){
WARN("No broadcast interfaces to send with");
return -1;
}
}
// just drop it now
if (drop)
return -1;
p->sendBroadcast=1;
}
struct overlay_frame *l=queue->last;
@ -210,48 +241,32 @@ int overlay_payload_enqueue(struct overlay_frame *p)
overlay_update_queue_schedule(queue, p);
if (0) overlay_queue_dump(queue);
return 0;
}
static void
overlay_init_packet(struct outgoing_packet *packet, overlay_interface *interface, int tick){
overlay_init_packet(struct outgoing_packet *packet, struct subscriber *destination, int flags,
overlay_interface *interface, struct sockaddr_in addr, int tick){
packet->interface = interface;
packet->i = (interface - overlay_interfaces);
packet->dest=interface->broadcast_address;
packet->dest=addr;
packet->buffer=ob_new();
packet->add_advertisements=1;
if (flags & PACKET_UNICAST)
packet->unicast_subscriber = destination;
ob_limitsize(packet->buffer, packet->interface->mtu);
ob_append_bytes(packet->buffer,magic_header,4);
overlay_address_clear();
overlay_packet_init_header(&packet->context, packet->buffer, destination, flags);
packet->header_length = ob_position(packet->buffer);
if (tick){
/* 1. Send announcement about ourselves, including one SID that we host if we host more than one SID
(the first SID we host becomes our own identity, saving a little bit of data here).
*/
overlay_add_selfannouncement(packet->i, packet->buffer);
overlay_add_selfannouncement(&packet->context, packet->i, packet->buffer);
/* Add advertisements for ROUTES */
overlay_route_add_advertisements(packet->interface, packet->buffer);
overlay_route_add_advertisements(&packet->context, packet->interface, packet->buffer);
}else{
// add a badly formatted dummy self announce payload to tell people we sent this.
ob_append_byte(packet->buffer, OF_TYPE_SELFANNOUNCE);
ob_append_byte(packet->buffer, 1);
ob_append_rfs(packet->buffer, SID_SIZE + 2);
/* from me, to me, via me
(it's shorter than an actual broadcast,
and receivers wont try to process it
since its not going to have a payload body anyway) */
overlay_address_append_self(interface, packet->buffer);
overlay_address_set_sender(my_subscriber);
ob_append_byte(packet->buffer, OA_CODE_PREVIOUS);
ob_append_byte(packet->buffer, OA_CODE_PREVIOUS);
ob_patch_rfs(packet->buffer, COMPUTE_RFS_LENGTH);
}
}
@ -261,12 +276,24 @@ overlay_calc_queue_time(overlay_txqueue *queue, struct overlay_frame *frame){
int ret=0;
time_ms_t send_time;
// ignore packet if the destination is currently unreachable
if (frame->destination && subscriber_is_reachable(frame->destination)==REACHABLE_NONE)
do{
if (frame->destination_resolved)
break;
if (!frame->destination)
break;
if (subscriber_is_reachable(frame->destination)&REACHABLE)
break;
if (directory_service){
if (subscriber_is_reachable(directory_service)&REACHABLE)
break;
}
// ignore payload alarm if the destination is currently unreachable
return 0;
}while(0);
// when is the next packet from this queue due?
send_time=queue->first->enqueued_at + queue->transmit_delay;
if (next_packet.alarm==0 || send_time < next_packet.alarm){
next_packet.alarm=send_time;
ret = 1;
@ -303,101 +330,100 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
even if we hear it from somewhere else in the mean time
*/
struct subscriber *next_hop = frame->destination;
if (next_hop){
switch(subscriber_is_reachable(next_hop)){
case REACHABLE_NONE:
if (!frame->destination_resolved){
frame->next_hop = frame->destination;
if (frame->next_hop){
// Where do we need to route this payload next?
int r = subscriber_is_reachable(frame->next_hop);
// first, should we try to bounce this payload off the directory service?
if (r==REACHABLE_NONE &&
directory_service &&
frame->next_hop!=directory_service){
frame->next_hop=directory_service;
r=subscriber_is_reachable(directory_service);
}
// do we need to route via a neighbour?
if (r&REACHABLE_INDIRECT){
frame->next_hop = frame->next_hop->next_hop;
r = subscriber_is_reachable(frame->next_hop);
}
if (!(r&REACHABLE_DIRECT)){
goto skip;
case REACHABLE_INDIRECT:
next_hop=next_hop->next_hop;
frame->sendBroadcast=0;
break;
case REACHABLE_DEFAULT_ROUTE:
next_hop=directory_service;
frame->sendBroadcast=0;
break;
case REACHABLE_DIRECT:
case REACHABLE_UNICAST:
frame->sendBroadcast=0;
break;
case REACHABLE_BROADCAST:
if (!frame->sendBroadcast){
if (frame->ttl>2)
frame->ttl=2;
frame->sendBroadcast=1;
if (is_all_matching(frame->broadcast_id.id, BROADCAST_LEN, 0)){
overlay_broadcast_generate_address(&frame->broadcast_id);
// mark it as already seen so we don't immediately retransmit it
overlay_broadcast_drop_check(&frame->broadcast_id);
}
int i;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
frame->broadcast_sent_via[i]=0;
}
frame->interface = frame->next_hop->interface;
if(r&REACHABLE_UNICAST){
frame->recvaddr = frame->next_hop->address;
frame->flags = PACKET_UNICAST;
// ignore resend logic for unicast packets, where wifi gives better resilience
frame->send_copies=1;
}else
frame->recvaddr = frame->interface->broadcast_address;
frame->destination_resolved=1;
}else{
if (packet->buffer){
// check if we can stuff into this packet
if (frame->broadcast_sent_via[packet->i]){
goto skip;
}
break;
frame->interface = packet->interface;
frame->recvaddr = packet->interface->broadcast_address;
}else{
// find an interface that we haven't broadcast on yet
frame->interface = NULL;
int i;
for(i=0;i<OVERLAY_MAX_INTERFACES;i++)
{
if (overlay_interfaces[i].state==INTERFACE_STATE_UP
&& !frame->broadcast_sent_via[i]){
frame->interface = &overlay_interfaces[i];
frame->recvaddr = overlay_interfaces[i].broadcast_address;
break;
}
}
if (!frame->interface){
// huh, we don't need to send it anywhere?
frame = overlay_queue_remove(queue, frame);
continue;
}
}
}
}
if (!packet->buffer){
// use the interface of the first payload we find
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
&& !frame->broadcast_sent_via[i]){
overlay_init_packet(packet, &overlay_interfaces[i], 0);
break;
}
}
if (!packet->buffer){
// oh dear, why is this broadcast still in the queue?
frame = overlay_queue_remove(queue, frame);
continue;
}
}else{
overlay_init_packet(packet, next_hop->interface, 0);
if (next_hop->reachable==REACHABLE_UNICAST){
packet->unicast_subscriber = next_hop;
packet->dest = next_hop->address;
packet->unicast=1;
}
}
overlay_init_packet(packet, frame->next_hop, frame->flags, frame->interface, frame->recvaddr, 0);
}else{
// make sure this payload can be sent via this interface
if (frame->sendBroadcast){
if (frame->broadcast_sent_via[packet->i]){
goto skip;
}
}else{
if(packet->interface != next_hop->interface)
goto skip;
if (next_hop->reachable==REACHABLE_DIRECT && packet->unicast)
goto skip;
if (next_hop->reachable==REACHABLE_UNICAST &&
((!packet->unicast) ||
packet->dest.sin_addr.s_addr != next_hop->address.sin_addr.s_addr))
goto skip;
// is this packet going our way?
if (frame->interface!=packet->interface || memcmp(&packet->dest, &frame->recvaddr, sizeof(packet->dest))!=0){
goto skip;
}
}
}
if (debug&DEBUG_OVERLAYFRAMES){
DEBUGF("Sending payload type %x len %d for %s via %s", frame->type, frame->payload->position,
DEBUGF("Sending payload type %x len %d for %s via %s", frame->type, ob_position(frame->payload),
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));
frame->next_hop?alloca_tohex_sid(frame->next_hop->sid):alloca_tohex(frame->broadcast_id.id, BROADCAST_LEN));
}
if (overlay_frame_append_payload(packet->interface, frame, next_hop, packet->buffer))
if (overlay_frame_append_payload(&packet->context, packet->interface, frame, packet->buffer)){
// payload was not queued
goto skip;
}
if (frame->destination)
frame->destination->last_tx=now;
if (frame->next_hop)
frame->next_hop->last_tx=now;
// don't send rhizome adverts if the packet contains a voice payload
if (frame->queue==OQ_ISOCHRONOUS_VOICE)
@ -406,7 +432,14 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
// mark the payload as sent
int keep_payload = 0;
if (frame->sendBroadcast){
if (frame->destination_resolved){
frame->send_copies --;
if (frame->send_copies>0){
keep_payload=1;
// make sure we don't schedule the next alarm immediately
frame->enqueued_at=gettime_ms();
}
}else{
int i;
frame->broadcast_sent_via[packet->i]=1;
@ -419,20 +452,15 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
break;
}
}
}else{
frame->send_copies --;
// ignore resend logic for unicast packets, where wifi gives better resilience
if (frame->send_copies>0 && !packet->unicast)
keep_payload=1;
}
if (!keep_payload){
frame = overlay_queue_remove(queue, frame);
continue;
}
}
skip:
// if we can't send the payload now, check when we should try
// if we can't send the payload now, check when we should try next
overlay_calc_queue_time(queue, frame);
frame = frame->next;
}
@ -458,24 +486,24 @@ overlay_fill_send_packet(struct outgoing_packet *packet, time_ms_t now) {
schedule(&next_packet);
if(packet->buffer){
// send the packet
if (packet->buffer->position>=HEADERFIELDS_LEN){
if (ob_position(packet->buffer) > packet->header_length){
// stuff rhizome announcements at the last moment
if (packet->add_advertisements)
overlay_rhizome_add_advertisements(packet->i,packet->buffer);
overlay_rhizome_add_advertisements(&packet->context, packet->i,packet->buffer);
if (debug&DEBUG_PACKETCONSTRUCTION)
dump("assembled packet",&packet->buffer->bytes[0],packet->buffer->position);
ob_dump(packet->buffer,"assembled packet");
if (overlay_broadcast_ensemble(packet->i, &packet->dest, packet->buffer->bytes, packet->buffer->position)){
if (overlay_broadcast_ensemble(packet->i, &packet->dest, ob_ptr(packet->buffer), ob_position(packet->buffer))){
// sendto failed. We probably don't have a valid route
if (packet->unicast_subscriber){
set_reachable(packet->unicast_subscriber, REACHABLE_NONE);
}
}
}
}else
WARN("No payloads were sent?");
ob_free(packet->buffer);
overlay_address_clear();
RETURN(1);
}
RETURN(0);
@ -512,7 +540,7 @@ overlay_tick_interface(int i, time_ms_t now) {
// initialise the packet buffer
bzero(&packet, sizeof(struct outgoing_packet));
overlay_init_packet(&packet, &overlay_interfaces[i], 1);
overlay_init_packet(&packet, NULL, 0, &overlay_interfaces[i], overlay_interfaces[i].broadcast_address, 1);
/* Stuff more payloads from queues and send it */
overlay_fill_send_packet(&packet, now);

@ -193,16 +193,6 @@ overlay_node *get_node(struct subscriber *subscriber, int create){
return subscriber->node;
}
overlay_node *overlay_route_find_node(const unsigned char *sid, int prefixLen, int createP)
{
if (*sid==0){
INFOF("Sid %s/%d cannot ever become a node!", alloca_tohex_sid(sid), prefixLen);
return NULL;
}
return get_node(find_subscriber(sid, prefixLen, createP), createP);
}
int overlay_route_ack_selfannounce(struct overlay_frame *f,
unsigned int s1,unsigned int s2,
int interface,
@ -247,9 +237,11 @@ int overlay_route_ack_selfannounce(struct overlay_frame *f,
/* set source to ourselves */
out->source = my_subscriber;
/* Try to use broadcast if we don't have a route yet */
if (out->destination->reachable == REACHABLE_NONE)
set_reachable(out->destination, REACHABLE_BROADCAST);
/* Assume immediate neighbour via broadcast packet if we don't have a route yet */
if (out->destination->reachable == REACHABLE_NONE){
out->destination->interface=f->interface;
set_reachable(out->destination, REACHABLE_ASSUMED|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
@ -454,12 +446,15 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
int best_observation=-1;
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;
// TODO assumption timeout...
if (n->subscriber->reachable&REACHABLE_ASSUMED){
reachable=n->subscriber->reachable;
interface=n->subscriber->interface;
}
if (n->neighbour_id)
{
/* Node is also a direct neighbour, so check score that way */
@ -476,7 +471,7 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
{
best_score=neighbour->scores[i];
best_observation=-1;
reachable=REACHABLE_DIRECT;
reachable=REACHABLE_BROADCAST;
interface = &overlay_interfaces[i];
}
}
@ -485,7 +480,9 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
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)
// only count observations from neighbours that we *know* we have a 2 way path to
if (n->observations[o].observed_score && n->observations[o].sender->reachable&REACHABLE
&& !(n->observations[o].sender->reachable&REACHABLE_ASSUMED))
{
int discounted_score=n->observations[o].observed_score;
discounted_score-=(now-n->observations[o].rx_time)/1000;
@ -519,7 +516,7 @@ int overlay_route_recalc_node_metrics(overlay_node *n, time_ms_t now)
case REACHABLE_INDIRECT:
n->subscriber->next_hop = next_hop;
break;
case REACHABLE_DIRECT:
case REACHABLE_BROADCAST:
n->subscriber->interface = interface;
n->subscriber->address = interface->broadcast_address;
break;
@ -723,15 +720,15 @@ int overlay_route_saw_selfannounce_ack(struct overlay_frame *f,long long now)
/* if to and via are the same, then this is evidence that we can get to the
node directly. */
int overlay_route_record_link(time_ms_t now, unsigned char *to,
unsigned char *via,int sender_interface,
int overlay_route_record_link(time_ms_t now, struct subscriber *to,
struct subscriber *via,int sender_interface,
unsigned int s1,unsigned int s2,int score,
int gateways_en_route)
{
IN();
if (debug & DEBUG_OVERLAYROUTING)
DEBUGF("to=%s, via=%s, sender_interface=%d, s1=%d, s2=%d score=%d gateways_en_route=%d",
alloca_tohex_sid(to), alloca_tohex_sid(via), sender_interface, s1, s2,
alloca_tohex_sid(to->sid), alloca_tohex_sid(via->sid), sender_interface, s1, s2,
score, gateways_en_route
);
@ -741,14 +738,10 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
RETURN(0);
}
overlay_node *n = overlay_route_find_node(to, SID_SIZE, 1 /* create node if missing */);
overlay_node *n = get_node(to,1);
if (!n)
RETURN(WHY("Could not create entry for node"));
struct subscriber *sender = find_subscriber(via, SID_SIZE, 1);
if (!sender)
RETURN(WHY("Could not create subscriber"));
int slot = -1;
int i;
for (i = 0; i < OVERLAY_MAX_OBSERVATIONS; ++i) {
@ -757,7 +750,7 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
slot = i;
/* If the intermediate host ("via") address and interface numbers match, then overwrite old
observation with new one */
if (n->observations[i].sender == sender) {
if (n->observations[i].sender == via) {
slot = i;
break;
}
@ -783,7 +776,7 @@ int overlay_route_record_link(time_ms_t now, unsigned char *to,
n->observations[slot].observed_score=0;
n->observations[slot].gateways_en_route=gateways_en_route;
n->observations[slot].rx_time=now;
n->observations[slot].sender = sender;
n->observations[slot].sender = via;
n->observations[slot].observed_score=score;
n->observations[slot].interface=sender_interface;

@ -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.
*/
#include "serval.h"
int packetOk(struct overlay_interface *interface, unsigned char *packet, size_t len,
unsigned char *transaction_id,int ttl,
struct sockaddr *recvaddr, size_t recvaddrlen,int parseP)
{
if (len<HEADERFIELDS_LEN) return WHY("Packet is too short");
if (packet[0]==0x4F&&packet[1]==0x10)
{
if (interface!=NULL)
{
return packetOkOverlay(interface,packet,len,transaction_id,ttl,
recvaddr,recvaddrlen,parseP);
}
else
/* We ignore overlay mesh packets in simple server mode, which is indicated by interface==-1 */
return WHY("Ignoring overlay mesh packet");
}
return WHY("Packet type not recognised.");
}
void write_uint64(unsigned char *o,uint64_t v)
{
int i;
for(i=0;i<8;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
void write_uint32(unsigned char *o,uint32_t v)
{
int i;
for(i=0;i<4;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
void write_uint16(unsigned char *o,uint16_t v)
{
int i;
for(i=0;i<2;i++)
{ *(o++)=v&0xff; v=v>>8; }
}
uint64_t read_uint64(unsigned char *o)
{
int i;
uint64_t v=0;
for(i=0;i<8;i++) v=(v<<8)|o[8-1-i];
return v;
}
uint32_t read_uint32(unsigned char *o)
{
int i;
uint32_t v=0;
for(i=0;i<4;i++) v=(v<<8)|o[4-1-i];
return v;
}
uint16_t read_uint16(unsigned char *o)
{
int i;
uint16_t v=0;
for(i=0;i<2;i++) v=(v<<8)|o[2-1-i];
return v;
}

@ -511,7 +511,7 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
/* TODO We should stream file straight into the database */
slot->start_time=gettime_ms();
if (create_rhizome_import_dir() == -1)
goto bail;
return -1;
if (slot->manifest) {
slot->file_len=slot->manifest->fileLength;
slot->rowid=
@ -519,15 +519,27 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
slot->file_len,
RHIZOME_PRIORITY_DEFAULT);
if (slot->rowid<0) {
WHYF_perror("Could not obtain rowid for blob for file '%s'",
return WHYF_perror("Could not obtain rowid for blob for file '%s'",
alloca_tohex_sid(slot->bid));
goto bail;
}
} else {
slot->rowid=-1;
}
if (slot->peer_ipandport.sin_family == AF_INET) {
slot->request_ofs = 0;
slot->state = RHIZOME_FETCH_CONNECTING;
slot->file_len = -1;
slot->file_ofs = 0;
slot->blob_buffer_bytes = 0;
if (slot->blob_buffer) {
free(slot->blob_buffer);
slot->blob_buffer=NULL;
}
slot->blob_buffer_size=0;
SHA512_Init(&slot->sha512_context);
if (slot->peer_ipandport.sin_family == AF_INET && slot->peer_ipandport.sin_port) {
/* Transfer via HTTP over IPv4 */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
WHY_perror("socket");
@ -558,18 +570,6 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
buf, ntohs(slot->peer_ipandport.sin_port), alloca_str_toprint(slot->request)
);
slot->alarm.poll.fd = sock;
slot->request_ofs = 0;
slot->state = RHIZOME_FETCH_CONNECTING;
slot->file_len = -1;
slot->file_ofs = 0;
slot->blob_buffer_bytes = 0;
if (slot->blob_buffer) {
free(slot->blob_buffer);
slot->blob_buffer=NULL;
}
slot->blob_buffer_size=0;
SHA512_Init(&slot->sha512_context);
/* Watch for activity on the socket */
slot->alarm.function = rhizome_fetch_poll;
fetch_stats.name = "rhizome_fetch_poll";
@ -580,7 +580,6 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
unschedule(&slot->alarm);
slot->alarm.alarm = gettime_ms() + RHIZOME_IDLE_TIMEOUT;
slot->alarm.deadline = slot->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
slot->alarm.function-rhizome_fetch_poll;
schedule(&slot->alarm);
return 0;
}
@ -588,15 +587,9 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
bail_http:
/* Fetch via overlay, either because no IP address was provided, or because
the connection/attempt to fetch via HTTP failed. */
WHY("Rhizome fetching via overlay not implemented");
slot->state=RHIZOME_FETCH_RXFILEMDP;
rhizome_fetch_switch_to_mdp(slot);
return 0;
bail:
if (sock != -1)
close(sock);
return -1;
}
/* Start fetching a bundle's payload ready for importing.
@ -1015,8 +1008,10 @@ static int rhizome_fetch_close(struct rhizome_fetch_slot *slot)
/* close socket and stop watching it */
unschedule(&slot->alarm);
unwatch(&slot->alarm);
close(slot->alarm.poll.fd);
if (slot->alarm.poll.fd>=0){
unwatch(&slot->alarm);
close(slot->alarm.poll.fd);
}
slot->alarm.poll.fd = -1;
slot->alarm.function=NULL;
@ -1067,6 +1062,7 @@ static void rhizome_fetch_mdp_slot_callback(struct sched_ent *alarm)
static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
{
IN();
// only issue new requests every 133ms.
// we automatically re-issue once we have received all packets in this
// request also, so if there is no packet loss, we can go substantially
@ -1084,13 +1080,13 @@ static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
mdp.packetTypeAndFlags=MDP_TX;
mdp.out.queue=OQ_ORDINARY;
mdp.out.payload_length=RHIZOME_BAR_BYTES+8+8+4+2;
mdp.out.payload_length=RHIZOME_MANIFEST_ID_BYTES+8+8+4+2;
bcopy(slot->bid,&mdp.out.payload[0],RHIZOME_MANIFEST_ID_BYTES);
write_uint64(&mdp.out.payload[RHIZOME_BAR_BYTES],slot->bidVersion);
write_uint64(&mdp.out.payload[RHIZOME_BAR_BYTES+8],slot->file_ofs);
write_uint32(&mdp.out.payload[RHIZOME_BAR_BYTES+8+8],slot->mdpRXBitmap);
write_uint16(&mdp.out.payload[RHIZOME_BAR_BYTES+8+8+4],slot->mdpRXBlockLength);
write_uint64(&mdp.out.payload[RHIZOME_MANIFEST_ID_BYTES],slot->bidVersion);
write_uint64(&mdp.out.payload[RHIZOME_MANIFEST_ID_BYTES+8],slot->file_ofs);
write_uint32(&mdp.out.payload[RHIZOME_MANIFEST_ID_BYTES+8+8],slot->mdpRXBitmap);
write_uint16(&mdp.out.payload[RHIZOME_MANIFEST_ID_BYTES+8+8+4],slot->mdpRXBlockLength);
if (0)
DEBUGF("src sid=%s, dst sid=%s, mdpRXWindowStart=0x%x",
@ -1110,7 +1106,7 @@ static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
slot->alarm.deadline=slot->alarm.alarm+500;
schedule(&slot->alarm);
return 0;
RETURN(0);
}
static int rhizome_fetch_mdp_requestmanifest(struct rhizome_fetch_slot *slot)
@ -1173,12 +1169,12 @@ static int rhizome_fetch_switch_to_mdp(struct rhizome_fetch_slot *slot)
DEBUGF("Trying to switch to MDP for Rhizome fetch: slot=0x%p",slot);
/* close socket and stop watching it */
unwatch(&slot->alarm);
unschedule(&slot->alarm);
if (slot->alarm.poll.fd!=-1) {
if (slot->alarm.poll.fd>=0) {
unwatch(&slot->alarm);
close(slot->alarm.poll.fd);
slot->alarm.poll.fd = -1;
}
unschedule(&slot->alarm);
/* Begin MDP fetch process.
1. Send initial request.
@ -1206,7 +1202,7 @@ static int rhizome_fetch_switch_to_mdp(struct rhizome_fetch_slot *slot)
slot->mdpIdleTimeout=5000; // give up if nothing received for 5 seconds
slot->mdpRXBitmap=0x00000000; // no blocks received yet
slot->mdpRXBlockLength=1024; // 200;
slot->mdpRXBlockLength=1024;
rhizome_fetch_mdp_requestblocks(slot);
} else {
/* We are requesting a manifest, which is stateless, except that we eventually
@ -1276,6 +1272,7 @@ int rhizome_fetch_flush_blob_buffer(struct rhizome_fetch_slot *slot)
int rhizome_write_content(struct rhizome_fetch_slot *slot, char *buffer, int bytes)
{
IN();
// Truncate to known length of file (handy for reading from journal bundles that
// might grow while we are reading from them).
if (bytes>(slot->file_len-slot->file_ofs))
@ -1330,8 +1327,8 @@ int rhizome_write_content(struct rhizome_fetch_slot *slot, char *buffer, int byt
slot->last_write_time=gettime_ms();
if (slot->file_ofs>=slot->file_len) {
/* got all of file */
// if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Received all of file via rhizome -- now to import it");
if (debug & DEBUG_RHIZOME_RX)
DEBUGF("Received all of file via rhizome -- now to import it");
if (slot->manifest) {
// Were fetching payload, now we have it.
@ -1351,7 +1348,7 @@ int rhizome_write_content(struct rhizome_fetch_slot *slot, char *buffer, int byt
"DELETE FROM FILES WHERE id='%s'",
slot->manifest->fileHexHash);
rhizome_fetch_close(slot);
return -1;
RETURN(-1);
} else {
INFOF("Updating row status: UPDATE FILES SET datavalid=1 WHERE id='%s'",
slot->manifest->fileHexHash);
@ -1408,11 +1405,11 @@ int rhizome_write_content(struct rhizome_fetch_slot *slot, char *buffer, int byt
(long long)slot->file_ofs/(gettime_ms()-slot->start_time),
slot->blob_buffer_size);
rhizome_fetch_close(slot);
return -1;
RETURN(-1);
}
// slot is still open
return 0;
RETURN(0);
}
int rhizome_received_content(unsigned char *bidprefix,
@ -1424,7 +1421,7 @@ int rhizome_received_content(unsigned char *bidprefix,
for(i=0;i<NQUEUES;i++) {
struct rhizome_fetch_slot *slot=&rhizome_fetch_queues[i].active;
if (slot->state==RHIZOME_FETCH_RXFILEMDP&&slot->bidP) {
if (!bcmp(slot->bid,bidprefix,16))
if (!memcmp(slot->bid,bidprefix,16))
{
if (slot->file_ofs==offset) {
if (!rhizome_write_content(slot,(char *)bytes,count))
@ -1446,11 +1443,6 @@ int rhizome_received_content(unsigned char *bidprefix,
}
RETURN(0);
}
else
if (0)
DEBUGF("Doesn't match this slot = 0x%p, because BIDs don't match: %s* vs %s",
alloca_tohex(bidprefix,16),
alloca_tohex_bid(rhizome_fetch_queues[i].active.bid));
}
}

@ -134,7 +134,7 @@ unsigned long long rhizome_bar_bidprefix_ll(unsigned char *bar)
int bundles_available=-1;
int bundle_offset[2]={0,0};
int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buffer *e)
int overlay_rhizome_add_advertisements(struct decode_context *context, int interface_number, struct overlay_buffer *e)
{
IN();
@ -157,31 +157,9 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
if (slots<1) { RETURN(WHY("No room for node advertisements")); }
if (ob_append_byte(e,OF_TYPE_RHIZOME_ADVERT))
RETURN(WHY("could not add rhizome bundle advertisement header"));
ob_append_byte(e, 1); /* TTL (1 byte) */
ob_append_rfs(e,1+11+1+2+RHIZOME_BAR_BYTES/* RFS */);
/* Stuff in dummy address fields (11 bytes) */
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_self(&overlay_interfaces[interface_number], e);
/* Randomly choose whether to advertise manifests or BARs first. */
int skipmanifests=random()&1;
/* Version of rhizome advert block (1 byte):
1 = manifests then BARs,
2 = BARs only,
3 = HTTP port then manifests then BARs,
4 = HTTP port then BARs only
*/
ob_append_byte(e,3+skipmanifests);
/* Rhizome HTTP server port number (2 bytes) */
ob_append_ui16(e, rhizome_http_server_port);
/* XXX Should add priority bundles here.
XXX Should prioritise bundles for subscribed groups, Serval-authorised files
etc over common bundles.
@ -218,6 +196,32 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
sqlite3_stmt *statement=NULL;
sqlite3_blob *blob=NULL;
ob_checkpoint(e);
if (overlay_frame_build_header(context, e,
0, OF_TYPE_RHIZOME_ADVERT, 0, 1,
NULL, NULL,
NULL, my_subscriber)){
ob_rewind(e);
return -1;
}
/* Version of rhizome advert block (1 byte):
1 = manifests then BARs,
2 = BARs only,
3 = HTTP port then manifests then BARs,
4 = HTTP port then BARs only
*/
if (ob_append_byte(e,3+skipmanifests)){
ob_rewind(e);
return -1;
}
/* Rhizome HTTP server port number (2 bytes) */
if (ob_append_ui16(e, rhizome_http_server_port)){
ob_rewind(e);
return -1;
}
for(pass=skipmanifests;pass<2;pass++) {
ob_checkpoint(e);
switch(pass) {
@ -230,8 +234,10 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
}
if (!statement) {
sqlite_set_debugmask(oldmask);
RETURN(WHY("Could not prepare sql statement for fetching BARs for advertisement"));
WHY("Could not prepare sql statement for fetching BARs for advertisement");
goto stopStuffing;
}
while( sqlite_step_retry(&retry, statement) == SQLITE_ROW
&& e->position+RHIZOME_BAR_BYTES<=e->sizeLimit
) {
@ -320,7 +326,7 @@ int overlay_rhizome_add_advertisements(int interface_number, struct overlay_buff
}
}
ob_patch_rfs(e, COMPUTE_RFS_LENGTH);
ob_patch_rfs(e);
sqlite_set_debugmask(oldmask);
RETURN(0);
@ -334,7 +340,7 @@ int overlay_rhizome_saw_advertisements(int i, struct overlay_frame *f, long long
if (!rhizome_db) { RETURN(0); }
int ad_frame_type=ob_get(f->payload);
struct sockaddr_in httpaddr = *(struct sockaddr_in *)f->recvaddr;
struct sockaddr_in httpaddr = f->recvaddr;
httpaddr.sin_port = htons(RHIZOME_HTTP_PORT);
int manifest_length;
rhizome_manifest *m=NULL;

@ -330,6 +330,7 @@ struct sched_ent{
struct overlay_buffer;
struct overlay_frame;
struct broadcast;
#define STRUCT_SCHED_ENT_UNUSED ((struct sched_ent){NULL, NULL, NULL, NULL, {-1, 0, 0}, 0LL, 0LL, NULL, -1})
@ -379,6 +380,8 @@ typedef struct overlay_interface {
struct sockaddr_in address;
struct sockaddr_in broadcast_address;
struct in_addr netmask;
// can we use this interface for routes to addresses in other subnets?
int default_route;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX on this interface.
For radio links the actual maximum and the maximum that is likely to be delivered reliably are
@ -427,14 +430,9 @@ void serverCleanUp();
int isTransactionInCache(unsigned char *transaction_id);
void insertTransactionInCache(unsigned char *transaction_id);
int packetOk(struct overlay_interface *interface,unsigned char *packet, size_t 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);
int recvttl, struct sockaddr *recvaddr, size_t recvaddrlen);
int overlay_frame_process(struct overlay_interface *interface, struct overlay_frame *f);
int overlay_frame_resolve_addresses(struct overlay_frame *f);
@ -445,10 +443,17 @@ int overlay_frame_resolve_addresses(struct overlay_frame *f);
time_ms_t overlay_time_until_next_tick();
int overlay_add_selfannouncement();
int overlay_frame_append_payload(overlay_interface *interface, struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b);
int overlay_add_selfannouncement(struct decode_context *context, int interface,struct overlay_buffer *b);
int overlay_frame_append_payload(struct decode_context *context, overlay_interface *interface,
struct overlay_frame *p, struct overlay_buffer *b);
int overlay_packet_init_header(struct decode_context *context, struct overlay_buffer *buff,
struct subscriber *destination, int flags);
int overlay_frame_build_header(struct decode_context *context, struct overlay_buffer *buff,
int queue, int type, int modifiers, int ttl,
struct broadcast *broadcast, struct subscriber *next_hop,
struct subscriber *destination, struct subscriber *source);
int overlay_interface_args(const char *arg);
int overlay_rhizome_add_advertisements(int interface_number,struct overlay_buffer *e);
int overlay_rhizome_add_advertisements(struct decode_context *context, int interface_number, struct overlay_buffer *e);
int overlay_add_local_identity(unsigned char *s);
extern int overlay_interface_count;
@ -492,11 +497,11 @@ overlay_node *overlay_route_find_node(const unsigned char *sid,int prefixLen,int
int overlayServerMode();
int overlay_payload_enqueue(struct overlay_frame *p);
int overlay_route_record_link( time_ms_t now,unsigned char *to,
unsigned char *via,int sender_interface,
int overlay_route_record_link( time_ms_t now, struct subscriber *to,
struct subscriber *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(overlay_interface *interface, struct overlay_buffer *e);
int overlay_route_add_advertisements(struct decode_context *context, overlay_interface *interface, struct overlay_buffer *e);
int ovleray_route_please_advertise(overlay_node *n);
int overlay_route_saw_advertisements(int i, struct overlay_frame *f, struct decode_context *context, time_ms_t now);
@ -589,10 +594,9 @@ int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
overlay_mdp_frame *mdpreply);
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
struct sockaddr_un *recvaddr,int recvaddlen);
int overlay_mdp_encode_ports(struct overlay_buffer *plaintext, int dst_port, int src_port);
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(struct overlay_frame *p, char *message);
int urandombytes(unsigned char *x,unsigned long long xlen);
#ifdef MALLOC_PARANOIA
@ -613,15 +617,13 @@ int is_codec_set(int codec, unsigned char *flags);
struct vomp_call_state *vomp_find_call_by_session(int session_token);
int vomp_mdp_received(overlay_mdp_frame *mdp);
int vomp_tick_interval();
int vomp_sample_size(int c);
int vomp_codec_timespan(int c);
int vomp_parse_dtmf_digit(char c);
int vomp_dial(unsigned char *local_sid, unsigned char *remote_sid, const char *local_did, const char *remote_did);
int vomp_pickup(struct vomp_call_state *call);
int vomp_hangup(struct vomp_call_state *call);
int vomp_ringing(struct vomp_call_state *call);
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length);
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, int time, int sequence,
const unsigned char *audio, int audio_length);
void monitor_get_all_supported_codecs(unsigned char *codecs);
int cli_putchar(char c);
@ -733,6 +735,7 @@ void overlay_route_tick(struct sched_ent *alarm);
void server_shutdown_check(struct sched_ent *alarm);
void overlay_mdp_poll(struct sched_ent *alarm);
int overlay_mdp_try_interal_services(overlay_mdp_frame *mdp);
int overlay_send_probe(struct subscriber *peer, struct sockaddr_in addr, overlay_interface *interface);
void fd_periodicstats(struct sched_ent *alarm);
void rhizome_check_connections(struct sched_ent *alarm);

@ -1,7 +1,6 @@
SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \
$(SERVAL_BASE)audio_reflector.c \
$(SERVAL_BASE)cli.c \
$(SERVAL_BASE)codecs.c \
$(SERVAL_BASE)commandline.c \
$(SERVAL_BASE)conf.c \
$(SERVAL_BASE)crypto.c \
@ -33,7 +32,6 @@ SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \
$(SERVAL_BASE)overlay_packetformats.c \
$(SERVAL_BASE)overlay_payload.c \
$(SERVAL_BASE)overlay_route.c \
$(SERVAL_BASE)packetformats.c \
$(SERVAL_BASE)performance_timing.c \
$(SERVAL_BASE)randombytes.c \
$(SERVAL_BASE)rhizome.c \

@ -279,6 +279,7 @@ start_servald_server() {
new_pids="$new_pids $apid"
fi
done
eval LOG$instance_name=$instance_servald_log
assert --message="a new servald process is running" --dump-on-fail="$instance_servald_log" [ -n "$new_pids" ]
assert --message="servald pidfile process is running" --dump-on-fail="$instance_servald_log" $pidfile_running
assert --message="servald log file $instance_servald_log is present" [ -r "$instance_servald_log" ]
@ -642,7 +643,6 @@ start_servald_instances() {
configure_servald_server
start_servald_server
eval DUMMY$instance_name="\$DUMMYNET"
eval LOG$instance_name="\$(shellarg "\$instance_servald_log")"
done
# Now wait until they see each other.
wait_until --sleep=0.25 instances_see_each_other "$@"

@ -29,13 +29,12 @@ configure_servald_server() {
setup() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C create_single_identity
foreach_instance +A +B +C +D create_single_identity
set_instance +D
executeOk_servald set did $SIDD $DIDC "Agent D Smith"
DIDD1=$DIDC
NAMED1="Agent D Smith"
create_identities 1
SIDD=$SIDD1
DIDD=$DIDD1
DIDD=$DIDC1
NAMED=$NAMED1
set_instance +A
executeOk_servald config set dna.helper.executable "$servald_build_root/directory_service"
@ -51,19 +50,25 @@ teardown() {
}
is_published() {
grep "PUBLISHED" $LOGA || return 1
tfw_log "grep \"PUBLISHED.*$1\" $LOGA"
grep "PUBLISHED.*$1" $LOGA || return 1
return 0
}
sent_directory_request() {
grep "Sending directory registration" $LOGD || return 1
tfw_log "grep \"Sending directory registration\" $1"
grep "Sending directory registration" $1 || return 1
return 0
}
doc_publish="Publish and retrieve a directory entry"
test_publish() {
wait_until sent_directory_request
wait_until is_published
wait_until sent_directory_request $LOGB
wait_until sent_directory_request $LOGC
wait_until sent_directory_request $LOGD
wait_until is_published $SIDB
wait_until is_published $SIDC
wait_until is_published $SIDD
stop_servald_server +B
stop_servald_server +C
stop_servald_server +D
@ -101,25 +106,27 @@ setup_routing() {
executeOk_servald config set mdp.dummyC.tick_ms 0
executeOk_servald config set dna.helper.executable "$servald_build_root/directory_service"
executeOk_servald config set debug.dnahelper on
start_routing_instance
set_instance +B
executeOk_servald config set interfaces "+>dummyB"
executeOk_servald config set mdp.dummyB.tick_ms 0
executeOk_servald config set directory.service $SIDA
executeOk_servald config set $SIDA.interface "dummyB"
executeOk_servald config set $SIDA.address 127.0.0.1
start_routing_instance
set_instance +C
executeOk_servald config set interfaces "+>dummyC"
executeOk_servald config set mdp.dummyC.tick_ms 0
executeOk_servald config set directory.service $SIDA
executeOk_servald config set $SIDA.interface "dummyC"
executeOk_servald config set $SIDA.address 127.0.0.1
start_routing_instance
foreach_instance +A +B +C start_routing_instance
}
doc_routing="Ping via relay node"
test_routing() {
wait_until sent_directory_request $LOGB
wait_until sent_directory_request $LOGC
wait_until is_published $SIDB
wait_until is_published $SIDC
set_instance +B
executeOk_servald dna lookup "$DIDC"
assertStdoutLineCount '==' 1

@ -43,23 +43,50 @@ start_routing_instance() {
start_servald_server
}
log_routing_table() {
executeOk_servald route print
tfw_cat --stdout --stderr
}
teardown() {
foreach_instance_with_pidfile log_routing_table
stop_all_servald_servers
kill_all_servald_processes
assert_no_servald_processes
report_all_servald_servers
}
setup_single_link() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
start_servald_instances +A +B
foreach_instance +A +B add_interface dummy1
foreach_instance +A +B start_routing_instance
}
doc_single_link="Start 2 instances on one link"
test_single_link() {
set_instance +A
executeOk_servald mdp ping $SIDB 3
executeOk_servald mdp ping $SIDB 10
tfw_cat --stdout --stderr
}
setup_multiple_nodes() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B +C +D add_interface dummy1
foreach_instance +A +B +C +D start_routing_instance
}
doc_multiple_nodes="Multiple nodes on one link"
test_multiple_nodes() {
set_instance +A
executeOk_servald mdp ping $SIDB 10
tfw_cat --stdout --stderr
executeOk_servald mdp ping $SIDC 3
tfw_cat --stdout --stderr
executeOk_servald mdp ping $SIDD 3
tfw_cat --stdout --stderr
}
@ -75,9 +102,8 @@ setup_multihop_linear() {
doc_multihop_linear="Start 4 instances in a linear arrangement"
test_multihop_linear() {
wait_until --sleep=0.25 instances_see_each_other +A +B +C +D
set_instance +A
executeOk_servald mdp ping $SIDD 3
executeOk_servald mdp ping $SIDD 10
tfw_cat --stdout --stderr
}
@ -99,7 +125,7 @@ setup_crowded_mess() {
doc_crowded_mess="Multiple possible paths"
test_crowded_mess() {
set_instance +A
executeOk_servald mdp ping $SIDH 5
executeOk_servald mdp ping $SIDH 10
tfw_cat --stdout --stderr
}

435
vomp.c

@ -124,16 +124,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define VOMP_STATE_INCALL 5
#define VOMP_STATE_CALLENDED 6
#define VOMP_REJECT_HANGUP 0
#define VOMP_REJECT_NOPHONE 1
#define VOMP_REJECT_NOCODEC 2
#define VOMP_REJECT_BUSY 3
#define VOMP_REJECT_TIMEOUT 4
#define VOMP_SESSION_MASK 0xffffff
#define VOMP_SESSION_MASK 0xffff
#define VOMP_MAX_CALLS 16
#define VOMP_VERSION 0x02
struct vomp_call_half {
unsigned char sid[SID_SIZE];
char did[64];
unsigned char state;
unsigned char codec;
unsigned int session;
unsigned int sequence;
};
@ -154,6 +159,8 @@ struct jitter_measurements{
int sample_count;
};
#define SEEN_SAMPLES 16
struct vomp_call_state {
struct sched_ent alarm;
struct vomp_call_half local;
@ -162,18 +169,13 @@ struct vomp_call_state {
time_ms_t create_time;
time_ms_t last_activity;
time_ms_t audio_clock;
int remote_audio_clock;
// last local & remote status we sent to all interested parties
int last_sent_status;
int rejection_reason;
unsigned char remote_codec_flags[CODEC_FLAGS_LENGTH];
struct jitter_measurements jitter;
// track when we first heard audio, so we can calculate timing from the current sequence number
int first_remote_audio_sequence;
// simple ring buffer of audio sample times, used to drop duplicate incoming frames
// stores end times, since this is an odd number we can initialise the buffer to zero's
int sample_pos;
unsigned int seen_samples[VOMP_MAX_RECENT_SAMPLES *4];
};
/* Some clients may only support one call at a time, even then we allow for multiple call states.
@ -181,17 +183,65 @@ struct vomp_call_state {
the ejection of newly allocated session numbers before the caller has had a chance
to progress the call to a further state. */
int vomp_call_count=0;
// TODO allocate call structures dynamically
struct vomp_call_state vomp_call_states[VOMP_MAX_CALLS];
struct profile_total vomp_stats;
static void vomp_process_tick(struct sched_ent *alarm);
static const char *vomp_describe_codec(int c);
strbuf strbuf_append_vomp_supported_codecs(strbuf sb, const unsigned char supported_codecs[256]);
void store_jitter_sample(struct jitter_measurements *measurements, int sample_clock, int local_clock){
static int vomp_codec_timespan(int c, int data_size)
{
switch(c) {
case VOMP_CODEC_16SIGNED: return data_size/16;
case VOMP_CODEC_ULAW: return data_size/8;
case VOMP_CODEC_ALAW: return data_size/8;
}
return -1;
}
int vomp_parse_dtmf_digit(char c)
{
if (c>='0'&&c<='9') return c-0x30;
switch (c) {
case 'a': case 'A': return 0xa;
case 'b': case 'B': return 0xb;
case 'c': case 'C': return 0xc;
case 'd': case 'D': return 0xd;
case '*': return 0xe;
case '#': return 0xf;
}
return -1;
}
char vomp_dtmf_digit_to_char(int digit)
{
if (digit<0) return '?';
if (digit<10) return '0'+digit;
if (digit<0xe) return 'A'+digit-0xa;
if (digit==0xe) return '*';
if (digit==0xf) return '#';
return '?';
}
static int store_jitter_sample(struct jitter_measurements *measurements, int sample_clock, int local_clock){
IN();
int i;
int i, count=0;
// have a quick look through recent samples, drop if already seen
if (measurements->sample_count>0){
i=measurements->next_sample -1;
while(count<SEEN_SAMPLES && count<=measurements->sample_count){
if (i<0)
i=measurements->sample_count -1;
if (measurements->samples[i].sample_clock == sample_clock)
RETURN(-1);
i--;
count++;
}
}
struct jitter_sample *sample = &measurements->samples[measurements->next_sample];
measurements->next_sample++;
@ -246,17 +296,19 @@ void store_jitter_sample(struct jitter_measurements *measurements, int sample_cl
if (sample_clock > measurements->max_sample_clock)
measurements->max_sample_clock=sample_clock;
OUT();
RETURN(0);
}
int get_jitter_size(struct jitter_measurements *measurements){
static int get_jitter_size(struct jitter_measurements *measurements){
IN();
int i=JITTER_SAMPLES -4;
int jitter;
if (i>=measurements->sample_count)
i=measurements->sample_count -1;
jitter=measurements->sorted_samples[i]->delta - measurements->sorted_samples[0]->delta;
do{
jitter=measurements->sorted_samples[i]->delta - measurements->sorted_samples[0]->delta;
i--;
}while(jitter > 1500);
RETURN(jitter);
}
@ -281,7 +333,7 @@ struct vomp_call_state *vomp_find_call_by_session(int session_token)
return NULL;
}
int vomp_generate_session_id()
static int vomp_generate_session_id()
{
int session_id=0;
while (!session_id)
@ -302,7 +354,7 @@ int vomp_generate_session_id()
return session_id;
}
struct vomp_call_state *vomp_create_call(unsigned char *remote_sid,
static struct vomp_call_state *vomp_create_call(unsigned char *remote_sid,
unsigned char *local_sid,
unsigned int remote_session,
unsigned int local_session)
@ -335,7 +387,7 @@ struct vomp_call_state *vomp_create_call(unsigned char *remote_sid,
return call;
}
struct vomp_call_state *vomp_find_or_create_call(unsigned char *remote_sid,
static struct vomp_call_state *vomp_find_or_create_call(unsigned char *remote_sid,
unsigned char *local_sid,
unsigned int sender_session,
unsigned int recvr_session,
@ -390,14 +442,17 @@ struct vomp_call_state *vomp_find_or_create_call(unsigned char *remote_sid,
return call;
}
/* Don't create a call record if either party has ended it */
if (sender_state==VOMP_STATE_CALLENDED || recvr_state==VOMP_STATE_CALLENDED)
/* Don't create a call record if either party has already ended it */
if (sender_state==VOMP_STATE_CALLENDED || recvr_state==VOMP_STATE_CALLENDED){
WHYF("Not creating a call record when the call has already ended");
return NULL;
}
/* Only create a call record if either party is in CALLPREP state */
if (sender_state==VOMP_STATE_CALLPREP || recvr_state==VOMP_STATE_CALLPREP)
/* Only create a call record if the remote party is trying to prepare a call */
if (sender_state==VOMP_STATE_CALLPREP && recvr_state==VOMP_STATE_NOCALL && recvr_session==0)
return vomp_create_call(remote_sid, local_sid, sender_session, recvr_session);
WHYF("Not creating a call record for state %d %d", sender_state, recvr_state);
return NULL;
}
@ -408,29 +463,19 @@ static void prepare_vomp_header(struct vomp_call_state *call, overlay_mdp_frame
bcopy(call->remote.sid,mdp->out.dst.sid,SID_SIZE);
mdp->out.dst.port=MDP_PORT_VOMP;
mdp->out.payload[0]=0x01; /* Normal VoMP frame */
mdp->out.payload[1]=(call->remote.state<<4)|call->local.state;
mdp->out.payload[2]=(call->remote.sequence>>8)&0xff;
mdp->out.payload[3]=(call->remote.sequence>>0)&0xff;
mdp->out.payload[4]=(call->local.sequence>>8)&0xff;
mdp->out.payload[5]=(call->local.sequence>>0)&0xff;
time_ms_t call_millis = gettime_ms() - call->create_time;
mdp->out.payload[6]=(call_millis>>8)&0xff;
mdp->out.payload[7]=(call_millis>>0)&0xff;
mdp->out.payload[8]=(call->remote.session>>16)&0xff;
mdp->out.payload[9]=(call->remote.session>>8)&0xff;
mdp->out.payload[10]=(call->remote.session>>0)&0xff;
mdp->out.payload[11]=(call->local.session>>16)&0xff;
mdp->out.payload[12]=(call->local.session>>8)&0xff;
mdp->out.payload[13]=(call->local.session>>0)&0xff;
mdp->out.payload_length=14;
mdp->out.payload[0]=VOMP_VERSION;
mdp->out.payload[1]=(call->local.session>>8)&0xff;
mdp->out.payload[2]=(call->local.session>>0)&0xff;
mdp->out.payload[3]=(call->remote.session>>8)&0xff;
mdp->out.payload[4]=(call->remote.session>>0)&0xff;
mdp->out.payload[5]=(call->remote.state<<4)|call->local.state;
mdp->out.payload_length=6;
}
/* send updated call status to end-point and to any interested listeners as
appropriate */
int vomp_send_status_remote(struct vomp_call_state *call)
static int vomp_send_status_remote(struct vomp_call_state *call)
{
overlay_mdp_frame mdp;
unsigned short *len=&mdp.out.payload_length;
@ -449,8 +494,6 @@ int vomp_send_status_remote(struct vomp_call_state *call)
for (i = 0; i < 256; ++i)
if (is_codec_set(i,codecs)) {
mdp.out.payload[(*len)++]=i;
if (debug & DEBUG_VOMP)
DEBUGF("I support the %s codec", vomp_describe_codec(i));
}
mdp.out.payload[(*len)++]=0;
@ -474,56 +517,46 @@ int vomp_send_status_remote(struct vomp_call_state *call)
return 0;
}
// copy audio into the rotor buffers
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length)
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, int time, int sequence,
const unsigned char *audio, int audio_length)
{
if (call->local.state!=VOMP_STATE_INCALL)
return -1;
int codec_block_size=vomp_sample_size(audio_codec);
int offset=0;
int codec_duration = vomp_codec_timespan(audio_codec);
while(offset<audio_length){
overlay_mdp_frame mdp;
unsigned short *len=&mdp.out.payload_length;
bzero(&mdp,sizeof(mdp));
prepare_vomp_header(call, &mdp);
/*
Note that in-call slew is the responsibility of the player, not the
recorder of audio. Basically if the audio queue starts to bank up,
then the player needs to drop samples.
*/
mdp.out.payload[(*len)++]=(call->audio_clock>>24)&0xff;
mdp.out.payload[(*len)++]=(call->audio_clock>>16)&0xff;
mdp.out.payload[(*len)++]=(call->audio_clock>>8)&0xff;
mdp.out.payload[(*len)++]=(call->audio_clock>>0)&0xff;
mdp.out.payload[(*len)++]=audio_codec;
if (offset+codec_block_size>audio_length)
codec_block_size = audio_length - offset;
bcopy(audio+offset,&mdp.out.payload[(*len)],codec_block_size);
(*len)+=codec_block_size;
offset+=codec_block_size;
call->audio_clock += codec_duration;
call->local.sequence++;
// send the payload more than once to add resilience to dropped packets
// TODO remove once network links have built in retries
mdp.out.send_copies=VOMP_MAX_RECENT_SAMPLES;
overlay_mdp_dispatch(&mdp,0,NULL,0);
// note we assume the caller will be consistent about providing time and sequence info
if (time==-1){
time = call->audio_clock;
call->audio_clock+=vomp_codec_timespan(audio_codec, audio_length);
}
if (sequence==-1)
sequence = call->local.sequence++;
overlay_mdp_frame mdp;
unsigned short *len=&mdp.out.payload_length;
bzero(&mdp,sizeof(mdp));
prepare_vomp_header(call, &mdp);
mdp.out.payload[(*len)++]=audio_codec;
time = time / 20;
mdp.out.payload[(*len)++]=(time>>8)&0xff;
mdp.out.payload[(*len)++]=(time>>0)&0xff;
mdp.out.payload[(*len)++]=(sequence>>8)&0xff;
mdp.out.payload[(*len)++]=(sequence>>0)&0xff;
bcopy(audio,&mdp.out.payload[(*len)],audio_length);
(*len)+=audio_length;
// send the payload more than once to add resilience to dropped packets
// TODO remove once network links have built in retries
mdp.out.send_copies=VOMP_MAX_RECENT_SAMPLES;
overlay_mdp_dispatch(&mdp,0,NULL,0);
return 0;
}
int monitor_call_status(struct vomp_call_state *call)
static int monitor_call_status(struct vomp_call_state *call)
{
char msg[1024];
int n = snprintf(msg,1024,"\nCALLSTATUS:%06x:%06x:%d:%d:%d:%s:%s:%s:%s\n",
@ -538,11 +571,11 @@ int monitor_call_status(struct vomp_call_state *call)
return 0;
}
int monitor_send_audio(struct vomp_call_state *call, int audio_codec, unsigned int start_time, unsigned int end_time, const unsigned char *audio, int audio_length, int sequence)
static int monitor_send_audio(struct vomp_call_state *call, int audio_codec, int time, int sequence,
const unsigned char *audio, int audio_length)
{
if (0) DEBUGF("Tell call monitor about audio for call %06x:%06x",
call->local.session,call->remote.session);
int sample_bytes=vomp_sample_size(audio_codec);
char msg[1024 + MAX_AUDIO_BYTES];
/* All commands followed by binary data start with *len:, so that
they can be easily parsed at the far end, even if not supported.
@ -552,21 +585,21 @@ int monitor_send_audio(struct vomp_call_state *call, int audio_codec, unsigned i
int jitter_delay = get_jitter_size(&call->jitter);
int msglen = snprintf(msg, 1024,
"\n*%d:AUDIOPACKET:%x:%d:%d:%d:%d:%d\n",
sample_bytes,
"\n*%d:AUDIO:%x:%d:%d:%d:%d\n",
audio_length,
call->local.session,
audio_codec, start_time, end_time,
sequence, jitter_delay);
audio_codec, time, sequence,
jitter_delay);
bcopy(audio, &msg[msglen], sample_bytes);
msglen+=sample_bytes;
bcopy(audio, &msg[msglen], audio_length);
msglen+=audio_length;
msg[msglen++]='\n';
monitor_tell_clients(msg, msglen, MONITOR_VOMP);
return 0;
}
// update local state and notify interested clients with the correct message
int vomp_update_local_state(struct vomp_call_state *call, int new_state){
static int vomp_update_local_state(struct vomp_call_state *call, int new_state){
if (call->local.state>=new_state)
return 0;
@ -606,7 +639,7 @@ int vomp_update_local_state(struct vomp_call_state *call, int new_state){
}
// update remote state and notify interested clients with the correct message
int vomp_update_remote_state(struct vomp_call_state *call, int new_state){
static int vomp_update_remote_state(struct vomp_call_state *call, int new_state){
if (call->remote.state>=new_state)
return 0;
@ -632,7 +665,7 @@ int vomp_update_remote_state(struct vomp_call_state *call, int new_state){
}
// send call state updates if required.
int vomp_update(struct vomp_call_state *call)
static int vomp_update(struct vomp_call_state *call)
{
int combined_status=(call->remote.state<<4)|call->local.state;
@ -654,58 +687,48 @@ int vomp_update(struct vomp_call_state *call)
return 0;
}
// check a small circular buffer of recently seen audio
// we're not trying to be perfect here, we still expect all clients to reorder and filter duplicates
int vomp_audio_already_seen(struct vomp_call_state *call, unsigned int end_time)
{
int i;
for(i=0;i<VOMP_MAX_RECENT_SAMPLES *4;i++)
if (call->seen_samples[i]==end_time)
return 1;
call->seen_samples[call->sample_pos]=end_time;
call->sample_pos++;
if (call->sample_pos>=VOMP_MAX_RECENT_SAMPLES *4)
call->sample_pos=0;
return 0;
static int to_absolute_value(int short_value, int reference_value){
short_value = (reference_value & 0xFFFF0000) | short_value;
if (short_value + 0x8000 < reference_value)
short_value+=0x10000;
if (short_value > reference_value + 0x8000)
short_value-=0x10000;
return short_value;
}
int vomp_process_audio(struct vomp_call_state *call,unsigned int sender_duration,overlay_mdp_frame *mdp,time_ms_t now)
static int vomp_process_audio(struct vomp_call_state *call, overlay_mdp_frame *mdp, time_ms_t now)
{
int ofs=14;
// if (mdp->in.payload_length>14)
// DEBUGF("got here (payload has %d bytes)",mdp->in.payload_length);
int ofs=6;
/* Get end time marker for sample block collection */
unsigned int e=0, s=0;
if(ofs>=mdp->in.payload_length)
return 0;
int sequence = call->remote.sequence;
int codec=mdp->in.payload[ofs++];
if(ofs<mdp->in.payload_length)
{
s=mdp->in.payload[ofs++]<<24;
s|=mdp->in.payload[ofs++]<<16;
s|=mdp->in.payload[ofs++]<<8;
s|=mdp->in.payload[ofs++]<<0;
sender_duration = (s&0xFFFF0000)|sender_duration;
int codec=mdp->in.payload[ofs++];
int audio_len = mdp->in.payload_length - ofs;
if ((!codec)||vomp_sample_size(codec)<0) return -1;
int time = mdp->in.payload[ofs]<<8 | mdp->in.payload[ofs+1]<<0;
ofs+=2;
int sequence = mdp->in.payload[ofs]<<8 | mdp->in.payload[ofs+1]<<0;
ofs+=2;
// rebuild absolute time value from short relative time.
call->remote_audio_clock=to_absolute_value(time, call->remote_audio_clock);
call->remote.sequence=to_absolute_value(sequence, call->remote.sequence);
time=call->remote_audio_clock * 20;
int audio_len = mdp->in.payload_length - ofs;
e = s + vomp_codec_timespan(codec) - 1;
/* Pass audio frame to all registered listeners */
if (!vomp_audio_already_seen(call, e)){
store_jitter_sample(&call->jitter, s, now);
if (monitor_socket_count)
monitor_send_audio(call, codec, s, e,
&mdp->in.payload[ofs],
audio_len,
sequence);
}
}
if (store_jitter_sample(&call->jitter, time, now))
return 0;
/* Pass audio frame to all registered listeners */
if (monitor_socket_count)
monitor_send_audio(call, codec, time, call->remote.sequence,
&mdp->in.payload[ofs],
audio_len);
return 0;
}
@ -722,7 +745,7 @@ int vomp_ringing(struct vomp_call_state *call){
return 0;
}
int vomp_call_destroy(struct vomp_call_state *call)
static int vomp_call_destroy(struct vomp_call_state *call)
{
if (debug & DEBUG_VOMP)
DEBUGF("Destroying call %06x:%06x [%s,%s]", call->local.session, call->remote.session, call->local.did,call->remote.did);
@ -807,9 +830,9 @@ int vomp_hangup(struct vomp_call_state *call)
return 0;
}
int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_mdp_frame *mdp)
static int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_mdp_frame *mdp)
{
int ofs=14;
int ofs=6;
if (debug & DEBUG_VOMP)
dump("codec list mdp frame", (unsigned char *)&mdp->in.payload[0],mdp->in.payload_length);
@ -846,18 +869,12 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
struct vomp_call_state *call=NULL;
switch(mdp->in.payload[0]) {
case 0x01: /* Ordinary VoMP state+optional audio frame */
case VOMP_VERSION:
{
int recvr_state=mdp->in.payload[1]>>4;
int sender_state=mdp->in.payload[1]&0xf;
unsigned int recvr_session=
(mdp->in.payload[8]<<16)|(mdp->in.payload[9]<<8)|mdp->in.payload[10];
unsigned int sender_session=
(mdp->in.payload[11]<<16)|(mdp->in.payload[12]<<8)|mdp->in.payload[13];
int sender_seq=(mdp->in.payload[4]<<8)+mdp->in.payload[5];
// cyclic ~1 minute timer...
unsigned int sender_duration = (mdp->in.payload[6]<<8) | mdp->in.payload[7];
unsigned int sender_session=(mdp->in.payload[1]<<8)|mdp->in.payload[2];
unsigned int recvr_session=(mdp->in.payload[3]<<8)|mdp->in.payload[4];
int recvr_state=mdp->in.payload[5]>>4;
int sender_state=mdp->in.payload[5]&0xf;
/* wants to create a call session.
Main aim here: replay protection. An adversary should not be able to
@ -877,12 +894,13 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
if (!recvr_session && (debug & DEBUG_VOMP))
DEBUG("recvr_session==0, created call");
recvr_state = call->local.state;
call->remote.sequence=sender_seq;
// stale packet or forgery attempt? Should we just drop it?
if (sender_state < call->remote.state)
sender_state = call->remote.state;
// TODO ignore state changes if sequence is stale?
// TODO ignore state changes that seem to go backwards?
// we don't really care what state they think we are in.
// Though we could use this information to indicate a network error.
recvr_state = call->local.state;
if ((!monitor_socket_count)
&&(!monitor_client_interested(MONITOR_VOMP)))
@ -890,11 +908,15 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
/* No registered listener, so we cannot answer the call, so just reject
it. */
WHY("Rejecting call, no listening clients");
call->rejection_reason=VOMP_REJECT_NOPHONE;
recvr_state=VOMP_STATE_CALLENDED;
/* now let the state machine progress to destroy the call */
}
if (recvr_state < VOMP_STATE_RINGINGOUT && sender_state < VOMP_STATE_RINGINGOUT){
// TODO, pass codec list to connected clients, let them pick a codec they can use first?
unsigned char supported_codecs[CODEC_FLAGS_LENGTH];
int i, found=0;
@ -915,6 +937,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
// nope, we can't speak the same language.
if (!found){
WHY("Rejecting call, no matching codecs found");
call->rejection_reason=VOMP_REJECT_NOCODEC;
recvr_state=VOMP_STATE_CALLENDED;
}
}
@ -922,7 +945,6 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
if (sender_state==VOMP_STATE_CALLENDED){
/* For whatever reason, the far end has given up on the call,
so we must also move to CALLENDED no matter what state we were in */
recvr_state=VOMP_STATE_CALLENDED;
}
@ -947,10 +969,11 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
that they would like us to start ringing.
So change our state to RINGINGIN. */
if (call->initiated_call)
if (call->initiated_call){
// hey, quit it, we were trying to call you.
call->rejection_reason=VOMP_REJECT_BUSY;
recvr_state=VOMP_STATE_CALLENDED;
else{
}else{
// Don't automatically transition to RINGIN, wait for a client to tell us when.
}
break;
@ -964,7 +987,6 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
don't indicate their ringing state to the user.
*/
if (call->initiated_call){
// TODO fail the call if we can't agree on codec's
recvr_state=VOMP_STATE_RINGINGOUT;
}else{
recvr_state=VOMP_STATE_CALLENDED;
@ -1002,7 +1024,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
// Fall through
case (VOMP_STATE_INCALL<<3)|VOMP_STATE_INCALL:
/* play any audio that they have sent us. */
vomp_process_audio(call,sender_duration,mdp,now);
vomp_process_audio(call,mdp,now);
break;
case (VOMP_STATE_CALLENDED<<3)|VOMP_STATE_NOCALL:
@ -1044,88 +1066,6 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
return WHY("Malformed VoMP MDP packet?");
}
static const char *vomp_describe_codec(int c)
{
switch(c) {
case VOMP_CODEC_NONE: return "none";
case VOMP_CODEC_CODEC2_2400: return "CODEC2@1400";
case VOMP_CODEC_CODEC2_1400: return "CODEC2@2400";
case VOMP_CODEC_GSMHALF: return "GSM-half-rate";
case VOMP_CODEC_GSMFULL: return "GSM-full-rate";
case VOMP_CODEC_16SIGNED: return "16bit-raw";
case VOMP_CODEC_8ULAW: return "8bit-uLaw";
case VOMP_CODEC_8ALAW: return "8bit-aLaw";
case VOMP_CODEC_PCM: return "PCM@8KHz";
case VOMP_CODEC_DTMF: return "DTMF";
case VOMP_CODEC_ENGAGED: return "Engaged-tone";
case VOMP_CODEC_ONHOLD: return "On-Hold";
}
return "unknown";
}
int vomp_sample_size(int c)
{
switch(c) {
case VOMP_CODEC_NONE: return 0;
case VOMP_CODEC_CODEC2_2400: return 7; /* actually 2550bps, 51 bits per 20ms,
but using whole byte here, so 2800bps */
case VOMP_CODEC_CODEC2_1400: return 7; /* per 40ms */
case VOMP_CODEC_GSMHALF: return 14; /* check. 5.6kbits */
case VOMP_CODEC_GSMFULL: return 33; /* padded to 13.2kbit/sec */
case VOMP_CODEC_16SIGNED: return 320; /* 8000x2bytes*0.02sec */
case VOMP_CODEC_8ULAW: return 160;
case VOMP_CODEC_8ALAW: return 160;
case VOMP_CODEC_PCM: return 320;
case VOMP_CODEC_DTMF: return 1;
case VOMP_CODEC_ENGAGED: return 0;
case VOMP_CODEC_ONHOLD: return 0;
}
return -1;
}
int vomp_codec_timespan(int c)
{
switch(c) {
case VOMP_CODEC_NONE: return 1;
case VOMP_CODEC_CODEC2_2400: return 20;
case VOMP_CODEC_CODEC2_1400: return 40;
case VOMP_CODEC_GSMHALF: return 20;
case VOMP_CODEC_GSMFULL: return 20;
case VOMP_CODEC_16SIGNED: return 20;
case VOMP_CODEC_8ULAW: return 20;
case VOMP_CODEC_8ALAW: return 20;
case VOMP_CODEC_PCM: return 20;
case VOMP_CODEC_DTMF: return 80;
case VOMP_CODEC_ENGAGED: return 20;
case VOMP_CODEC_ONHOLD: return 20;
}
return -1;
}
int vomp_parse_dtmf_digit(char c)
{
if (c>='0'&&c<='9') return c-0x30;
switch (c) {
case 'a': case 'A': return 0xa;
case 'b': case 'B': return 0xb;
case 'c': case 'C': return 0xc;
case 'd': case 'D': return 0xd;
case '*': return 0xe;
case '#': return 0xf;
}
return -1;
}
char vomp_dtmf_digit_to_char(int digit)
{
if (digit<0) return '?';
if (digit<10) return '0'+digit;
if (digit<0xe) return 'A'+digit-0xa;
if (digit==0xe) return '*';
if (digit==0xf) return '#';
return '?';
}
static void vomp_process_tick(struct sched_ent *alarm)
{
char msg[32];
@ -1145,6 +1085,7 @@ static void vomp_process_tick(struct sched_ent *alarm)
(call->last_activity+VOMP_CALL_NETWORK_TIMEOUT<now) ){
/* tell any local clients that call has died */
call->rejection_reason=VOMP_REJECT_TIMEOUT;
vomp_update_local_state(call, VOMP_STATE_CALLENDED);
vomp_update_remote_state(call, VOMP_STATE_CALLENDED);
vomp_update(call);

@ -29,6 +29,8 @@
#include "monitor-client.h"
#include "str.h"
#include "constants.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
int call_token=-1;
int seen_audio=0;
@ -55,18 +57,10 @@ static void send_pickup(int session_id){
static void send_call(const char *sid, const char *caller_id, const char *remote_ext){
monitor_client_writeline(monitor_client_fd, "call %s %s %s\n", sid, caller_id, remote_ext);
}
#if 0
This function commented out to avoid "defined but not used" compiler warning. Once you need
it, just get rid of the #if0..#endif and this comment.
-- Andrew Bettison <andrew@servalproject.com>
static void send_audio(int session_id, unsigned char *buffer, int len, int codec){
monitor_client_writeline_and_data(monitor_client_fd, buffer, len, "audio %06x %d\n", session_id, codec);
}
#endif
static int remote_call(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
int token = strtol(argv[0], NULL, 16);
@ -130,10 +124,15 @@ static int remote_hangup(char *cmd, int argc, char **argv, unsigned char *data,
static int remote_audio(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
int token = strtol(argv[0], NULL, 16);
if (call_token == token){
if (!seen_audio){
printf("Incoming audio\n");
fflush(stdout);
seen_audio=1;
int codec = strtol(argv[1], NULL, 10);
// int start_time = strtol(argv[2], NULL, 10);
// int sequence = strtol(argv[3], NULL, 10);
switch (codec){
case VOMP_CODEC_TEXT:
data[dataLen]=0;
printf("%s\n",data);
fflush(stdout);
break;
}
}else
send_hangup(token);
@ -178,7 +177,7 @@ struct monitor_command_handler console_handlers[]={
{.command="ANSWERED", .handler=remote_pickup},
{.command="CALLTO", .handler=remote_dialing},
{.command="HANGUP", .handler=remote_hangup},
{.command="AUDIOPACKET", .handler=remote_audio},
{.command="AUDIO", .handler=remote_audio},
{.command="CODECS", .handler=remote_codecs},
{.command="INFO", .handler=remote_print},
{.command="CALLSTATUS", .handler=remote_noop},
@ -216,6 +215,29 @@ static int console_hangup(int argc, const char *const *argv, struct command_line
return 0;
}
static int console_audio(int argc, const char *const *argv, struct command_line_option *o, void *context){
if (call_token==-1){
printf("No active call\n");
fflush(stdout);
}else{
static char buf[256];
static struct strbuf str_buf = STRUCT_STRBUF_EMPTY;
int i;
strbuf_init(&str_buf, buf, sizeof(buf));
for (i = 0; i < argc; ++i) {
if (i)
strbuf_putc(&str_buf, ' ');
if (argv[i])
strbuf_toprint_quoted(&str_buf, "\"\"", argv[i]);
else
strbuf_puts(&str_buf, "NULL");
}
send_audio(call_token, (unsigned char *)strbuf_str(&str_buf), strbuf_len(&str_buf), VOMP_CODEC_TEXT);
}
return 0;
}
static int console_usage(int argc, const char *const *argv, struct command_line_option *o, void *context);
struct command_line_option console_commands[]={
@ -223,6 +245,7 @@ struct command_line_option console_commands[]={
{console_dial,{"call","<sid>","[<local_number>]","[<remote_extension>]",NULL},0,"Start dialling a given person"},
{console_hangup,{"hangup",NULL},0,"Hangup the phone line"},
{console_usage,{"help",NULL},0,"This usage message"},
{console_audio,{"say","...",NULL},0,"Send a text string to the other party"},
{NULL},
};
@ -301,8 +324,8 @@ int app_vomp_console(int argc, const char *const *argv, struct command_line_opti
monitor_client_fd = monitor_client_open(&monitor_state);
monitor_client_writeline(monitor_client_fd, "monitor vomp %d %d %d\n",
VOMP_CODEC_8ULAW,VOMP_CODEC_8ALAW,VOMP_CODEC_PCM);
monitor_client_writeline(monitor_client_fd, "monitor vomp %d\n",
VOMP_CODEC_TEXT);
set_nonblock(monitor_client_fd);