mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-26 22:10:09 +00:00
Merge remote-tracking branch 'origin/master' into rhizomeovermdp
Conflicts: rhizome_fetch.c
This commit is contained in:
commit
4b73e42bed
codecs.ccommandline.cconstants.hdataformats.cdirectory_client.ckeyring.cmdp_client.cmdp_client.hmonitor.coverlay.coverlay_address.coverlay_address.hoverlay_advertise.coverlay_buffer.coverlay_buffer.hoverlay_interface.coverlay_mdp.coverlay_mdp_services.coverlay_olsr.coverlay_packet.hoverlay_packetformats.coverlay_payload.coverlay_queue.coverlay_route.cpacketformats.crhizome_fetch.crhizome_packetformats.cserval.hsourcefiles.mktestdefs.sh
tests
vomp.cvomp_console.c
52
codecs.c
52
codecs.c
@ -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,
|
||||
|
162
constants.h
162
constants.h
@ -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
|
||||
|
122
dataformats.c
122
dataformats.c
@ -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));
|
||||
|
14
mdp_client.c
14
mdp_client.c
@ -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 */
|
||||
|
10
mdp_client.h
10
mdp_client.h
@ -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();
|
||||
|
17
monitor.c
17
monitor.c
@ -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);
|
||||
}
|
||||
|
171
overlay_buffer.c
171
overlay_buffer.c
@ -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
|
||||
|
376
overlay_mdp.c
376
overlay_mdp.c
@ -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");
|
||||
|
336
overlay_queue.c
336
overlay_queue.c
@ -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;
|
||||
|
39
serval.h
39
serval.h
@ -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
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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user