@@ -2210,38 +2210,70 @@ defmodule ExICE.Priv.ICEAgent do
22102210 end
22112211
22122212 defp get_or_create_local_cand ( ice_agent , xor_addr , conn_check_pair ) do
2213+ conn_check_local_cand = Map . fetch! ( ice_agent . local_cands , conn_check_pair . local_cand_id )
2214+
22132215 local_cand =
22142216 find_local_cand ( Map . values ( ice_agent . local_cands ) , xor_addr . address , xor_addr . port )
22152217
2216- if local_cand do
2217- { local_cand , ice_agent }
2218- else
2219- # prflx candidate sec 7.2.5.3.1
2220- # TODO calculate correct prio and foundation
2221- local_cand = Map . fetch! ( ice_agent . local_cands , conn_check_pair . local_cand_id )
2218+ cond do
2219+ # When we try to send UDP datagram from bridge interfaces, that can be used to create local candidates,
2220+ # our source IP address is translated from bridge one to our physical network interface card address.
22222221
2223- priority =
2224- Candidate . priority! ( ice_agent . local_preferences , local_cand . base . base_address , :prflx )
2225-
2226- cand =
2227- Candidate.Prflx . new (
2228- address: xor_addr . address ,
2229- port: xor_addr . port ,
2230- base_address: local_cand . base . base_address ,
2231- base_port: local_cand . base . base_port ,
2232- priority: priority ,
2233- transport_module: ice_agent . transport_module ,
2234- socket: local_cand . base . socket
2235- )
2222+ # This behavior can cause specific scenarios to arise:
22362223
2237- Logger . debug ( "Adding new local prflx candidate: #{ inspect ( cand ) } " )
2224+ # L - local side
2225+ # R - remote side
2226+ # RC1 - remote candidate
22382227
2239- ice_agent = % __MODULE__ {
2240- ice_agent
2241- | local_cands: Map . put ( ice_agent . local_cands , cand . base . id , cand )
2242- }
2228+ # 1. L opens socket on interface 1 (I1), port 5000 - first local candidate (LC1)
2229+ # 2. L opens socket on interface 2 (I2), port 5000 - second local candidate (LC2)
2230+ # 3. L sends a connectivity check from LC1 to RC1.
2231+ # Given LC1 operates via I1, which is a bridge interface, its source address is rewritten to I2.
2232+ # This also creates a mapping in host's NAT from I1:5000 to I2:5000.
2233+ # 4. R perceives the request from L as originating from I2, port 5000, and responds successfully to I2, port 5000
2234+ # 5. This response arrives to the I1 port 5000 (because of the mapping in host's NAT).
2235+ # L notices that R recognized its check as one coming from I2, port 5000.
2236+
2237+ # At this moment, sending anything from I2:5000 would require OS to create another mapping in its NAT table from I2:5000 to I2:5000.
2238+ # However, because there is already an existing NAT mapping from I1:5000 to I2:5000 this send operation will fail and return an EPERM error.
2239+
2240+ # We consistently use the discovered pair socket for sending.
2241+ # Therefore, we cannot use LC2-RC1 as a valid pair discovered through a check on LC1-RC1.
2242+ # Attempting to send anything from LC1-RC1 would actually involve using the LC2 socket.
2243+ # This action is not possible while the mapping from I1:5000 to I2:5000 exists.
2244+ local_cand && local_cand . base . socket == conn_check_local_cand . base . socket ->
2245+ { local_cand , ice_agent }
2246+
2247+ local_cand ->
2248+ { conn_check_local_cand , ice_agent }
2249+
2250+ true ->
2251+ # prflx candidate sec 7.2.5.3.1
2252+ # TODO calculate correct prio and foundation
2253+ local_cand = conn_check_local_cand
22432254
2244- { cand , ice_agent }
2255+ priority =
2256+ Candidate . priority! ( ice_agent . local_preferences , local_cand . base . base_address , :prflx )
2257+
2258+ cand =
2259+ Candidate.Prflx . new (
2260+ address: xor_addr . address ,
2261+ port: xor_addr . port ,
2262+ base_address: local_cand . base . base_address ,
2263+ base_port: local_cand . base . base_port ,
2264+ priority: priority ,
2265+ transport_module: ice_agent . transport_module ,
2266+ socket: local_cand . base . socket
2267+ )
2268+
2269+ Logger . debug ( "Adding new local prflx candidate: #{ inspect ( cand ) } " )
2270+
2271+ ice_agent = % __MODULE__ {
2272+ ice_agent
2273+ | local_cands: Map . put ( ice_agent . local_cands , cand . base . id , cand )
2274+ }
2275+
2276+ { cand , ice_agent }
22452277 end
22462278 end
22472279
0 commit comments