2013-11-02 10:35:33 -04:00
/*
* libretroshare / src / services : groutermatrix . cc
*
* Services for RetroShare .
*
* Copyright 2013 by Cyril Soler
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library 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
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " csoler@users.sourceforge.net " .
*
*/
2013-11-08 17:22:40 -05:00
# include "groutertypes.h"
2013-11-02 10:35:33 -04:00
# include "groutermatrix.h"
2013-12-27 15:06:47 -05:00
# include "grouteritems.h"
2013-11-02 10:35:33 -04:00
2015-10-25 17:16:16 -04:00
# define ROUTING_MATRIX_DEBUG
2015-04-21 16:09:20 -04:00
2013-11-05 16:15:26 -05:00
GRouterMatrix : : GRouterMatrix ( )
2013-11-02 10:35:33 -04:00
{
2013-11-05 16:15:26 -05:00
_proba_need_updating = true ;
2013-11-02 10:35:33 -04:00
}
2015-10-25 17:16:16 -04:00
bool GRouterMatrix : : addTrackingInfo ( const RsGxsMessageId & mid , const RsPeerId & source_friend )
{
time_t now = time ( NULL ) ;
uint32_t fid = getFriendId ( source_friend ) ;
RoutingTrackEntry rte ;
rte . friend_id = fid ;
rte . time_stamp = now ;
_tracking_clues [ mid ] = rte ;
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " GRouterMatrix::addTrackingInfo(): Added clue mid= " < < mid < < " , from " < < source_friend < < " ID= " < < fid < < std : : endl ;
# endif
return true ;
}
bool GRouterMatrix : : cleanUp ( )
{
// remove all tracking entries that have become too old.
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " GRouterMatrix::cleanup() " < < std : : endl ;
# endif
time_t now = time ( NULL ) ;
for ( std : : map < RsGxsMessageId , RoutingTrackEntry > : : iterator it ( _tracking_clues . begin ( ) ) ; it ! = _tracking_clues . end ( ) ; )
if ( it - > second . time_stamp + RS_GROUTER_MAX_KEEP_TRACKING_CLUES < now )
{
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " removing old entry msgId= " < < it - > first < < " , from id " < < it - > second . friend_id < < " , obtained " < < ( now - it - > second . time_stamp ) < < " secs ago. " < < std : : endl ;
# endif
std : : map < RsGxsMessageId , RoutingTrackEntry > : : iterator tmp ( it ) ;
+ + tmp ;
_tracking_clues . erase ( it ) ;
it = tmp ;
}
else
+ + it ;
return true ;
}
2014-03-29 10:18:05 -04:00
bool GRouterMatrix : : addRoutingClue ( const GRouterKeyId & key_id , const RsPeerId & source_friend , float weight )
2013-11-05 16:15:26 -05:00
{
// 1 - get the friend index.
//
uint32_t fid = getFriendId ( source_friend ) ;
// 2 - get the Key map, and add the routing clue.
//
time_t now = time ( NULL ) ;
RoutingMatrixHitEntry rc ;
2014-03-29 10:18:05 -04:00
rc . weight = weight ;
2013-11-05 16:15:26 -05:00
rc . time_stamp = now ;
rc . friend_id = fid ;
2013-11-08 17:22:40 -05:00
std : : list < RoutingMatrixHitEntry > & lst ( _routing_clues [ key_id ] ) ;
// Prevent flooding. Happens in two scenarii:
// 1 - a user restarts RS very often => keys get republished for some reason
// 2 - a user intentionnaly floods a key
2014-10-19 17:30:28 -04:00
//
// Solution is to look for all recorded events, and not add any new event if an event came from the same friend
// too close in the past. Going through the list is not costly since it is bounded to RS_GROUTER_MATRIX_MAX_HIT_ENTRIES elemts.
for ( std : : list < RoutingMatrixHitEntry > : : const_iterator mit ( lst . begin ( ) ) ; mit ! = lst . end ( ) ; + + mit )
if ( ( * mit ) . friend_id = = fid & & ( * mit ) . time_stamp + RS_GROUTER_MATRIX_MIN_TIME_BETWEEN_HITS > now )
{
std : : cerr < < " GRouterMatrix::addRoutingClue(): too many clues for key " < < key_id . toStdString ( ) < < " from friend " < < source_friend < < " in a small interval of " < < now - lst . front ( ) . time_stamp < < " seconds. Flooding? " < < std : : endl ;
return false ;
}
2013-11-08 17:22:40 -05:00
lst . push_front ( rc ) ; // create it if necessary
// Remove older elements
//
uint32_t sz = lst . size ( ) ; // O(n)!
for ( uint32_t i = RS_GROUTER_MATRIX_MAX_HIT_ENTRIES ; i < sz ; + + i )
{
lst . pop_back ( ) ;
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " Poped one entry " < < std : : endl ;
# endif
2013-11-08 17:22:40 -05:00
}
2013-11-05 16:15:26 -05:00
_proba_need_updating = true ; // always, since we added new clues.
return true ;
}
2014-03-17 16:56:06 -04:00
uint32_t GRouterMatrix : : getFriendId_const ( const RsPeerId & source_friend ) const
2013-11-08 17:22:40 -05:00
{
2014-03-17 16:56:06 -04:00
std : : map < RsPeerId , uint32_t > : : const_iterator it = _friend_indices . find ( source_friend ) ;
2013-11-05 16:15:26 -05:00
2013-11-08 17:22:40 -05:00
if ( it = = _friend_indices . end ( ) )
return _reverse_friend_indices . size ( ) ;
else
return it - > second ;
}
2014-03-17 16:56:06 -04:00
uint32_t GRouterMatrix : : getFriendId ( const RsPeerId & source_friend )
2013-11-05 16:15:26 -05:00
{
2014-03-17 16:56:06 -04:00
std : : map < RsPeerId , uint32_t > : : const_iterator it = _friend_indices . find ( source_friend ) ;
2013-11-05 16:15:26 -05:00
if ( it = = _friend_indices . end ( ) )
{
// add a new friend
uint32_t new_id = _reverse_friend_indices . size ( ) ;
_reverse_friend_indices . push_back ( source_friend ) ;
_friend_indices [ source_friend ] = new_id ;
return new_id ;
}
else
return it - > second ;
}
2014-03-29 10:18:05 -04:00
void GRouterMatrix : : getListOfKnownKeys ( std : : vector < GRouterKeyId > & key_ids ) const
{
key_ids . clear ( ) ;
for ( std : : map < GRouterKeyId , std : : vector < float > > : : const_iterator it ( _time_combined_hits . begin ( ) ) ; it ! = _time_combined_hits . end ( ) ; + + it )
key_ids . push_back ( it - > first ) ;
}
2013-11-05 16:15:26 -05:00
void GRouterMatrix : : debugDump ( ) const
{
std : : cerr < < " Proba needs up: " < < _proba_need_updating < < std : : endl ;
2013-11-08 17:22:40 -05:00
std : : cerr < < " Known keys: " < < _time_combined_hits . size ( ) < < std : : endl ;
2013-11-05 16:15:26 -05:00
std : : cerr < < " Routing events: " < < std : : endl ;
time_t now = time ( NULL ) ;
for ( std : : map < GRouterKeyId , std : : list < RoutingMatrixHitEntry > > : : const_iterator it ( _routing_clues . begin ( ) ) ; it ! = _routing_clues . end ( ) ; + + it )
{
std : : cerr < < " " < < it - > first . toStdString ( ) < < " : " ;
for ( std : : list < RoutingMatrixHitEntry > : : const_iterator it2 ( it - > second . begin ( ) ) ; it2 ! = it - > second . end ( ) ; + + it2 )
std : : cerr < < now - ( * it2 ) . time_stamp < < " ( " < < ( * it2 ) . friend_id < < " , " < < ( * it2 ) . weight < < " ) " ;
std : : cerr < < std : : endl ;
}
2013-11-08 17:22:40 -05:00
std : : cerr < < " Routing values: " < < std : : endl ;
2013-11-05 16:15:26 -05:00
for ( std : : map < GRouterKeyId , std : : vector < float > > : : const_iterator it ( _time_combined_hits . begin ( ) ) ; it ! = _time_combined_hits . end ( ) ; + + it )
{
2013-12-28 16:47:15 -05:00
std : : cerr < < " " < < it - > first . toStdString ( ) < < " : " ;
2013-11-05 16:15:26 -05:00
for ( uint32_t i = 0 ; i < it - > second . size ( ) ; + + i )
std : : cerr < < it - > second [ i ] < < " " ;
std : : cerr < < std : : endl ;
}
}
2014-03-29 10:18:05 -04:00
bool GRouterMatrix : : computeRoutingProbabilities ( const GRouterKeyId & key_id , const std : : vector < RsPeerId > & friends , std : : vector < float > & probas ) const
2013-11-05 16:15:26 -05:00
{
// Routing probabilities are computed according to routing clues
//
// For a given key, each friend has a known set of routing clues (time_t, weight)
// We combine these to compute a static weight for each friend/key pair.
// This is performed in updateRoutingProbabilities()
//
// Then for a given list of online friends, the weights are computed into probabilities,
// that always sum up to 1.
//
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
if ( _proba_need_updating )
std : : cerr < < " GRouterMatrix::computeRoutingProbabilities(): matrix is not up to date. Not a real problem, but still... " < < std : : endl ;
# endif
2013-11-08 17:22:40 -05:00
2014-03-29 10:18:05 -04:00
probas . resize ( friends . size ( ) , 0.0f ) ;
2013-11-08 17:22:40 -05:00
float total = 0.0f ;
std : : map < GRouterKeyId , std : : vector < float > > : : const_iterator it2 = _time_combined_hits . find ( key_id ) ;
if ( it2 = = _time_combined_hits . end ( ) )
{
2015-04-17 17:37:26 -04:00
// The key is not known. In this case, we return a zero probability for all peers.
//
float p = 0.0f ; //1.0f / friends.size() ;
2014-03-29 10:18:05 -04:00
probas . clear ( ) ;
probas . resize ( friends . size ( ) , p ) ;
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " GRouterMatrix::computeRoutingProbabilities(): key id " < < key_id . toStdString ( ) < < " does not exist! Returning uniform probabilities. " < < std : : endl ;
# endif
2013-11-08 17:22:40 -05:00
return false ;
}
const std : : vector < float > & w ( it2 - > second ) ;
2014-03-29 10:18:05 -04:00
for ( uint32_t i = 0 ; i < friends . size ( ) ; + + i )
2013-11-08 17:22:40 -05:00
{
2014-03-29 10:18:05 -04:00
uint32_t findex = getFriendId_const ( friends [ i ] ) ;
2013-11-08 17:22:40 -05:00
if ( findex > = w . size ( ) )
2014-03-29 10:18:05 -04:00
probas [ i ] = 0.0f ;
2013-11-08 17:22:40 -05:00
else
{
2014-03-29 10:18:05 -04:00
probas [ i ] = w [ findex ] ;
2013-11-08 17:22:40 -05:00
total + = w [ findex ] ;
}
}
if ( total > 0.0f )
2014-04-12 15:58:45 -04:00
for ( uint32_t i = 0 ; i < friends . size ( ) ; + + i )
2014-03-29 10:18:05 -04:00
probas [ i ] / = total ;
2013-11-08 17:22:40 -05:00
2013-11-05 16:15:26 -05:00
return true ;
}
bool GRouterMatrix : : updateRoutingProbabilities ( )
{
if ( ! _proba_need_updating )
return false ;
time_t now = time ( NULL ) ;
for ( std : : map < GRouterKeyId , std : : list < RoutingMatrixHitEntry > > : : const_iterator it ( _routing_clues . begin ( ) ) ; it ! = _routing_clues . end ( ) ; + + it )
{
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " " < < it - > first . toStdString ( ) < < " : " ;
# endif
2013-11-05 16:15:26 -05:00
std : : vector < float > & v ( _time_combined_hits [ it - > first ] ) ;
v . clear ( ) ;
v . resize ( _friend_indices . size ( ) , 0.0f ) ;
for ( std : : list < RoutingMatrixHitEntry > : : const_iterator it2 ( it - > second . begin ( ) ) ; it2 ! = it - > second . end ( ) ; + + it2 )
2015-04-20 17:24:22 -04:00
{
// Half life period is 7 days.
float time_difference_in_days = 1 + ( now - ( * it2 ) . time_stamp ) / ( 7 * 86400.0f ) ;
2013-11-05 16:15:26 -05:00
v [ ( * it2 ) . friend_id ] + = ( * it2 ) . weight / ( time_difference_in_days * time_difference_in_days ) ;
}
2015-04-21 16:09:20 -04:00
}
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " done. " < < std : : endl ;
# endif
2013-12-27 15:06:47 -05:00
2013-11-05 16:15:26 -05:00
_proba_need_updating = false ;
return true ;
}
2013-12-27 15:06:47 -05:00
bool GRouterMatrix : : saveList ( std : : list < RsItem * > & items )
{
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " GRoutingMatrix::saveList() " < < std : : endl ;
# endif
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
RsGRouterMatrixFriendListItem * item = new RsGRouterMatrixFriendListItem ;
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
item - > reverse_friend_indices = _reverse_friend_indices ;
items . push_back ( item ) ;
2013-11-05 16:15:26 -05:00
2015-10-25 18:07:17 -04:00
for ( std : : map < GRouterKeyId , std : : list < RoutingMatrixHitEntry > > : : const_iterator it ( _routing_clues . begin ( ) ) ; it ! = _routing_clues . end ( ) ; + + it )
{
RsGRouterMatrixCluesItem * item = new RsGRouterMatrixCluesItem ;
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
item - > destination_key = it - > first ;
item - > clues = it - > second ;
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
items . push_back ( item ) ;
}
2013-11-05 16:15:26 -05:00
2015-10-25 18:07:17 -04:00
for ( std : : map < RsGxsMessageId , RoutingTrackEntry > : : const_iterator it ( _tracking_clues . begin ( ) ) ; it ! = _tracking_clues . end ( ) ; + + it )
{
RsGRouterMatrixTrackItem * item = new RsGRouterMatrixTrackItem ;
item - > provider_id = it - > second . friend_id ;
item - > time_stamp = it - > second . time_stamp ;
item - > message_id = it - > first ;
items . push_back ( item ) ;
}
return true ;
2013-12-27 15:06:47 -05:00
}
bool GRouterMatrix : : loadList ( std : : list < RsItem * > & items )
{
2015-10-25 18:07:17 -04:00
RsGRouterMatrixFriendListItem * itm1 = NULL ;
RsGRouterMatrixCluesItem * itm2 = NULL ;
RsGRouterMatrixTrackItem * itm3 = NULL ;
2013-11-05 16:15:26 -05:00
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " GRoutingMatrix::loadList() " < < std : : endl ;
# endif
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
for ( std : : list < RsItem * > : : const_iterator it ( items . begin ( ) ) ; it ! = items . end ( ) ; + + it )
{
if ( NULL ! = ( itm3 = dynamic_cast < RsGRouterMatrixTrackItem * > ( * it ) ) )
{
2015-04-21 16:09:20 -04:00
# ifdef ROUTING_MATRIX_DEBUG
2015-10-25 18:07:17 -04:00
std : : cerr < < " initing tracking clues. " < < std : : endl ;
2015-04-21 16:09:20 -04:00
# endif
2015-10-25 18:07:17 -04:00
RoutingTrackEntry rte ;
rte . friend_id = itm3 - > provider_id ;
rte . time_stamp = itm3 - > time_stamp ;
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
_tracking_clues [ itm3 - > message_id ] = rte ;
}
if ( NULL ! = ( itm2 = dynamic_cast < RsGRouterMatrixCluesItem * > ( * it ) ) )
{
# ifdef ROUTING_MATRIX_DEBUG
std : : cerr < < " initing routing clues. " < < std : : endl ;
# endif
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
_routing_clues [ itm2 - > destination_key ] = itm2 - > clues ;
_proba_need_updating = true ; // notifies to re-compute all the info.
}
if ( NULL ! = ( itm1 = dynamic_cast < RsGRouterMatrixFriendListItem * > ( * it ) ) )
{
_reverse_friend_indices = itm1 - > reverse_friend_indices ;
_friend_indices . clear ( ) ;
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
for ( uint32_t i = 0 ; i < _reverse_friend_indices . size ( ) ; + + i )
_friend_indices [ _reverse_friend_indices [ i ] ] = i ;
2013-12-27 15:06:47 -05:00
2015-10-25 18:07:17 -04:00
_proba_need_updating = true ; // notifies to re-compute all the info.
}
}
return true ;
2013-12-27 15:06:47 -05:00
}
2013-11-02 10:35:33 -04:00