@ -75,7 +75,7 @@ void MyMesh::pushPostToClient(ClientInfo *client, PostInfo &post) {
if ( reply ) {
if ( client - > out_path_len = = OUT_PATH_UNKNOWN ) {
unsigned long delay_millis = 0 ;
sendFlood ( reply , delay_millis , _prefs . path_hash_mode + 1 ) ;
sendFloodScoped ( default_scope , reply , delay_millis , _prefs . path_hash_mode + 1 ) ; // REVISIT
client - > extra . room . ack_timeout = futureMillis ( PUSH_ACK_TIMEOUT_FLOOD ) ;
} else {
sendDirect ( reply , client - > out_path , client - > out_path_len ) ;
@ -286,6 +286,23 @@ bool MyMesh::allowPacketForward(const mesh::Packet *packet) {
return true ;
}
bool MyMesh : : filterRecvFloodPacket ( mesh : : Packet * pkt ) {
// just try to determine region for packet (apply later in allowPacketForward())
if ( pkt - > getRouteType ( ) = = ROUTE_TYPE_TRANSPORT_FLOOD ) {
recv_pkt_region = region_map . findMatch ( pkt , REGION_DENY_FLOOD ) ;
} else if ( pkt - > getRouteType ( ) = = ROUTE_TYPE_FLOOD ) {
if ( region_map . getWildcard ( ) . flags & REGION_DENY_FLOOD ) {
recv_pkt_region = NULL ;
} else {
recv_pkt_region = & region_map . getWildcard ( ) ;
}
} else {
recv_pkt_region = NULL ;
}
// do normal processing
return false ;
}
void MyMesh : : onAnonDataRecv ( mesh : : Packet * packet , const uint8_t * secret , const mesh : : Identity & sender ,
uint8_t * data , size_t len ) {
if ( packet - > getPayloadType ( ) = = PAYLOAD_TYPE_ANON_REQ ) { // received an initial request by a possible admin
@ -361,14 +378,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 , client - > shared_secret , packet - > path , packet - > path_len ,
PAYLOAD_TYPE_RESPONSE , reply_data , 13 ) ;
if ( path ) sendFlood ( path , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
if ( path ) sendFloodReply ( path , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
} else {
mesh : : Packet * reply = createDatagram ( PAYLOAD_TYPE_RESPONSE , sender , client - > shared_secret , reply_data , 13 ) ;
if ( reply ) {
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 , packet - > getPathHashSize ( ) ) ;
sendFloodReply ( reply , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
}
}
}
@ -458,7 +475,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx,
if ( send_ack ) {
if ( client - > out_path_len = = OUT_PATH_UNKNOWN ) {
mesh : : Packet * ack = createAck ( ack_hash ) ;
if ( ack ) sendFlood ( ack , TXT_ACK_DELAY , packet - > getPathHashSize ( ) ) ;
if ( ack ) sendFloodReply ( ack , TXT_ACK_DELAY , packet - > getPathHashSize ( ) ) ;
delay_millis = TXT_ACK_DELAY + REPLY_DELAY_MILLIS ;
} else {
uint32_t d = TXT_ACK_DELAY ;
@ -491,7 +508,7 @@ 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 = = OUT_PATH_UNKNOWN ) {
sendFlood ( reply , delay_millis + SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
sendFloodReply ( reply , delay_millis + SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
} else {
sendDirect ( reply , client - > out_path , client - > out_path_len , delay_millis + SERVER_RESPONSE_DELAY ) ;
}
@ -546,14 +563,14 @@ 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 , packet - > getPathHashSize ( ) ) ;
if ( path ) sendFloodReply ( 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 ! = 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 , packet - > getPathHashSize ( ) ) ;
sendFloodReply ( reply , SERVER_RESPONSE_DELAY , packet - > getPathHashSize ( ) ) ;
}
}
}
@ -595,12 +612,16 @@ void MyMesh::onAckRecv(mesh::Packet *packet, uint32_t ack_crc) {
MyMesh : : MyMesh ( mesh : : MainBoard & board , mesh : : Radio & radio , mesh : : MillisecondClock & ms , mesh : : RNG & rng ,
mesh : : RTCClock & rtc , mesh : : MeshTables & tables )
: mesh : : Mesh ( radio , ms , rng , rtc , * new StaticPoolPacketManager ( 32 ) , tables ) ,
_cli ( board , rtc , sensors , acl , & _prefs , this ) , telemetry ( MAX_PACKET_PAYLOAD - 4 ) {
region_map ( key_store ) , temp_map ( key_store ) ,
_cli ( board , rtc , sensors , region_map , acl , & _prefs , this ) ,
telemetry ( MAX_PACKET_PAYLOAD - 4 )
{
last_millis = 0 ;
uptime_millis = 0 ;
next_local_advert = next_flood_advert = 0 ;
dirty_contacts_expiry = 0 ;
_logging = false ;
region_load_active = false ;
set_radio_at = revert_radio_at = 0 ;
// defaults
@ -637,6 +658,8 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
next_push = 0 ;
memset ( posts , 0 , sizeof ( posts ) ) ;
_num_posted = _num_post_pushes = 0 ;
memset ( default_scope . key , 0 , sizeof ( default_scope . key ) ) ;
}
void MyMesh : : begin ( FILESYSTEM * fs ) {
@ -646,6 +669,27 @@ void MyMesh::begin(FILESYSTEM *fs) {
_cli . loadPrefs ( _fs ) ;
acl . load ( _fs , self_id ) ;
region_map . load ( _fs ) ;
// establish default-scope
{
RegionEntry * r = region_map . getDefaultRegion ( ) ;
if ( r ) {
region_map . getTransportKeysFor ( * r , & default_scope , 1 ) ;
} else {
# ifdef DEFAULT_FLOOD_SCOPE_NAME
r = region_map . findByName ( DEFAULT_FLOOD_SCOPE_NAME ) ;
if ( r = = NULL ) {
r = region_map . putRegion ( DEFAULT_FLOOD_SCOPE_NAME , 0 ) ; // auto-create the default scope region
if ( r ) { r - > flags = 0 ; } // Allow-flood
}
if ( r ) {
region_map . setDefaultRegion ( r ) ;
region_map . getTransportKeysFor ( * r , & default_scope , 1 ) ;
}
# endif
}
}
radio_set_params ( _prefs . freq , _prefs . bw , _prefs . sf , _prefs . cr ) ;
radio_set_tx_power ( _prefs . tx_power_dbm ) ;
@ -660,6 +704,30 @@ void MyMesh::begin(FILESYSTEM *fs) {
# endif
}
void MyMesh : : sendFloodScoped ( const TransportKey & scope , mesh : : Packet * pkt , uint32_t delay_millis , uint8_t path_hash_size ) {
if ( scope . isNull ( ) ) {
sendFlood ( pkt , delay_millis , path_hash_size ) ;
} else {
uint16_t codes [ 2 ] ;
codes [ 0 ] = scope . calcTransportCode ( pkt ) ;
codes [ 1 ] = 0 ; // REVISIT: set to 'home' Region, for sender/return region?
sendFlood ( pkt , codes , delay_millis , path_hash_size ) ;
}
}
void MyMesh : : sendFloodReply ( mesh : : Packet * packet , unsigned long delay_millis , uint8_t path_hash_size ) {
if ( recv_pkt_region ) { // if _request_ packet scope is known, send reply with same scope
TransportKey scope ;
if ( region_map . getTransportKeysFor ( * recv_pkt_region , & scope , 1 ) = = 0 ) {
sendFloodScoped ( default_scope , packet , delay_millis , path_hash_size ) ;
} else {
sendFloodScoped ( scope , packet , delay_millis , path_hash_size ) ;
}
} else {
sendFloodScoped ( default_scope , packet , delay_millis , path_hash_size ) ;
}
}
void MyMesh : : applyTempRadioParams ( float freq , float bw , uint8_t sf , uint8_t cr , int timeout_mins ) {
set_radio_at = futureMillis ( 2000 ) ; // give CLI reply some time to be sent back, before applying temp radio params
pending_freq = freq ;
@ -687,7 +755,7 @@ void MyMesh::sendSelfAdvertisement(int delay_millis, bool flood) {
mesh : : Packet * pkt = createSelfAdvert ( ) ;
if ( pkt ) {
if ( flood ) {
sendFlood ( pkt , delay_millis , _prefs . path_hash_mode + 1 ) ;
sendFloodScoped ( default_scope , pkt , delay_millis , _prefs . path_hash_mode + 1 ) ;
} else {
sendZeroHop ( pkt , delay_millis ) ;
}
@ -744,6 +812,25 @@ void MyMesh::saveIdentity(const mesh::LocalIdentity &new_id) {
store . save ( " _main " , new_id ) ;
}
void MyMesh : : startRegionsLoad ( ) {
temp_map . resetFrom ( region_map ) ; // rebuild regions in a temp instance
memset ( load_stack , 0 , sizeof ( load_stack ) ) ;
load_stack [ 0 ] = & temp_map . getWildcard ( ) ;
region_load_active = true ;
}
bool MyMesh : : saveRegions ( ) {
return region_map . save ( _fs ) ;
}
void MyMesh : : onDefaultRegionChanged ( const RegionEntry * r ) {
if ( r ) {
region_map . getTransportKeysFor ( * r , & default_scope , 1 ) ;
} else {
memset ( default_scope . key , 0 , sizeof ( default_scope . key ) ) ;
}
}
void MyMesh : : clearStats ( ) {
radio_driver . resetStats ( ) ;
resetStats ( ) ;
@ -764,6 +851,40 @@ void MyMesh::formatPacketStatsReply(char *reply) {
}
void MyMesh : : handleCommand ( uint32_t sender_timestamp , char * command , char * reply ) {
if ( region_load_active ) {
if ( StrHelper : : isBlank ( command ) ) { // empty/blank line, signal to terminate 'load' operation
region_map = temp_map ; // copy over the temp instance as new current map
region_load_active = false ;
sprintf ( reply , " OK - loaded %d regions " , region_map . getCount ( ) ) ;
} else {
char * np = command ;
while ( * np = = ' ' ) np + + ; // skip indent
int indent = np - command ;
char * ep = np ;
while ( RegionMap : : is_name_char ( * ep ) ) ep + + ;
if ( * ep ) { * ep + + = 0 ; } // set null terminator for end of name
while ( * ep & & * ep ! = ' F ' ) ep + + ; // look for (optional) flags
if ( indent > 0 & & indent < 8 & & strlen ( np ) > 0 ) {
auto parent = load_stack [ indent - 1 ] ;
if ( parent ) {
auto old = region_map . findByName ( np ) ;
auto nw = temp_map . putRegion ( np , parent - > id , old ? old - > id : 0 ) ; // carry-over the current ID (if name already exists)
if ( nw ) {
nw - > flags = old ? old - > flags : ( * ep = = ' F ' ? 0 : REGION_DENY_FLOOD ) ; // carry-over flags from curr
load_stack [ indent ] = nw ; // keep pointers to parent regions, to resolve parent_id's
}
}
}
reply [ 0 ] = 0 ;
}
return ;
}
while ( * command = = ' ' )
command + + ; // skip leading spaces
@ -865,7 +986,7 @@ void MyMesh::loop() {
if ( next_flood_advert & & millisHasNowPassed ( next_flood_advert ) ) {
mesh : : Packet * pkt = createSelfAdvert ( ) ;
uint32_t delay_millis = 0 ;
if ( pkt ) sendFlood ( pkt , delay_millis , _prefs . path_hash_mode + 1 ) ;
if ( pkt ) sendFloodScoped ( default_scope , pkt , delay_millis , _prefs . path_hash_mode + 1 ) ;
updateFloodAdvertTimer ( ) ; // schedule next flood advert
updateAdvertTimer ( ) ; // also schedule local advert (so they don't overlap)