mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-21 09:51:50 +00:00
Merge branch 'anyservice' into 'development'
Allows any valid "service" manifest field in the "rhizome add file" command Many improvements in Rhizome manifest parsing; stricter manifest syntax rules (no comment or blank lines, field names must be alphanumeric identifiers), faster preliminary manifest inspection when receiving manifest advertisements or syncing manifests The 'development' branch introduces "struct socket_address" which coincidentally fixed the recently encountered Linux kernel 3.12 recvmsg(2) EINVAL problem, so that 'rhizomeprotocol' tests which fail on the 'anyservice' branch will pass after this merge
This commit is contained in:
commit
8db5f9c14a
1
cli.c
1
cli.c
@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "serval.h"
|
||||
#include "rhizome.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
int cli_usage(const struct cli_schema *commands, XPRINTF xpf)
|
||||
{
|
||||
|
171
commandline.c
171
commandline.c
@ -46,6 +46,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "overlay_address.h"
|
||||
#include "overlay_buffer.h"
|
||||
#include "keyring.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
extern struct cli_schema command_line_options[];
|
||||
|
||||
@ -931,9 +932,6 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
int64_t interval_ms = 1000;
|
||||
str_to_uint64_interval_ms(opt_interval, &interval_ms, NULL);
|
||||
|
||||
overlay_mdp_frame mdp;
|
||||
bzero(&mdp, sizeof(overlay_mdp_frame));
|
||||
|
||||
/* First sequence number in the echo frames */
|
||||
unsigned int firstSeq=random();
|
||||
unsigned int sequence_number=firstSeq;
|
||||
@ -941,22 +939,23 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
int broadcast = is_sid_t_broadcast(ping_sid);
|
||||
|
||||
/* Bind to MDP socket and await confirmation */
|
||||
if ((mdp_sockfd = overlay_mdp_client_socket()) < 0)
|
||||
if ((mdp_sockfd = mdp_socket()) < 0)
|
||||
return WHY("Cannot create MDP socket");
|
||||
|
||||
sid_t srcsid;
|
||||
mdp_port_t port=32768+(random()&32767);
|
||||
if (overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid)) {
|
||||
overlay_mdp_client_close(mdp_sockfd);
|
||||
return WHY("Could not get local address");
|
||||
}
|
||||
if (overlay_mdp_bind(mdp_sockfd, &srcsid, port)) {
|
||||
overlay_mdp_client_close(mdp_sockfd);
|
||||
return WHY("Could not bind to MDP socket");
|
||||
}
|
||||
struct mdp_header mdp_header;
|
||||
bzero(&mdp_header, sizeof(mdp_header));
|
||||
|
||||
mdp_header.local.sid = BIND_PRIMARY;
|
||||
mdp_header.remote.sid = ping_sid;
|
||||
mdp_header.remote.port = MDP_PORT_ECHO;
|
||||
mdp_header.qos = OQ_MESH_MANAGEMENT;
|
||||
mdp_header.ttl = PAYLOAD_TTL_DEFAULT;
|
||||
mdp_header.flags = MDP_FLAG_BIND;
|
||||
if (broadcast)
|
||||
mdp_header.flags |= MDP_FLAG_NO_CRYPT;
|
||||
|
||||
/* TODO Eventually we should try to resolve SID to phone number and vice versa */
|
||||
cli_printf(context, "MDP PING %s (%s): 12 data bytes", alloca_tohex_sid_t(ping_sid), alloca_tohex_sid_t(ping_sid));
|
||||
cli_printf(context, "MDP PING %s: 12 data bytes", alloca_tohex_sid_t(ping_sid));
|
||||
cli_delim(context, "\n");
|
||||
cli_flush(context);
|
||||
|
||||
@ -968,81 +967,91 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
|
||||
if (broadcast)
|
||||
WARN("broadcast ping packets will not be encrypted");
|
||||
|
||||
for (; icount==0 || tx_count<icount; ++sequence_number) {
|
||||
/* Now send the ping packets */
|
||||
mdp.packetTypeAndFlags=MDP_TX;
|
||||
if (broadcast) mdp.packetTypeAndFlags|=MDP_NOCRYPT;
|
||||
mdp.out.src.port=port;
|
||||
mdp.out.src.sid = srcsid;
|
||||
mdp.out.dst.sid = ping_sid;
|
||||
mdp.out.queue=OQ_MESH_MANAGEMENT;
|
||||
/* Set port to well known echo port */
|
||||
mdp.out.dst.port=MDP_PORT_ECHO;
|
||||
mdp.out.payload_length=4+8;
|
||||
int *seq=(int *)&mdp.out.payload;
|
||||
*seq=sequence_number;
|
||||
write_uint64(&mdp.out.payload[4], gettime_ms());
|
||||
|
||||
int res=overlay_mdp_send(mdp_sockfd, &mdp, 0, 0);
|
||||
if (res) {
|
||||
WHYF("could not dispatch PING frame #%d (error %d)%s%s",
|
||||
sequence_number - firstSeq,
|
||||
res,
|
||||
mdp.packetTypeAndFlags == MDP_ERROR ? ": " : "",
|
||||
mdp.packetTypeAndFlags == MDP_ERROR ? mdp.error.message : ""
|
||||
);
|
||||
} else
|
||||
tx_count++;
|
||||
|
||||
// send a ping packet
|
||||
{
|
||||
uint8_t payload[12];
|
||||
int *seq=(int *)payload;
|
||||
*seq=sequence_number;
|
||||
write_uint64(&payload[4], gettime_ms());
|
||||
|
||||
int r = mdp_send(mdp_sockfd, &mdp_header, payload, sizeof(payload));
|
||||
if (r<0)
|
||||
WHY_perror("mdp_send");
|
||||
else
|
||||
tx_count++;
|
||||
}
|
||||
|
||||
/* Now look for replies until one second has passed, and print any replies
|
||||
with appropriate information as required */
|
||||
time_ms_t now = gettime_ms();
|
||||
time_ms_t finish = now + (tx_count < icount?interval_ms:timeout_ms);
|
||||
time_ms_t finish = now + ((tx_count < icount || icount==0)?interval_ms:timeout_ms);
|
||||
for (; !servalShutdown && now < finish; now = gettime_ms()) {
|
||||
time_ms_t poll_timeout_ms = finish - gettime_ms();
|
||||
int result = overlay_mdp_client_poll(mdp_sockfd, poll_timeout_ms);
|
||||
|
||||
if (result>0) {
|
||||
int ttl=-1;
|
||||
if (overlay_mdp_recv(mdp_sockfd, &mdp, port, &ttl)==0) {
|
||||
switch(mdp.packetTypeAndFlags&MDP_TYPE_MASK) {
|
||||
case MDP_ERROR:
|
||||
WHYF("mdpping: overlay_mdp_recv: %s (code %d)", mdp.error.message, mdp.error.error);
|
||||
break;
|
||||
case MDP_TX:
|
||||
{
|
||||
int *rxseq=(int *)&mdp.in.payload;
|
||||
time_ms_t txtime = read_uint64(&mdp.in.payload[4]);
|
||||
int hop_count = 64 - mdp.in.ttl;
|
||||
time_ms_t delay = gettime_ms() - txtime;
|
||||
cli_printf(context, "%s: seq=%d time=%"PRId64"ms hops=%d %s%s",
|
||||
alloca_tohex_sid_t(mdp.in.src.sid),
|
||||
(*rxseq)-firstSeq+1,
|
||||
(int64_t)delay,
|
||||
hop_count,
|
||||
mdp.packetTypeAndFlags&MDP_NOCRYPT?"":" ENCRYPTED",
|
||||
mdp.packetTypeAndFlags&MDP_NOSIGN?"":" SIGNED");
|
||||
cli_delim(context, "\n");
|
||||
cli_flush(context);
|
||||
// TODO Put duplicate pong detection here so that stats work properly.
|
||||
rx_count++;
|
||||
ret=0;
|
||||
rx_ms+=delay;
|
||||
if (rx_mintime>delay||rx_mintime==-1) rx_mintime=delay;
|
||||
if (delay>rx_maxtime) rx_maxtime=delay;
|
||||
rx_times[rx_count%1024]=delay;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WHYF("mdpping: overlay_mdp_recv: Unexpected MDP frame type 0x%x", mdp.packetTypeAndFlags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mdp_poll(mdp_sockfd, poll_timeout_ms)<=0)
|
||||
continue;
|
||||
|
||||
struct mdp_header mdp_recv_header;
|
||||
uint8_t recv_payload[12];
|
||||
ssize_t len = mdp_recv(mdp_sockfd, &mdp_recv_header, recv_payload, sizeof(recv_payload));
|
||||
|
||||
if (len<0){
|
||||
WHY_perror("mdp_recv");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mdp_recv_header.flags & MDP_FLAG_ERROR){
|
||||
WHY("Serval daemon reported an error, please check the log for more information");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mdp_recv_header.flags & MDP_FLAG_BIND){
|
||||
// received port binding confirmation
|
||||
mdp_header.local = mdp_recv_header.local;
|
||||
mdp_header.flags &= ~MDP_FLAG_BIND;
|
||||
DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(mdp_header.local.sid), mdp_header.local.port);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len<sizeof(recv_payload)){
|
||||
DEBUGF("Ignoring ping response as it is too short");
|
||||
continue;
|
||||
}
|
||||
|
||||
int *rxseq=(int *)&recv_payload;
|
||||
time_ms_t txtime = read_uint64(&recv_payload[4]);
|
||||
int hop_count = 64 - mdp_recv_header.ttl;
|
||||
time_ms_t delay = gettime_ms() - txtime;
|
||||
|
||||
cli_put_hexvalue(context, mdp_recv_header.remote.sid.binary, SID_SIZE, ": seq=");
|
||||
cli_put_long(context, (*rxseq)-firstSeq+1, " time=");
|
||||
cli_put_long(context, delay, "ms hops=");
|
||||
cli_put_long(context, hop_count, "");
|
||||
|
||||
if (mdp_recv_header.flags&MDP_FLAG_NO_CRYPT)
|
||||
cli_put_string(context, "", "");
|
||||
else
|
||||
cli_put_string(context, " ENCRYPTED", "");
|
||||
|
||||
if (mdp_recv_header.flags&MDP_FLAG_NO_SIGN)
|
||||
cli_put_string(context, "", "\n");
|
||||
else
|
||||
cli_put_string(context, " SIGNED", "\n");
|
||||
cli_flush(context);
|
||||
// TODO Put duplicate pong detection here so that stats work properly.
|
||||
rx_count++;
|
||||
ret=0;
|
||||
rx_ms+=delay;
|
||||
if (rx_mintime>delay||rx_mintime==-1) rx_mintime=delay;
|
||||
if (delay>rx_maxtime) rx_maxtime=delay;
|
||||
rx_times[rx_count%1024]=delay;
|
||||
}
|
||||
}
|
||||
|
||||
overlay_mdp_client_close(mdp_sockfd);
|
||||
mdp_close(mdp_sockfd);
|
||||
|
||||
{
|
||||
float rx_stddev=0;
|
||||
@ -2262,7 +2271,7 @@ static int handle_pins(const struct cli_parsed *parsed, struct cli_context *cont
|
||||
WHYF("Timeout while waiting for response");
|
||||
break;
|
||||
}
|
||||
if (rev_header.flags & MDP_FLAG_OK){
|
||||
if (rev_header.flags & MDP_FLAG_CLOSE){
|
||||
ret=0;
|
||||
break;
|
||||
}
|
||||
@ -2332,7 +2341,7 @@ int app_id_list(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
// TODO receive and decode other details about this identity
|
||||
}
|
||||
|
||||
if (rev_header.flags & MDP_FLAG_OK){
|
||||
if (rev_header.flags & MDP_FLAG_CLOSE){
|
||||
ret=0;
|
||||
break;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "strbuf.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "conf.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
int cf_opt_boolean(bool_t *booleanp, const char *text)
|
||||
{
|
||||
|
@ -242,9 +242,7 @@ ATOM(bool_t, gateway, 0, boolean,, "")
|
||||
ATOM(bool_t, keyring, 0, boolean,, "")
|
||||
ATOM(bool_t, security, 0, boolean,, "")
|
||||
ATOM(bool_t, mdprequests, 0, boolean,, "")
|
||||
ATOM(bool_t, mavlink, 0, boolean,, "")
|
||||
ATOM(bool_t, mavlink_payloads, 0, boolean,, "")
|
||||
ATOM(bool_t, mavlinkfsm, 0, boolean,, "")
|
||||
ATOM(bool_t, radio_link, 0, boolean,, "")
|
||||
ATOM(bool_t, peers, 0, boolean,, "")
|
||||
ATOM(bool_t, overlaybuffer, 0, boolean,, "")
|
||||
ATOM(bool_t, overlayframes, 0, boolean,, "")
|
||||
@ -432,6 +430,7 @@ ATOM(bool_t, external_blobs, 0, boolean,, "Store rhizome bundles
|
||||
|
||||
ATOM(uint64_t, rhizome_mdp_block_size, 512, uint64_scaled,, "Rhizome MDP block size.")
|
||||
ATOM(uint64_t, idle_timeout, RHIZOME_IDLE_TIMEOUT, uint64_scaled,, "Rhizome transfer timeout if no data received.")
|
||||
ATOM(uint64_t, mdp_stall_timeout, 1000, uint64_scaled,, "Timeout to request more data via mdp.")
|
||||
ATOM(uint32_t, fetch_delay_ms, 50, uint32_nonzero,, "Delay from receiving first bundle advert to initiating fetch")
|
||||
SUB_STRUCT(rhizome_direct, direct,)
|
||||
SUB_STRUCT(rhizome_api, api,)
|
||||
@ -477,8 +476,6 @@ ATOM(bool_t, debug, 0, boolean,, "If true, log details
|
||||
ATOM(bool_t, point_to_point, 0, boolean,, "If true, assume there will only be two devices on this interface")
|
||||
ATOM(bool_t, ctsrts, 0, boolean,, "If true, enable CTS/RTS hardware handshaking")
|
||||
ATOM(int32_t, uartbps, 57600, int32_rs232baudrate,, "Speed of serial UART link speed (which may be different to serial device link speed)")
|
||||
ATOM(int32_t, throttle, 0, int32_nonneg,, "Limit transmit speed of serial interface (bytes per second)")
|
||||
ATOM(int32_t, burst_size, 0, int32_nonneg,, "Write no more than this many bytes at a time to a serial interface")
|
||||
END_STRUCT
|
||||
|
||||
ARRAY(interface_list, NO_DUPLICATES)
|
||||
|
@ -17,10 +17,11 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "serval.h"
|
||||
#include "rhizome.h"
|
||||
#include "str.h"
|
||||
#include <ctype.h>
|
||||
#include "dataformats.h"
|
||||
|
||||
int cmp_sid_t(const sid_t *a, const sid_t *b)
|
||||
{
|
||||
@ -214,7 +215,7 @@ void write_uint16(unsigned char *o,uint16_t v)
|
||||
{ *(o++)=v&0xff; v=v>>8; }
|
||||
}
|
||||
|
||||
uint64_t read_uint64(unsigned char *o)
|
||||
uint64_t read_uint64(const unsigned char *o)
|
||||
{
|
||||
int i;
|
||||
uint64_t v=0;
|
||||
@ -222,7 +223,7 @@ uint64_t read_uint64(unsigned char *o)
|
||||
return v;
|
||||
}
|
||||
|
||||
uint32_t read_uint32(unsigned char *o)
|
||||
uint32_t read_uint32(const unsigned char *o)
|
||||
{
|
||||
int i;
|
||||
uint32_t v=0;
|
||||
@ -230,7 +231,7 @@ uint32_t read_uint32(unsigned char *o)
|
||||
return v;
|
||||
}
|
||||
|
||||
uint16_t read_uint16(unsigned char *o)
|
||||
uint16_t read_uint16(const unsigned char *o)
|
||||
{
|
||||
int i;
|
||||
uint16_t v=0;
|
||||
|
26
dataformats.h
Normal file
26
dataformats.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __SERVALD_DATA_FORMATS_H
|
||||
#define __SERVALD_DATA_FORMATS_H
|
||||
|
||||
int str_is_subscriber_id(const char *sid);
|
||||
int strn_is_subscriber_id(const char *sid, size_t *lenp);
|
||||
int str_is_did(const char *did);
|
||||
int strn_is_did(const char *did, size_t *lenp);
|
||||
|
||||
int rhizome_strn_is_manifest_id(const char *text);
|
||||
int rhizome_str_is_manifest_id(const char *text);
|
||||
int rhizome_strn_is_bundle_key(const char *text);
|
||||
int rhizome_str_is_bundle_key(const char *text);
|
||||
int rhizome_strn_is_bundle_crypt_key(const char *text);
|
||||
int rhizome_str_is_bundle_crypt_key(const char *text);
|
||||
int rhizome_strn_is_file_hash(const char *text);
|
||||
int rhizome_str_is_file_hash(const char *text);
|
||||
int rhizome_str_is_manifest_service(const char *text);
|
||||
|
||||
void write_uint64(unsigned char *o,uint64_t v);
|
||||
void write_uint16(unsigned char *o,uint16_t v);
|
||||
void write_uint32(unsigned char *o,uint32_t v);
|
||||
uint64_t read_uint64(const unsigned char *o);
|
||||
uint32_t read_uint32(const unsigned char *o);
|
||||
uint16_t read_uint16(const unsigned char *o);
|
||||
|
||||
#endif
|
@ -52,7 +52,7 @@ static void directory_send(struct subscriber *directory_service, const sid_t *si
|
||||
// Used by tests
|
||||
INFOF("Sending directory registration for %s*, %s, %s to %s*",
|
||||
alloca_tohex_sid_t_trunc(*sidp, 14), did, name, alloca_tohex_sid_t_trunc(directory_service->sid, 14));
|
||||
overlay_mdp_dispatch(&request, 0, NULL, 0);
|
||||
overlay_mdp_dispatch(&request, NULL);
|
||||
}
|
||||
|
||||
// send a registration packet for each unlocked identity
|
||||
|
@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "strbuf.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "overlay_address.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
/*
|
||||
The challenge with making an interface for calling an external program to
|
||||
|
92
fakeradio.c
92
fakeradio.c
@ -339,30 +339,49 @@ int transfer_bytes(struct radio_state *radios)
|
||||
log_time();
|
||||
fprintf(stderr, "Transferring %d byte packet from %s to %s\n", bytes, t->name, r->name);
|
||||
}
|
||||
|
||||
int i, j;
|
||||
for (i=0;i<bytes && r->rxb_len<sizeof(r->rxbuffer);i++){
|
||||
char byte = t->txbuffer[i];
|
||||
// introduce bit errors
|
||||
for(j=0;j<8;j++) {
|
||||
if (random()<ber) {
|
||||
byte^=(1<<j);
|
||||
fprintf(stderr,"Flipped a bit\n");
|
||||
int dropped=0;
|
||||
|
||||
// preamble length in bits that must arrive intact
|
||||
#define PREAMBLE_LENGTH (20+8)
|
||||
|
||||
// simulate the probability of a bit error in the packet pre-amble and drop the whole packet
|
||||
for (i=0;i<PREAMBLE_LENGTH;i++){
|
||||
if (random()<ber)
|
||||
dropped=1;
|
||||
}
|
||||
|
||||
if (dropped){
|
||||
fprintf(stderr,"Dropped the whole radio packet due to bit flip in the pre-amble\n");
|
||||
}else{
|
||||
for (i=0;i<bytes && r->rxb_len<sizeof(r->rxbuffer);i++){
|
||||
char byte = t->txbuffer[i];
|
||||
// introduce bit errors
|
||||
for(j=0;j<8;j++) {
|
||||
if (random()<ber) {
|
||||
byte^=(1<<j);
|
||||
fprintf(stderr,"Flipped a bit\n");
|
||||
}
|
||||
}
|
||||
r->rxbuffer[r->rxb_len++]=byte;
|
||||
}
|
||||
r->rxbuffer[r->rxb_len++]=byte;
|
||||
}
|
||||
|
||||
if (bytes>0 && bytes < t->txb_len)
|
||||
bcopy(&t->txbuffer[bytes], t->txbuffer, t->txb_len - bytes);
|
||||
t->txb_len-=bytes;
|
||||
|
||||
if (bytes==0 || --t->tx_count<=0){
|
||||
// swap who's turn it is to transmit
|
||||
transmitter = receiver;
|
||||
r->tx_count=6;
|
||||
}
|
||||
// set the wait time for the next transmission
|
||||
next_transmit_time = gettime_ms() + (bytes+10)/chars_per_ms;
|
||||
next_transmit_time = gettime_ms() + 5 + bytes/chars_per_ms;
|
||||
|
||||
if (bytes==0 || --t->tx_count<=0){
|
||||
// swap who's turn it is to transmit after sending 3 packets or running out of data.
|
||||
transmitter = receiver;
|
||||
r->tx_count=3;
|
||||
// add Tx->Rx change time (it's about 40ms between receiving empty packets)
|
||||
next_transmit_time+=15;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@ -380,21 +399,33 @@ int calc_ber(double target_packet_fraction)
|
||||
// so no point starting smaller than that.
|
||||
// Only ~30,000,000 reduces packet delivery rate to
|
||||
// ~1%, so the search range is fairly narrow.
|
||||
ber=9000000;
|
||||
if (target_packet_fraction<=0.9) ber=13000000;
|
||||
if (target_packet_fraction<=0.5) ber=18000000;
|
||||
if (target_packet_fraction<=0.25) ber=21000000;
|
||||
if (target_packet_fraction<=0.1) ber=24000000;
|
||||
if (target_packet_fraction<=0.05) ber=26000000;
|
||||
ber=0;
|
||||
if (target_packet_fraction<=0.9) ber=6900000;
|
||||
if (target_packet_fraction<=0.5) ber=16900000;
|
||||
if (target_packet_fraction<=0.25) ber=20600000;
|
||||
if (target_packet_fraction<=0.1) ber=23400000;
|
||||
if (target_packet_fraction<=0.05) ber=28600000;
|
||||
|
||||
for(;ber<0x70ffffff;ber+=100000)
|
||||
{
|
||||
int packet_errors=0;
|
||||
for(p=0;p<1000;p++) {
|
||||
int byte_errors=0;
|
||||
for(byte=0;byte<byte_count;byte++) {
|
||||
for(bit=0;bit<8;bit++) if (random()<ber) { byte_errors++; break; }
|
||||
if (byte_errors>max_error_bytes) { packet_errors++; break; }
|
||||
int dropped = 0;
|
||||
for (byte=0;byte<PREAMBLE_LENGTH;byte++){
|
||||
if (random()<ber){
|
||||
dropped = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dropped){
|
||||
for(byte=0;byte<byte_count;byte++) {
|
||||
for(bit=0;bit<8;bit++) if (random()<ber) { byte_errors++; break; }
|
||||
if (byte_errors>max_error_bytes) { dropped=1; break; }
|
||||
}
|
||||
}
|
||||
if (dropped)
|
||||
packet_errors++;
|
||||
}
|
||||
if (packet_errors>=((1.0-target_packet_fraction)*1000)) break;
|
||||
}
|
||||
@ -404,13 +435,11 @@ int calc_ber(double target_packet_fraction)
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
if (argv[1]) {
|
||||
if (argc>=1) {
|
||||
chars_per_ms=atol(argv[1]);
|
||||
if (argv[2])
|
||||
if (argc>=2)
|
||||
ber=calc_ber(atof(argv[2]));
|
||||
}
|
||||
fprintf(stderr, "Sending %d bytes per ms\n", chars_per_ms);
|
||||
fprintf(stderr, "Introducing %f%% bit errors\n", (ber * 100.0) / 0xFFFFFFFF);
|
||||
|
||||
struct pollfd fds[2];
|
||||
struct radio_state radios[2];
|
||||
@ -418,18 +447,21 @@ int main(int argc,char **argv)
|
||||
bzero(&radios,sizeof radios);
|
||||
|
||||
int i;
|
||||
radios[0].name="left";
|
||||
radios[1].name="right";
|
||||
for (i=0;i<2;i++){
|
||||
radios[i].fd=posix_openpt(O_RDWR|O_NOCTTY);
|
||||
grantpt(radios[i].fd);
|
||||
unlockpt(radios[i].fd);
|
||||
fcntl(radios[i].fd,F_SETFL,fcntl(radios[i].fd, F_GETFL, NULL)|O_NONBLOCK);
|
||||
fprintf(stdout,"%s\n",ptsname(radios[i].fd));
|
||||
fprintf(stdout,"%s:%s\n", radios[i].name, ptsname(radios[i].fd));
|
||||
fds[i].fd = radios[i].fd;
|
||||
}
|
||||
radios[0].name="left";
|
||||
radios[1].name="right";
|
||||
fflush(stdout);
|
||||
|
||||
fprintf(stderr, "Sending %d bytes per ms\n", chars_per_ms);
|
||||
fprintf(stderr, "Introducing %f%% bit errors\n", (ber * 100.0) / 0xFFFFFFFF);
|
||||
|
||||
while(1) {
|
||||
// what events do we need to poll for? how long can we block?
|
||||
int64_t now = gettime_ms();
|
||||
|
45
golay.c
45
golay.c
@ -1,13 +1,14 @@
|
||||
|
||||
#define POLY 0xAE3 /* or use the other polynomial, 0xC75 */
|
||||
#include <inttypes.h>
|
||||
|
||||
static unsigned long golay(unsigned long cw)
|
||||
static uint32_t golay(uint32_t cw)
|
||||
/* This function calculates [23,12] Golay codewords.
|
||||
The format of the returned longint is
|
||||
[checkbits(11),data(12)]. */
|
||||
{
|
||||
int i;
|
||||
unsigned long c;
|
||||
uint32_t c;
|
||||
cw&=0xfffl;
|
||||
c=cw; /* save original codeword */
|
||||
for (i=1; i<=12; i++) /* examine each data bit */
|
||||
@ -19,16 +20,16 @@ static unsigned long golay(unsigned long cw)
|
||||
return((cw<<12)|c); /* assemble codeword */
|
||||
}
|
||||
|
||||
static int parity(unsigned long cw)
|
||||
static int parity(uint32_t cw)
|
||||
/* This function checks the overall parity of codeword cw.
|
||||
If parity is even, 0 is returned, else 1. */
|
||||
{
|
||||
unsigned char p;
|
||||
|
||||
uint8_t p;
|
||||
|
||||
/* XOR the bytes of the codeword */
|
||||
p=*(unsigned char*)&cw;
|
||||
p^=*((unsigned char*)&cw+1);
|
||||
p^=*((unsigned char*)&cw+2);
|
||||
p=cw & 0xFF;
|
||||
p^=(cw>>8) & 0xFF;
|
||||
p^=(cw>>16) & 0xFF;
|
||||
|
||||
/* XOR the halves of the intermediate result */
|
||||
p=p ^ (p>>4);
|
||||
@ -39,9 +40,9 @@ static int parity(unsigned long cw)
|
||||
return(p & 1);
|
||||
}
|
||||
|
||||
int golay_encode(unsigned char *data)
|
||||
int golay_encode(uint8_t *data)
|
||||
{
|
||||
unsigned long cw = data[0] | (data[1]<<8) | (data[2]<<16);
|
||||
uint32_t cw = data[0] | (data[1]<<8) | (data[2]<<16);
|
||||
cw = golay(cw);
|
||||
if (parity(cw))
|
||||
cw|=0x800000l;
|
||||
@ -51,7 +52,7 @@ int golay_encode(unsigned char *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long syndrome(unsigned long cw)
|
||||
static uint32_t syndrome(uint32_t cw)
|
||||
/* This function calculates and returns the syndrome
|
||||
of a [23,12] Golay codeword. */
|
||||
{
|
||||
@ -66,7 +67,7 @@ static unsigned long syndrome(unsigned long cw)
|
||||
return(cw<<12); /* value pairs with upper bits of cw */
|
||||
}
|
||||
|
||||
static int weight(unsigned long cw)
|
||||
static int weight(uint32_t cw)
|
||||
/* This function calculates the weight of
|
||||
23 bit codeword cw. */
|
||||
{
|
||||
@ -88,7 +89,7 @@ static int weight(unsigned long cw)
|
||||
return(bits);
|
||||
}
|
||||
|
||||
static unsigned long rotate_left(unsigned long cw, int n)
|
||||
static uint32_t rotate_left(uint32_t cw, int n)
|
||||
/* This function rotates 23 bit codeword cw left by n bits. */
|
||||
{
|
||||
int i;
|
||||
@ -107,7 +108,7 @@ static unsigned long rotate_left(unsigned long cw, int n)
|
||||
return(cw & 0x7fffffl);
|
||||
}
|
||||
|
||||
static unsigned long rotate_right(unsigned long cw, int n)
|
||||
static uint32_t rotate_right(uint32_t cw, int n)
|
||||
/* This function rotates 23 bit codeword cw right by n bits. */
|
||||
{
|
||||
int i;
|
||||
@ -126,20 +127,20 @@ static unsigned long rotate_right(unsigned long cw, int n)
|
||||
return(cw & 0x7fffffl);
|
||||
}
|
||||
|
||||
static unsigned long correct(unsigned long cw, int *errs)
|
||||
static uint32_t correct(uint32_t cw, int *errs)
|
||||
/* This function corrects Golay [23,12] codeword cw, returning the
|
||||
corrected codeword. This function will produce the corrected codeword
|
||||
for three or fewer errors. It will produce some other valid Golay
|
||||
codeword for four or more errors, possibly not the intended
|
||||
one. *errs is set to the number of bit errors corrected. */
|
||||
{
|
||||
unsigned char
|
||||
uint8_t
|
||||
w; /* current syndrome limit weight, 2 or 3 */
|
||||
unsigned long
|
||||
uint32_t
|
||||
mask; /* mask for bit flipping */
|
||||
int
|
||||
i,j; /* index */
|
||||
unsigned long
|
||||
uint32_t
|
||||
s, /* calculated syndrome */
|
||||
cwsaver; /* saves initial value of cw */
|
||||
|
||||
@ -187,17 +188,17 @@ static unsigned long correct(unsigned long cw, int *errs)
|
||||
return(cwsaver); /* return original if no corrections */
|
||||
} /* correct */
|
||||
|
||||
int golay_decode(int *errs, const unsigned char *data)
|
||||
int golay_decode(int *errs, const uint8_t *data)
|
||||
/* This function decodes codeword *cw , error correction is attempted,
|
||||
with *errs set to the number of bits corrected, and returning 0 if
|
||||
no errors exist, or 1 if parity errors exist. */
|
||||
{
|
||||
unsigned long cw = data[0] | (data[1]<<8) | (data[2]<<16);
|
||||
unsigned long parity_bit=cw & 0x800000l;
|
||||
uint32_t cw = data[0] | (data[1]<<8) | (data[2]<<16);
|
||||
uint32_t parity_bit=cw & 0x800000l;
|
||||
cw&=~0x800000l; /* remove parity bit for correction */
|
||||
cw=correct(cw, errs); /* correct up to three bits */
|
||||
cw|=parity_bit;
|
||||
if (parity(cw))
|
||||
return -1;
|
||||
*errs++;
|
||||
return cw&0xFFF;
|
||||
} /* decode */
|
||||
|
10
golay.h
10
golay.h
@ -1,2 +1,8 @@
|
||||
int golay_encode(unsigned char *data);
|
||||
int golay_decode(int *errs, unsigned char *data);
|
||||
|
||||
#ifndef __SERVALD_GOLAY_H
|
||||
#define __SERVALD_GOLAY_H
|
||||
|
||||
int golay_encode(uint8_t *data);
|
||||
int golay_decode(int *errs, uint8_t *data);
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@ HDRS= fifo.h \
|
||||
rhizome.h \
|
||||
serval.h \
|
||||
keyring.h \
|
||||
socket.h \
|
||||
cli.h \
|
||||
str.h \
|
||||
rotbuf.h \
|
||||
@ -18,6 +19,7 @@ HDRS= fifo.h \
|
||||
conf.h \
|
||||
conf_schema.h \
|
||||
crypto.h \
|
||||
dataformats.h \
|
||||
log.h \
|
||||
net.h \
|
||||
fdqueue.h \
|
||||
@ -26,4 +28,5 @@ HDRS= fifo.h \
|
||||
constants.h \
|
||||
monitor-client.h \
|
||||
mdp_client.h \
|
||||
radio_link.h \
|
||||
sqlite-amalgamation-3070900/sqlite3.h
|
||||
|
11
keyring.c
11
keyring.c
@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "crypto.h"
|
||||
#include "overlay_packet.h"
|
||||
#include "keyring.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
static void keyring_free_keypair(keypair *kp);
|
||||
static void keyring_free_context(keyring_context *c);
|
||||
@ -1764,7 +1765,7 @@ static int keyring_respond_sas(keyring_file *k, overlay_mdp_frame *req)
|
||||
alloca_tohex_sid_t(req->out.src.sid), req->out.src.port,
|
||||
alloca_tohex_sid_t(req->out.dst.sid), req->out.dst.port
|
||||
);
|
||||
return overlay_mdp_dispatch(req,0,NULL,0);
|
||||
return overlay_mdp_dispatch(req, NULL);
|
||||
}
|
||||
|
||||
// someone else is claiming to be me on this network
|
||||
@ -1790,7 +1791,7 @@ int keyring_send_unlock(struct subscriber *subscriber)
|
||||
if (crypto_sign_message(subscriber, mdp.out.payload, sizeof(mdp.out.payload), &len))
|
||||
return -1;
|
||||
mdp.out.payload_length=len;
|
||||
return overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0);
|
||||
return overlay_mdp_dispatch(&mdp, NULL);
|
||||
}
|
||||
|
||||
static int keyring_send_challenge(struct subscriber *source, struct subscriber *dest)
|
||||
@ -1815,7 +1816,7 @@ static int keyring_send_challenge(struct subscriber *source, struct subscriber *
|
||||
bcopy(source->identity->challenge, &mdp.out.payload[1], sizeof(source->identity->challenge));
|
||||
mdp.out.payload_length+=sizeof(source->identity->challenge);
|
||||
|
||||
return overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0);
|
||||
return overlay_mdp_dispatch(&mdp, NULL);
|
||||
}
|
||||
|
||||
static int keyring_respond_challenge(struct subscriber *subscriber, overlay_mdp_frame *req)
|
||||
@ -1839,7 +1840,7 @@ static int keyring_respond_challenge(struct subscriber *subscriber, overlay_mdp_
|
||||
if (crypto_sign_message(subscriber, mdp.out.payload, sizeof(mdp.out.payload), &len))
|
||||
return -1;
|
||||
mdp.out.payload_length=len;
|
||||
return overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0);
|
||||
return overlay_mdp_dispatch(&mdp, NULL);
|
||||
}
|
||||
|
||||
static int keyring_process_challenge(keyring_file *k, struct subscriber *subscriber, overlay_mdp_frame *req)
|
||||
@ -1925,7 +1926,7 @@ int keyring_send_sas_request(struct subscriber *subscriber){
|
||||
mdp.out.payload_length=1;
|
||||
mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN;
|
||||
|
||||
if (overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0))
|
||||
if (overlay_mdp_dispatch(&mdp, NULL))
|
||||
return WHY("Failed to send SAS resolution request");
|
||||
if (config.debug.keyring)
|
||||
DEBUGF("Dispatched SAS resolution request");
|
||||
|
407
mavlink.c
407
mavlink.c
@ -1,407 +0,0 @@
|
||||
// -*- Mode: C; c-basic-offset: 2; -*-
|
||||
//
|
||||
// Copyright (c) 2012 Andrew Tridgell, All Rights Reserved
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// o Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// o Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
/*
|
||||
Portions Copyright (C) 2013 Paul Gardner-Stephen
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "overlay_buffer.h"
|
||||
#include "golay.h"
|
||||
|
||||
#define MAVLINK_MSG_ID_RADIO 166
|
||||
#define MAVLINK_MSG_ID_DATASTREAM 67
|
||||
int MAVLINK_MESSAGE_CRCS[]={72, 39, 190, 92, 191, 217, 104, 119, 0, 219, 60, 186, 10, 0, 0, 0, 0, 0, 0, 0, 89, 159, 162, 121, 0, 149, 222, 110, 179, 136, 66, 126, 185, 147, 112, 252, 162, 215, 229, 128, 9, 106, 101, 213, 4, 229, 21, 214, 215, 14, 206, 50, 157, 126, 108, 213, 95, 5, 127, 0, 0, 0, 57, 126, 130, 119, 193, 191, 236, 158, 143, 0, 0, 104, 123, 131, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 143, 29, 208, 188, 118, 242, 19, 97, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 224, 60, 106, 7};
|
||||
|
||||
// use '3D' for 3DRadio
|
||||
#define RADIO_SOURCE_SYSTEM '3'
|
||||
#define RADIO_SOURCE_COMPONENT 'D'
|
||||
|
||||
uint16_t mavlink_crc(unsigned char *buf,int length)
|
||||
{
|
||||
uint16_t sum = 0xFFFF;
|
||||
uint8_t i, stoplen;
|
||||
|
||||
stoplen = length + 6;
|
||||
|
||||
// MAVLink 1.0 has an extra CRC seed
|
||||
buf[length+6] = MAVLINK_MESSAGE_CRCS[buf[5]];
|
||||
stoplen++;
|
||||
|
||||
i = 1;
|
||||
while (i<stoplen) {
|
||||
uint8_t tmp;
|
||||
tmp = buf[i] ^ (uint8_t)(sum&0xff);
|
||||
tmp ^= (tmp<<4);
|
||||
sum = (sum>>8) ^ (tmp<<8) ^ (tmp<<3) ^ (tmp>>4);
|
||||
i++;
|
||||
}
|
||||
buf[length+6]=sum&0xff;
|
||||
buf[length+7]=sum>>8;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
we use a hand-crafted MAVLink packet based on the following
|
||||
message definition
|
||||
|
||||
<message name="RADIO" id="166">
|
||||
<description>Status generated by radio</description>
|
||||
<field type="uint8_t" name="rssi">local signal strength</field>
|
||||
<field type="uint8_t" name="remrssi">remote signal strength</field>
|
||||
<field type="uint8_t" name="txbuf">percentage free space in transmit buffer</field>
|
||||
<field type="uint8_t" name="noise">background noise level</field>
|
||||
<field type="uint8_t" name="remnoise">remote background noise level</field>
|
||||
<field type="uint16_t" name="rxerrors">receive errors</field>
|
||||
<field type="uint16_t" name="fixed">count of error corrected packets</field>
|
||||
</message>
|
||||
*/
|
||||
struct mavlink_RADIO_v09 {
|
||||
uint8_t rssi;
|
||||
uint8_t remrssi;
|
||||
uint8_t txbuf;
|
||||
uint8_t noise;
|
||||
uint8_t remnoise;
|
||||
uint16_t rxerrors;
|
||||
uint16_t fixed;
|
||||
};
|
||||
struct mavlink_RADIO_v10 {
|
||||
uint16_t rxerrors;
|
||||
uint16_t fixed;
|
||||
uint8_t rssi;
|
||||
uint8_t remrssi;
|
||||
uint8_t txbuf;
|
||||
uint8_t noise;
|
||||
uint8_t remnoise;
|
||||
};
|
||||
|
||||
/*
|
||||
Each mavlink frame consists of 0xfe followed by a standard 6 byte header.
|
||||
Normally the payload plus a 2-byte CRC follows.
|
||||
We are replacing the CRC check with a Reed-Solomon code to correct as well
|
||||
as detect upto 16 bytes with errors, in return for a 32-byte overhead.
|
||||
|
||||
The nature of the particular library we are using is that the overhead is
|
||||
basically fixed, but we can shorten the data section.
|
||||
|
||||
Note that the mavlink headers are not protected against errors. This is a
|
||||
limitation of the radio firmware at present. One day we will re-write the
|
||||
radio firmware so that we can send and receive raw radio frames, and get
|
||||
rid of the mavlink framing altogether, and just send R-S protected payloads.
|
||||
|
||||
Not ideal, but will be fine for now.
|
||||
*/
|
||||
|
||||
#include "fec-3.0.1/fixed.h"
|
||||
void encode_rs_8(data_t *data, data_t *parity,int pad);
|
||||
int decode_rs_8(data_t *data, int *eras_pos, int no_eras, int pad);
|
||||
|
||||
int mavlink_encode_packet(struct overlay_interface *interface)
|
||||
{
|
||||
int count = ob_remaining(interface->tx_packet);
|
||||
int startP = (ob_position(interface->tx_packet) == 0);
|
||||
int endP = 1;
|
||||
if (count+6+32 > 255){
|
||||
count = 255-6-32;
|
||||
endP = 0;
|
||||
}
|
||||
interface->txbuffer[0]=0xfe; // mavlink v1.0 frame
|
||||
/* payload len, excluding 6 byte header and 2 byte CRC.
|
||||
But we use a 4-byte CRC, so need to add two to count to make packet lengths
|
||||
be as expected.
|
||||
Note that this construction will result in CRC errors by non-servald
|
||||
programmes, which is probably more helpful than otherwise.
|
||||
*/
|
||||
// we need 32 bytes for the parity, but this field assumes
|
||||
// that there is a 2 byte CRC, so we can save two bytes
|
||||
int len = count+32 - 2;
|
||||
interface->txbuffer[1]=len;
|
||||
interface->txbuffer[2]=(len & 0xF);
|
||||
interface->txbuffer[3]=0;
|
||||
golay_encode(&interface->txbuffer[1]);
|
||||
|
||||
interface->txbuffer[4]=(interface->mavlink_seq++) & 0x3f;
|
||||
if (startP) interface->txbuffer[4]|=0x40;
|
||||
if (endP) interface->txbuffer[4]|=0x80;
|
||||
interface->txbuffer[5]=MAVLINK_MSG_ID_DATASTREAM;
|
||||
|
||||
ob_get_bytes(interface->tx_packet, &interface->txbuffer[6], count);
|
||||
|
||||
encode_rs_8(&interface->txbuffer[4], &interface->txbuffer[6+count], 223 - (count+2));
|
||||
interface->tx_bytes_pending=len + 8;
|
||||
if (endP){
|
||||
ob_free(interface->tx_packet);
|
||||
interface->tx_packet=NULL;
|
||||
overlay_queue_schedule_next(gettime_ms());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mavlink_heartbeat(unsigned char *frame,int *outlen)
|
||||
{
|
||||
int count=9;
|
||||
bzero(frame, count+8);
|
||||
|
||||
frame[0]=0xfe; // mavlink v1.0 frame
|
||||
// Must be 9 to indicate heartbeat
|
||||
frame[1]=count; // payload len, excluding 6 byte header and 2 byte CRC
|
||||
frame[2]=(count & 0xF); // packet sequence
|
||||
frame[3]=0x00; // system ID of sender (MAV_TYPE_GENERIC)
|
||||
golay_encode(&frame[1]);
|
||||
frame[4]=0xf1; // component ID of sender (MAV_COMP_ID_UART_BRIDGE)
|
||||
// Must be zero to indicate heartbeat
|
||||
frame[5]=0; // message ID type of this frame: DATA_STREAM
|
||||
|
||||
// extra magic number to detect remote heartbeat requests
|
||||
frame[14]=0x55;
|
||||
frame[15]=0x05;
|
||||
golay_encode(&frame[14]);
|
||||
|
||||
*outlen=count+8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_heartbeat(struct overlay_interface *interface, const unsigned char *payload)
|
||||
{
|
||||
if (payload[0]==0xFE
|
||||
&& payload[1]==9
|
||||
&& payload[3]==RADIO_SOURCE_SYSTEM
|
||||
&& payload[4]==RADIO_SOURCE_COMPONENT
|
||||
&& payload[5]==MAVLINK_MSG_ID_RADIO){
|
||||
|
||||
// we can assume that radio status packets arrive without corruption
|
||||
interface->radio_rssi=(1.0*payload[10]-payload[13])/1.9;
|
||||
interface->remote_rssi=(1.0*payload[11] - payload[14])/1.9;
|
||||
int free_space = payload[12];
|
||||
int free_bytes = (free_space * 1280) / 100 - 30;
|
||||
interface->remaining_space = free_bytes;
|
||||
if (free_bytes>0)
|
||||
interface->next_tx_allowed = gettime_ms();
|
||||
if (free_bytes>720)
|
||||
interface->next_heartbeat=gettime_ms()+1000;
|
||||
if (config.debug.packetradio) {
|
||||
INFOF("Link budget = %+ddB, remote link budget = %+ddB, buffer space = %d%% (approx %d)",
|
||||
interface->radio_rssi,
|
||||
interface->remote_rssi,
|
||||
free_space, free_bytes);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mavlink_parse(struct overlay_interface *interface, struct slip_decode_state *state,
|
||||
int packet_length, unsigned char *payload, int *backtrack)
|
||||
{
|
||||
*backtrack=0;
|
||||
if (packet_length==9){
|
||||
// make sure we've heard the start and end of a remote heartbeat request
|
||||
int errs=0;
|
||||
int tail = golay_decode(&errs, &payload[14]);
|
||||
if (tail == 0x555){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int data_bytes = packet_length - (32 - 2);
|
||||
// preserve the last 16 bytes of data
|
||||
unsigned char old_footer[32];
|
||||
unsigned char *payload_footer=&payload[packet_length+8-sizeof(old_footer)];
|
||||
bcopy(payload_footer, old_footer, sizeof(old_footer));
|
||||
|
||||
int pad=223 - (data_bytes + 2);
|
||||
int errors=decode_rs_8(&payload[4], NULL, 0, pad);
|
||||
if (errors==-1){
|
||||
if (config.debug.mavlink)
|
||||
DEBUGF("Reed-Solomon error correction failed");
|
||||
return 0;
|
||||
}
|
||||
*backtrack=errors;
|
||||
|
||||
int seq=payload[4]&0x3f;
|
||||
|
||||
if (config.debug.mavlink){
|
||||
DEBUGF("Received RS protected message, len: %d, errors: %d, seq: %d, flags:%s%s",
|
||||
data_bytes,
|
||||
errors,
|
||||
seq,
|
||||
payload[4]&0x40?" start":"",
|
||||
payload[4]&0x80?" end":"");
|
||||
}
|
||||
|
||||
if (seq != ((state->mavlink_seq+1)&0x3f)){
|
||||
// reject partial packet if we missed a sequence number
|
||||
if (config.debug.mavlink)
|
||||
DEBUGF("Rejecting packet, sequence jumped from %d to %d", state->mavlink_seq, seq);
|
||||
state->packet_length=sizeof(state->dst)+1;
|
||||
}
|
||||
|
||||
if (payload[4]&0x40){
|
||||
// start a new packet
|
||||
state->packet_length=0;
|
||||
}
|
||||
|
||||
state->mavlink_seq=payload[4]&0x3f;
|
||||
if (state->packet_length + data_bytes > sizeof(state->dst)){
|
||||
if (config.debug.mavlink)
|
||||
DEBUG("Fragmented packet is too long or a previous piece was missed - discarding");
|
||||
state->packet_length=sizeof(state->dst)+1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bcopy(&payload[6], &state->dst[state->packet_length], data_bytes);
|
||||
state->packet_length+=data_bytes;
|
||||
|
||||
if (payload[4]&0x80) {
|
||||
if (config.debug.mavlink)
|
||||
DEBUGF("PDU Complete (length=%d)",state->packet_length);
|
||||
state->dst_offset=0;
|
||||
|
||||
packetOkOverlay(interface, state->dst, state->packet_length, -1, NULL, 0);
|
||||
state->packet_length=sizeof(state->dst)+1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int decode_length(struct slip_decode_state *state, unsigned char *p)
|
||||
{
|
||||
// look for a valid golay encoded length
|
||||
int errs=0;
|
||||
int length = golay_decode(&errs, p);
|
||||
if (length<0 || ((length >>8) & 0xF) != (length&0xF))
|
||||
return -1;
|
||||
length=length&0xFF;
|
||||
if (length!=9 && (length<31 || length+8>255))
|
||||
return -1;
|
||||
|
||||
if (config.debug.mavlink && (errs || state->mavlink_payload_length!=*p))
|
||||
DEBUGF("Decoded length %d to %d with %d errs", *p, length, errs);
|
||||
|
||||
state->mavlink_payload_length=length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mavlink_decode(struct overlay_interface *interface, struct slip_decode_state *state, uint8_t c)
|
||||
{
|
||||
if (state->mavlink_payload_start + state->mavlink_payload_offset >= sizeof(state->mavlink_payload)){
|
||||
// drop one byte if we run out of space
|
||||
if (config.debug.mavlink)
|
||||
DEBUGF("Dropped %02x, buffer full", state->mavlink_payload[0]);
|
||||
bcopy(state->mavlink_payload+1, state->mavlink_payload, sizeof(state->mavlink_payload) -1);
|
||||
state->mavlink_payload_start--;
|
||||
}
|
||||
|
||||
unsigned char *p = &state->mavlink_payload[state->mavlink_payload_start];
|
||||
p[state->mavlink_payload_offset++]=c;
|
||||
|
||||
while(1){
|
||||
// look for packet length headers
|
||||
p = &state->mavlink_payload[state->mavlink_payload_start];
|
||||
while(state->mavlink_payload_length==0 && state->mavlink_payload_offset>=6){
|
||||
if (p[0]==0xFE
|
||||
&& p[1]==9
|
||||
&& p[3]==RADIO_SOURCE_SYSTEM
|
||||
&& p[4]==RADIO_SOURCE_COMPONENT
|
||||
&& p[5]==MAVLINK_MSG_ID_RADIO){
|
||||
//looks like a valid heartbeat response header, read the rest and process it
|
||||
state->mavlink_payload_length=9;
|
||||
break;
|
||||
}
|
||||
|
||||
if (decode_length(state, &p[1])==0)
|
||||
break;
|
||||
|
||||
state->mavlink_payload_start++;
|
||||
state->mavlink_payload_offset--;
|
||||
p++;
|
||||
}
|
||||
|
||||
// wait for a whole packet
|
||||
if (!state->mavlink_payload_length || state->mavlink_payload_offset < state->mavlink_payload_length+8)
|
||||
return 0;
|
||||
|
||||
if (parse_heartbeat(interface, p)){
|
||||
// cut the bytes of the heartbeat out of the buffer
|
||||
state->mavlink_payload_offset -= state->mavlink_payload_length+8;
|
||||
if (state->mavlink_payload_offset){
|
||||
// shuffle bytes backwards
|
||||
bcopy(&p[state->mavlink_payload_length+8], p, state->mavlink_payload_offset);
|
||||
}
|
||||
// restart parsing for a valid header from the beginning of out buffer
|
||||
state->mavlink_payload_offset+=state->mavlink_payload_start;
|
||||
state->mavlink_payload_start=0;
|
||||
state->mavlink_payload_length=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// is this a well formed packet?
|
||||
int backtrack=0;
|
||||
if (mavlink_parse(interface, state, state->mavlink_payload_length, p, &backtrack)==1){
|
||||
// Since we know we've synced with the remote party,
|
||||
// and there's nothing we can do about any earlier data
|
||||
// throw away everything before the end of this packet
|
||||
if (state->mavlink_payload_start && config.debug.mavlink)
|
||||
dump("Skipped", state->mavlink_payload, state->mavlink_payload_start);
|
||||
|
||||
// If the packet is truncated by less than 16 bytes, RS protection should be enough to recover the packet,
|
||||
// but we may need to examine the last few bytes to find the start of the next packet.
|
||||
state->mavlink_payload_offset -= state->mavlink_payload_length+8-backtrack;
|
||||
if (state->mavlink_payload_offset){
|
||||
// shuffle all remaining bytes back to the start of the buffer
|
||||
bcopy(&state->mavlink_payload[state->mavlink_payload_start + state->mavlink_payload_length+8-backtrack],
|
||||
state->mavlink_payload, state->mavlink_payload_offset);
|
||||
}
|
||||
state->mavlink_payload_start=0;
|
||||
}else{
|
||||
// ignore the first byte for now and start looking for another packet header
|
||||
// we may find a heartbeat in the middle that we need to cut out first
|
||||
state->mavlink_payload_start++;
|
||||
state->mavlink_payload_offset--;
|
||||
}
|
||||
state->mavlink_payload_length=0;
|
||||
};
|
||||
}
|
157
mdp_client.c
157
mdp_client.c
@ -27,6 +27,7 @@
|
||||
#include "overlay_address.h"
|
||||
#include "overlay_packet.h"
|
||||
#include "mdp_client.h"
|
||||
#include "socket.h"
|
||||
|
||||
int mdp_socket(void)
|
||||
{
|
||||
@ -34,49 +35,70 @@ int mdp_socket(void)
|
||||
return overlay_mdp_client_socket();
|
||||
}
|
||||
|
||||
int mdp_close(int socket)
|
||||
static void mdp_unlink(int mdp_sock)
|
||||
{
|
||||
// use the same process for closing sockets, though this will need to change once bind is implemented
|
||||
return overlay_mdp_client_close(socket);
|
||||
// get the socket name and unlink it from the filesystem if not abstract
|
||||
struct socket_address addr;
|
||||
addr.addrlen = sizeof addr.store;
|
||||
if (getsockname(mdp_sock, &addr.addr, &addr.addrlen))
|
||||
WHYF_perror("getsockname(%d)", mdp_sock);
|
||||
else if (addr.addr.sa_family==AF_UNIX
|
||||
&& addr.addrlen > sizeof addr.local.sun_family
|
||||
&& addr.addrlen <= sizeof addr.local && addr.local.sun_path[0] != '\0') {
|
||||
if (unlink(addr.local.sun_path) == -1)
|
||||
WARNF_perror("unlink(%s)", alloca_str_toprint(addr.local.sun_path));
|
||||
}
|
||||
close(mdp_sock);
|
||||
}
|
||||
|
||||
int mdp_send(int socket, const struct mdp_header *header, const unsigned char *payload, ssize_t len)
|
||||
int mdp_close(int socket)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
if (make_local_sockaddr(&addr, &addrlen, "mdp.2.socket") == -1)
|
||||
// tell the daemon to drop all bindings
|
||||
struct mdp_header header={
|
||||
.flags = MDP_FLAG_CLOSE,
|
||||
.local.port = 0,
|
||||
};
|
||||
|
||||
mdp_send(socket, &header, NULL, 0);
|
||||
|
||||
// remove socket
|
||||
mdp_unlink(socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdp_send(int socket, const struct mdp_header *header, const uint8_t *payload, size_t len)
|
||||
{
|
||||
struct socket_address addr;
|
||||
if (make_local_sockaddr(&addr, "mdp.2.socket") == -1)
|
||||
return -1;
|
||||
|
||||
struct iovec iov[]={
|
||||
{
|
||||
.iov_base = (void *)header,
|
||||
.iov_len = sizeof(struct mdp_header)
|
||||
},
|
||||
{
|
||||
.iov_base = (void *)payload,
|
||||
.iov_len = len
|
||||
struct fragmented_data data={
|
||||
.fragment_count=2,
|
||||
.iov={
|
||||
{
|
||||
.iov_base = (void*)header,
|
||||
.iov_len = sizeof(struct mdp_header)
|
||||
},
|
||||
{
|
||||
.iov_base = (void*)payload,
|
||||
.iov_len = len
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct msghdr hdr={
|
||||
.msg_name=&addr,
|
||||
.msg_namelen=addrlen,
|
||||
.msg_iov=iov,
|
||||
.msg_iovlen=2,
|
||||
};
|
||||
|
||||
return sendmsg(socket, &hdr, 0);
|
||||
return send_message(socket, &addr, &data);
|
||||
}
|
||||
|
||||
ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, ssize_t max_len)
|
||||
ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_t max_len)
|
||||
{
|
||||
/* Construct name of socket to receive from. */
|
||||
struct sockaddr_un mdp_addr;
|
||||
socklen_t mdp_addrlen;
|
||||
if (make_local_sockaddr(&mdp_addr, &mdp_addrlen, "mdp.2.socket") == -1)
|
||||
return -1;
|
||||
errno=0;
|
||||
struct socket_address mdp_addr;
|
||||
if (make_local_sockaddr(&mdp_addr, "mdp.2.socket") == -1)
|
||||
return WHY("Failed to build socket address");
|
||||
|
||||
struct sockaddr_un addr;
|
||||
struct socket_address addr;
|
||||
struct iovec iov[]={
|
||||
{
|
||||
.iov_base = (void *)header,
|
||||
@ -89,25 +111,26 @@ ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload,
|
||||
};
|
||||
|
||||
struct msghdr hdr={
|
||||
.msg_name=&addr,
|
||||
.msg_namelen=sizeof(struct sockaddr_un),
|
||||
.msg_name=&addr.addr,
|
||||
.msg_namelen=sizeof(addr.store),
|
||||
.msg_iov=iov,
|
||||
.msg_iovlen=2,
|
||||
};
|
||||
|
||||
ssize_t len = recvmsg(socket, &hdr, 0);
|
||||
if (len<sizeof(struct mdp_header))
|
||||
return -1;
|
||||
|
||||
return WHYF("Received message is too short (%d)", (int)len);
|
||||
addr.addrlen=hdr.msg_namelen;
|
||||
// double check that the incoming address matches the servald daemon
|
||||
if (cmp_sockaddr((struct sockaddr *)&addr, hdr.msg_namelen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0
|
||||
&& ( addr.sun_family != AF_UNIX
|
||||
|| real_sockaddr(&addr, hdr.msg_namelen, &addr, &hdr.msg_namelen) <= 0
|
||||
|| cmp_sockaddr((struct sockaddr *)&addr, hdr.msg_namelen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0
|
||||
if (cmp_sockaddr(&addr, &mdp_addr) != 0
|
||||
&& ( addr.local.sun_family != AF_UNIX
|
||||
|| real_sockaddr(&addr, &addr) <= 0
|
||||
|| cmp_sockaddr(&addr, &mdp_addr) != 0
|
||||
)
|
||||
)
|
||||
return -1;
|
||||
|
||||
return WHYF("Received message came from %s instead of %s?",
|
||||
alloca_socket_address(&addr),
|
||||
alloca_socket_address(&mdp_addr));
|
||||
return len - sizeof(struct mdp_header);
|
||||
}
|
||||
|
||||
@ -125,19 +148,18 @@ int overlay_mdp_send(int mdp_sockfd, overlay_mdp_frame *mdp, int flags, int time
|
||||
if (len == -1)
|
||||
return WHY("MDP frame invalid (could not compute length)");
|
||||
/* Construct name of socket to send to. */
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
if (make_local_sockaddr(&addr, &addrlen, "mdp.socket") == -1)
|
||||
struct socket_address addr;
|
||||
if (make_local_sockaddr(&addr, "mdp.socket") == -1)
|
||||
return -1;
|
||||
// Send to that socket
|
||||
set_nonblock(mdp_sockfd);
|
||||
ssize_t result = sendto(mdp_sockfd, mdp, (size_t)len, 0, (struct sockaddr *)&addr, addrlen);
|
||||
ssize_t result = sendto(mdp_sockfd, mdp, (size_t)len, 0, &addr.addr, addr.addrlen);
|
||||
set_block(mdp_sockfd);
|
||||
if ((size_t)result != (size_t)len) {
|
||||
if (result == -1)
|
||||
WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", mdp_sockfd, (size_t)len, alloca_sockaddr(&addr, addrlen));
|
||||
WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", mdp_sockfd, (size_t)len, alloca_socket_address(&addr));
|
||||
else
|
||||
WHYF("sendto() sent %zu bytes of MDP reply (%zu) to socket=%d", (size_t)result, (size_t)len, mdp_sockfd);
|
||||
WHYF("sendto() sent %zu bytes of MDP reply (%zu) to %s", (size_t)result, (size_t)len, alloca_socket_address(&addr));
|
||||
mdp->packetTypeAndFlags=MDP_ERROR;
|
||||
mdp->error.error=1;
|
||||
snprintf(mdp->error.message,128,"Error sending frame to MDP server.");
|
||||
@ -181,16 +203,15 @@ int overlay_mdp_client_socket(void)
|
||||
{
|
||||
/* Create local per-client socket to MDP server (connection is always local) */
|
||||
int mdp_sockfd;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
struct socket_address addr;
|
||||
uint32_t random_value;
|
||||
if (urandombytes((unsigned char *)&random_value, sizeof random_value) == -1)
|
||||
return WHY("urandombytes() failed");
|
||||
if (make_local_sockaddr(&addr, &addrlen, "mdp.client.%u.%08lx.socket", getpid(), (unsigned long)random_value) == -1)
|
||||
if (make_local_sockaddr(&addr, "mdp.client.%u.%08lx.socket", getpid(), (unsigned long)random_value) == -1)
|
||||
return -1;
|
||||
if ((mdp_sockfd = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
|
||||
return -1;
|
||||
if (socket_bind(mdp_sockfd, (struct sockaddr *)&addr, addrlen) == -1) {
|
||||
if (socket_bind(mdp_sockfd, &addr.addr, addr.addrlen) == -1) {
|
||||
close(mdp_sockfd);
|
||||
return -1;
|
||||
}
|
||||
@ -204,16 +225,8 @@ int overlay_mdp_client_close(int mdp_sockfd)
|
||||
overlay_mdp_frame mdp;
|
||||
mdp.packetTypeAndFlags = MDP_GOODBYE;
|
||||
overlay_mdp_send(mdp_sockfd, &mdp, 0, 0);
|
||||
// get the socket name and unlink it from the filesystem if not abstract
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen = sizeof addr;
|
||||
if (getsockname(mdp_sockfd, (struct sockaddr *)&addr, &addrlen))
|
||||
WHYF_perror("getsockname(%d)", mdp_sockfd);
|
||||
else if (addrlen > sizeof addr.sun_family && addrlen <= sizeof addr && addr.sun_path[0] != '\0') {
|
||||
if (unlink(addr.sun_path) == -1)
|
||||
WARNF_perror("unlink(%s)", alloca_str_toprint(addr.sun_path));
|
||||
}
|
||||
close(mdp_sockfd);
|
||||
|
||||
mdp_unlink(mdp_sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -236,38 +249,40 @@ int overlay_mdp_client_poll(int mdp_sockfd, time_ms_t timeout_ms)
|
||||
int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, mdp_port_t port, int *ttl)
|
||||
{
|
||||
/* Construct name of socket to receive from. */
|
||||
struct sockaddr_un mdp_addr;
|
||||
socklen_t mdp_addrlen;
|
||||
if (make_local_sockaddr(&mdp_addr, &mdp_addrlen, "mdp.socket") == -1)
|
||||
struct socket_address mdp_addr;
|
||||
if (make_local_sockaddr(&mdp_addr, "mdp.socket") == -1)
|
||||
return -1;
|
||||
|
||||
/* Check if reply available */
|
||||
struct sockaddr_un recvaddr;
|
||||
socklen_t recvaddrlen = sizeof recvaddr;
|
||||
struct socket_address recvaddr;
|
||||
recvaddr.addrlen = sizeof recvaddr.store;
|
||||
ssize_t len;
|
||||
mdp->packetTypeAndFlags = 0;
|
||||
set_nonblock(mdp_sockfd);
|
||||
len = recvwithttl(mdp_sockfd, (unsigned char *)mdp, sizeof(overlay_mdp_frame), ttl, (struct sockaddr *)&recvaddr, &recvaddrlen);
|
||||
len = recvwithttl(mdp_sockfd, (unsigned char *)mdp, sizeof(overlay_mdp_frame), ttl, &recvaddr);
|
||||
if (len == -1)
|
||||
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p,%p)", mdp_sockfd, mdp, sizeof(overlay_mdp_frame), *ttl, &recvaddr, &recvaddrlen);
|
||||
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p(%s))",
|
||||
mdp_sockfd, mdp, sizeof(overlay_mdp_frame), *ttl,
|
||||
&recvaddr, alloca_socket_address(&recvaddr)
|
||||
);
|
||||
set_block(mdp_sockfd);
|
||||
if (len <= 0)
|
||||
return -1; // no packet received
|
||||
|
||||
// If the received address overflowed the buffer, then it cannot have come from the server, whose
|
||||
// address must always fit within a struct sockaddr_un.
|
||||
if (recvaddrlen > sizeof recvaddr)
|
||||
if (recvaddr.addrlen > sizeof recvaddr.store)
|
||||
return WHY("reply did not come from server: address overrun");
|
||||
|
||||
// Compare the address of the sender with the address of our server, to ensure they are the same.
|
||||
// If the comparison fails, then try using realpath(3) on the sender address and compare again.
|
||||
if ( cmp_sockaddr((struct sockaddr *)&recvaddr, recvaddrlen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0
|
||||
&& ( recvaddr.sun_family != AF_UNIX
|
||||
|| real_sockaddr(&recvaddr, recvaddrlen, &recvaddr, &recvaddrlen) <= 0
|
||||
|| cmp_sockaddr((struct sockaddr *)&recvaddr, recvaddrlen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0
|
||||
if ( cmp_sockaddr(&recvaddr, &mdp_addr) != 0
|
||||
&& ( recvaddr.local.sun_family != AF_UNIX
|
||||
|| real_sockaddr(&recvaddr, &recvaddr) <= 0
|
||||
|| cmp_sockaddr(&recvaddr, &mdp_addr) != 0
|
||||
)
|
||||
)
|
||||
return WHYF("reply did not come from server: %s", alloca_sockaddr(&recvaddr, recvaddrlen));
|
||||
return WHYF("reply did not come from server: %s", alloca_socket_address(&recvaddr));
|
||||
|
||||
// silently drop incoming packets for the wrong port number
|
||||
if (port>0 && port != mdp->in.dst.port){
|
||||
|
17
mdp_client.h
17
mdp_client.h
@ -31,8 +31,9 @@ struct mdp_sockaddr {
|
||||
|
||||
#define MDP_FLAG_NO_CRYPT (1<<0)
|
||||
#define MDP_FLAG_NO_SIGN (1<<1)
|
||||
#define MDP_FLAG_BIND_ALL (1<<2)
|
||||
#define MDP_FLAG_OK (1<<3)
|
||||
#define MDP_FLAG_BIND (1<<2)
|
||||
|
||||
#define MDP_FLAG_CLOSE (1<<3)
|
||||
#define MDP_FLAG_ERROR (1<<4)
|
||||
|
||||
struct mdp_header {
|
||||
@ -43,6 +44,9 @@ struct mdp_header {
|
||||
uint8_t ttl;
|
||||
};
|
||||
|
||||
#define BIND_PRIMARY SID_ANY
|
||||
#define BIND_ALL SID_BROADCAST
|
||||
|
||||
#define TYPE_SID 1
|
||||
#define TYPE_PIN 2
|
||||
#define ACTION_LOCK 1
|
||||
@ -50,6 +54,7 @@ struct mdp_header {
|
||||
|
||||
/* Port numbers for commands sent to the local daemon*/
|
||||
|
||||
#define MDP_LISTEN 0
|
||||
/* lock and unlock identities from the local keyring
|
||||
* Requests start with an mdp_identity_request structure followed by a list of pins or SIDs
|
||||
*/
|
||||
@ -82,13 +87,15 @@ struct overlay_mdp_scan{
|
||||
struct in_addr addr;
|
||||
};
|
||||
|
||||
/* V2 interface */
|
||||
/* low level V2 mdp interface */
|
||||
int mdp_socket(void);
|
||||
int mdp_close(int socket);
|
||||
int mdp_send(int socket, const struct mdp_header *header, const unsigned char *payload, ssize_t len);
|
||||
ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, ssize_t max_len);
|
||||
int mdp_send(int socket, const struct mdp_header *header, const uint8_t *payload, size_t len);
|
||||
ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_t max_len);
|
||||
int mdp_poll(int socket, time_ms_t timeout_ms);
|
||||
|
||||
|
||||
|
||||
/* Client-side MDP function */
|
||||
int overlay_mdp_client_socket(void);
|
||||
int overlay_mdp_client_close(int mdp_sockfd);
|
||||
|
1
meshms.c
1
meshms.c
@ -6,6 +6,7 @@
|
||||
#include "crypto.h"
|
||||
#include "strlcpy.h"
|
||||
#include "keyring.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
#define MESHMS_BLOCK_TYPE_ACK 0x01
|
||||
#define MESHMS_BLOCK_TYPE_MESSAGE 0x02
|
||||
|
@ -36,15 +36,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#endif
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "str.h"
|
||||
#include "strbuf_helpers.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "monitor-client.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define STATE_INIT 0
|
||||
#define STATE_DATA 1
|
||||
@ -72,12 +72,11 @@ int monitor_client_open(struct monitor_state **res)
|
||||
int fd;
|
||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
return WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)");
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
if (make_local_sockaddr(&addr, &addrlen, "monitor.socket") == -1)
|
||||
struct socket_address addr;
|
||||
if (make_local_sockaddr(&addr, "monitor.socket") == -1)
|
||||
return -1;
|
||||
INFOF("Attempting to connect to %s", alloca_sockaddr(&addr, addrlen));
|
||||
if (socket_connect(fd, (struct sockaddr*)&addr, addrlen) == -1) {
|
||||
INFOF("Attempting to connect to %s", alloca_socket_address(&addr));
|
||||
if (socket_connect(fd, &addr.addr, addr.addrlen) == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
11
monitor.c
11
monitor.c
@ -32,6 +32,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "strbuf_helpers.h"
|
||||
#include "overlay_address.h"
|
||||
#include "monitor-client.h"
|
||||
#include "socket.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
#ifdef HAVE_UCRED_H
|
||||
#include <ucred.h>
|
||||
@ -80,11 +82,10 @@ int monitor_setup_sockets()
|
||||
int sock = -1;
|
||||
if ((sock = esocket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
goto error;
|
||||
struct sockaddr_un addr;
|
||||
socklen_t addrlen;
|
||||
if (make_local_sockaddr(&addr, &addrlen, "monitor.socket") == -1)
|
||||
struct socket_address addr;
|
||||
if (make_local_sockaddr(&addr, "monitor.socket") == -1)
|
||||
goto error;
|
||||
if (socket_bind(sock, (struct sockaddr*)&addr, addrlen) == -1)
|
||||
if (socket_bind(sock, &addr.addr, addr.addrlen) == -1)
|
||||
goto error;
|
||||
if (socket_listen(sock, MAX_MONITOR_SOCKETS) == -1)
|
||||
goto error;
|
||||
@ -97,7 +98,7 @@ int monitor_setup_sockets()
|
||||
named_socket.poll.fd=sock;
|
||||
named_socket.poll.events=POLLIN;
|
||||
watch(&named_socket);
|
||||
INFOF("Monitor socket: fd=%d %s", sock, alloca_sockaddr(&addr, addrlen));
|
||||
INFOF("Monitor socket: fd=%d %s", sock, alloca_socket_address(&addr));
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
10
net.c
10
net.c
@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "net.h"
|
||||
#include "socket.h"
|
||||
#include "str.h"
|
||||
#include "strbuf_helpers.h"
|
||||
|
||||
@ -138,8 +139,7 @@ ssize_t _write_str_nonblock(int fd, const char *str, struct __sourceloc __whence
|
||||
return _write_all_nonblock(fd, str, strlen(str), __whence);
|
||||
}
|
||||
|
||||
ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl,
|
||||
struct sockaddr *recvaddr, socklen_t *recvaddrlen)
|
||||
ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl, struct socket_address *recvaddr)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
@ -147,8 +147,8 @@ ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl,
|
||||
iov[0].iov_base=buffer;
|
||||
iov[0].iov_len=bufferlen;
|
||||
bzero(&msg,sizeof(msg));
|
||||
msg.msg_name = recvaddr;
|
||||
msg.msg_namelen = *recvaddrlen;
|
||||
msg.msg_name = &recvaddr->store;
|
||||
msg.msg_namelen = recvaddr->addrlen;
|
||||
msg.msg_iov = &iov[0];
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cmsgcmsg;
|
||||
@ -187,7 +187,7 @@ ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl,
|
||||
}
|
||||
}
|
||||
}
|
||||
*recvaddrlen=msg.msg_namelen;
|
||||
recvaddr->addrlen = msg.msg_namelen;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
4
net.h
4
net.h
@ -52,6 +52,8 @@ ssize_t _write_all_nonblock(int fd, const void *buf, size_t len, struct __source
|
||||
ssize_t _writev_all(int fd, const struct iovec *iov, int iovcnt, struct __sourceloc __whence);
|
||||
ssize_t _write_str(int fd, const char *str, struct __sourceloc __whence);
|
||||
ssize_t _write_str_nonblock(int fd, const char *str, struct __sourceloc __whence);
|
||||
ssize_t recvwithttl(int sock, unsigned char *buffer, size_t bufferlen, int *ttl, struct sockaddr *recvaddr, socklen_t *recvaddrlen);
|
||||
|
||||
struct socket_address;
|
||||
ssize_t recvwithttl(int sock, unsigned char *buffer, size_t bufferlen, int *ttl, struct socket_address *);
|
||||
|
||||
#endif // __SERVALD_NET_H
|
||||
|
@ -167,7 +167,7 @@ ssize_t _ob_makespace(struct __sourceloc __whence, struct overlay_buffer *b, siz
|
||||
{
|
||||
assert(b != NULL);
|
||||
if (config.debug.overlaybuffer)
|
||||
DEBUGF("ob_makespace(b=%p, bytes=%d) b->bytes=%p b->position=%d b->allocSize=%d",
|
||||
DEBUGF("ob_makespace(b=%p, bytes=%zd) b->bytes=%p b->position=%d b->allocSize=%d",
|
||||
b, bytes, b->bytes, b->position, b->allocSize);
|
||||
assert(b->position >= 0);
|
||||
if (b->sizeLimit != -1)
|
||||
@ -177,7 +177,7 @@ ssize_t _ob_makespace(struct __sourceloc __whence, struct overlay_buffer *b, siz
|
||||
assert(b->bytes != NULL);
|
||||
if (b->sizeLimit != -1 && b->position + bytes > b->sizeLimit) {
|
||||
if (config.debug.packetformats)
|
||||
DEBUGF("ob_makespace(): asked for space to %u, beyond size limit of %u", b->position + bytes, b->sizeLimit);
|
||||
DEBUGF("ob_makespace(): asked for space to %zu, beyond size limit of %u", b->position + bytes, b->sizeLimit);
|
||||
return 0;
|
||||
}
|
||||
if (b->position + bytes <= b->allocSize)
|
||||
@ -185,7 +185,7 @@ ssize_t _ob_makespace(struct __sourceloc __whence, struct overlay_buffer *b, siz
|
||||
// Don't realloc a static buffer.
|
||||
if (b->bytes && b->allocated == NULL) {
|
||||
if (config.debug.packetformats)
|
||||
DEBUGF("ob_makespace(): asked for space to %u, beyond static buffer size of %u", b->position + bytes, b->allocSize);
|
||||
DEBUGF("ob_makespace(): asked for space to %zu, beyond static buffer size of %u", b->position + bytes, b->allocSize);
|
||||
return 0;
|
||||
}
|
||||
int newSize=b->position+bytes;
|
||||
|
@ -25,11 +25,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include <fnmatch.h>
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "net.h"
|
||||
#include "socket.h"
|
||||
#include "strbuf.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "overlay_buffer.h"
|
||||
#include "overlay_packet.h"
|
||||
#include "str.h"
|
||||
#include "radio_link.h"
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
@ -48,7 +51,6 @@ struct profile_total sock_any_stats;
|
||||
|
||||
static void overlay_interface_poll(struct sched_ent *alarm);
|
||||
static int re_init_socket(int interface_index);
|
||||
static void write_stream_buffer(overlay_interface *interface);
|
||||
|
||||
static void
|
||||
overlay_interface_close(overlay_interface *interface){
|
||||
@ -58,6 +60,8 @@ overlay_interface_close(overlay_interface *interface){
|
||||
unschedule(&interface->alarm);
|
||||
unwatch(&interface->alarm);
|
||||
close(interface->alarm.poll.fd);
|
||||
if (interface->radio_link_state)
|
||||
radio_link_free(interface);
|
||||
interface->alarm.poll.fd=-1;
|
||||
interface->state=INTERFACE_STATE_DOWN;
|
||||
}
|
||||
@ -75,8 +79,7 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface)
|
||||
switch(interface->type){
|
||||
case OVERLAY_INTERFACE_PACKETRADIO:
|
||||
strbuf_puts(b, "Type: Packet Radio<br>");
|
||||
strbuf_sprintf(b, "RSSI: %ddB<br>",interface->radio_rssi);
|
||||
strbuf_sprintf(b, "Remote RSSI: %ddB<br>",interface->remote_rssi);
|
||||
radio_link_state_html(b, interface);
|
||||
break;
|
||||
case OVERLAY_INTERFACE_ETHERNET:
|
||||
strbuf_puts(b, "Type: Ethernet<br>");
|
||||
@ -247,37 +250,39 @@ int overlay_interface_compare(overlay_interface *one, overlay_interface *two)
|
||||
// OSX doesn't recieve broadcast packets on sockets bound to an interface's address
|
||||
// So we have to bind a socket to INADDR_ANY to receive these packets.
|
||||
static void
|
||||
overlay_interface_read_any(struct sched_ent *alarm){
|
||||
overlay_interface_read_any(struct sched_ent *alarm)
|
||||
{
|
||||
if (alarm->poll.revents & POLLIN) {
|
||||
int plen=0;
|
||||
int recvttl=1;
|
||||
unsigned char packet[16384];
|
||||
overlay_interface *interface=NULL;
|
||||
struct sockaddr src_addr;
|
||||
socklen_t addrlen = sizeof(src_addr);
|
||||
struct socket_address recvaddr;
|
||||
recvaddr.addrlen = sizeof recvaddr.store;
|
||||
|
||||
/* Read only one UDP packet per call to share resources more fairly, and also
|
||||
enable stats to accurately count packets received */
|
||||
plen = recvwithttl(alarm->poll.fd, packet, sizeof packet, &recvttl, &src_addr, &addrlen);
|
||||
plen = recvwithttl(alarm->poll.fd, packet, sizeof(packet), &recvttl, &recvaddr);
|
||||
if (plen == -1) {
|
||||
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p,%p)", alarm->poll.fd, packet, sizeof packet, recvttl, &src_addr, &addrlen);
|
||||
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p(%s))",
|
||||
alarm->poll.fd, packet, sizeof packet, recvttl,
|
||||
&recvaddr, alloca_socket_address(&recvaddr)
|
||||
);
|
||||
unwatch(alarm);
|
||||
close(alarm->poll.fd);
|
||||
return;
|
||||
}
|
||||
|
||||
struct in_addr src = ((struct sockaddr_in *)&src_addr)->sin_addr;
|
||||
|
||||
/* Try to identify the real interface that the packet arrived on */
|
||||
interface = overlay_interface_find(src, 0);
|
||||
interface = overlay_interface_find(recvaddr.inet.sin_addr, 0);
|
||||
|
||||
/* Drop the packet if we don't find a match */
|
||||
if (!interface){
|
||||
if (config.debug.overlayinterfaces)
|
||||
DEBUGF("Could not find matching interface for packet received from %s", inet_ntoa(src));
|
||||
DEBUGF("Could not find matching interface for packet received from %s", inet_ntoa(recvaddr.inet.sin_addr));
|
||||
return;
|
||||
}
|
||||
packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen);
|
||||
packetOkOverlay(interface, packet, plen, recvttl, &recvaddr);
|
||||
}
|
||||
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
|
||||
INFO("Closing broadcast socket due to error");
|
||||
@ -410,8 +415,6 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
|
||||
set_destination_ref(&interface->destination, NULL);
|
||||
interface->destination = new_destination(interface, ifconfig->encapsulation);
|
||||
|
||||
interface->throttle_bytes_per_second = ifconfig->throttle;
|
||||
interface->throttle_burst_write_size = ifconfig->burst_size;
|
||||
/* Pick a reasonable default MTU.
|
||||
This will ultimately get tuned by the bandwidth and other properties of the interface */
|
||||
interface->mtu = 1200;
|
||||
@ -531,10 +534,7 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
|
||||
|
||||
switch (ifconfig->socket_type) {
|
||||
case SOCK_STREAM:
|
||||
interface->slip_decode_state.dst_offset=0;
|
||||
/* The encapsulation type should be configurable, but for now default to the one that should
|
||||
be safe on the RFD900 radios, and that also allows us to receive RSSI reports inline */
|
||||
interface->slip_decode_state.encapsulator=SLIP_FORMAT_MAVLINK;
|
||||
radio_link_init(interface);
|
||||
interface->alarm.poll.events=POLLIN|POLLOUT;
|
||||
watch(&interface->alarm);
|
||||
|
||||
@ -573,25 +573,27 @@ cleanup:
|
||||
return cleanup_ret;
|
||||
}
|
||||
|
||||
static void interface_read_dgram(struct overlay_interface *interface){
|
||||
static void interface_read_dgram(struct overlay_interface *interface)
|
||||
{
|
||||
int plen=0;
|
||||
unsigned char packet[8096];
|
||||
|
||||
struct sockaddr src_addr;
|
||||
socklen_t addrlen = sizeof(src_addr);
|
||||
|
||||
|
||||
struct socket_address recvaddr;
|
||||
recvaddr.addrlen = sizeof recvaddr.store;
|
||||
|
||||
/* Read only one UDP packet per call to share resources more fairly, and also
|
||||
enable stats to accurately count packets received */
|
||||
int recvttl=1;
|
||||
plen = recvwithttl(interface->alarm.poll.fd, packet, sizeof packet, &recvttl, &src_addr, &addrlen);
|
||||
plen = recvwithttl(interface->alarm.poll.fd,packet, sizeof(packet), &recvttl, &recvaddr);
|
||||
if (plen == -1) {
|
||||
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p,%p)", interface->alarm.poll.fd, packet, sizeof packet, recvttl, &src_addr, &addrlen);
|
||||
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p(%s))",
|
||||
interface->alarm.poll.fd, packet, sizeof packet, recvttl,
|
||||
&recvaddr, alloca_socket_address(&recvaddr)
|
||||
);
|
||||
overlay_interface_close(interface);
|
||||
return;
|
||||
}
|
||||
|
||||
packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen);
|
||||
packetOkOverlay(interface, packet, plen, recvttl, &recvaddr);
|
||||
}
|
||||
|
||||
struct file_packet{
|
||||
@ -682,8 +684,10 @@ static void interface_read_file(struct overlay_interface *interface)
|
||||
alloca_sockaddr_in(&packet.dst_addr)
|
||||
);
|
||||
}else{
|
||||
packetOkOverlay(interface, packet.payload, packet.payload_length, -1,
|
||||
(struct sockaddr*)&packet.src_addr, (socklen_t) sizeof(packet.src_addr));
|
||||
struct socket_address srcaddr;
|
||||
srcaddr.addrlen = sizeof packet.src_addr;
|
||||
srcaddr.inet = packet.src_addr;
|
||||
packetOkOverlay(interface, packet.payload, packet.payload_length, -1, &srcaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -717,101 +721,15 @@ static void interface_read_stream(struct overlay_interface *interface){
|
||||
OUT();
|
||||
return;
|
||||
}
|
||||
struct slip_decode_state *state=&interface->slip_decode_state;
|
||||
|
||||
|
||||
int i;
|
||||
for (i=0;i<nread;i++)
|
||||
mavlink_decode(interface, state, buffer[i]);
|
||||
radio_link_decode(interface, buffer[i]);
|
||||
|
||||
OUT();
|
||||
}
|
||||
|
||||
static void write_stream_buffer(overlay_interface *interface){
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
// Throttle output to a prescribed bit-rate
|
||||
// first, reduce the number of bytes based on the configured burst size
|
||||
int bytes_allowed=interface->throttle_burst_write_size;
|
||||
|
||||
int total_written=0;
|
||||
while (interface->tx_bytes_pending>0 || interface->tx_packet || interface->next_heartbeat <= now) {
|
||||
|
||||
if (interface->tx_bytes_pending==0){
|
||||
if (interface->next_heartbeat <= now){
|
||||
// Queue a hearbeat now
|
||||
mavlink_heartbeat(interface->txbuffer,&interface->tx_bytes_pending);
|
||||
if (config.debug.packetradio)
|
||||
DEBUGF("Sending heartbeat");
|
||||
interface->next_heartbeat = now+1000;
|
||||
}else if(interface->tx_packet && interface->remaining_space >= 256 + 8+9){
|
||||
// prepare a new link layer packet in txbuffer
|
||||
if (mavlink_encode_packet(interface))
|
||||
break;
|
||||
if (interface->remaining_space - interface->tx_bytes_pending < 256 + 8+9)
|
||||
interface->next_heartbeat = now;
|
||||
}
|
||||
}
|
||||
|
||||
if (interface->next_tx_allowed > now)
|
||||
break;
|
||||
|
||||
int bytes = interface->tx_bytes_pending;
|
||||
if (interface->throttle_burst_write_size && bytes>bytes_allowed)
|
||||
bytes=bytes_allowed;
|
||||
if (bytes<=0)
|
||||
break;
|
||||
|
||||
int written=write(interface->alarm.poll.fd, interface->txbuffer, bytes);
|
||||
if (written<=0){
|
||||
DEBUGF("Blocking for POLLOUT");
|
||||
break;
|
||||
}
|
||||
|
||||
interface->remaining_space-=written;
|
||||
interface->tx_bytes_pending-=written;
|
||||
total_written+=written;
|
||||
bytes_allowed-=written;
|
||||
if (interface->tx_bytes_pending){
|
||||
bcopy(&interface->txbuffer[written],&interface->txbuffer[0],
|
||||
interface->tx_bytes_pending);
|
||||
DEBUGF("Partial write, %d left", interface->tx_bytes_pending);
|
||||
}
|
||||
}
|
||||
|
||||
if (total_written>0){
|
||||
// Now when are we allowed to send more?
|
||||
int rate = interface->throttle_bytes_per_second;
|
||||
if (interface->remaining_space<=0)
|
||||
rate = 600;
|
||||
if (rate){
|
||||
int delay = total_written*1000/rate;
|
||||
if (config.debug.throttling)
|
||||
DEBUGF("Throttling for %dms (%d).", delay, interface->remaining_space);
|
||||
interface->next_tx_allowed = now + delay;
|
||||
}
|
||||
}
|
||||
|
||||
time_ms_t next_write = interface->next_tx_allowed;
|
||||
if (interface->tx_bytes_pending<=0){
|
||||
next_write = interface->next_heartbeat;
|
||||
}
|
||||
|
||||
if (interface->alarm.alarm==-1 || next_write < interface->alarm.alarm){
|
||||
interface->alarm.alarm = next_write;
|
||||
interface->alarm.deadline = interface->alarm.alarm+10;
|
||||
}
|
||||
|
||||
if (interface->tx_bytes_pending>0 && next_write <= now){
|
||||
// more to write, so set the POLLOUT flag
|
||||
interface->alarm.poll.events|=POLLOUT;
|
||||
} else {
|
||||
// Nothing to write, so clear POLLOUT flag
|
||||
interface->alarm.poll.events&=~POLLOUT;
|
||||
}
|
||||
watch(&interface->alarm);
|
||||
}
|
||||
|
||||
|
||||
static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
{
|
||||
struct overlay_interface *interface = (overlay_interface *)alarm;
|
||||
@ -823,7 +741,7 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
if (interface->state==INTERFACE_STATE_UP
|
||||
&& interface->destination->tick_ms>0
|
||||
&& interface->send_broadcasts
|
||||
&& !interface->tx_packet){
|
||||
&& !radio_link_is_busy(interface)){
|
||||
|
||||
if (now >= interface->destination->last_tx+interface->destination->tick_ms)
|
||||
overlay_send_tick_packet(interface->destination);
|
||||
@ -834,8 +752,8 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
|
||||
switch(interface->socket_type){
|
||||
case SOCK_STREAM:
|
||||
write_stream_buffer(interface);
|
||||
break;
|
||||
radio_link_tx(interface);
|
||||
return;
|
||||
case SOCK_DGRAM:
|
||||
break;
|
||||
case SOCK_FILE:
|
||||
@ -855,14 +773,8 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
if (alarm->poll.revents & POLLOUT){
|
||||
switch(interface->socket_type){
|
||||
case SOCK_STREAM:
|
||||
write_stream_buffer(interface);
|
||||
if (alarm->alarm!=-1 && interface->state==INTERFACE_STATE_UP) {
|
||||
if (alarm->alarm < now)
|
||||
alarm->alarm = now;
|
||||
unschedule(alarm);
|
||||
schedule(alarm);
|
||||
}
|
||||
break;
|
||||
radio_link_tx(interface);
|
||||
return;
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_FILE:
|
||||
//XXX error? fatal?
|
||||
@ -878,14 +790,9 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
case SOCK_STREAM:
|
||||
interface_read_stream(interface);
|
||||
// if we read a valid heartbeat packet, we may be able to write more bytes now.
|
||||
if (interface->state==INTERFACE_STATE_UP && interface->remaining_space>0){
|
||||
write_stream_buffer(interface);
|
||||
if (alarm->alarm!=-1 && interface->state==INTERFACE_STATE_UP) {
|
||||
if (alarm->alarm < now)
|
||||
alarm->alarm = now;
|
||||
unschedule(alarm);
|
||||
schedule(alarm);
|
||||
}
|
||||
if (interface->state==INTERFACE_STATE_UP){
|
||||
radio_link_tx(interface);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case SOCK_FILE:
|
||||
@ -925,24 +832,7 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
|
||||
|
||||
switch(interface->socket_type){
|
||||
case SOCK_STREAM:
|
||||
{
|
||||
if (interface->tx_packet){
|
||||
ob_free(buffer);
|
||||
return WHYF("Cannot send two packets to a stream at the same time");
|
||||
}
|
||||
|
||||
// prepare the buffer for reading
|
||||
ob_flip(buffer);
|
||||
interface->tx_packet = buffer;
|
||||
write_stream_buffer(interface);
|
||||
|
||||
if (interface->alarm.alarm!=-1){
|
||||
unschedule(&interface->alarm);
|
||||
schedule(&interface->alarm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return radio_link_queue_packet(interface, buffer);
|
||||
|
||||
case SOCK_FILE:
|
||||
{
|
||||
|
@ -313,7 +313,7 @@ int overlay_mdp_service_stun_req(overlay_mdp_frame *mdp)
|
||||
if (reply.out.payload_length){
|
||||
if (config.debug.overlayrouting)
|
||||
DEBUGF("Sending reply");
|
||||
overlay_mdp_dispatch(&reply,0 /* system generated */, NULL,0);
|
||||
overlay_mdp_dispatch(&reply, NULL);
|
||||
}
|
||||
ob_free(replypayload);
|
||||
ob_free(payload);
|
||||
@ -387,7 +387,7 @@ int overlay_send_stun_request(struct subscriber *server, struct subscriber *requ
|
||||
mdp.out.payload_length=ob_position(payload);
|
||||
if (config.debug.overlayrouting)
|
||||
DEBUGF("Sending STUN request to %s", alloca_tohex_sid_t(server->sid));
|
||||
overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
}
|
||||
ob_free(payload);
|
||||
return 0;
|
||||
|
847
overlay_mdp.c
847
overlay_mdp.c
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "crypto.h"
|
||||
#include "log.h"
|
||||
#include "keyring.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, uint64_t version, uint64_t fileOffset, uint32_t bitmap, uint16_t blockLength)
|
||||
{
|
||||
@ -99,7 +100,7 @@ int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, ui
|
||||
reply.out.payload[0]='T';
|
||||
|
||||
// send packet
|
||||
if (overlay_mdp_dispatch(&reply,0 /* system generated */, NULL,0))
|
||||
if (overlay_mdp_dispatch(&reply, NULL))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -252,8 +253,7 @@ int overlay_mdp_service_echo(overlay_mdp_frame *mdp)
|
||||
mdp->packetTypeAndFlags&=~(MDP_NOCRYPT|MDP_NOSIGN);
|
||||
|
||||
/* queue frame for delivery */
|
||||
overlay_mdp_dispatch(mdp,0 /* system generated */,
|
||||
NULL,0);
|
||||
overlay_mdp_dispatch(mdp, NULL);
|
||||
mdp->packetTypeAndFlags=preserved;
|
||||
|
||||
/* and switch addresses back around in case the caller was planning on
|
||||
@ -342,20 +342,20 @@ static int overlay_mdp_service_trace(overlay_mdp_frame *mdp){
|
||||
mdp->out.payload_length = ob_position(b);
|
||||
mdp->out.src.sid = my_subscriber->sid;
|
||||
mdp->out.dst.sid = next->sid;
|
||||
ret = overlay_mdp_dispatch(mdp, 0, NULL, 0);
|
||||
ret = overlay_mdp_dispatch(mdp, NULL);
|
||||
end:
|
||||
ob_free(b);
|
||||
RETURN(ret);
|
||||
}
|
||||
|
||||
static int overlay_mdp_service_manifest_requests(struct overlay_frame *frame, overlay_mdp_frame *mdp)
|
||||
static int overlay_mdp_service_manifest_requests(struct overlay_frame *frame, const uint8_t *payload, size_t len)
|
||||
{
|
||||
int offset=0;
|
||||
while (offset<mdp->out.payload_length) {
|
||||
while (offset<len) {
|
||||
rhizome_manifest *m = rhizome_new_manifest();
|
||||
if (!m)
|
||||
return WHY("Unable to allocate manifest");
|
||||
unsigned char *bar = &mdp->out.payload[offset];
|
||||
const unsigned char *bar = &payload[offset];
|
||||
if (!rhizome_retrieve_manifest_by_prefix(&bar[RHIZOME_BAR_PREFIX_OFFSET], RHIZOME_BAR_PREFIX_BYTES, m)){
|
||||
rhizome_advertise_manifest(frame->source, m);
|
||||
// pre-emptively send the payload if it will fit in a single packet
|
||||
@ -368,7 +368,7 @@ static int overlay_mdp_service_manifest_requests(struct overlay_frame *frame, ov
|
||||
return 0;
|
||||
}
|
||||
|
||||
int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp)
|
||||
int overlay_mdp_try_internal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp)
|
||||
{
|
||||
IN();
|
||||
switch(mdp->out.dst.port) {
|
||||
@ -383,7 +383,7 @@ int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_fr
|
||||
case MDP_PORT_STUN: RETURN(overlay_mdp_service_stun(mdp));
|
||||
case MDP_PORT_RHIZOME_REQUEST: RETURN(overlay_mdp_service_rhizomerequest(frame, mdp));
|
||||
case MDP_PORT_RHIZOME_RESPONSE: RETURN(overlay_mdp_service_rhizomeresponse(mdp));
|
||||
case MDP_PORT_RHIZOME_MANIFEST_REQUEST: RETURN(overlay_mdp_service_manifest_requests(frame, mdp));
|
||||
case MDP_PORT_RHIZOME_MANIFEST_REQUEST: RETURN(overlay_mdp_service_manifest_requests(frame, mdp->out.payload, mdp->out.payload_length));
|
||||
case MDP_PORT_RHIZOME_SYNC: RETURN(overlay_mdp_service_rhizome_sync(frame, mdp));
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "socket.h"
|
||||
#include "str.h"
|
||||
#include "strbuf.h"
|
||||
#include "overlay_buffer.h"
|
||||
@ -320,7 +321,7 @@ int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface
|
||||
}
|
||||
|
||||
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
|
||||
int recvttl, struct sockaddr *recvaddr, socklen_t recvaddrlen)
|
||||
int recvttl, struct socket_address *recvaddr)
|
||||
{
|
||||
IN();
|
||||
/*
|
||||
@ -385,8 +386,8 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
|
||||
}
|
||||
}
|
||||
|
||||
if (recvaddr&&recvaddr->sa_family!=AF_INET)
|
||||
RETURN(WHYF("Unexpected protocol family %d",recvaddr->sa_family));
|
||||
if (recvaddr && recvaddr->addr.sa_family != AF_INET)
|
||||
RETURN(WHYF("Unexpected protocol family %d", recvaddr->addr.sa_family));
|
||||
|
||||
struct overlay_frame f;
|
||||
struct decode_context context;
|
||||
@ -399,11 +400,11 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
|
||||
|
||||
f.interface = interface;
|
||||
if (recvaddr)
|
||||
f.recvaddr = *((struct sockaddr_in *)recvaddr);
|
||||
f.recvaddr = recvaddr->inet;
|
||||
else
|
||||
bzero(&f.recvaddr, sizeof f.recvaddr);
|
||||
|
||||
int ret=parseEnvelopeHeader(&context, interface, (struct sockaddr_in *)recvaddr, b);
|
||||
int ret=parseEnvelopeHeader(&context, interface, recvaddr ? &recvaddr->inet : NULL, b);
|
||||
if (ret){
|
||||
ob_free(b);
|
||||
RETURN(ret);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "conf.h"
|
||||
#include "overlay_buffer.h"
|
||||
#include "overlay_packet.h"
|
||||
#include "radio_link.h"
|
||||
#include "str.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
@ -290,7 +291,7 @@ overlay_calc_queue_time(overlay_txqueue *queue, struct overlay_frame *frame){
|
||||
int i;
|
||||
for(i=0;i<frame->destination_count;i++)
|
||||
{
|
||||
if (frame->destinations[i].destination->interface->tx_packet)
|
||||
if (radio_link_is_busy(frame->destinations[i].destination->interface))
|
||||
continue;
|
||||
time_ms_t next_packet = limit_next_allowed(&frame->destinations[i].destination->transfer_limit);
|
||||
if (frame->destinations[i].transmit_time){
|
||||
@ -403,8 +404,7 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
|
||||
}
|
||||
}else{
|
||||
// skip this interface if the stream tx buffer has data
|
||||
if (dest->interface->socket_type==SOCK_STREAM
|
||||
&& dest->interface->tx_packet)
|
||||
if (radio_link_is_busy(dest->interface))
|
||||
continue;
|
||||
|
||||
// can we send a packet on this interface now?
|
||||
|
@ -149,17 +149,8 @@ int fd_showstats()
|
||||
stats = stats->_next;
|
||||
}
|
||||
|
||||
// Show periodic rhizome transfer information, but only
|
||||
// if there are some active rhizome transfers.
|
||||
if (rhizome_active_fetch_count()!=0)
|
||||
INFOF("Rhizome transfer progress: %"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64" (remaining %"PRIu64")",
|
||||
rhizome_active_fetch_bytes_received(0),
|
||||
rhizome_active_fetch_bytes_received(1),
|
||||
rhizome_active_fetch_bytes_received(2),
|
||||
rhizome_active_fetch_bytes_received(3),
|
||||
rhizome_active_fetch_bytes_received(4),
|
||||
rhizome_active_fetch_bytes_received(5),
|
||||
rhizome_fetch_queue_bytes());
|
||||
// Show periodic rhizome transfer information
|
||||
rhizome_fetch_log_short_status();
|
||||
|
||||
// Report any functions that take too much time
|
||||
if (!config.debug.timing)
|
||||
@ -168,8 +159,8 @@ int fd_showstats()
|
||||
while(stats!=NULL){
|
||||
/* If a function spends more than 1 second in any
|
||||
notionally 3 second period, then dob on it */
|
||||
if (stats->total_time>1000
|
||||
&&strcmp(stats->name,"Idle (in poll)"))
|
||||
if ((stats->total_time>1000 || stats->calls > 10000)
|
||||
&& strcmp(stats->name,"Idle (in poll)"))
|
||||
fd_showstat(&total,stats);
|
||||
stats = stats->_next;
|
||||
}
|
||||
|
546
radio_link.c
Normal file
546
radio_link.c
Normal file
@ -0,0 +1,546 @@
|
||||
// -*- Mode: C; c-basic-offset: 2; -*-
|
||||
//
|
||||
// Copyright (c) 2012 Andrew Tridgell, All Rights Reserved
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// o Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// o Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in
|
||||
// the documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
/*
|
||||
Portions Copyright (C) 2013 Paul Gardner-Stephen
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "overlay_buffer.h"
|
||||
#include "golay.h"
|
||||
#include "radio_link.h"
|
||||
|
||||
#define MAVLINK_MSG_ID_RADIO 166
|
||||
#define MAVLINK_MSG_ID_DATASTREAM 67
|
||||
|
||||
// use '3D' for 3DRadio
|
||||
#define RADIO_SOURCE_SYSTEM '3'
|
||||
#define RADIO_SOURCE_COMPONENT 'D'
|
||||
|
||||
/*
|
||||
we use a hand-crafted MAVLink packet based on the following
|
||||
message definition
|
||||
|
||||
struct mavlink_RADIO_v10 {
|
||||
uint16_t rxerrors; // receive errors
|
||||
uint16_t fixed; // count of error corrected packets
|
||||
uint8_t rssi; // local signal strength
|
||||
uint8_t remrssi; // remote signal strength
|
||||
uint8_t txbuf; // percentage free space in transmit buffer
|
||||
uint8_t noise; // background noise level
|
||||
uint8_t remnoise; // remote background noise level
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
#define FEC_LENGTH 32
|
||||
#define FEC_MAX_BYTES 223
|
||||
#define RADIO_HEADER_LENGTH 6
|
||||
#define RADIO_USED_HEADER_LENGTH 4
|
||||
#define RADIO_CRC_LENGTH 2
|
||||
|
||||
#define LINK_PAYLOAD_MTU (LINK_MTU - FEC_LENGTH - RADIO_HEADER_LENGTH - RADIO_CRC_LENGTH)
|
||||
|
||||
struct radio_link_state{
|
||||
// next seq for transmission
|
||||
int tx_seq;
|
||||
|
||||
// small buffer for parsing incoming bytes from the serial interface,
|
||||
// looking for recoverable link layer packets
|
||||
// should be large enough to hold at least one packet from the remote end
|
||||
// plus one heartbeat packet from the local firmware
|
||||
uint8_t payload[LINK_MTU*3];
|
||||
|
||||
// decoded length of next link layer packet
|
||||
// including all header and footer bytes
|
||||
int payload_length;
|
||||
// last rx seq for reassembly
|
||||
int seq;
|
||||
// offset within payload that we have found a valid looking header
|
||||
int payload_start;
|
||||
// offset after payload_start for incoming bytes
|
||||
int payload_offset;
|
||||
|
||||
// small buffer for assembling mdp payloads.
|
||||
uint8_t dst[MDP_MTU];
|
||||
// length of recovered packet
|
||||
int packet_length;
|
||||
|
||||
// next firmware heartbeat
|
||||
time_ms_t next_heartbeat;
|
||||
|
||||
time_ms_t last_packet;
|
||||
|
||||
// parsed rssi
|
||||
int radio_rssi;
|
||||
int remote_rssi;
|
||||
// estimated firmware buffer space
|
||||
int32_t remaining_space;
|
||||
|
||||
// next serial write
|
||||
uint64_t next_tx_allowed;
|
||||
// partially sent packet
|
||||
struct overlay_buffer *tx_packet;
|
||||
|
||||
// serial write buffer
|
||||
uint8_t txbuffer[LINK_MTU];
|
||||
int tx_bytes;
|
||||
int tx_pos;
|
||||
};
|
||||
|
||||
/*
|
||||
Each mavlink frame consists of 0xfe followed by a standard 6 byte header.
|
||||
Normally the payload plus a 2-byte CRC follows.
|
||||
We are replacing the CRC check with a Reed-Solomon code to correct as well
|
||||
as detect upto 16 bytes with errors, in return for a 32-byte overhead.
|
||||
|
||||
The nature of the particular library we are using is that the overhead is
|
||||
basically fixed, but we can shorten the data section.
|
||||
|
||||
Note that the mavlink headers are not protected against errors. This is a
|
||||
limitation of the radio firmware at present. One day we will re-write the
|
||||
radio firmware so that we can send and receive raw radio frames, and get
|
||||
rid of the mavlink framing altogether, and just send R-S protected payloads.
|
||||
|
||||
Not ideal, but will be fine for now.
|
||||
*/
|
||||
|
||||
#include "fec-3.0.1/fixed.h"
|
||||
void encode_rs_8(data_t *data, data_t *parity,int pad);
|
||||
int decode_rs_8(data_t *data, int *eras_pos, int no_eras, int pad);
|
||||
|
||||
int radio_link_free(struct overlay_interface *interface)
|
||||
{
|
||||
if (interface->radio_link_state){
|
||||
free(interface->radio_link_state);
|
||||
interface->radio_link_state=NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int radio_link_init(struct overlay_interface *interface)
|
||||
{
|
||||
interface->radio_link_state = emalloc_zero(sizeof(struct radio_link_state));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void radio_link_state_html(struct strbuf *b, struct overlay_interface *interface)
|
||||
{
|
||||
struct radio_link_state *state = interface->radio_link_state;
|
||||
strbuf_sprintf(b, "RSSI: %ddB<br>", state->radio_rssi);
|
||||
strbuf_sprintf(b, "Remote RSSI: %ddB<br>", state->remote_rssi);
|
||||
}
|
||||
|
||||
// write a new link layer packet to interface->txbuffer
|
||||
// consuming more bytes from the next interface->tx_packet if required
|
||||
static int radio_link_encode_packet(struct radio_link_state *link_state)
|
||||
{
|
||||
// if we have nothing interesting left to send, don't create a packet at all
|
||||
if (!link_state->tx_packet)
|
||||
return 0;
|
||||
|
||||
int count = ob_remaining(link_state->tx_packet);
|
||||
int startP = (ob_position(link_state->tx_packet) == 0);
|
||||
int endP = 1;
|
||||
if (count > LINK_PAYLOAD_MTU){
|
||||
count = LINK_PAYLOAD_MTU;
|
||||
endP = 0;
|
||||
}
|
||||
|
||||
link_state->txbuffer[0]=0xfe; // mavlink v1.0 magic header
|
||||
|
||||
// we need to add FEC_LENGTH for FEC, but the length field doesn't include the expected headers or CRC
|
||||
int len = count + FEC_LENGTH - RADIO_CRC_LENGTH;
|
||||
link_state->txbuffer[1]=len; // mavlink payload length
|
||||
link_state->txbuffer[2]=(len & 0xF);
|
||||
link_state->txbuffer[3]=0;
|
||||
|
||||
// add golay encoding so that decoding the actual length is more reliable
|
||||
golay_encode(&link_state->txbuffer[1]);
|
||||
|
||||
|
||||
link_state->txbuffer[4]=(link_state->tx_seq++) & 0x3f;
|
||||
if (startP) link_state->txbuffer[4]|=0x40;
|
||||
if (endP) link_state->txbuffer[4]|=0x80;
|
||||
link_state->txbuffer[5]=MAVLINK_MSG_ID_DATASTREAM;
|
||||
|
||||
ob_get_bytes(link_state->tx_packet, &link_state->txbuffer[6], count);
|
||||
|
||||
encode_rs_8(&link_state->txbuffer[4], &link_state->txbuffer[6+count], FEC_MAX_BYTES - (count+2));
|
||||
link_state->tx_bytes=len + RADIO_CRC_LENGTH + RADIO_HEADER_LENGTH;
|
||||
if (endP){
|
||||
ob_free(link_state->tx_packet);
|
||||
link_state->tx_packet=NULL;
|
||||
overlay_queue_schedule_next(gettime_ms());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int radio_link_is_busy(struct overlay_interface *interface)
|
||||
{
|
||||
if (interface->radio_link_state && interface->radio_link_state->tx_packet)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int radio_link_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer)
|
||||
{
|
||||
struct radio_link_state *link_state = interface->radio_link_state;
|
||||
|
||||
if (link_state->tx_packet){
|
||||
ob_free(buffer);
|
||||
return WHYF("Cannot send two packets to a stream at the same time");
|
||||
}
|
||||
|
||||
// prepare the buffer for reading
|
||||
ob_flip(buffer);
|
||||
link_state->tx_packet = buffer;
|
||||
radio_link_tx(interface);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int build_heartbeat(struct radio_link_state *link_state)
|
||||
{
|
||||
int count=9;
|
||||
bzero(link_state->txbuffer, count + RADIO_CRC_LENGTH + RADIO_HEADER_LENGTH);
|
||||
|
||||
link_state->txbuffer[0]=0xfe; // mavlink v1.0 link_state->txbuffer
|
||||
// Must be 9 to indicate heartbeat
|
||||
link_state->txbuffer[1]=count; // payload len, excluding 6 byte header and 2 byte CRC
|
||||
link_state->txbuffer[2]=(count & 0xF); // packet sequence
|
||||
link_state->txbuffer[3]=0x00; // system ID of sender (MAV_TYPE_GENERIC)
|
||||
// we're golay encoding the length to improve the probability of skipping it correctly
|
||||
golay_encode(&link_state->txbuffer[1]);
|
||||
link_state->txbuffer[4]=0xf1; // component ID of sender (MAV_COMP_ID_UART_BRIDGE)
|
||||
// Must be zero to indicate heartbeat
|
||||
link_state->txbuffer[5]=0; // message ID type of this link_state->txbuffer: DATA_STREAM
|
||||
|
||||
// extra magic number to help correctly detect remote heartbeat requests
|
||||
link_state->txbuffer[14]=0x55;
|
||||
link_state->txbuffer[15]=0x05;
|
||||
golay_encode(&link_state->txbuffer[14]);
|
||||
link_state->tx_bytes = count + RADIO_CRC_LENGTH + RADIO_HEADER_LENGTH;
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("Produced heartbeat");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// write a new link layer packet to interface->txbuffer
|
||||
// consuming more bytes from the next interface->tx_packet if required
|
||||
int radio_link_tx(struct overlay_interface *interface)
|
||||
{
|
||||
struct radio_link_state *link_state = interface->radio_link_state;
|
||||
|
||||
unschedule(&interface->alarm);
|
||||
interface->alarm.alarm = 0;
|
||||
time_ms_t next_tick = interface->destination->last_tx+interface->destination->tick_ms;
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
while(1){
|
||||
|
||||
if (link_state->tx_bytes){
|
||||
if (link_state->next_tx_allowed > now){
|
||||
interface->alarm.alarm = link_state->next_tx_allowed;
|
||||
break;
|
||||
}
|
||||
|
||||
int written=write(interface->alarm.poll.fd, &link_state->txbuffer[link_state->tx_pos], link_state->tx_bytes);
|
||||
if (written<=0){
|
||||
interface->alarm.poll.events|=POLLOUT;
|
||||
break;
|
||||
}
|
||||
link_state->remaining_space-=written;
|
||||
link_state->tx_bytes-=written;
|
||||
if (link_state->tx_bytes)
|
||||
link_state->tx_pos+=written;
|
||||
else
|
||||
link_state->tx_pos=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
interface->alarm.poll.events&=~POLLOUT;
|
||||
|
||||
if (link_state->next_heartbeat<=now){
|
||||
build_heartbeat(link_state);
|
||||
link_state->next_heartbeat = now + 1000;
|
||||
continue;
|
||||
}
|
||||
|
||||
// out of space? Don't bother to send anything interesting
|
||||
// until we hear the next heartbeat response
|
||||
if (link_state->remaining_space < LINK_MTU + HEARTBEAT_SIZE){
|
||||
interface->alarm.alarm = link_state->next_heartbeat;
|
||||
break;
|
||||
}
|
||||
|
||||
if (link_state->remaining_space < LINK_MTU + HEARTBEAT_SIZE)
|
||||
link_state->next_heartbeat = now;
|
||||
|
||||
if (!link_state->tx_packet){
|
||||
// finished current packet, wait for more.
|
||||
interface->alarm.alarm = next_tick;
|
||||
break;
|
||||
}
|
||||
|
||||
// encode another packet fragment
|
||||
radio_link_encode_packet(link_state);
|
||||
link_state->last_packet = now;
|
||||
}
|
||||
|
||||
watch(&interface->alarm);
|
||||
if (interface->alarm.alarm<now)
|
||||
interface->alarm.alarm=now;
|
||||
if (interface->alarm.alarm){
|
||||
interface->alarm.deadline = interface->alarm.alarm+100;
|
||||
schedule(&interface->alarm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_heartbeat(struct radio_link_state *state, const unsigned char *payload)
|
||||
{
|
||||
if (payload[0]==0xFE
|
||||
&& payload[1]==9
|
||||
&& payload[3]==RADIO_SOURCE_SYSTEM
|
||||
&& payload[4]==RADIO_SOURCE_COMPONENT
|
||||
&& payload[5]==MAVLINK_MSG_ID_RADIO){
|
||||
|
||||
// we can assume that radio status packets arrive without corruption
|
||||
state->radio_rssi=(1.0*payload[10]-payload[13])/1.9;
|
||||
state->remote_rssi=(1.0*payload[11] - payload[14])/1.9;
|
||||
int free_space = payload[12];
|
||||
int free_bytes = (free_space * 1280) / 100 - 30;
|
||||
state->remaining_space = free_bytes;
|
||||
if (free_bytes>0)
|
||||
state->next_tx_allowed = gettime_ms();
|
||||
if (free_bytes>720)
|
||||
state->next_heartbeat=gettime_ms()+1000;
|
||||
if (config.debug.packetradio)
|
||||
INFOF("Link budget = %+ddB, remote link budget = %+ddB, buffer space = %d%% (approx %d)",
|
||||
state->radio_rssi,
|
||||
state->remote_rssi,
|
||||
free_space, free_bytes);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radio_link_parse(struct overlay_interface *interface, struct radio_link_state *state,
|
||||
size_t packet_length, uint8_t *payload, int *backtrack)
|
||||
{
|
||||
*backtrack=0;
|
||||
if (packet_length==17){
|
||||
// if we've heard the start and end of a remote heartbeat request
|
||||
// we can skip it without checking anything else
|
||||
int errs=0;
|
||||
int tail = golay_decode(&errs, &payload[14]);
|
||||
if (tail == 0x555){
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("Decoded remote heartbeat request");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t data_bytes = packet_length - (RADIO_USED_HEADER_LENGTH + FEC_LENGTH);
|
||||
|
||||
int errors=decode_rs_8(&payload[4], NULL, 0, FEC_MAX_BYTES - data_bytes);
|
||||
if (errors==-1){
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("Reed-Solomon error correction failed");
|
||||
return 0;
|
||||
}
|
||||
*backtrack=errors;
|
||||
data_bytes -= 2;
|
||||
int seq=payload[4]&0x3f;
|
||||
|
||||
if (config.debug.radio_link){
|
||||
DEBUGF("Received RS protected message, len: %zd, errors: %d, seq: %d, flags:%s%s",
|
||||
data_bytes,
|
||||
errors,
|
||||
seq,
|
||||
payload[4]&0x40?" start":"",
|
||||
payload[4]&0x80?" end":"");
|
||||
}
|
||||
|
||||
if (seq != ((state->seq+1)&0x3f)){
|
||||
// reject partial packet if we missed a sequence number
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("Rejecting packet, sequence jumped from %d to %d", state->seq, seq);
|
||||
state->packet_length=sizeof(state->dst)+1;
|
||||
}
|
||||
|
||||
if (payload[4]&0x40){
|
||||
// start a new packet
|
||||
state->packet_length=0;
|
||||
}
|
||||
|
||||
state->seq=payload[4]&0x3f;
|
||||
if (state->packet_length + data_bytes > sizeof(state->dst)){
|
||||
if (config.debug.radio_link)
|
||||
DEBUG("Fragmented packet is too long or a previous piece was missed - discarding");
|
||||
state->packet_length=sizeof(state->dst)+1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bcopy(&payload[RADIO_HEADER_LENGTH], &state->dst[state->packet_length], data_bytes);
|
||||
state->packet_length+=data_bytes;
|
||||
|
||||
if (payload[4]&0x80) {
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("PDU Complete (length=%d)",state->packet_length);
|
||||
|
||||
packetOkOverlay(interface, state->dst, state->packet_length, -1, NULL);
|
||||
state->packet_length=sizeof(state->dst)+1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int decode_length(struct radio_link_state *state, unsigned char *p)
|
||||
{
|
||||
// look for a valid golay encoded length
|
||||
int errs=0;
|
||||
int length = golay_decode(&errs, p);
|
||||
if (length<0 || ((length >>8) & 0xF) != (length&0xF))
|
||||
return -1;
|
||||
length=length&0xFF;
|
||||
length += RADIO_HEADER_LENGTH + RADIO_CRC_LENGTH;
|
||||
|
||||
if (length!=17 && (length <= FEC_LENGTH || length > LINK_MTU))
|
||||
return -1;
|
||||
|
||||
if (config.debug.radio_link && (errs || state->payload_length!=*p))
|
||||
DEBUGF("Decoded length %d to %d with %d errs", *p, length, errs);
|
||||
|
||||
state->payload_length=length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// add one byte at a time from the serial link, and attempt to decode packets
|
||||
int radio_link_decode(struct overlay_interface *interface, uint8_t c)
|
||||
{
|
||||
IN();
|
||||
struct radio_link_state *state=interface->radio_link_state;
|
||||
|
||||
if (state->payload_start + state->payload_offset >= sizeof(state->payload)){
|
||||
// drop one byte if we run out of space
|
||||
if (config.debug.radio_link)
|
||||
DEBUGF("Dropped %02x, buffer full", state->payload[0]);
|
||||
bcopy(state->payload+1, state->payload, sizeof(state->payload) -1);
|
||||
state->payload_start--;
|
||||
}
|
||||
|
||||
unsigned char *p = &state->payload[state->payload_start];
|
||||
p[state->payload_offset++]=c;
|
||||
|
||||
while(1){
|
||||
// look for packet length headers
|
||||
p = &state->payload[state->payload_start];
|
||||
while(state->payload_length==0 && state->payload_offset>=6){
|
||||
if (p[0]==0xFE
|
||||
&& p[1]==9
|
||||
&& p[3]==RADIO_SOURCE_SYSTEM
|
||||
&& p[4]==RADIO_SOURCE_COMPONENT
|
||||
&& p[5]==MAVLINK_MSG_ID_RADIO){
|
||||
//looks like a valid heartbeat response header, read the rest and process it
|
||||
state->payload_length=17;
|
||||
break;
|
||||
}
|
||||
|
||||
if (decode_length(state, &p[1])==0)
|
||||
break;
|
||||
|
||||
state->payload_start++;
|
||||
state->payload_offset--;
|
||||
p++;
|
||||
}
|
||||
|
||||
// wait for a whole packet
|
||||
if (!state->payload_length || state->payload_offset < state->payload_length)
|
||||
RETURN(0);
|
||||
|
||||
if (parse_heartbeat(state, p)){
|
||||
// cut the bytes of the heartbeat out of the buffer
|
||||
state->payload_offset -= state->payload_length;
|
||||
if (state->payload_offset){
|
||||
// shuffle bytes backwards
|
||||
bcopy(&p[state->payload_length], p, state->payload_offset);
|
||||
}
|
||||
// restart parsing for a valid header from the beginning of out buffer
|
||||
state->payload_offset+=state->payload_start;
|
||||
state->payload_start=0;
|
||||
state->payload_length=0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// is this a well formed packet?
|
||||
int backtrack=0;
|
||||
if (radio_link_parse(interface, state, state->payload_length, p, &backtrack)==1){
|
||||
// Since we know we've synced with the remote party,
|
||||
// and there's nothing we can do about any earlier data
|
||||
// throw away everything before the end of this packet
|
||||
if (state->payload_start && config.debug.radio_link)
|
||||
dump("Skipped", state->payload, state->payload_start);
|
||||
|
||||
// If the packet is truncated by less than 16 bytes, RS protection should be enough to recover the packet,
|
||||
// but we may need to examine the last few bytes to find the start of the next packet.
|
||||
state->payload_offset -= state->payload_length - backtrack;
|
||||
if (state->payload_offset){
|
||||
// shuffle all remaining bytes back to the start of the buffer
|
||||
bcopy(&state->payload[state->payload_start + state->payload_length - backtrack],
|
||||
state->payload, state->payload_offset);
|
||||
}
|
||||
state->payload_start=0;
|
||||
}else{
|
||||
// ignore the first byte for now and start looking for another packet header
|
||||
// we may find a heartbeat in the middle that we need to cut out first
|
||||
state->payload_start++;
|
||||
state->payload_offset--;
|
||||
}
|
||||
state->payload_length=0;
|
||||
};
|
||||
RETURN(0);
|
||||
}
|
15
radio_link.h
Normal file
15
radio_link.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef __SERVALD_RADIO_LINK_H
|
||||
#define __SERVALD_RADIO_LINK_H
|
||||
|
||||
#define HEARTBEAT_SIZE (8+9)
|
||||
#define LINK_MTU 255
|
||||
|
||||
int radio_link_free(struct overlay_interface *interface);
|
||||
int radio_link_init(struct overlay_interface *interface);
|
||||
int radio_link_decode(struct overlay_interface *interface, uint8_t c);
|
||||
int radio_link_tx(struct overlay_interface *interface);
|
||||
void radio_link_state_html(struct strbuf *b, struct overlay_interface *interface);
|
||||
int radio_link_is_busy(struct overlay_interface *interface);
|
||||
int radio_link_queue_packet(struct overlay_interface *interface, struct overlay_buffer *buffer);
|
||||
|
||||
#endif
|
@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "conf.h"
|
||||
#include "str.h"
|
||||
#include "rhizome.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
int is_rhizome_enabled()
|
||||
{
|
||||
|
11
rhizome.h
11
rhizome.h
@ -424,16 +424,6 @@ int rhizome_cleanup(struct rhizome_cleanup_report *report);
|
||||
int rhizome_manifest_createid(rhizome_manifest *m);
|
||||
int rhizome_get_bundle_from_seed(rhizome_manifest *m, const char *seed);
|
||||
|
||||
int rhizome_strn_is_manifest_id(const char *text);
|
||||
int rhizome_str_is_manifest_id(const char *text);
|
||||
int rhizome_strn_is_bundle_key(const char *text);
|
||||
int rhizome_str_is_bundle_key(const char *text);
|
||||
int rhizome_strn_is_bundle_crypt_key(const char *text);
|
||||
int rhizome_str_is_bundle_crypt_key(const char *text);
|
||||
int rhizome_strn_is_file_hash(const char *text);
|
||||
int rhizome_str_is_file_hash(const char *text);
|
||||
int rhizome_str_is_manifest_service(const char *text);
|
||||
|
||||
int is_http_header_complete(const char *buf, size_t len, size_t read_since_last_call);
|
||||
|
||||
typedef struct sqlite_retry_state {
|
||||
@ -908,7 +898,6 @@ enum rhizome_start_fetch_result {
|
||||
enum rhizome_start_fetch_result rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip, const sid_t *sidp, const unsigned char *prefix, size_t prefix_length);
|
||||
int rhizome_any_fetch_active();
|
||||
int rhizome_any_fetch_queued();
|
||||
uint64_t rhizome_fetch_queue_bytes();
|
||||
int rhizome_fetch_status_html(struct strbuf *b);
|
||||
int rhizome_fetch_has_queue_space(unsigned char log2_size);
|
||||
|
||||
|
@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "str.h"
|
||||
#include "mem.h"
|
||||
#include "keyring.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
static const char *rhizome_manifest_get(const rhizome_manifest *m, const char *var)
|
||||
{
|
||||
|
@ -23,13 +23,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "crypto_sign_edwards25519sha512batch.h"
|
||||
#include "nacl/src/crypto_sign_edwards25519sha512batch_ref/ge.h"
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "str.h"
|
||||
#include "rhizome.h"
|
||||
#include "crypto.h"
|
||||
#include "keyring.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
/* Work out the encrypt/decrypt key for the supplied manifest.
|
||||
If the manifest is not encrypted, then return NULL.
|
||||
|
@ -26,6 +26,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "str.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "overlay_address.h"
|
||||
#include "socket.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
/* Represents a queued fetch of a bundle payload, for which the manifest is already known.
|
||||
*/
|
||||
@ -149,23 +151,14 @@ static const char * fetch_state(int state)
|
||||
}
|
||||
}
|
||||
|
||||
int rhizome_active_fetch_count()
|
||||
{
|
||||
int i,active=0;
|
||||
for(i=0;i<NQUEUES;i++)
|
||||
if (rhizome_fetch_queues[i].active.state!=RHIZOME_FETCH_FREE)
|
||||
active++;
|
||||
return active;
|
||||
}
|
||||
|
||||
uint64_t rhizome_active_fetch_bytes_received(int q)
|
||||
static uint64_t rhizome_active_fetch_bytes_received(int q)
|
||||
{
|
||||
if (q<0 || q>=NQUEUES) return -1;
|
||||
if (rhizome_fetch_queues[q].active.state==RHIZOME_FETCH_FREE) return -1;
|
||||
return rhizome_fetch_queues[q].active.write_state.file_offset;
|
||||
}
|
||||
|
||||
uint64_t rhizome_fetch_queue_bytes()
|
||||
static uint64_t rhizome_fetch_queue_bytes()
|
||||
{
|
||||
uint64_t bytes = 0;
|
||||
unsigned i;
|
||||
@ -185,6 +178,25 @@ uint64_t rhizome_fetch_queue_bytes()
|
||||
return bytes;
|
||||
}
|
||||
|
||||
void rhizome_fetch_log_short_status()
|
||||
{
|
||||
int i,active=0;
|
||||
for(i=0;i<NQUEUES;i++)
|
||||
if (rhizome_fetch_queues[i].active.state!=RHIZOME_FETCH_FREE)
|
||||
active++;
|
||||
if (!active)
|
||||
return;
|
||||
|
||||
INFOF("Rhizome transfer progress: %"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64" (remaining %"PRIu64")",
|
||||
rhizome_active_fetch_bytes_received(0),
|
||||
rhizome_active_fetch_bytes_received(1),
|
||||
rhizome_active_fetch_bytes_received(2),
|
||||
rhizome_active_fetch_bytes_received(3),
|
||||
rhizome_active_fetch_bytes_received(4),
|
||||
rhizome_active_fetch_bytes_received(5),
|
||||
rhizome_fetch_queue_bytes());
|
||||
}
|
||||
|
||||
int rhizome_fetch_status_html(strbuf b)
|
||||
{
|
||||
unsigned i;
|
||||
@ -230,10 +242,9 @@ static struct profile_total fetch_stats = { .name="rhizome_fetch_poll" };
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
static struct rhizome_fetch_queue *rhizome_find_queue(uint64_t size)
|
||||
static struct rhizome_fetch_queue *rhizome_find_queue(unsigned char log_size)
|
||||
{
|
||||
int i;
|
||||
unsigned char log_size = log2ll(size);
|
||||
for (i = 0; i < NQUEUES; ++i) {
|
||||
struct rhizome_fetch_queue *q = &rhizome_fetch_queues[i];
|
||||
if (log_size < q->log_size_threshold)
|
||||
@ -824,17 +835,14 @@ static void rhizome_start_next_queued_fetches(struct sched_ent *alarm)
|
||||
|
||||
/* Do we have space to add a fetch candidate of this size? */
|
||||
int rhizome_fetch_has_queue_space(unsigned char log2_size){
|
||||
int i;
|
||||
for (i = 0; i < NQUEUES; ++i) {
|
||||
struct rhizome_fetch_queue *q = &rhizome_fetch_queues[i];
|
||||
if (log2_size < q->log_size_threshold){
|
||||
// is there an empty candidate?
|
||||
unsigned j;
|
||||
for (j=0;j < q->candidate_queue_size;j++)
|
||||
if (!q->candidate_queue[j].manifest)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
struct rhizome_fetch_queue *q = rhizome_find_queue(log2_size);
|
||||
if (q){
|
||||
// is there an empty candidate?
|
||||
unsigned j=0;
|
||||
for (j=0;j < q->candidate_queue_size;j++)
|
||||
if (!q->candidate_queue[j].manifest)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -899,7 +907,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock
|
||||
}
|
||||
|
||||
// Find the proper queue for the payload. If there is none suitable, it is an error.
|
||||
struct rhizome_fetch_queue *qi = rhizome_find_queue(m->filesize);
|
||||
struct rhizome_fetch_queue *qi = rhizome_find_queue(log2ll(m->filesize));
|
||||
if (!qi) {
|
||||
WHYF("No suitable fetch queue for bundle size=%"PRIu64, m->filesize);
|
||||
rhizome_manifest_free(m);
|
||||
@ -1036,8 +1044,8 @@ static void rhizome_fetch_mdp_slot_callback(struct sched_ent *alarm)
|
||||
struct rhizome_fetch_slot *slot=(struct rhizome_fetch_slot*)alarm;
|
||||
|
||||
time_ms_t now = gettime_ms();
|
||||
if (now-slot->last_write_time>slot->mdpIdleTimeout) {
|
||||
DEBUGF("MDP connection timed out: last RX %"PRId64"ms ago (read %"PRIu64" of %"PRIu64" bytes)",
|
||||
if (now - slot->last_write_time > slot->mdpIdleTimeout) {
|
||||
DEBUGF("MDP connection timed out: last RX %"PRId64"ms ago (read %"PRId64" of %"PRId64" bytes)",
|
||||
now-slot->last_write_time,
|
||||
slot->write_state.file_offset,
|
||||
slot->write_state.file_length);
|
||||
@ -1063,7 +1071,7 @@ static int rhizome_fetch_mdp_touch_timeout(struct rhizome_fetch_slot *slot)
|
||||
// For now, we will just make the timeout 1 second from the time of the last
|
||||
// received block.
|
||||
unschedule(&slot->alarm);
|
||||
slot->alarm.alarm=gettime_ms()+1000;
|
||||
slot->alarm.alarm=gettime_ms()+config.rhizome.mdp_stall_timeout;
|
||||
slot->alarm.deadline=slot->alarm.alarm+500;
|
||||
schedule(&slot->alarm);
|
||||
return 0;
|
||||
@ -1121,7 +1129,7 @@ static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
|
||||
slot->write_state.file_offset,
|
||||
slot->bidVersion);
|
||||
|
||||
overlay_mdp_dispatch(&mdp,0 /* system generated */,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
|
||||
// remember when we sent the request so that we can adjust the inter-request
|
||||
// interval based on how fast the packets arrive.
|
||||
@ -1221,8 +1229,15 @@ static int rhizome_fetch_switch_to_mdp(struct rhizome_fetch_slot *slot)
|
||||
down too much. Much careful thought is required to optimise this
|
||||
transport.
|
||||
*/
|
||||
slot->mdpIdleTimeout=config.rhizome.idle_timeout; // give up if nothing received for 5 seconds
|
||||
slot->mdpRXBlockLength=config.rhizome.rhizome_mdp_block_size; // Rhizome over MDP block size
|
||||
slot->mdpIdleTimeout = config.rhizome.idle_timeout; // give up if nothing received for 5 seconds
|
||||
|
||||
unsigned char log_size=log2ll(slot->manifest->filesize);
|
||||
struct rhizome_fetch_queue *q=rhizome_find_queue(log_size);
|
||||
// increase the timeout based on the queue number
|
||||
if (q)
|
||||
slot->mdpIdleTimeout *= 1+(q - rhizome_fetch_queues);
|
||||
|
||||
slot->mdpRXBlockLength = config.rhizome.rhizome_mdp_block_size; // Rhizome over MDP block size
|
||||
rhizome_fetch_mdp_requestblocks(slot);
|
||||
|
||||
RETURN(0);
|
||||
|
@ -474,7 +474,7 @@ next:
|
||||
lookup_time = (end_time - start_time);
|
||||
|
||||
if (mdp.out.payload_length>0)
|
||||
overlay_mdp_dispatch(&mdp,0 /* system generated */,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
|
||||
end:
|
||||
sqlite_set_tracefunc(oldfunc);
|
||||
|
@ -93,7 +93,7 @@ static void rhizome_sync_request(struct subscriber *subscriber, uint64_t token,
|
||||
mdp.out.payload_length = ob_position(b);
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Sending request to %s for BARs from %"PRIu64" %s", alloca_tohex_sid_t(subscriber->sid), token, forwards?"forwards":"backwards");
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
ob_free(b);
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ static void rhizome_sync_send_requests(struct subscriber *subscriber, struct rhi
|
||||
break;
|
||||
}
|
||||
if (mdp.out.payload_length!=0)
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
|
||||
// send request for more bars if we have room to cache them
|
||||
if (state->bar_count >= CACHE_BARS)
|
||||
@ -440,7 +440,7 @@ static void sync_send_response(struct subscriber *dest, int forwards, uint64_t t
|
||||
mdp.out.payload_length = ob_position(b);
|
||||
if (config.debug.rhizome_ads)
|
||||
DEBUGF("Sending %d BARs from %"PRIu64" to %"PRIu64, count, token, last);
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
}
|
||||
ob_free(b);
|
||||
OUT();
|
||||
|
83
serval.h
83
serval.h
@ -163,11 +163,6 @@ int cmp_sid_t(const sid_t *a, const sid_t *b);
|
||||
int str_to_sid_t(sid_t *sid, const char *hex);
|
||||
int strn_to_sid_t(sid_t *sid, const char *hex, const char **endp);
|
||||
|
||||
int str_is_subscriber_id(const char *sid);
|
||||
int strn_is_subscriber_id(const char *sid, size_t *lenp);
|
||||
int str_is_did(const char *did);
|
||||
int strn_is_did(const char *did, size_t *lenp);
|
||||
|
||||
#define alloca_tohex_sas(sas) alloca_tohex((sas), SAS_SIZE)
|
||||
|
||||
/*
|
||||
@ -195,28 +190,6 @@ int formf_serval_instance_path(struct __sourceloc, char *buf, size_t bufsiz, con
|
||||
int vformf_serval_instance_path(struct __sourceloc, char *buf, size_t bufsiz, const char *fmt, va_list);
|
||||
void serval_setinstancepath(const char *instancepath);
|
||||
|
||||
/* Basic socket operations.
|
||||
*/
|
||||
int _make_local_sockaddr(struct __sourceloc, struct sockaddr_un *sockname, socklen_t *addrlen, const char *fmt, ...)
|
||||
__attribute__((format(printf, 4, 5)));
|
||||
int _esocket(struct __sourceloc, int domain, int type, int protocol);
|
||||
int _socket_bind(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int _socket_connect(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int _socket_listen(struct __sourceloc, int sock, int backlog);
|
||||
int _socket_set_reuseaddr(struct __sourceloc, int sock, int reuseP);
|
||||
int _socket_set_rcvbufsize(struct __sourceloc, int sock, unsigned buffer_size);
|
||||
|
||||
#define make_local_sockaddr(sockname, addrlenp, fmt,...) _make_local_sockaddr(__WHENCE__, (sockname), (addrlenp), (fmt), ##__VA_ARGS__)
|
||||
#define esocket(domain, type, protocol) _esocket(__WHENCE__, (domain), (type), (protocol))
|
||||
#define socket_bind(sock, addr, addrlen) _socket_bind(__WHENCE__, (sock), (addr), (addrlen))
|
||||
#define socket_connect(sock, addr, addrlen) _socket_connect(__WHENCE__, (sock), (addr), (addrlen))
|
||||
#define socket_listen(sock, backlog) _socket_listen(__WHENCE__, (sock), (backlog))
|
||||
#define socket_set_reuseaddr(sock, reuseP) _socket_set_reuseaddr(__WHENCE__, (sock), (reuseP))
|
||||
#define socket_set_rcvbufsize(sock, buffer_size) _socket_set_rcvbufsize(__WHENCE__, (sock), (buffer_size))
|
||||
|
||||
int real_sockaddr(const struct sockaddr_un *src_addr, socklen_t src_addrlen, struct sockaddr_un *dst_addr, socklen_t *dst_addrlen);
|
||||
int cmp_sockaddr(const struct sockaddr *, socklen_t, const struct sockaddr *, socklen_t);
|
||||
|
||||
#define SERVER_CONFIG_RELOAD_INTERVAL_MS 1000
|
||||
|
||||
struct cli_parsed;
|
||||
@ -299,12 +272,6 @@ struct slip_decode_state{
|
||||
uint32_t crc;
|
||||
int src_offset;
|
||||
int dst_offset;
|
||||
|
||||
int mavlink_payload_length;
|
||||
int mavlink_seq;
|
||||
int mavlink_payload_start;
|
||||
int mavlink_payload_offset;
|
||||
uint8_t mavlink_payload[1024];
|
||||
};
|
||||
|
||||
struct overlay_interface;
|
||||
@ -377,21 +344,7 @@ typedef struct overlay_interface {
|
||||
int recv_count;
|
||||
int tx_count;
|
||||
|
||||
// stream socket tx state;
|
||||
struct overlay_buffer *tx_packet;
|
||||
unsigned char txbuffer[OVERLAY_INTERFACE_RX_BUFFER_SIZE];
|
||||
int tx_bytes_pending;
|
||||
// Throttle TX rate if required (stream interfaces only for now)
|
||||
uint32_t throttle_bytes_per_second;
|
||||
uint32_t throttle_burst_write_size;
|
||||
uint64_t next_tx_allowed;
|
||||
int32_t remaining_space;
|
||||
time_ms_t next_heartbeat;
|
||||
int mavlink_seq;
|
||||
int radio_rssi;
|
||||
int remote_rssi;
|
||||
|
||||
struct slip_decode_state slip_decode_state;
|
||||
struct radio_link_state *radio_link_state;
|
||||
|
||||
// copy of ifconfig flags
|
||||
uint16_t drop_packets;
|
||||
@ -451,7 +404,7 @@ void insertTransactionInCache(unsigned char *transaction_id);
|
||||
|
||||
int overlay_forward_payload(struct overlay_frame *f);
|
||||
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
|
||||
int recvttl, struct sockaddr *recvaddr, socklen_t recvaddrlen);
|
||||
int recvttl, struct socket_address *recvaddr);
|
||||
int parseMdpPacketHeader(struct decode_context *context, struct overlay_frame *frame,
|
||||
struct overlay_buffer *buffer, struct subscriber **nexthop);
|
||||
int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface *interface,
|
||||
@ -508,9 +461,6 @@ int rhizome_opendb();
|
||||
int parseCommandLine(struct cli_context *context, const char *argv0, int argc, const char *const *argv);
|
||||
|
||||
int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||
int overlay_mdp_reply_error(int sock,
|
||||
struct sockaddr_un *recvaddr, socklen_t recvaddrlen,
|
||||
int error_number,char *message);
|
||||
|
||||
typedef uint32_t mdp_port_t;
|
||||
#define PRImdp_port_t "#08" PRIx32
|
||||
@ -572,13 +522,18 @@ typedef struct overlay_mdp_frame {
|
||||
|
||||
/* Server-side MDP functions */
|
||||
int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp);
|
||||
int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr, socklen_t recvaddrlen,
|
||||
overlay_mdp_frame *mdpreply);
|
||||
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
|
||||
struct sockaddr_un *recvaddr, socklen_t recvaddrlen);
|
||||
struct socket_address;
|
||||
int overlay_mdp_dispatch(overlay_mdp_frame *mdp, struct socket_address *client);
|
||||
void overlay_mdp_encode_ports(struct overlay_buffer *plaintext, mdp_port_t dst_port, mdp_port_t src_port);
|
||||
int overlay_mdp_dnalookup_reply(const sockaddr_mdp *dstaddr, const sid_t *resolved_sidp, const char *uri, const char *did, const char *name);
|
||||
|
||||
struct mdp_header;
|
||||
int mdp_bind_internal(struct subscriber *subscriber, mdp_port_t port,
|
||||
int (*internal)(const struct mdp_header *header, const uint8_t *payload, size_t len));
|
||||
int mdp_unbind_internal(struct subscriber *subscriber, mdp_port_t port,
|
||||
int (*internal)(const struct mdp_header *header, const uint8_t *payload, size_t len));
|
||||
|
||||
|
||||
struct vomp_call_state;
|
||||
|
||||
void set_codec_flag(int codec, unsigned char *flags);
|
||||
@ -688,7 +643,7 @@ int overlay_packetradio_tx_packet(struct overlay_frame *frame);
|
||||
void overlay_dummy_poll(struct sched_ent *alarm);
|
||||
void server_config_reload(struct sched_ent *alarm);
|
||||
void server_shutdown_check(struct sched_ent *alarm);
|
||||
int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp);
|
||||
int overlay_mdp_try_internal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp);
|
||||
int overlay_send_probe(struct subscriber *peer, struct network_destination *destination, int queue);
|
||||
int overlay_send_stun_request(struct subscriber *server, struct subscriber *request);
|
||||
void fd_periodicstats(struct sched_ent *alarm);
|
||||
@ -713,13 +668,6 @@ int limit_init(struct limit_state *state, int rate_micro_seconds);
|
||||
int olsr_init_socket(void);
|
||||
int olsr_send(struct overlay_frame *frame);
|
||||
|
||||
void write_uint64(unsigned char *o,uint64_t v);
|
||||
void write_uint16(unsigned char *o,uint16_t v);
|
||||
void write_uint32(unsigned char *o,uint32_t v);
|
||||
uint64_t read_uint64(unsigned char *o);
|
||||
uint32_t read_uint32(unsigned char *o);
|
||||
uint16_t read_uint16(unsigned char *o);
|
||||
|
||||
int pack_uint(unsigned char *buffer, uint64_t v);
|
||||
int measure_packed_uint(uint64_t v);
|
||||
int unpack_uint(unsigned char *buffer, int buff_size, uint64_t *v);
|
||||
@ -730,8 +678,7 @@ int slip_decode(struct slip_decode_state *state);
|
||||
int upper7_decode(struct slip_decode_state *state,unsigned char byte);
|
||||
uint32_t Crc32_ComputeBuf( uint32_t inCrc32, const void *buf,
|
||||
size_t bufLen );
|
||||
int rhizome_active_fetch_count();
|
||||
uint64_t rhizome_active_fetch_bytes_received(int q);
|
||||
void rhizome_fetch_log_short_status();
|
||||
extern int64_t bundles_available;
|
||||
extern char crash_handler_clue[1024];
|
||||
|
||||
@ -753,8 +700,4 @@ int link_stop_routing(struct subscriber *subscriber);
|
||||
|
||||
int generate_nonce(unsigned char *nonce,int bytes);
|
||||
|
||||
int mavlink_decode(struct overlay_interface *interface, struct slip_decode_state *state,uint8_t c);
|
||||
int mavlink_heartbeat(unsigned char *frame,int *outlen);
|
||||
int mavlink_encode_packet(struct overlay_interface *interface);
|
||||
|
||||
#endif // __SERVALD_SERVALD_H
|
||||
|
1
slip.c
1
slip.c
@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "dataformats.h"
|
||||
|
||||
#define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __WHENCE__, (M), (P), (N))
|
||||
|
||||
|
118
socket.c
118
socket.c
@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* Form the name of an AF_UNIX (local) socket in the instance directory as an absolute path.
|
||||
* Under Linux, this will create a socket name in the abstract namespace. This permits us to use
|
||||
@ -40,25 +41,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
* @author Daniel O'Connor <daniel@servalproject.com>
|
||||
*/
|
||||
int _make_local_sockaddr(struct __sourceloc __whence, struct sockaddr_un *addr, socklen_t *addrlen, const char *fmt, ...)
|
||||
int _make_local_sockaddr(struct __sourceloc __whence, struct socket_address *addr, const char *fmt, ...)
|
||||
{
|
||||
bzero(addr, sizeof(*addr));
|
||||
addr->local.sun_family = AF_UNIX;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int r = vformf_serval_instance_path(__WHENCE__, addr->sun_path, sizeof addr->sun_path, fmt, ap);
|
||||
int r = vformf_serval_instance_path(__WHENCE__, addr->local.sun_path, sizeof addr->local.sun_path, fmt, ap);
|
||||
va_end(ap);
|
||||
if (!r)
|
||||
return WHY("socket name overflow");
|
||||
if (real_sockaddr(addr, sizeof addr->sun_family + strlen(addr->sun_path) + 1, addr, addrlen) == -1)
|
||||
return -1;
|
||||
addr->addrlen=sizeof addr->local.sun_family + strlen(addr->local.sun_path) + 1;
|
||||
// TODO perform real path transformation in making the serval instance path
|
||||
// if (real_sockaddr(addr, addr) == -1)
|
||||
// return -1;
|
||||
|
||||
#ifdef USE_ABSTRACT_NAMESPACE
|
||||
// For the abstract name we use the absolute path name with the initial '/' replaced by the
|
||||
// leading nul. This ensures that different instances of the Serval daemon have different socket
|
||||
// names.
|
||||
addr->sun_path[0] = '\0'; // mark as Linux abstract socket
|
||||
--*addrlen; // do not count trailing nul in abstract socket name
|
||||
addr->local.sun_path[0] = '\0'; // mark as Linux abstract socket
|
||||
--addr->addrlen; // do not count trailing nul in abstract socket name
|
||||
#endif // USE_ABSTRACT_NAMESPACE
|
||||
addr->sun_family = AF_UNIX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -74,31 +78,33 @@ int _make_local_sockaddr(struct __sourceloc __whence, struct sockaddr_un *addr,
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int real_sockaddr(const struct sockaddr_un *src_addr, socklen_t src_addrlen, struct sockaddr_un *dst_addr, socklen_t *dst_addrlen)
|
||||
int real_sockaddr(const struct socket_address *src_addr, struct socket_address *dst_addr)
|
||||
{
|
||||
int src_path_len = src_addrlen - sizeof src_addr->sun_family;
|
||||
if ( src_addrlen >= sizeof src_addr->sun_family + 1
|
||||
&& src_addr->sun_family == AF_UNIX
|
||||
&& src_addr->sun_path[0] != '\0'
|
||||
&& src_addr->sun_path[src_path_len - 1] == '\0'
|
||||
int src_path_len = src_addr->addrlen - sizeof src_addr->local.sun_family;
|
||||
if ( src_addr->addrlen >= sizeof src_addr->local.sun_family + 1
|
||||
&& src_addr->local.sun_family == AF_UNIX
|
||||
&& src_addr->local.sun_path[0] != '\0'
|
||||
&& src_addr->local.sun_path[src_path_len - 1] == '\0'
|
||||
) {
|
||||
char real_path[PATH_MAX];
|
||||
size_t real_path_len;
|
||||
if (realpath(src_addr->sun_path, real_path) == NULL)
|
||||
return WHYF_perror("realpath(%s)", alloca_str_toprint(src_addr->sun_path));
|
||||
else if ((real_path_len = strlen(real_path) + 1) > sizeof dst_addr->sun_path)
|
||||
return WHYF("sockaddr overrun: realpath(%s) returned %s", alloca_str_toprint(src_addr->sun_path), alloca_str_toprint(real_path));
|
||||
if (realpath(src_addr->local.sun_path, real_path) == NULL)
|
||||
return WHYF_perror("realpath(%s)", alloca_str_toprint(src_addr->local.sun_path));
|
||||
else if ((real_path_len = strlen(real_path) + 1) > sizeof dst_addr->local.sun_path)
|
||||
return WHYF("sockaddr overrun: realpath(%s) returned %s",
|
||||
alloca_str_toprint(src_addr->local.sun_path), alloca_str_toprint(real_path));
|
||||
else if ( real_path_len != src_path_len
|
||||
|| memcmp(real_path, src_addr->sun_path, src_path_len) != 0
|
||||
|| memcmp(real_path, src_addr->local.sun_path, src_path_len) != 0
|
||||
) {
|
||||
memcpy(dst_addr->sun_path, real_path, real_path_len);
|
||||
*dst_addrlen = real_path_len + sizeof dst_addr->sun_family;
|
||||
memcpy(dst_addr->local.sun_path, real_path, real_path_len);
|
||||
dst_addr->addrlen = real_path_len + sizeof dst_addr->local.sun_family;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (dst_addr != src_addr)
|
||||
memcpy(dst_addr, src_addr, src_addrlen);
|
||||
*dst_addrlen = src_addrlen;
|
||||
if (dst_addr != src_addr){
|
||||
memcpy(&dst_addr->addr, &src_addr->addr, src_addr->addrlen);
|
||||
dst_addr->addrlen = src_addr->addrlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -107,43 +113,43 @@ int real_sockaddr(const struct sockaddr_un *src_addr, socklen_t src_addrlen, str
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int cmp_sockaddr(const struct sockaddr *addrA, socklen_t addrlenA, const struct sockaddr *addrB, socklen_t addrlenB)
|
||||
int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address *addrB)
|
||||
{
|
||||
// Two zero-length sockaddrs are equal.
|
||||
if (addrlenA == 0 && addrlenB == 0)
|
||||
if (addrA->addrlen == 0 && addrB->addrlen == 0)
|
||||
return 0;
|
||||
// If either sockaddr is truncated, then we compare the bytes we have.
|
||||
if (addrlenA < sizeof addrA->sa_family || addrlenB < sizeof addrB->sa_family) {
|
||||
int c = memcmp(addrA, addrB, addrlenA < addrlenB ? addrlenA : addrlenB);
|
||||
if (addrA->addrlen < sizeof addrA->addr.sa_family || addrB->addrlen < sizeof addrB->addr.sa_family) {
|
||||
int c = memcmp(addrA, addrB, addrA->addrlen < addrB->addrlen ? addrA->addrlen : addrB->addrlen);
|
||||
if (c == 0)
|
||||
c = addrlenA < addrlenB ? -1 : addrlenA > addrlenB ? 1 : 0;
|
||||
c = addrA->addrlen < addrB->addrlen ? -1 : addrA->addrlen > addrB->addrlen ? 1 : 0;
|
||||
return c;
|
||||
}
|
||||
// Order first by address family.
|
||||
if (addrA->sa_family < addrB->sa_family)
|
||||
if (addrA->addr.sa_family < addrB->addr.sa_family)
|
||||
return -1;
|
||||
if (addrA->sa_family > addrB->sa_family)
|
||||
if (addrA->addr.sa_family > addrB->addr.sa_family)
|
||||
return 1;
|
||||
// Both addresses are in the same family...
|
||||
switch (addrA->sa_family) {
|
||||
switch (addrA->addr.sa_family) {
|
||||
case AF_UNIX: {
|
||||
unsigned pathlenA = addrlenA - sizeof ((const struct sockaddr_un *)addrA)->sun_family;
|
||||
unsigned pathlenB = addrlenB - sizeof ((const struct sockaddr_un *)addrB)->sun_family;
|
||||
unsigned pathlenA = addrA->addrlen - sizeof (addrA->local.sun_family);
|
||||
unsigned pathlenB = addrB->addrlen - sizeof (addrB->local.sun_family);
|
||||
int c;
|
||||
if ( pathlenA > 1 && pathlenB > 1
|
||||
&& ((const struct sockaddr_un *)addrA)->sun_path[0] == '\0'
|
||||
&& ((const struct sockaddr_un *)addrB)->sun_path[0] == '\0'
|
||||
&& addrA->local.sun_path[0] == '\0'
|
||||
&& addrB->local.sun_path[0] == '\0'
|
||||
) {
|
||||
// Both abstract sockets - just compare names, nul bytes are not terminators.
|
||||
c = memcmp(&((const struct sockaddr_un *)addrA)->sun_path[1],
|
||||
&((const struct sockaddr_un *)addrB)->sun_path[1],
|
||||
c = memcmp(&addrA->local.sun_path[1],
|
||||
&addrB->local.sun_path[1],
|
||||
(pathlenA < pathlenB ? pathlenA : pathlenB) - 1);
|
||||
} else {
|
||||
// Either or both are named local file sockets. If the file names are identical up to the
|
||||
// first nul, then the addresses are equal. This collates abstract socket names, whose first
|
||||
// character is a nul, ahead of all non-empty file socket names.
|
||||
c = strncmp(((const struct sockaddr_un *)addrA)->sun_path,
|
||||
((const struct sockaddr_un *)addrB)->sun_path,
|
||||
c = strncmp(addrA->local.sun_path,
|
||||
addrB->local.sun_path,
|
||||
(pathlenA < pathlenB ? pathlenA : pathlenB));
|
||||
}
|
||||
if (c == 0)
|
||||
@ -153,9 +159,10 @@ int cmp_sockaddr(const struct sockaddr *addrA, socklen_t addrlenA, const struct
|
||||
break;
|
||||
}
|
||||
// Fall back to comparing raw data bytes.
|
||||
int c = memcmp(addrA->sa_data, addrB->sa_data, (addrlenA < addrlenB ? addrlenA : addrlenB) - sizeof addrA->sa_family);
|
||||
int c = memcmp(addrA->addr.sa_data, addrB->addr.sa_data,
|
||||
(addrA->addrlen < addrB->addrlen ? addrA->addrlen : addrB->addrlen) - sizeof addrA->addr.sa_family);
|
||||
if (c == 0)
|
||||
c = addrlenA < addrlenB ? -1 : addrlenA > addrlenB ? 1 : 0;
|
||||
c = addrA->addrlen < addrB->addrlen ? -1 : addrA->addrlen > addrB->addrlen ? 1 : 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -225,3 +232,32 @@ int _socket_set_rcvbufsize(struct __sourceloc __whence, int sock, unsigned buffe
|
||||
DEBUGF("setsockopt(%d, SOL_SOCKET, SO_RCVBUF, &%u, %u)", sock, buffer_size, (unsigned)sizeof buffer_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t _send_message(struct __sourceloc __whence, int fd, const struct socket_address *address, const struct fragmented_data *data)
|
||||
{
|
||||
struct msghdr hdr={
|
||||
.msg_name=(void *)&address->addr,
|
||||
.msg_namelen=address->addrlen,
|
||||
.msg_iov=(struct iovec*)data->iov,
|
||||
.msg_iovlen=data->fragment_count,
|
||||
};
|
||||
|
||||
ssize_t ret = sendmsg(fd, &hdr, 0);
|
||||
if (ret==-1)
|
||||
WHYF_perror("sendmsg(%d,%s,%lu)", fd, alloca_socket_address(address), (unsigned long)address->addrlen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t _recv_message(struct __sourceloc __whence, int fd, struct socket_address *address, struct fragmented_data *data)
|
||||
{
|
||||
struct msghdr hdr={
|
||||
.msg_name=(void *)&address->addr,
|
||||
.msg_namelen=address->addrlen,
|
||||
.msg_iov=data->iov,
|
||||
.msg_iovlen=data->fragment_count,
|
||||
};
|
||||
ssize_t ret = recvmsg(fd, &hdr, 0);
|
||||
if (ret==-1)
|
||||
WHYF_perror("recvmsg(%d,%s,%lu)", fd, alloca_socket_address(address), (unsigned long)address->addrlen);
|
||||
return ret;
|
||||
}
|
||||
|
57
socket.h
Normal file
57
socket.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef __SERVALD_SOCKET_H
|
||||
#define __SERVALD_SOCKET_H
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
struct socket_address{
|
||||
socklen_t addrlen;
|
||||
union{
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_un local; // name "unix" is a predefined macro
|
||||
struct sockaddr_in inet;
|
||||
struct sockaddr_storage store;
|
||||
};
|
||||
};
|
||||
|
||||
/* Basic socket operations.
|
||||
*/
|
||||
int _make_local_sockaddr(struct __sourceloc, struct socket_address *addr, const char *fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
int _esocket(struct __sourceloc, int domain, int type, int protocol);
|
||||
int _socket_bind(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int _socket_connect(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int _socket_listen(struct __sourceloc, int sock, int backlog);
|
||||
int _socket_set_reuseaddr(struct __sourceloc, int sock, int reuseP);
|
||||
int _socket_set_rcvbufsize(struct __sourceloc, int sock, unsigned buffer_size);
|
||||
|
||||
#define make_local_sockaddr(sockname, fmt,...) _make_local_sockaddr(__WHENCE__, (sockname), (fmt), ##__VA_ARGS__)
|
||||
#define esocket(domain, type, protocol) _esocket(__WHENCE__, (domain), (type), (protocol))
|
||||
#define socket_bind(sock, addr, addrlen) _socket_bind(__WHENCE__, (sock), (addr), (addrlen))
|
||||
#define socket_connect(sock, addr, addrlen) _socket_connect(__WHENCE__, (sock), (addr), (addrlen))
|
||||
#define socket_listen(sock, backlog) _socket_listen(__WHENCE__, (sock), (backlog))
|
||||
#define socket_set_reuseaddr(sock, reuseP) _socket_set_reuseaddr(__WHENCE__, (sock), (reuseP))
|
||||
#define socket_set_rcvbufsize(sock, buffer_size) _socket_set_rcvbufsize(__WHENCE__, (sock), (buffer_size))
|
||||
|
||||
int real_sockaddr(const struct socket_address *src_addr, struct socket_address *dst_addr);
|
||||
int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address *addrB);
|
||||
|
||||
// helper functions for manipulating fragmented packet data
|
||||
#define MAX_FRAGMENTS 8
|
||||
struct fragmented_data{
|
||||
int fragment_count;
|
||||
struct iovec iov[MAX_FRAGMENTS];
|
||||
};
|
||||
|
||||
int prepend_fragment(struct fragmented_data *data, const uint8_t *payload, size_t len);
|
||||
int append_fragment(struct fragmented_data *data, const uint8_t *payload, size_t len);
|
||||
size_t copy_fragment(struct fragmented_data *src, uint8_t *dest, size_t length);
|
||||
|
||||
ssize_t _send_message(struct __sourceloc, int fd, const struct socket_address *address, const struct fragmented_data *data);
|
||||
ssize_t _recv_message(struct __sourceloc, int fd, struct socket_address *address, struct fragmented_data *data);
|
||||
|
||||
#define send_message(fd, address, data) _send_message(__WHENCE__, (fd), (address), (data))
|
||||
#define recv_message(fd, address, data) _recv_message(__WHENCE__, (fd), (address), (data))
|
||||
|
||||
#endif
|
@ -19,7 +19,7 @@ SERVAL_SOURCES = \
|
||||
$(SERVAL_BASE)log.c \
|
||||
$(SERVAL_BASE)lsif.c \
|
||||
$(SERVAL_BASE)main.c \
|
||||
$(SERVAL_BASE)mavlink.c \
|
||||
$(SERVAL_BASE)radio_link.c \
|
||||
$(SERVAL_BASE)meshms.c \
|
||||
$(SERVAL_BASE)mdp_client.c \
|
||||
$(SERVAL_BASE)os.c \
|
||||
|
@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "http_server.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "str.h"
|
||||
#include "socket.h"
|
||||
|
||||
static inline strbuf _toprint(strbuf sb, char c)
|
||||
{
|
||||
@ -374,6 +375,11 @@ strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t
|
||||
return sb;
|
||||
}
|
||||
|
||||
strbuf strbuf_append_socket_address(strbuf sb, const struct socket_address *addr)
|
||||
{
|
||||
return strbuf_append_sockaddr(sb, &addr->addr, addr->addrlen);
|
||||
}
|
||||
|
||||
strbuf strbuf_append_strftime(strbuf sb, const char *format, const struct tm *tm)
|
||||
{
|
||||
// First, try calling strftime(3) directly on the buffer in the strbuf, if there is one and it
|
||||
|
@ -139,6 +139,10 @@ struct sockaddr;
|
||||
strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t addrlen);
|
||||
#define alloca_sockaddr(addr, addrlen) strbuf_str(strbuf_append_sockaddr(strbuf_alloca(200), (const struct sockaddr *)(addr), (addrlen)))
|
||||
|
||||
struct socket_address;
|
||||
strbuf strbuf_append_socket_address(strbuf sb, const struct socket_address *addr);
|
||||
#define alloca_socket_address(addr) strbuf_str(strbuf_append_socket_address(strbuf_alloca(200), (addr)))
|
||||
|
||||
/* Append a strftime(3) string.
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
|
@ -704,9 +704,9 @@ start_radio_instance() {
|
||||
set debug.rhizome_tx on \
|
||||
set debug.rhizome_rx on \
|
||||
set debug.throttling on \
|
||||
set debug.mavlink on \
|
||||
set debug.radio_link on \
|
||||
set rhizome.advertise.interval 5000 \
|
||||
set rhizome.rhizome_mdp_block_size 350 \
|
||||
set rhizome.rhizome_mdp_block_size 375 \
|
||||
set log.console.level debug \
|
||||
set log.console.show_pid on \
|
||||
set log.console.show_time on \
|
||||
@ -719,17 +719,23 @@ start_radio_instance() {
|
||||
wait_until interface_up
|
||||
}
|
||||
|
||||
start_fakeradio() {
|
||||
$servald_build_root/fakeradio $1 $2 > "$SERVALD_VAR/radioout" 2> "$SERVALD_VAR/radioerr" &
|
||||
FAKERADIO_PID=$!
|
||||
wait_until $GREP "^right:" "$SERVALD_VAR/radioout"
|
||||
local _line=`head "$SERVALD_VAR/radioout" -n 1`
|
||||
END1="${_line#*:}"
|
||||
_line=`tail "$SERVALD_VAR/radioout" -n 1`
|
||||
END2="${_line#*:}"
|
||||
tfw_log "Started fakeradio pid=$FAKERADIO_PID, end1=$END1, end2=$END2"
|
||||
}
|
||||
|
||||
doc_SimulatedRadio="MDP Transfer over simulated radio link (~90% packet arrival)"
|
||||
setup_SimulatedRadio() {
|
||||
setup_common
|
||||
$servald_build_root/fakeradio 6 0.9 > "$SERVALD_VAR/radioout" 2> "$SERVALD_VAR/radioerr" &
|
||||
FAKERADIO_PID=$!
|
||||
sleep 5
|
||||
local END1=`head "$SERVALD_VAR/radioout" -n 1`
|
||||
local END2=`tail "$SERVALD_VAR/radioout" -n 1`
|
||||
tfw_log "Started fakeradio pid=$FAKERADIO_PID, end1=$END1, end2=$END2"
|
||||
start_fakeradio 4 0.9
|
||||
set_instance +A
|
||||
rhizome_add_file file1 10000
|
||||
rhizome_add_file file1 5000
|
||||
executeOk_servald config \
|
||||
set interfaces.1.file "$END1"
|
||||
set_instance +B
|
||||
@ -750,14 +756,9 @@ teardown_SimulatedRadio() {
|
||||
doc_SimulatedRadio2="MDP Transfer over simulated radio link (~50% packet arrival)"
|
||||
setup_SimulatedRadio2() {
|
||||
setup_common
|
||||
$servald_build_root/fakeradio 6 0.5 > "$SERVALD_VAR/radioout" 2> "$SERVALD_VAR/radioerr" &
|
||||
FAKERADIO_PID=$!
|
||||
sleep 1
|
||||
local END1=`head "$SERVALD_VAR/radioout" -n 1`
|
||||
local END2=`tail "$SERVALD_VAR/radioout" -n 1`
|
||||
tfw_log "Started fakeradio pid=$FAKERADIO_PID, end1=$END1, end2=$END2"
|
||||
start_fakeradio 4 0.5
|
||||
set_instance +A
|
||||
rhizome_add_file file1 10000
|
||||
rhizome_add_file file1 5000
|
||||
executeOk_servald config \
|
||||
set interfaces.1.file "$END1"
|
||||
set_instance +B
|
||||
|
@ -260,18 +260,23 @@ setup_slip_encoding() {
|
||||
test_slip_encoding() {
|
||||
executeOk_servald test slip --seed=1 --iterations=2000
|
||||
}
|
||||
start_fakeradio() {
|
||||
$servald_build_root/fakeradio 4 1 > "$SERVALD_VAR/radioout" 2> "$SERVALD_VAR/radioerr" &
|
||||
FAKERADIO_PID=$!
|
||||
wait_until $GREP "^right:" "$SERVALD_VAR/radioout"
|
||||
local _line=`head "$SERVALD_VAR/radioout" -n 1`
|
||||
END1="${_line#*:}"
|
||||
_line=`tail "$SERVALD_VAR/radioout" -n 1`
|
||||
END2="${_line#*:}"
|
||||
tfw_log "Started fakeradio pid=$FAKERADIO_PID, end1=$END1, end2=$END2"
|
||||
}
|
||||
|
||||
doc_simulate_extender="Simulate a mesh extender radio link"
|
||||
setup_simulate_extender() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
foreach_instance +A +B create_single_identity
|
||||
$servald_build_root/fakeradio 1 0.8 > "$SERVALD_VAR/radioout" 2> "$SERVALD_VAR/radioerr" &
|
||||
FAKERADIO_PID=$!
|
||||
sleep 1
|
||||
local END1=`head "$SERVALD_VAR/radioout" -n 1`
|
||||
local END2=`tail "$SERVALD_VAR/radioout" -n 1`
|
||||
tfw_log "Started fakeradio pid=$FAKERADIO_PID, end1=$END1, end2=$END2"
|
||||
start_fakeradio
|
||||
set_instance +A
|
||||
executeOk_servald config \
|
||||
set interfaces.1.file "$END1"
|
||||
@ -282,10 +287,9 @@ setup_simulate_extender() {
|
||||
executeOk_servald config \
|
||||
set debug.throttling on \
|
||||
set debug.packetradio on \
|
||||
set debug.mavlink on \
|
||||
set debug.radio_link on \
|
||||
set interfaces.1.type CATEAR \
|
||||
set interfaces.1.mdp.tick_ms 5000 \
|
||||
set interfaces.1.mdp.packet_interval 5000 \
|
||||
set interfaces.1.socket_type STREAM \
|
||||
set interfaces.1.encapsulation SINGLE \
|
||||
set interfaces.1.point_to_point on
|
||||
|
4
vomp.c
4
vomp.c
@ -523,7 +523,7 @@ static int vomp_send_status_remote(struct vomp_call_state *call)
|
||||
|
||||
call->local.sequence++;
|
||||
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -561,7 +561,7 @@ int vomp_received_audio(struct vomp_call_state *call, int audio_codec, int time,
|
||||
|
||||
mdp.out.queue=OQ_ISOCHRONOUS_VOICE;
|
||||
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
overlay_mdp_dispatch(&mdp, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user