@@ -27,8 +27,25 @@ defmodule ExICE.Priv.Candidate do
2727 @ callback send_data ( t ( ) , :inet . ip_address ( ) , :inet . port_number ( ) , binary ( ) ) ::
2828 { :ok , t ( ) } | { :error , term ( ) , t ( ) }
2929
30- @ spec priority ( type ( ) ) :: integer ( )
31- def priority ( type ) do
30+ @ spec priority! ( % { :inet . ip_address ( ) => non_neg_integer ( ) } , :inet . ip_address ( ) , type ( ) ) ::
31+ non_neg_integer ( )
32+ def priority! ( local_preferences , base_address , type ) do
33+ local_preference = Map . fetch! ( local_preferences , base_address )
34+ do_priority ( local_preference , type )
35+ end
36+
37+ @ spec priority ( % { :inet . ip_address ( ) => non_neg_integer ( ) } , :inet . ip_address ( ) , type ( ) ) ::
38+ { % { :inet . ip_address ( ) => non_neg_integer ( ) } , non_neg_integer ( ) }
39+ def priority ( local_preferences , base_address , type ) do
40+ local_preference =
41+ Map . get ( local_preferences , base_address ) || generate_local_preference ( local_preferences )
42+
43+ local_preferences = Map . put ( local_preferences , base_address , local_preference )
44+
45+ { local_preferences , do_priority ( local_preference , type ) }
46+ end
47+
48+ defp do_priority ( local_preference , type ) do
3249 type_preference =
3350 case type do
3451 :host -> 126
@@ -37,14 +54,25 @@ defmodule ExICE.Priv.Candidate do
3754 :relay -> 0
3855 end
3956
40- # That's not fully correct as according to RFC 8445 sec. 5.1.2.1 we should:
41- # * use value of 65535 when there is only one IP address
42- # * use different values when there are multiple IP addresses
43- local_preference = 65_535
44-
4557 2 ** 24 * type_preference + 2 ** 8 * local_preference + 2 ** 0 * ( 256 - 1 )
4658 end
4759
60+ defp generate_local_preference ( local_preferences , attempts \\ 200 )
61+
62+ defp generate_local_preference ( _local_preferences , 0 ) ,
63+ do: raise ( "Couldn't generate local preference" )
64+
65+ defp generate_local_preference ( local_preferences , attempts ) do
66+ # this should give us a number from 0 to 2**16-1
67+ << pref :: 16 >> = :crypto . strong_rand_bytes ( 2 )
68+
69+ if Map . has_key? ( local_preferences , pref ) do
70+ generate_local_preference ( local_preferences , attempts - 1 )
71+ else
72+ pref
73+ end
74+ end
75+
4876 @ spec foundation ( type ( ) , :inet . ip_address ( ) | String . t ( ) , :inet . ip_address ( ) | nil , atom ( ) ) ::
4977 integer ( )
5078 def foundation ( type , ip , stun_turn_ip , transport ) do
0 commit comments