@@ -92,6 +92,7 @@ juice_agent_t *agent_create(const juice_config_t *config) {
9292	}
9393
9494	bool  alloc_failed  =  false;
95+ 	agent -> ice_tcp_mode  =  JUICE_ICE_TCP_MODE_NONE ;
9596	agent -> config .concurrency_mode  =  config -> concurrency_mode ;
9697	agent -> config .stun_server_host  =  alloc_string_copy (config -> stun_server_host , & alloc_failed );
9798	agent -> config .stun_server_port  =  config -> stun_server_port ;
@@ -211,6 +212,20 @@ static thread_return_t THREAD_CALL resolver_thread_entry(void *arg) {
211212	return  (thread_return_t )0 ;
212213}
213214
215+ void  agent_add_ice_tcp_local_candidate (juice_agent_t  * agent , addr_record_t  * record ) {
216+ 	ice_candidate_t  candidate ;
217+ 	if  (ice_create_local_candidate (ICE_CANDIDATE_TYPE_HOST , 1 , agent -> local .candidates_count , record , & candidate , ICE_CANDIDATE_TRANSPORT_TCP_TYPE_ACTIVE )) {
218+         JLOG_ERROR ("Failed to create ice-tcp candidate" );
219+ 		return ;
220+ 	}
221+ 
222+ 	if  (ice_add_candidate (& candidate , & agent -> local )) {
223+ 		JLOG_ERROR ("Failed to add ice-tcp candidate to local description" );
224+ 	}
225+ 
226+ 	return ;
227+ }
228+ 
214229int  agent_gather_candidates (juice_agent_t  * agent ) {
215230	JLOG_VERBOSE ("Gathering candidates" );
216231	if  (agent -> conn_impl ) {
@@ -252,7 +267,7 @@ int agent_gather_candidates(juice_agent_t *agent) {
252267	for  (int  i  =  0 ; i  <  records_count ; ++ i ) {
253268		ice_candidate_t  candidate ;
254269		if  (ice_create_local_candidate (ICE_CANDIDATE_TYPE_HOST , 1 , agent -> local .candidates_count ,
255- 		                               records  +  i , & candidate )) {
270+ 		                               records  +  i , & candidate ,  ICE_CANDIDATE_TRANSPORT_UDP )) {
256271			JLOG_ERROR ("Failed to create host candidate" );
257272			continue ;
258273		}
@@ -266,6 +281,14 @@ int agent_gather_candidates(juice_agent_t *agent) {
266281		}
267282	}
268283
284+ 	if  (agent -> ice_tcp_mode  ==  JUICE_ICE_TCP_MODE_ACTIVE ) {
285+ 		if  (records_count  >  0 ) {
286+ 			agent_add_ice_tcp_local_candidate (agent , & records [0 ]);
287+ 		} else  {
288+ 			JLOG_WARN ("No local host candidates gathered, unable to add ice-tcp" );
289+ 		}
290+ 	}
291+ 
269292	ice_sort_candidates (& agent -> local );
270293
271294	for  (int  i  =  0 ; i  <  agent -> entries_count ; ++ i )
@@ -341,7 +364,7 @@ int agent_resolve_servers(juice_agent_t *agent) {
341364			conn_unlock (agent );
342365
343366			addr_record_t  records [DEFAULT_MAX_RECORDS_COUNT ];
344- 			int  records_count  =  addr_resolve (hostname , service , records , DEFAULT_MAX_RECORDS_COUNT );
367+ 			int  records_count  =  addr_resolve (hostname , service , SOCK_DGRAM ,  records , DEFAULT_MAX_RECORDS_COUNT );
345368
346369			conn_lock (agent );
347370
@@ -426,7 +449,7 @@ int agent_resolve_servers(juice_agent_t *agent) {
426449		conn_unlock (agent );
427450
428451		addr_record_t  records [MAX_STUN_SERVER_RECORDS_COUNT ];
429- 		int  records_count  =  addr_resolve (hostname , service , records , MAX_STUN_SERVER_RECORDS_COUNT );
452+ 		int  records_count  =  addr_resolve (hostname , service , SOCK_DGRAM ,  records , MAX_STUN_SERVER_RECORDS_COUNT );
430453
431454		conn_lock (agent );
432455
@@ -825,6 +848,34 @@ int agent_input(juice_agent_t *agent, char *buf, size_t len, const addr_record_t
825848	return  -1 ;
826849}
827850
851+ void  agent_register_entry_for_candidate_pair (juice_agent_t  * agent , ice_candidate_pair_t  * pair , agent_stun_entry_t  * relay_entry ) {
852+ 	JLOG_VERBOSE ("Registering STUN entry %d for candidate pair checking" , agent -> entries_count );
853+ 	agent_stun_entry_t  * entry  =  agent -> entries  +  agent -> entries_count ;
854+ 	entry -> type  =  AGENT_STUN_ENTRY_TYPE_CHECK ;
855+ 	entry -> state  =  AGENT_STUN_ENTRY_STATE_IDLE ;
856+ 	entry -> mode  =  AGENT_MODE_UNKNOWN ;
857+ 	entry -> pair  =  pair ;
858+ 	entry -> record  =  pair -> remote -> resolved ;
859+ 	entry -> relay_entry  =  relay_entry ;
860+ 	juice_random (entry -> transaction_id , STUN_TRANSACTION_ID_SIZE );
861+ 	entry -> transaction_id_expired  =  false;
862+ 	++ agent -> entries_count ;
863+ 
864+ 	if  (pair -> remote -> type  ==  ICE_CANDIDATE_TYPE_HOST )
865+ 		agent_translate_host_candidate_entry (agent , entry );
866+ }
867+ 
868+ void  agent_tcp_conn_connected (juice_agent_t  * agent ) {
869+ 	for  (int  i  =  0 ; i  <  agent -> candidate_pairs_count ; ++ i ) {
870+ 		ice_candidate_pair_t  * pair  =  agent -> ordered_pairs [i ];
871+ 		if  (pair -> remote -> transport  !=  ICE_CANDIDATE_TRANSPORT_UDP ) {
872+ 			agent_register_entry_for_candidate_pair (agent , pair , NULL );
873+ 			agent_unfreeze_candidate_pair (agent , pair );
874+ 		}
875+ 	}
876+ 	conn_interrupt (agent );
877+ }
878+ 
828879int  agent_bookkeeping (juice_agent_t  * agent , timestamp_t  * next_timestamp ) {
829880	JLOG_VERBOSE ("Bookkeeping..." );
830881
@@ -998,6 +1049,10 @@ int agent_bookkeeping(juice_agent_t *agent, timestamp_t *next_timestamp) {
9981049				++ pending_count ;
9991050			}
10001051		}
1052+ 
1053+ 		if  (pair -> remote -> transport  !=  ICE_CANDIDATE_TRANSPORT_UDP ) {
1054+ 			conn_tcp_connect (agent , & pair -> remote -> resolved , agent_tcp_conn_connected );
1055+ 		}
10011056	}
10021057
10031058	if  (agent -> mode  ==  AGENT_MODE_CONTROLLING  &&  nominated_pair ) {
@@ -1629,7 +1684,7 @@ int agent_send_stun_binding(juice_agent_t *agent, agent_stun_entry_t *entry, stu
16291684			                ? (int )(entry -> pair -> local  -  agent -> local .candidates )
16301685			                : 0 ;
16311686			msg .priority  = 
1632- 			    ice_compute_priority (ICE_CANDIDATE_TYPE_PEER_REFLEXIVE , family , 1 , index );
1687+ 			    ice_compute_priority (ICE_CANDIDATE_TYPE_PEER_REFLEXIVE , family , 1 , index , false );
16331688
16341689			// RFC 8445 8.1.1. Nominating Pairs: 
16351690			// Once the controlling agent has picked a valid pair for nomination, it repeats the 
@@ -2177,7 +2232,7 @@ int agent_add_local_relayed_candidate(juice_agent_t *agent, const addr_record_t
21772232	}
21782233	ice_candidate_t  candidate ;
21792234	if  (ice_create_local_candidate (ICE_CANDIDATE_TYPE_RELAYED , 1 , agent -> local .candidates_count ,
2180- 	                               record , & candidate )) {
2235+ 	                               record , & candidate ,  ICE_CANDIDATE_TRANSPORT_UDP )) {
21812236		JLOG_ERROR ("Failed to create relayed candidate" );
21822237		return  -1 ;
21832238	}
@@ -2220,7 +2275,7 @@ int agent_add_local_reflexive_candidate(juice_agent_t *agent, ice_candidate_type
22202275		return  0 ;
22212276	}
22222277	ice_candidate_t  candidate ;
2223- 	if  (ice_create_local_candidate (type , 1 , agent -> local .candidates_count , record , & candidate )) {
2278+ 	if  (ice_create_local_candidate (type , 1 , agent -> local .candidates_count , record , & candidate ,  ICE_CANDIDATE_TRANSPORT_UDP )) {
22242279		JLOG_ERROR ("Failed to create reflexive candidate" );
22252280		return  -1 ;
22262281	}
@@ -2260,7 +2315,7 @@ int agent_add_remote_reflexive_candidate(juice_agent_t *agent, ice_candidate_typ
22602315		return  0 ;
22612316	}
22622317	ice_candidate_t  candidate ;
2263- 	if  (ice_create_local_candidate (type , 1 , agent -> local .candidates_count , record , & candidate )) {
2318+ 	if  (ice_create_local_candidate (type , 1 , agent -> local .candidates_count , record , & candidate ,  ICE_CANDIDATE_TRANSPORT_UDP )) {
22642319		JLOG_ERROR ("Failed to create reflexive candidate" );
22652320		return  -1 ;
22662321	}
@@ -2297,6 +2352,27 @@ int agent_add_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, // lo
22972352		return  -1 ;
22982353	}
22992354
2355+ 	bool  is_tcp  =  remote -> transport  !=  ICE_CANDIDATE_TRANSPORT_UDP ;
2356+ 	if  (is_tcp ) {
2357+ 		if  (agent -> ice_tcp_mode  !=  JUICE_ICE_TCP_MODE_ACTIVE ) {
2358+ 			JLOG_WARN ("ICE-TCP is disabled ignoring TCP Candidate" );
2359+ 			return  0 ;
2360+ 		}
2361+ 
2362+ 		if  (remote -> transport  !=  ICE_CANDIDATE_TRANSPORT_TCP_TYPE_PASSIVE  &&  remote -> transport  !=  ICE_CANDIDATE_TRANSPORT_TCP_TYPE_SO ) {
2363+ 			JLOG_INFO ("Ignoring ICE-TCP Candidate that is not passive or simultaneous open" );
2364+ 			return  0 ;
2365+ 		}
2366+ 
2367+ 		for  (int  i  =  0 ; i  <  agent -> candidate_pairs_count ; ++ i ) {
2368+ 			ice_candidate_pair_t  * pair  =  & agent -> candidate_pairs [i ];
2369+ 			if  (pair -> remote -> transport  !=  ICE_CANDIDATE_TRANSPORT_UDP ) {
2370+ 				JLOG_INFO ("Only one ICE-TCP remote candidate is supported ignoring TCP Candidate" );
2371+ 				return  0 ;
2372+ 			}
2373+ 		}
2374+ 	}
2375+ 
23002376	JLOG_VERBOSE ("Adding new candidate pair, priority=%"  PRIu64 , pair .priority );
23012377
23022378	// Add pair 
@@ -2327,20 +2403,9 @@ int agent_add_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, // lo
23272403		}
23282404	}
23292405
2330- 	JLOG_VERBOSE ("Registering STUN entry %d for candidate pair checking" , agent -> entries_count );
2331- 	agent_stun_entry_t  * entry  =  agent -> entries  +  agent -> entries_count ;
2332- 	entry -> type  =  AGENT_STUN_ENTRY_TYPE_CHECK ;
2333- 	entry -> state  =  AGENT_STUN_ENTRY_STATE_IDLE ;
2334- 	entry -> mode  =  AGENT_MODE_UNKNOWN ;
2335- 	entry -> pair  =  pos ;
2336- 	entry -> record  =  pos -> remote -> resolved ;
2337- 	entry -> relay_entry  =  relay_entry ;
2338- 	juice_random (entry -> transaction_id , STUN_TRANSACTION_ID_SIZE );
2339- 	entry -> transaction_id_expired  =  false;
2340- 	++ agent -> entries_count ;
2341- 
2342- 	if  (remote -> type  ==  ICE_CANDIDATE_TYPE_HOST )
2343- 		agent_translate_host_candidate_entry (agent , entry );
2406+ 	if  (!is_tcp ) {
2407+ 		agent_register_entry_for_candidate_pair (agent , pos , relay_entry );
2408+ 	}
23442409
23452410	if  (agent -> mode  ==  AGENT_MODE_CONTROLLING ) {
23462411		for  (int  i  =  0 ; i  <  agent -> candidate_pairs_count ; ++ i ) {
@@ -2358,7 +2423,7 @@ int agent_add_candidate_pair(juice_agent_t *agent, ice_candidate_t *local, // lo
23582423	}
23592424
23602425	// There is only one component, therefore we can unfreeze if no pair is nominated 
2361- 	if  (* agent -> remote .ice_ufrag  !=  '\0'  && 
2426+ 	if  (! is_tcp   &&   * agent -> remote .ice_ufrag  !=  '\0'  && 
23622427	    (!agent -> selected_pair  ||  !agent -> selected_pair -> nominated )) {
23632428		JLOG_VERBOSE ("Unfreezing the new candidate pair" );
23642429		agent_unfreeze_candidate_pair (agent , pos );
@@ -2623,6 +2688,17 @@ agent_stun_entry_t *agent_find_entry_from_record(juice_agent_t *agent, const add
26232688	return  NULL ;
26242689}
26252690
2691+ int  agent_set_ice_tcp_mode (juice_agent_t  * agent , juice_ice_tcp_mode_t  ice_tcp_mode )
2692+ {
2693+ 	if  (agent -> conn_impl ) {
2694+ 		JLOG_WARN ("Unable to set ICE attributes, candidates gathering already started" );
2695+ 		return  JUICE_ERR_FAILED ;
2696+ 	}
2697+ 
2698+ 	agent -> ice_tcp_mode  =  ice_tcp_mode ;
2699+ 	return  JUICE_ERR_SUCCESS ;
2700+ }
2701+ 
26262702void  agent_translate_host_candidate_entry (juice_agent_t  * agent , agent_stun_entry_t  * entry ) {
26272703	if  (!entry -> pair  ||  entry -> pair -> remote -> type  !=  ICE_CANDIDATE_TYPE_HOST )
26282704		return ;
0 commit comments