@@ -9,6 +9,7 @@ pub mod query;
9
9
use chrono:: { DateTime , Local } ;
10
10
use itertools:: Itertools ;
11
11
use once_cell:: sync:: Lazy ;
12
+ use rand:: { seq:: IteratorRandom , thread_rng} ;
12
13
use std:: {
13
14
path:: Path ,
14
15
sync:: { Arc , Mutex } ,
@@ -694,31 +695,32 @@ impl RelaySelector {
694
695
config. custom_lists ,
695
696
) ;
696
697
697
- // This algorithm gracefully handles a particular edge case that arise when a constraint on
698
- // the exit relay is more specific than on the entry relay which forces the relay selector
699
- // to choose one specific relay. The relay selector could end up selecting that specific
700
- // relay as the entry relay, thus leaving no remaining exit relay candidates or vice versa.
698
+ fn pick_random_excluding < ' a > ( list : & ' a [ Relay ] , exclude : & ' a Relay ) -> Option < & ' a Relay > {
699
+ list. iter ( )
700
+ . filter ( |& a| a != exclude)
701
+ . choose ( & mut thread_rng ( ) )
702
+ }
703
+ // We avoid picking the same relay for entry and exit by choosing one and excluding it when
704
+ // choosing the other.
701
705
let ( exit, entry) = match ( exit_candidates. as_slice ( ) , entry_candidates. as_slice ( ) ) {
702
706
( [ exit] , [ entry] ) if exit == entry => None ,
707
+ // In the case where there is only one exit to choose from, we have to pick it before
708
+ // the entry
703
709
( exits, [ entry] ) if exits. contains ( entry) => {
704
- let exit = helpers:: random ( exits, entry) . ok_or ( Error :: NoRelay ) ?;
705
- Some ( ( exit, entry) )
710
+ pick_random_excluding ( exits, entry) . map ( |exit| ( exit, entry) )
706
711
}
712
+ // Vice versa for the case of only one entry
707
713
( [ exit] , entries) if entries. contains ( exit) => {
708
- let entry = helpers:: random ( entries, exit) . ok_or ( Error :: NoRelay ) ?;
709
- Some ( ( exit, entry) )
710
- }
711
- ( exits, entries) => {
712
- let exit = helpers:: pick_random_relay ( exits) . ok_or ( Error :: NoRelay ) ?;
713
- let entry = helpers:: random ( entries, exit) . ok_or ( Error :: NoRelay ) ?;
714
- Some ( ( exit, entry) )
714
+ pick_random_excluding ( entries, exit) . map ( |entry| ( exit, entry) )
715
715
}
716
+ ( exits, entries) => helpers:: pick_random_relay ( exits)
717
+ . and_then ( |exit| pick_random_excluding ( entries, exit) . map ( |entry| ( exit, entry) ) ) ,
716
718
}
717
719
. ok_or ( Error :: NoRelay ) ?;
718
720
719
721
Ok ( WireguardConfig :: Multihop {
720
- exit : exit. clone ( ) ,
721
- entry : entry. clone ( ) ,
722
+ exit : exit. to_owned ( ) ,
723
+ entry : entry. to_owned ( ) ,
722
724
} )
723
725
}
724
726
0 commit comments