doubango/tinyNET/test/test_ice.h
c732d49e
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * This file is part of Open Source Doubango Framework.
 *
 * DOUBANGO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DOUBANGO 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DOUBANGO.
 *
 */
 
 #ifndef TNET_TEST_ICE_H
 #define TNET_TEST_ICE_H
 
 #undef kStunUsrName
 #undef kStunPwd
 
 #define kStunUsrName			"bossiel@yahoo.fr"
 #define kStunPwd				"tinynet"
 #define kStunServerIP			"ns313841.ovh.net" /*"numb.viagenie.ca"*/ /*stun.ekiga.net*/
 
 #define kSkipHosts				1
 #define kSkipReflexives			1 // server reflexive: STUN
 #define kSkipPeers				1 // peer reflexive
 #define kSkipRelays				0 // relays: TURN
 
 #define kTurnTrue				1
 #define kStunTrue				1
 #define kTurnFalse				0
 #define kStunFalse				0
 
 static const tsk_bool_t use_rtcp = tsk_false;
 
 static struct tnet_ice_ctx_s *p_ice_ctx1 = tsk_null;
 static struct tnet_ice_ctx_s *p_ice_ctx2 = tsk_null;
 
 static void test_ice_print_local_candidates(const struct tnet_ice_ctx_s *pc_ctx)
 {
 	tsk_size_t index = 0;
 	const tnet_ice_candidate_t* candidate;
 	char* p_str = tsk_null;
 
 	while ((candidate = tnet_ice_ctx_get_local_candidate_at(pc_ctx, index++))) {
 		tsk_strcat_2(&p_str, "%s\r\n", tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate));
 	}
 	TSK_DEBUG_INFO("ICE LOCAL CANDIDATES:\n%s", p_str);
 	TSK_FREE(p_str);
 }
 
 static char* test_ice_get_local_candidates(const struct tnet_ice_ctx_s *pc_ctx)
 {
 	tsk_size_t index = 0;
 	const tnet_ice_candidate_t* candidate;
 	char* p_str = tsk_null;
 
 	while ((candidate = tnet_ice_ctx_get_local_candidate_at(pc_ctx, index++))) {
 		if (kSkipHosts && candidate->type_e == tnet_ice_cand_type_host) {
 			continue;
 		}
 		if (kSkipReflexives && candidate->type_e == tnet_ice_cand_type_srflx) {
 			continue;
 		}
 		if (kSkipRelays && candidate->type_e == tnet_ice_cand_type_relay) {
 			continue;
 		}
 		if (kSkipPeers && candidate->type_e == tnet_ice_cand_type_prflx) {
 			continue;
 		}
 		tsk_strcat_2(&p_str, "%s\r\n", tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate));
 	}
 	return p_str;
 }
 
 static int test_ice_rtp_callback(const void* callback_data, const uint8_t* data_ptr, tsk_size_t data_size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr)
 {
 	struct tnet_ice_ctx_s *p_ice_ctx = (struct tnet_ice_ctx_s *)callback_data;
 
 	TSK_DEBUG_INFO("\n\nICE rtp callback (incoming data): %.*s\n\n", data_size, data_ptr);
 
 #if 0
 	tnet_ice_ctx_send_turn_rtp(p_ice_ctx, data_ptr, data_size);
 #endif
 
 	return 0;
 }
 
 static int test_ice_state_callback(const tnet_ice_event_t *e)
 {
 	struct tnet_ice_ctx_s *p_ice_ctx = (struct tnet_ice_ctx_s *)e->ctx;
 	int ret = 0;
 
 	TSK_DEBUG_INFO("ICE state callback: %s", e->phrase);
 
 	switch(e->type)
 	{
 		case tnet_ice_event_type_gathering_completed:
 			{
 				test_ice_print_local_candidates(p_ice_ctx);
 				if (p_ice_ctx == p_ice_ctx1) {
 					if ((ret = tnet_ice_ctx_start(p_ice_ctx2))) {
 						goto bail;
 					}
 				}
 				else {
 					const tnet_ice_candidate_t* candidate;
 					char* p_cand;
 
 					p_cand = test_ice_get_local_candidates(p_ice_ctx2);
 					candidate = tnet_ice_ctx_get_local_candidate_first(p_ice_ctx2);
 					ret = tnet_ice_ctx_set_remote_candidates(p_ice_ctx1, p_cand, candidate->ufrag, candidate->pwd, tsk_true, tsk_false);
 					if (ret == 0) {
 						TSK_FREE(p_cand);
 						p_cand = test_ice_get_local_candidates(p_ice_ctx1);
 						candidate = tnet_ice_ctx_get_local_candidate_first(p_ice_ctx1);
 						ret = tnet_ice_ctx_set_remote_candidates(p_ice_ctx2, p_cand, candidate->ufrag, candidate->pwd, tsk_false, tsk_false);
 						TSK_FREE(p_cand);
 					}
 				}
 				break;
 			}
 
 		case tnet_ice_event_type_conncheck_succeed:
 			{
 				const char kTurnData[] = "TURN data to send for testing";
 				const tnet_ice_candidate_t *candidate_offer, *candidate_answer_src, *candidate_answer_dest;
 
 				// === RTP === //
 				ret = tnet_ice_ctx_get_nominated_symetric_candidates(p_ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTP, &candidate_offer, &candidate_answer_src, &candidate_answer_dest);
 				if (ret == 0) {
 					TSK_DEBUG_INFO("Nominated candidate(RTP): Offer=[[%s]], AnswerSrc=[[%s]], AnswerDest=[[%s]]",
 						tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_offer),
 						tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_src),
 						tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_dest));
 
 					if (tnet_ice_ctx_is_turn_rtp_active(p_ice_ctx)) {
 						tnet_ice_ctx_send_turn_rtp(p_ice_ctx, kTurnData, sizeof(kTurnData));
 					}
 				}
 				// === RTCP === //
 				if (use_rtcp) {
 					ret = tnet_ice_ctx_get_nominated_symetric_candidates(p_ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTCP, &candidate_offer, &candidate_answer_src, &candidate_answer_dest);
 					if (ret == 0) {
 						TSK_DEBUG_INFO("Nominated candidate(RTCP): Offer=[[%s]], AnswerSrc=[[%s]], AnswerDest=[[%s]]",
 							tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_offer),
 							tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_src),
 							tnet_ice_candidate_tostring((tnet_ice_candidate_t*)candidate_answer_dest));
 						if (tnet_ice_ctx_is_turn_rtcp_active(p_ice_ctx)) {
 							tnet_ice_ctx_send_turn_rtcp(p_ice_ctx, kTurnData, sizeof(kTurnData));
 						}
 					}
 				}
 				break;
 			}
 	}
 
 bail:
 	return ret;
 }
 
 void test_ice()
 {
 	int ret;
 	static const tsk_bool_t use_ipv6 = tsk_false;
 	static const tsk_bool_t use_ice_jingle = tsk_false;
 	static const tsk_bool_t use_video = tsk_false;
 	
 	if (!(p_ice_ctx1 = tnet_ice_ctx_create(use_ice_jingle, use_ipv6, use_rtcp, use_video, test_ice_state_callback, tsk_null))) {
 		goto bail;
 	}
 	if (!(p_ice_ctx2 = tnet_ice_ctx_create(use_ice_jingle, use_ipv6, use_rtcp, use_video, test_ice_state_callback, tsk_null))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_turn_enabled(p_ice_ctx1, 1))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_turn_enabled(p_ice_ctx2, 1))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_stun_enabled(p_ice_ctx1, 1))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_stun_enabled(p_ice_ctx2, 1))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_userdata(p_ice_ctx1, p_ice_ctx1))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_userdata(p_ice_ctx2, p_ice_ctx2))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_rtp_callback(p_ice_ctx1, test_ice_rtp_callback, p_ice_ctx1))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_rtp_callback(p_ice_ctx2, test_ice_rtp_callback, p_ice_ctx2))) {
 		goto bail;
 	}
 #if 0 //@deprecated
 	if ((ret = tnet_ice_ctx_set_stun(p_ice_ctx1, kStunServerIP, 3478, kStunSoftware, kStunUsrName, kStunPwd))) {
 		goto bail;
 	}
 	if ((ret = tnet_ice_ctx_set_stun(p_ice_ctx2, kStunServerIP, 3478, kStunSoftware, kStunUsrName, kStunPwd))) {
 		goto bail;
 	}
 #else
 	tnet_ice_ctx_add_server(p_ice_ctx1, "udp", kStunServerIP, 3478, kTurnFalse, kStunTrue, kStunUsrName, kStunPwd); // STUN-UDP
 	tnet_ice_ctx_add_server(p_ice_ctx1, "tcp", kStunServerIP, 3478, kTurnTrue, kStunFalse, kStunUsrName, kStunPwd); // TURN-TCP
 	tnet_ice_ctx_add_server(p_ice_ctx2, "udp", kStunServerIP, 3478, kTurnFalse, kStunTrue, kStunUsrName, kStunPwd); // STUN-UDP
 	tnet_ice_ctx_add_server(p_ice_ctx2, "tcp", kStunServerIP, 3478, kTurnTrue, kStunFalse, kStunUsrName, kStunPwd); // TURN-TCP
 #endif
 	if ((ret = tnet_ice_ctx_start(p_ice_ctx1))) {
 		goto bail;
 	}
 	// start ctx2 when we finish gathering ctx1's candidates
 	//if ((ret = tnet_ice_ctx_start(p_ice_ctx2))) {
 	//	goto bail;
 	//}
 
 	getchar();
 	
 	// ret = tnet_ice_ctx_stop(p_ice_ctx1);
 	// ret = tnet_ice_ctx_stop(p_ice_ctx2);
 
 bail:
 	TSK_OBJECT_SAFE_FREE(p_ice_ctx1);
 	TSK_OBJECT_SAFE_FREE(p_ice_ctx2);
 }
 
 
 #endif /* TNET_TEST_ICE_H */