@ -129,7 +129,7 @@ uint8_t MyMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secr
}
if ( is_flood ) {
client - > out_path_len = - 1 ; // need to rediscover out_path
client - > out_path_len = OUT_PATH_UNKNOWN ; // need to rediscover out_path
}
uint32_t now = getRTCClock ( ) - > getCurrentTimeUnique ( ) ;
@ -147,9 +147,12 @@ uint8_t MyMesh::handleLoginReq(const mesh::Identity& sender, const uint8_t* secr
uint8_t MyMesh : : handleAnonRegionsReq ( const mesh : : Identity & sender , uint32_t sender_timestamp , const uint8_t * data ) {
if ( anon_limiter . allow ( rtc_clock . getCurrentTime ( ) ) ) {
// request data has: {reply-path-len}{reply-path}
reply_path_len = * data + + & 0x3F ;
memcpy ( reply_path , data , reply_path_len ) ;
// data += reply_path_len;
reply_path_len = * data & 63 ;
reply_path_hash_size = ( * data > > 6 ) + 1 ;
data + + ;
memcpy ( reply_path , data , ( ( uint8_t ) reply_path_len ) * reply_path_hash_size ) ;
// data += (uint8_t)reply_path_len * reply_path_hash_size;
memcpy ( reply_data , & sender_timestamp , 4 ) ; // prefix with sender_timestamp, like a tag
uint32_t now = getRTCClock ( ) - > getCurrentTime ( ) ;
@ -163,9 +166,12 @@ uint8_t MyMesh::handleAnonRegionsReq(const mesh::Identity& sender, uint32_t send
uint8_t MyMesh : : handleAnonOwnerReq ( const mesh : : Identity & sender , uint32_t sender_timestamp , const uint8_t * data ) {
if ( anon_limiter . allow ( rtc_clock . getCurrentTime ( ) ) ) {
// request data has: {reply-path-len}{reply-path}
reply_path_len = * data + + & 0x3F ;
memcpy ( reply_path , data , reply_path_len ) ;
// data += reply_path_len;
reply_path_len = * data & 63 ;
reply_path_hash_size = ( * data > > 6 ) + 1 ;
data + + ;
memcpy ( reply_path , data , ( ( uint8_t ) reply_path_len ) * reply_path_hash_size ) ;
// data += (uint8_t)reply_path_len * reply_path_hash_size;
memcpy ( reply_data , & sender_timestamp , 4 ) ; // prefix with sender_timestamp, like a tag
uint32_t now = getRTCClock ( ) - > getCurrentTime ( ) ;
@ -180,9 +186,12 @@ uint8_t MyMesh::handleAnonOwnerReq(const mesh::Identity& sender, uint32_t sender
uint8_t MyMesh : : handleAnonClockReq ( const mesh : : Identity & sender , uint32_t sender_timestamp , const uint8_t * data ) {
if ( anon_limiter . allow ( rtc_clock . getCurrentTime ( ) ) ) {
// request data has: {reply-path-len}{reply-path}
reply_path_len = * data + + & 0x3F ;
memcpy ( reply_path , data , reply_path_len ) ;
// data += reply_path_len;
reply_path_len = * data & 63 ;
reply_path_hash_size = ( * data > > 6 ) + 1 ;
data + + ;
memcpy ( reply_path , data , ( ( uint8_t ) reply_path_len ) * reply_path_hash_size ) ;
// data += (uint8_t)reply_path_len * reply_path_hash_size;
memcpy ( reply_data , & sender_timestamp , 4 ) ; // prefix with sender_timestamp, like a tag
uint32_t now = getRTCClock ( ) - > getCurrentTime ( ) ;
@ -292,6 +301,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t
// create copy of neighbours list, skipping empty entries so we can sort it separately from main list
int16_t neighbours_count = 0 ;
# if MAX_NEIGHBOURS
NeighbourInfo * sorted_neighbours [ MAX_NEIGHBOURS ] ;
for ( int i = 0 ; i < MAX_NEIGHBOURS ; i + + ) {
auto neighbour = & neighbours [ i ] ;
@ -327,6 +337,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t
return a - > snr < b - > snr ; // asc
} ) ;
}
# endif
// build results buffer
int results_count = 0 ;
@ -341,6 +352,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t
break ;
}
# if MAX_NEIGHBOURS
// add next neighbour to results
auto neighbour = sorted_neighbours [ index + offset ] ;
uint32_t heard_seconds_ago = getRTCClock ( ) - > getCurrentTime ( ) - neighbour - > heard_timestamp ;
@ -348,6 +360,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t
memcpy ( & results_buffer [ results_offset ] , & heard_seconds_ago , 4 ) ; results_offset + = 4 ;
memcpy ( & results_buffer [ results_offset ] , & neighbour - > snr , 1 ) ; results_offset + = 1 ;
results_count + + ;
# endif
}
@ -383,13 +396,44 @@ File MyMesh::openAppend(const char *fname) {
# endif
}
static uint8_t max_loop_minimal [ ] = { 0 , /* 1-byte */ 4 , /* 2-byte */ 2 , /* 3-byte */ 1 } ;
static uint8_t max_loop_moderate [ ] = { 0 , /* 1-byte */ 2 , /* 2-byte */ 1 , /* 3-byte */ 1 } ;
static uint8_t max_loop_strict [ ] = { 0 , /* 1-byte */ 1 , /* 2-byte */ 1 , /* 3-byte */ 1 } ;
bool MyMesh : : isLooped ( const mesh : : Packet * packet , const uint8_t max_counters [ ] ) {
uint8_t hash_size = packet - > getPathHashSize ( ) ;
uint8_t hash_count = packet - > getPathHashCount ( ) ;
uint8_t n = 0 ;
const uint8_t * path = packet - > path ;
while ( hash_count > 0 ) { // count how many times this node is already in the path
if ( self_id . isHashMatch ( path , hash_size ) ) n + + ;
hash_count - - ;
path + = hash_size ;
}
return n > = max_counters [ hash_size ] ;
}
bool MyMesh : : allowPacketForward ( const mesh : : Packet * packet ) {
if ( _prefs . disable_fwd ) return false ;
if ( packet - > isRouteFlood ( ) & & packet - > path_len > = _prefs . flood_max ) return false ;
if ( packet - > isRouteFlood ( ) & & packet - > getPathHashCount ( ) > = _prefs . flood_max ) return false ;
if ( packet - > isRouteFlood ( ) & & recv_pkt_region = = NULL ) {
MESH_DEBUG_PRINTLN ( " allowPacketForward: unknown transport code, or wildcard not allowed for FLOOD packet " ) ;
return false ;
}
if ( packet - > isRouteFlood ( ) & & _prefs . loop_detect ! = LOOP_DETECT_OFF ) {
const uint8_t * maximums ;
if ( _prefs . loop_detect = = LOOP_DETECT_MINIMAL ) {
maximums = max_loop_minimal ;
} else if ( _prefs . loop_detect = = LOOP_DETECT_MODERATE ) {
maximums = max_loop_moderate ;
} else {
maximums = max_loop_strict ;
}
if ( isLooped ( packet , maximums ) ) {
MESH_DEBUG_PRINTLN ( " allowPacketForward: FLOOD packet loop detected! " ) ;
return false ;
}
}
return true ;
}
@ -480,11 +524,11 @@ int MyMesh::calcRxDelay(float score, uint32_t air_time) const {
}
uint32_t MyMesh : : getRetransmitDelay ( const mesh : : Packet * packet ) {
uint32_t t = ( _radio - > getEstAirtimeFor ( packet - > path_len + packet - > payload_len + 2 ) * _prefs . tx_delay_factor ) ;
uint32_t t = ( _radio - > getEstAirtimeFor ( packet - > getPathByteLen ( ) + packet - > payload_len + 2 ) * _prefs . tx_delay_factor ) ;
return getRNG ( ) - > nextInt ( 0 , 5 * t + 1 ) ;
}
uint32_t MyMesh : : getDirectRetransmitDelay ( const mesh : : Packet * packet ) {
uint32_t t = ( _radio - > getEstAirtimeFor ( packet - > path_len + packet - > payload_len + 2 ) * _prefs . direct_tx_delay_factor ) ;
uint32_t t = ( _radio - > getEstAirtimeFor ( packet - > getPathByteLen ( ) + packet - > payload_len + 2 ) * _prefs . direct_tx_delay_factor ) ;
return getRNG ( ) - > nextInt ( 0 , 5 * t + 1 ) ;
}
@ -534,13 +578,14 @@ void MyMesh::onAnonDataRecv(mesh::Packet *packet, const uint8_t *secret, const m
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh : : Packet * path = createPathReturn ( sender , secret , packet - > path , packet - > path_len ,
PAYLOAD_TYPE_RESPONSE , reply_data , reply_len ) ;
if ( path ) sendFlood ( path , SERVER_RESPONSE_DELAY ) ;
if ( path ) sendFlood ( path , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
} else if ( reply_path_len < 0 ) {
mesh : : Packet * reply = createDatagram ( PAYLOAD_TYPE_RESPONSE , sender , secret , reply_data , reply_len ) ;
if ( reply ) sendFlood ( reply , SERVER_RESPONSE_DELAY ) ;
if ( reply ) sendFlood ( reply , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
} else {
mesh : : Packet * reply = createDatagram ( PAYLOAD_TYPE_RESPONSE , sender , secret , reply_data , reply_len ) ;
if ( reply ) sendDirect ( reply , reply_path , reply_path_len , SERVER_RESPONSE_DELAY ) ;
uint8_t path_len = ( ( reply_path_hash_size - 1 ) < < 6 ) | ( reply_path_len & 63 ) ;
if ( reply ) sendDirect ( reply , reply_path , path_len , SERVER_RESPONSE_DELAY ) ;
}
}
}
@ -609,15 +654,15 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh : : Packet * path = createPathReturn ( client - > id , secret , packet - > path , packet - > path_len ,
PAYLOAD_TYPE_RESPONSE , reply_data , reply_len ) ;
if ( path ) sendFlood ( path , SERVER_RESPONSE_DELAY ) ;
if ( path ) sendFlood ( path , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
} else {
mesh : : Packet * reply =
createDatagram ( PAYLOAD_TYPE_RESPONSE , client - > id , secret , reply_data , reply_len ) ;
if ( reply ) {
if ( client - > out_path_len > = 0 ) { // we have an out_path, so send DIRECT
if ( client - > out_path_len ! = OUT_PATH_UNKNOWN ) { // we have an out_path, so send DIRECT
sendDirect ( reply , client - > out_path , client - > out_path_len , SERVER_RESPONSE_DELAY ) ;
} else {
sendFlood ( reply , SERVER_RESPONSE_DELAY ) ;
sendFlood ( reply , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
}
}
}
@ -647,8 +692,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
mesh : : Packet * ack = createAck ( ack_hash ) ;
if ( ack ) {
if ( client - > out_path_len < 0 ) {
sendFlood ( ack , TXT_ACK_DELAY ) ;
if ( client - > out_path_len = = OUT_PATH_UNKNOWN ) {
sendFlood ( ack , TXT_ACK_DELAY , packet - > getPathHashSize ( ) ) ;
} else {
sendDirect ( ack , client - > out_path , client - > out_path_len , TXT_ACK_DELAY ) ;
}
@ -675,8 +720,8 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
auto reply = createDatagram ( PAYLOAD_TYPE_TXT_MSG , client - > id , secret , temp , 5 + text_len ) ;
if ( reply ) {
if ( client - > out_path_len < 0 ) {
sendFlood ( reply , CLI_REPLY_DELAY_MILLIS ) ;
if ( client - > out_path_len = = OUT_PATH_UNKNOWN ) {
sendFlood ( reply , CLI_REPLY_DELAY_MILLIS , packet - > getPathHashSize ( ) ) ;
} else {
sendDirect ( reply , client - > out_path , client - > out_path_len , CLI_REPLY_DELAY_MILLIS ) ;
}
@ -697,7 +742,8 @@ bool MyMesh::onPeerPathRecv(mesh::Packet *packet, int sender_idx, const uint8_t
MESH_DEBUG_PRINTLN ( " PATH to client, path_len=%d " , ( uint32_t ) path_len ) ;
auto client = acl . getClientByIdx ( i ) ;
memcpy ( client - > out_path , path , client - > out_path_len = path_len ) ; // store a copy of path, for sendDirect()
// store a copy of path, for sendDirect()
client - > out_path_len = mesh : : Packet : : copyPath ( client - > out_path , path , path_len ) ;
client - > last_activity = getRTCClock ( ) - > getCurrentTime ( ) ;
} else {
MESH_DEBUG_PRINTLN ( " onPeerPathRecv: invalid peer idx: %d " , i ) ;
@ -738,6 +784,47 @@ void MyMesh::onControlDataRecv(mesh::Packet* packet) {
sendZeroHop ( resp , getRetransmitDelay ( resp ) * 4 ) ; // apply random delay (widened x4), as multiple nodes can respond to this
}
}
} else if ( type = = CTL_TYPE_NODE_DISCOVER_RESP & & packet - > payload_len > = 6 ) {
uint8_t node_type = packet - > payload [ 0 ] & 0x0F ;
if ( node_type ! = ADV_TYPE_REPEATER ) {
return ;
}
if ( packet - > payload_len < 6 + PUB_KEY_SIZE ) {
MESH_DEBUG_PRINTLN ( " onControlDataRecv: DISCOVER_RESP pubkey too short: %d " , ( uint32_t ) packet - > payload_len ) ;
return ;
}
if ( pending_discover_tag = = 0 | | millisHasNowPassed ( pending_discover_until ) ) {
pending_discover_tag = 0 ;
return ;
}
uint32_t tag ;
memcpy ( & tag , & packet - > payload [ 2 ] , 4 ) ;
if ( tag ! = pending_discover_tag ) {
return ;
}
mesh : : Identity id ( & packet - > payload [ 6 ] ) ;
if ( id . matches ( self_id ) ) {
return ;
}
putNeighbour ( id , rtc_clock . getCurrentTime ( ) , packet - > getSNR ( ) ) ;
}
}
void MyMesh : : sendNodeDiscoverReq ( ) {
uint8_t data [ 10 ] ;
data [ 0 ] = CTL_TYPE_NODE_DISCOVER_REQ ; // prefix_only=0
data [ 1 ] = ( 1 < < ADV_TYPE_REPEATER ) ;
getRNG ( ) - > random ( & data [ 2 ] , 4 ) ; // tag
memcpy ( & pending_discover_tag , & data [ 2 ] , 4 ) ;
pending_discover_until = futureMillis ( 60000 ) ;
uint32_t since = 0 ;
memcpy ( & data [ 6 ] , & since , 4 ) ;
auto pkt = createControlData ( data , sizeof ( data ) ) ;
if ( pkt ) {
sendZeroHop ( pkt ) ;
}
}
@ -771,7 +858,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs . airtime_factor = 1.0 ; // one half
_prefs . rx_delay_base = 0.0f ; // turn off by default, was 10.0;
_prefs . tx_delay_factor = 0.5f ; // was 0.25f
_prefs . direct_tx_delay_factor = 0.2f ; // was zero
_prefs . direct_tx_delay_factor = 0.3f ; // was 0.2
StrHelper : : strncpy ( _prefs . node_name , ADVERT_NAME , sizeof ( _prefs . node_name ) ) ;
_prefs . node_lat = ADVERT_LAT ;
_prefs . node_lon = ADVERT_LON ;
@ -801,6 +888,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs . advert_loc_policy = ADVERT_LOC_PREFS ;
_prefs . adc_multiplier = 0.0f ; // 0.0f means use default board multiplier
pending_discover_tag = 0 ;
pending_discover_until = 0 ;
}
void MyMesh : : begin ( FILESYSTEM * fs ) {
@ -858,7 +948,7 @@ void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh : : Packet * pkt = createSelfAdvert ( ) ;
if ( pkt ) {
if ( flood ) {
sendFlood ( pkt , delay_millis ) ;
sendFlood ( pkt , delay_millis , _prefs . path_hash_mode + 1 ) ;
} else {
sendZeroHop ( pkt , delay_millis ) ;
}
@ -1168,6 +1258,15 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
} else {
strcpy ( reply , " Err - ?? " ) ;
}
} else if ( memcmp ( command , " discover.neighbors " , 18 ) = = 0 ) {
const char * sub = command + 18 ;
while ( * sub = = ' ' ) sub + + ;
if ( * sub ! = 0 ) {
strcpy ( reply , " Err - discover.neighbors has no options " ) ;
} else {
sendNodeDiscoverReq ( ) ;
strcpy ( reply , " OK - Discover sent " ) ;
}
} else {
_cli . handleCommand ( sender_timestamp , command , reply ) ; // common CLI commands
}