diff --git a/tinyDAV/src/bfcp/tdav_session_bfcp.c b/tinyDAV/src/bfcp/tdav_session_bfcp.c index c69babcf..021ca633 100755 --- a/tinyDAV/src/bfcp/tdav_session_bfcp.c +++ b/tinyDAV/src/bfcp/tdav_session_bfcp.c @@ -102,7 +102,7 @@ static int _tdav_session_bfcp_set(tmedia_session_t* p_self, const tmedia_param_t else if (tsk_striequals(param->key, "local-ip")) { tsk_strupdate(&p_bfcp->p_local_ip, param->value); } - else if (tsk_striequals(param->key, "local-ipver")) { + else if (tsk_striequals(param->key, "use-ipv6")) { p_bfcp->b_use_ipv6 = tsk_striequals(param->value, "ipv6"); } } diff --git a/tinyDAV/src/msrp/tdav_session_msrp.c b/tinyDAV/src/msrp/tdav_session_msrp.c index 950fa253..a29c7c7f 100755 --- a/tinyDAV/src/msrp/tdav_session_msrp.c +++ b/tinyDAV/src/msrp/tdav_session_msrp.c @@ -370,7 +370,7 @@ int tdav_session_msrp_set(tmedia_session_t* self, const tmedia_param_t* param) else if(tsk_striequals(param->key, "local-ip")) { tsk_strupdate(&msrp->local_ip, param->value); } - else if(tsk_striequals(param->key, "local-ipver")) { + else if(tsk_striequals(param->key, "use-ipv6")) { msrp->useIPv6 = tsk_striequals(param->value, "ipv6"); } else if(tsk_striequals(param->key, "accept-types")) { diff --git a/tinyDAV/src/tdav_session_av.c b/tinyDAV/src/tdav_session_av.c index 31401007..3a0ea411 100755 --- a/tinyDAV/src/tdav_session_av.c +++ b/tinyDAV/src/tdav_session_av.c @@ -305,7 +305,7 @@ tsk_bool_t tdav_session_av_set(tdav_session_av_t* self, const tmedia_param_t* pa tsk_strupdate(&self->local_ip, (const char*)param->value); return tsk_true; } - else if(tsk_striequals(param->key, "local-ipver")) { + else if(tsk_striequals(param->key, "use-ipv6")) { self->use_ipv6 = tsk_striequals(param->value, "ipv6"); return tsk_true; } @@ -876,11 +876,11 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ *updated = (base->ro_changed || !base->M.lo); if(!base->M.lo) { - if((base->M.lo = tsdp_header_M_create(base->plugin->media, self->rtp_manager->rtp.public_port, "RTP/AVP"))) { + if((base->M.lo = tsdp_header_M_create(base->plugin->media, self->rtp_manager->rtp.public_addr.port, "RTP/AVP"))) { /* If NATT is active, do not rely on the global IP address Connection line */ if(self->natt_ctx) { tsdp_header_M_add_headers(base->M.lo, - TSDP_HEADER_C_VA_ARGS("IN", self->use_ipv6 ? "IP6" : "IP4", self->rtp_manager->rtp.public_ip), + TSDP_HEADER_C_VA_ARGS("IN", TNET_SOCKET_TYPE_IS_IPV6(self->rtp_manager->rtp.public_addr.type) ? "IP6" : "IP4", self->rtp_manager->rtp.public_addr.ip), tsk_null); } /* 3GPP TS 24.229 - 6.1.1 General @@ -1337,10 +1337,10 @@ const tsdp_header_M_t* tdav_session_av_get_lo(tdav_session_av_t* self, tsk_bool_ } else { if(base->M.lo->C) { - tsk_strupdate(&base->M.lo->C->addr, self->rtp_manager->rtp.public_ip); - tsk_strupdate(&base->M.lo->C->addrtype, (self->use_ipv6 ? "IP6" : "IP4")); + tsk_strupdate(&base->M.lo->C->addr, self->rtp_manager->rtp.public_addr.ip); + tsk_strupdate(&base->M.lo->C->addrtype, (TNET_SOCKET_TYPE_IS_IPV6(self->rtp_manager->rtp.public_addr.type) ? "IP6" : "IP4")); } - base->M.lo->port = self->rtp_manager->rtp.public_port; + base->M.lo->port = self->rtp_manager->rtp.public_addr.port; } if(self->media_type & tmedia_audio) { diff --git a/tinyMEDIA/include/tinymedia/tmedia_session.h b/tinyMEDIA/include/tinymedia/tmedia_session.h index 698f61f9..bb11d960 100755 --- a/tinyMEDIA/include/tinymedia/tmedia_session.h +++ b/tinyMEDIA/include/tinymedia/tmedia_session.h @@ -306,10 +306,12 @@ typedef struct tmedia_session_mgr_s { tsk_bool_t offerer; //! local IP address or FQDN char* addr; + tnet_socket_type_t addr_type; //! public IP address or FQDN char* public_addr; - //! whether the @a addr is IPv6 or not (useful when @addr is a FQDN) - tsk_bool_t ipv6; + tnet_socket_type_t public_addr_type; + //! whether to enable IPv6 + tsk_bool_t use_ipv6; struct { uint32_t lo_ver; @@ -538,7 +540,7 @@ tmedia_session_param_type_t; //#define TMEDIA_SESSION_SET_QOS(TYPE_ENUM, STRENGTH_ENUM) tmedia_sptype_qos, (tmedia_qos_stype_t)TYPE_ENUM, (tmedia_qos_strength_t)STRENGTH_ENUM -TINYMEDIA_API tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t ipv6, tsk_bool_t offerer); +TINYMEDIA_API tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t use_ipv6, tsk_bool_t offerer); TINYMEDIA_API int tmedia_session_mgr_set_media_type(tmedia_session_mgr_t* self, tmedia_type_t type); TINYMEDIA_API int tmedia_session_mgr_set_media_type_2(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t force); TINYMEDIA_API int tmedia_session_mgr_set_codecs_supported(tmedia_session_mgr_t* self, tmedia_codec_id_t codecs_supported); diff --git a/tinyMEDIA/src/tmedia_session.c b/tinyMEDIA/src/tmedia_session.c index 72c924a9..b41ef9a3 100755 --- a/tinyMEDIA/src/tmedia_session.c +++ b/tinyMEDIA/src/tmedia_session.c @@ -31,6 +31,8 @@ #include "ice/tnet_ice_ctx.h" +#include "tnet_utils.h" + #include "tsk_memory.h" #include "tsk_debug.h" @@ -816,7 +818,7 @@ filter_neg_codecs: * will create an audio/video session. * @retval new @ref tmedia_session_mgr_t object */ -tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t ipv6, tsk_bool_t offerer) +tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t use_ipv6, tsk_bool_t offerer) { tmedia_session_mgr_t* mgr; @@ -828,7 +830,10 @@ tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* /* init */ mgr->type = type; mgr->addr = tsk_strdup(addr); - mgr->ipv6 = ipv6; + mgr->addr_type = tsk_strempty(mgr->addr) + ? (use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4) + : (tnet_is_ipv6(mgr->addr, 0) ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4); + mgr->use_ipv6 = use_ipv6; /* load sessions (will allow us to generate lo) */ if (offerer) { @@ -913,6 +918,7 @@ int tmedia_session_mgr_set_natt_ctx(tmedia_session_mgr_t* self, struct tnet_nat_ TSK_OBJECT_SAFE_FREE(self->natt_ctx); self->natt_ctx = tsk_object_ref(natt_ctx); tsk_strupdate(&self->public_addr, public_addr); + tnet_nat_get_socket_type(natt_ctx, &self->public_addr_type); tmedia_session_mgr_set(self, TMEDIA_SESSION_SET_POBJECT(self->type, "natt-ctx", self->natt_ctx), @@ -2211,7 +2217,7 @@ static int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t* self) TMEDIA_SESSION_SET_POBJECT(tmedia_bfcp_video, "ice-ctx", self->ice.ctx_bfcpvid), TMEDIA_SESSION_SET_STR(self->type, "local-ip", self->addr), - TMEDIA_SESSION_SET_STR(self->type, "local-ipver", self->ipv6 ? "ipv6" : "ipv4"), + TMEDIA_SESSION_SET_STR(self->type, "use-ipv6", self->use_ipv6 ? "ipv6" : "ipv4"), TMEDIA_SESSION_SET_INT32(self->type, "bandwidth-level", self->bl), TMEDIA_SESSION_SET_NULL()); // set callback functions @@ -2350,10 +2356,12 @@ static const tsdp_message_t* _tmedia_session_mgr_get_lo(tmedia_session_mgr_t* se goto bail; } else { - if ((self->sdp.lo = tsdp_message_create_empty(self->public_addr ? self->public_addr : self->addr, self->ipv6, new_ver_num))) { + const char* addr = self->public_addr ? self->public_addr : self->addr; + tsk_bool_t ipv6 = self->public_addr ? TNET_SOCKET_TYPE_IS_IPV6(self->public_addr_type) : TNET_SOCKET_TYPE_IS_IPV6(self->addr_type); + if ((self->sdp.lo = tsdp_message_create_empty(addr, ipv6, new_ver_num))) { /* Set connection "c=" */ tsdp_message_add_headers(self->sdp.lo, - TSDP_HEADER_C_VA_ARGS("IN", self->ipv6 ? "IP6" : "IP4", self->public_addr ? self->public_addr : self->addr), + TSDP_HEADER_C_VA_ARGS("IN", ipv6 ? "IP6" : "IP4", addr), tsk_null); if (inc_ver) { ++self->sdp.lo_ver; diff --git a/tinyNET/src/ice/tnet_ice_ctx.c b/tinyNET/src/ice/tnet_ice_ctx.c index 6e5e5be4..924e0d3a 100755 --- a/tinyNET/src/ice/tnet_ice_ctx.c +++ b/tinyNET/src/ice/tnet_ice_ctx.c @@ -80,6 +80,8 @@ #define kIcePairsBuildingTimeMax 2500 // maximum time to build pairs +#define kIceDefaultDualStack tsk_true + typedef tsk_list_t tnet_ice_servers_L_t; static const char* foundation_default = tsk_null; @@ -194,6 +196,12 @@ static tnet_ice_server_t* tnet_ice_server_create( TSK_DEBUG_ERROR("Invalid server address (host=%s, port=%d, transport=%d)", str_server_addr, u_server_port, e_transport); return tsk_null; } + if (obj_server_addr.ss_family == AF_INET6) { + TNET_SOCKET_TYPE_SET_IPV6Only(e_transport); + } + else { + TNET_SOCKET_TYPE_SET_IPV4Only(e_transport); + } if ((ice_server = tsk_object_new(&tnet_ice_server_def_s))) { ice_server->e_proto = e_proto; @@ -218,6 +226,7 @@ typedef struct tnet_ice_ctx_s { tnet_ice_callback_f callback; const void* userdata; tsk_bool_t use_ipv6; + tsk_bool_t dual_stack; tsk_bool_t use_rtcp; tsk_bool_t use_rtcpmux; tsk_bool_t is_video; @@ -400,6 +409,8 @@ static tsk_object_t* tnet_ice_ctx_ctor(tsk_object_t * self, va_list * app) */ ctx->Rc = kIceDefaultRC; + ctx->dual_stack = kIceDefaultDualStack; + ctx->tie_breaker = ((tsk_time_now() << 32) ^ tsk_time_now()); ctx->is_ice_jingle = tsk_false; ctx->is_stun_enabled = kIceDefaultStunEnabled; @@ -595,6 +606,15 @@ int tnet_ice_ctx_add_server( TSK_DEBUG_ERROR("'%s' not a valid transport proto", transport_proto); return -1; } + if (self->dual_stack) { + TNET_SOCKET_TYPE_SET_IPV46(socket_type); + } + else if (self->use_ipv6) { + TNET_SOCKET_TYPE_SET_IPV6Only(socket_type); + } + else { + TNET_SOCKET_TYPE_SET_IPV4Only(socket_type); + } return _tnet_ice_ctx_server_add(self, e_proto, socket_type, server_addr, server_port, kStunSoftware, @@ -1117,7 +1137,7 @@ bail: // Started -> (GatherHostCandidates) -> (GatheringHostCandidates) static int _tnet_ice_ctx_fsm_Started_2_GatheringHostCandidates_X_GatherHostCandidates(va_list *app) { - int ret = 0; + int ret = 0, i; tnet_ice_ctx_t* self; tnet_addresses_L_t* addresses; const tsk_list_item_t *item; @@ -1129,21 +1149,42 @@ static int _tnet_ice_ctx_fsm_Started_2_GatheringHostCandidates_X_GatherHostCandi uint16_t local_pref, curr_local_pref; tnet_ip_t best_local_ip; tsk_bool_t check_best_local_ip; + int af_inets[2] = { AF_UNSPEC, AF_UNSPEC }; static const tsk_bool_t dnsserver = tsk_false; static const long if_index_any = -1; // any interface static const char* destination = "doubango.org"; self = va_arg(*app, tnet_ice_ctx_t *); - socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4; - - addresses = tnet_get_addresses((self->use_ipv6 ? AF_INET6 : AF_INET), self->unicast, self->anycast, self->multicast, dnsserver, if_index_any); - if (!addresses || TSK_LIST_IS_EMPTY(addresses)) { - TSK_DEBUG_ERROR("Failed to get addresses"); + socket_type = self->dual_stack + ? tnet_socket_type_udp_ipv46 + : (self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4); + + // Create list of addresses + if (!(addresses = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create addresses-list"); ret = -1; goto bail; - } - + } + // Set IPv4 flag + if (TNET_SOCKET_TYPE_IS_IPV4(socket_type)) { + af_inets[0] = AF_INET; + } + // Set IPv6 flag + if (TNET_SOCKET_TYPE_IS_IPV6(socket_type)) { + af_inets[1] = AF_INET6; + } + /* IPv4/IPv6 addresses */ + for (i = 0; i < sizeof(af_inets)/sizeof(af_inets[0]); ++i) { + if (af_inets[i] != AF_UNSPEC) { + tnet_addresses_L_t* list = tnet_get_addresses(af_inets[i], self->unicast, self->anycast, self->multicast, dnsserver, if_index_any); + if (list && !TSK_LIST_IS_EMPTY(list)) { + tsk_list_pushback_list(addresses, list); + } + TSK_OBJECT_SAFE_FREE(list); + } + } + check_best_local_ip = (tnet_getbestsource(destination, 5060, socket_type, &best_local_ip) == 0); curr_local_pref = local_pref = check_best_local_ip ? 0xFFFE : 0xFFFF; @@ -1163,7 +1204,7 @@ static int _tnet_ice_ctx_fsm_Started_2_GatheringHostCandidates_X_GatherHostCandi } // host candidates - ret = tnet_ice_utils_create_sockets(socket_type, + ret = tnet_ice_utils_create_sockets((address->family == AF_INET6) ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4, address->ip, &socket_rtp, self->use_rtcp ? &socket_rtcp : tsk_null); if (ret == 0) { @@ -1371,7 +1412,7 @@ static int _tnet_ice_ctx_fsm_GatheringHostCandidatesDone_2_GatheringReflexiveCan if (!(candidate = (tnet_ice_candidate_t*)item->data)) { continue; } - if (candidate->socket && tsk_strnullORempty(candidate->stun.srflx_addr)) { + if (candidate->socket && candidate->transport_e == ice_server->e_transport && tsk_strnullORempty(candidate->stun.srflx_addr)) { ret = tnet_ice_candidate_send_stun_bind_request(candidate, &ice_server->obj_server_addr, ice_server->str_username, ice_server->str_password); } } @@ -2759,8 +2800,9 @@ static int _tnet_ice_ctx_server_add(struct tnet_ice_ctx_s* self, enum tnet_ice_s const char* str_software, const char* str_username, const char* str_password) { - struct tnet_ice_server_s* ice_server; - int ret = -1; + struct tnet_ice_server_s* ice_server = tsk_null; + enum tnet_socket_type_e e_transports[2] = { tnet_socket_type_invalid, tnet_socket_type_invalid}; + int ret = -1, i; if (!self || !e_proto || !str_server_addr || !u_server_port) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; @@ -2782,12 +2824,38 @@ static int _tnet_ice_ctx_server_add(struct tnet_ice_ctx_s* self, enum tnet_ice_s ret = 0; // Not an error goto bail; } - if (!(ice_server = tnet_ice_server_create(e_proto, e_transport, str_server_addr, u_server_port, str_software, str_username, str_password))) { - TSK_DEBUG_ERROR("Failed to create ICE server(proto=%d, transport=%d, addr=%s, port=%hu)", e_proto, e_transport, str_server_addr, u_server_port); - goto bail; - } - tsk_list_push_back_data(self->servers, (void**)&ice_server); - TSK_OBJECT_SAFE_FREE(ice_server); + // Guess the supported IP versions from the server address + if (self->dual_stack) { + enum tnet_socket_type_e server_addr_type = tnet_get_type(str_server_addr, u_server_port); + if (TNET_SOCKET_TYPE_IS_IPV4(server_addr_type)) { + e_transports[0] = e_transport; + TNET_SOCKET_TYPE_SET_IPV4Only(e_transports[0]); + } + if (TNET_SOCKET_TYPE_IS_IPV6(server_addr_type)) { + e_transports[1] = e_transport; + TNET_SOCKET_TYPE_SET_IPV6Only(e_transports[1]); + } + } + else { + e_transports[0] = e_transport; + if (self->use_ipv6) { + TNET_SOCKET_TYPE_SET_IPV6Only(e_transports[0]); + } + else { + TNET_SOCKET_TYPE_SET_IPV4Only(e_transports[0]); + } + } + // Add the ICE servers + for (i = 0; i < sizeof(e_transports)/sizeof(e_transports[0]); ++i) { + if (TNET_SOCKET_TYPE_IS_VALID(e_transports[i])) { + if (!(ice_server = tnet_ice_server_create(e_proto, e_transports[i], str_server_addr, u_server_port, str_software, str_username, str_password))) { + TSK_DEBUG_ERROR("Failed to create ICE server(proto=%d, transport=%d, addr=%s, port=%hu)", e_proto, e_transport, str_server_addr, u_server_port); + goto bail; + } + tsk_list_push_back_data(self->servers, (void**)&ice_server); + TSK_OBJECT_SAFE_FREE(ice_server); + } + } ret = 0; bail: diff --git a/tinyNET/src/tnet_nat.c b/tinyNET/src/tnet_nat.c index 7e536c1a..1a9df9fd 100755 --- a/tinyNET/src/tnet_nat.c +++ b/tinyNET/src/tnet_nat.c @@ -129,6 +129,16 @@ int tnet_nat_set_server_address(struct tnet_nat_ctx_s* p_self, const char* pc_se return 0; } +int tnet_nat_get_socket_type(const struct tnet_nat_ctx_s* p_self, enum tnet_socket_type_e* type) +{ + if (!p_self || !type) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *type = p_self->socket_type; + return 0; +} + /**@ingroup tnet_nat_group * * Sets the address and port of the STUN/TURN server. diff --git a/tinyNET/src/tnet_nat.h b/tinyNET/src/tnet_nat.h index 626851d4..fd453652 100755 --- a/tinyNET/src/tnet_nat.h +++ b/tinyNET/src/tnet_nat.h @@ -30,6 +30,7 @@ struct tnet_nat_ctx_s; struct tnet_stun_binding_s; enum tnet_socket_type_e; +TINYNET_API int tnet_nat_get_socket_type(const struct tnet_nat_ctx_s* p_self, enum tnet_socket_type_e* type); TINYNET_API int tnet_nat_set_server_address(struct tnet_nat_ctx_s* p_self, const char* pc_srv_addr); TINYNET_API int tnet_nat_set_server(struct tnet_nat_ctx_s* p_self, const char* pc_srv_addr, tnet_port_t u_srv_port); TINYNET_API tnet_stun_binding_id_t tnet_nat_stun_bind(const struct tnet_nat_ctx_s* p_self, const tnet_fd_t localFD); diff --git a/tinyNET/src/tnet_socket.h b/tinyNET/src/tnet_socket.h index daceb536..fb518ac3 100755 --- a/tinyNET/src/tnet_socket.h +++ b/tinyNET/src/tnet_socket.h @@ -132,6 +132,7 @@ tnet_socket_type_t; #define TNET_SOCKET_TYPE_SET_IPV4Only(type) (type = TNET_SOCKET_TYPE_IS_IPV6(type) ? (type ^TNET_SOCKET_TYPE_IPV6)|TNET_SOCKET_TYPE_IPV4 : type) #define TNET_SOCKET_TYPE_SET_IPV6(type) (type |= TNET_SOCKET_TYPE_IPV6) #define TNET_SOCKET_TYPE_SET_IPV6Only(type) (type = TNET_SOCKET_TYPE_IS_IPV4(type) ? (type ^TNET_SOCKET_TYPE_IPV4)|TNET_SOCKET_TYPE_IPV6 : type) +#define TNET_SOCKET_TYPE_SET_IPV46(type) (type |= TNET_SOCKET_TYPE_IPV46) #define TNET_SOCKET_TYPE_SET_IPSEC(type) (type |=TNET_SOCKET_TYPE_IPSEC) diff --git a/tinyNET/src/tnet_transport.c b/tinyNET/src/tnet_transport.c index fe9810e5..4c173156 100755 --- a/tinyNET/src/tnet_transport.c +++ b/tinyNET/src/tnet_transport.c @@ -157,6 +157,7 @@ tnet_transport_t* tnet_transport_create(const char* host, tnet_port_t port, tnet if ((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))) { transport->local_ip = tsk_strdup(transport->master->ip); transport->bind_local_port = transport->master->port; + transport->type = transport->master->type; } else { TSK_DEBUG_ERROR("Failed to create master socket"); diff --git a/tinyNET/src/tnet_utils.c b/tinyNET/src/tnet_utils.c index d01facda..693f6729 100755 --- a/tinyNET/src/tnet_utils.c +++ b/tinyNET/src/tnet_utils.c @@ -837,7 +837,7 @@ int tnet_getbestsource(const char* destination, tnet_port_t port, tnet_socket_ty tnet_addresses_L_t* addresses = tsk_null; const tsk_list_item_t* item; - if (!(addresses = tnet_get_addresses(TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET, tsk_true, tsk_false, tsk_false, tsk_false, dwBestIfIndex))) { + if (!(addresses = tnet_get_addresses(destAddr.ss_family, tsk_true, tsk_false, tsk_false, tsk_false, dwBestIfIndex))) { ret = -2; TSK_DEBUG_ERROR("Failed to retrieve addresses."); goto bail; @@ -1053,34 +1053,50 @@ int tnet_getpeername(tnet_fd_t fd, struct sockaddr_storage *result) return -1; } -/**@ingroup tnet_utils_group - * Retrieves the socket type of a File Descriptor. - * @param fd The File descriptor for which to retrive the type. - * @retval @ref tnet_socket_type_t. - */ -tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd) +tnet_socket_type_t tnet_get_type(const char* host, tnet_port_t port) { - tnet_socket_type_t type = tnet_socket_type_invalid; + tnet_socket_type_t ret = TNET_SOCKET_TYPE_UDP; + if (host) { + int status; + tsk_istr_t srv; + struct addrinfo *result = tsk_null; + struct addrinfo hints; + const struct addrinfo *ptr = tsk_null; - /*if(fd >0) - { - struct sockaddr_storage ss; - if(!tnet_get_sockaddr(fd, &ss)) - { - if(((struct sockaddr *)&ss)->sa_family == AF_INET) - { - TNET_SOCKET_TYPE_AS_IPV4(type); - } - else if(((struct sockaddr *)&ss)->sa_family == AF_INET6) - { - TNET_SOCKET_TYPE_AS_IPV6(type); - } - } - }*/ + /* set the port: used as the default service */ + if (port) { + tsk_itoa(port, &srv); + } + else { + memset(srv, '\0', sizeof(srv)); + } - return type; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + if ((status = tnet_getaddrinfo(host, srv, &hints, &result))) { + TNET_PRINT_LAST_ERROR("getaddrinfo(%s:%d) failed", host, port); + goto done; + } + + for (ptr = result; ptr; ptr = ptr->ai_next) { + if (ptr->ai_family == AF_INET) { + TNET_SOCKET_TYPE_SET_IPV4(ret); + } + else if (ptr->ai_family == AF_INET6) { + TNET_SOCKET_TYPE_SET_IPV6(ret); + } + } +done: + tnet_freeaddrinfo(result); + } + + return ret; } + /**@ingroup tnet_utils_group * Gets the IP family of the @a host (e.g. "google.com" or "192.168.16.104" or "::1"). * If the @a host is FQDN associated with both IPv4 and IPv6 then the result is unpredictable. @@ -1127,6 +1143,12 @@ done: return ret; } +tsk_bool_t tnet_is_ipv6(const char* host, tnet_port_t port) +{ + tnet_socket_type_t type = tnet_get_type(host, port); + return TNET_SOCKET_TYPE_IS_IPV6(type); +} + /**@ingroup tnet_utils_group * Gets the IP address and the Port of a @b sockaddr object. * @param addr [in] A pointer to @b sockaddr structure for which to retrieve the IP address and port. diff --git a/tinyNET/src/tnet_utils.h b/tinyNET/src/tnet_utils.h index a3abbc93..9ed67650 100755 --- a/tinyNET/src/tnet_utils.h +++ b/tinyNET/src/tnet_utils.h @@ -93,8 +93,9 @@ TINYNET_API int tnet_getaddrinfo(const char *node, const char *service, const st TINYNET_API void tnet_freeaddrinfo(struct addrinfo *ai); TINYNET_API int tnet_getsockname(tnet_fd_t fd, struct sockaddr_storage *result); TINYNET_API int tnet_getpeername(tnet_fd_t fd, struct sockaddr_storage *result); -TINYNET_API tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd); TINYNET_API tnet_family_t tnet_get_family(const char* host, tnet_port_t port); +TINYNET_API tnet_socket_type_t tnet_get_type(const char* host, tnet_port_t port); +TINYNET_API tsk_bool_t tnet_is_ipv6(const char* host, tnet_port_t port); TINYNET_API int tnet_get_ip_n_port(tnet_fd_t fd, tsk_bool_t getlocal, tnet_ip_t *ip, tnet_port_t *port); TINYNET_API int tnet_get_sockip_n_port(const struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port); TINYNET_API int tnet_get_peerip_n_port(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port); diff --git a/tinyRTP/include/tinyrtp/trtp_manager.h b/tinyRTP/include/tinyrtp/trtp_manager.h index e409c7b1..61d9fcba 100755 --- a/tinyRTP/include/tinyrtp/trtp_manager.h +++ b/tinyRTP/include/tinyrtp/trtp_manager.h @@ -90,8 +90,11 @@ typedef struct trtp_manager_s { tnet_port_t remote_port; struct sockaddr_storage remote_addr; - char* public_ip; - tnet_port_t public_port; + struct { + char* ip; + tnet_port_t port; + tnet_socket_type_t type; + } public_addr; struct { uint32_t local; @@ -117,8 +120,11 @@ typedef struct trtp_manager_s { struct sockaddr_storage remote_addr; tnet_socket_t* local_socket; - char* public_ip; - tnet_port_t public_port; + struct { + char* ip; + tnet_port_t port; + tnet_socket_type_t type; + } public_addr; struct { const void* usrdata; diff --git a/tinyRTP/src/trtp_manager.c b/tinyRTP/src/trtp_manager.c index 16aeab19..d1fcff1b 100755 --- a/tinyRTP/src/trtp_manager.c +++ b/tinyRTP/src/trtp_manager.c @@ -833,8 +833,8 @@ static int _trtp_manager_ice_init(trtp_manager_t* self) if (candidate_answer_dest) { // could be "null" if remote peer is ICE-lite tsk_strupdate(&self->rtp.remote_ip, candidate_answer_dest->connection_addr); self->rtp.remote_port = candidate_answer_dest->port; - tsk_strupdate(&self->rtp.public_ip, candidate_offer->connection_addr); - self->rtp.public_port = candidate_offer->port; + tsk_strupdate(&self->rtp.public_addr.ip, candidate_offer->connection_addr); + self->rtp.public_addr.port = candidate_offer->port; } // get rtp nominated symetric candidates @@ -845,8 +845,8 @@ static int _trtp_manager_ice_init(trtp_manager_t* self) // set rtp local and remote IPs and ports tsk_strupdate(&self->rtcp.remote_ip, candidate_answer_dest->connection_addr); self->rtcp.remote_port = candidate_answer_dest->port; - tsk_strupdate(&self->rtcp.public_ip, candidate_offer->connection_addr); - self->rtcp.public_port = candidate_offer->port; + tsk_strupdate(&self->rtcp.public_addr.ip, candidate_offer->connection_addr); + self->rtcp.public_addr.port = candidate_offer->port; TSK_OBJECT_SAFE_FREE(self->rtcp.local_socket); // Get RTCP socket if (self->is_ice_turn_active && candidate_offer->turn.ss) { @@ -918,6 +918,7 @@ int trtp_manager_prepare(trtp_manager_t* self) { const char *rtp_local_ip = tsk_null, *rtcp_local_ip = tsk_null; tnet_port_t rtp_local_port = 0, rtcp_local_port = 0; + tnet_socket_type_t socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4; if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); @@ -939,7 +940,12 @@ int trtp_manager_prepare(trtp_manager_t* self) #define __retry_count_max 5 #define __retry_count_max_minus1 (__retry_count_max - 1) uint8_t retry_count = __retry_count_max; - tnet_socket_type_t socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4; + tnet_socket_type_t socket_type = tnet_socket_type_invalid; + + // If local IP is defined then check its address family + if (!tsk_strempty(self->local_ip)) { + socket_type = tnet_get_type(self->local_ip, rtp_local_port); // IP @ always returns IPv4Only or IPv6Only + } /* Creates local rtp and rtcp sockets */ while(retry_count--) { @@ -949,8 +955,8 @@ int trtp_manager_prepare(trtp_manager_t* self) tnet_port_t local_port = 6060; #else // first check => try to use port from latest active session if exist - tnet_port_t local_port = (retry_count == __retry_count_max_minus1 && (self->port_range.start <= self->rtp.public_port && self->rtp.public_port <= self->port_range.stop)) - ? self->rtp.public_port + tnet_port_t local_port = (retry_count == __retry_count_max_minus1 && (self->port_range.start <= self->rtp.public_addr.port && self->rtp.public_addr.port <= self->port_range.stop)) + ? self->rtp.public_addr.port : (((rand() ^ ++counter) % (self->port_range.stop - self->port_range.start)) + self->port_range.start); #endif local_port = (local_port & 0xFFFE); /* turn to even number */ @@ -987,11 +993,13 @@ int trtp_manager_prepare(trtp_manager_t* self) } }// end-of-else(!ice) - tsk_strupdate(&self->rtp.public_ip, rtp_local_ip); - self->rtp.public_port = rtp_local_port; + tsk_strupdate(&self->rtp.public_addr.ip, rtp_local_ip); + self->rtp.public_addr.port = rtp_local_port; + self->rtp.public_addr.type = socket_type; - tsk_strupdate(&self->rtcp.public_ip, rtcp_local_ip); - self->rtcp.public_port = rtcp_local_port; + tsk_strupdate(&self->rtcp.public_addr.ip, rtcp_local_ip); + self->rtcp.public_addr.port = rtcp_local_port; + self->rtcp.public_addr.type = socket_type; if(self->transport) { /* set callback function */ @@ -1225,15 +1233,15 @@ int trtp_manager_set_natt_ctx(trtp_manager_t* self, struct tnet_nat_ctx_s* natt_ tnet_port_t public_port = 0; // get RTP public IP and Port if(!tnet_transport_get_public_ip_n_port(self->transport, self->transport->master->fd, &public_ip, &public_port)) { - tsk_strupdate(&self->rtp.public_ip, public_ip); - self->rtp.public_port = public_port; + tsk_strupdate(&self->rtp.public_addr.ip, public_ip); + self->rtp.public_addr.port = public_port; } // get RTCP public IP and Port memset(public_ip, 0, sizeof(public_ip)); public_port = 0; if(self->rtcp.local_socket && !tnet_transport_get_public_ip_n_port(self->transport, self->rtcp.local_socket->fd, &public_ip, &public_port)) { - tsk_strupdate(&self->rtcp.public_ip, public_ip); - self->rtcp.public_port = public_port; + tsk_strupdate(&self->rtcp.public_addr.ip, public_ip); + self->rtcp.public_addr.port = public_port; } // re-enable sockets to be able to receive STUN packets #if 0 @@ -1826,8 +1834,8 @@ int trtp_manager_stop(trtp_manager_t* self) // Free RTCP info to make sure these values will be updated in next start() TSK_OBJECT_SAFE_FREE(self->rtcp.local_socket); TSK_OBJECT_SAFE_FREE(self->rtcp.session); - self->rtcp.public_port = self->rtcp.remote_port = 0; - TSK_FREE(self->rtcp.public_ip); + self->rtcp.public_addr.port = self->rtcp.remote_port = 0; + TSK_FREE(self->rtcp.public_addr.ip); TSK_FREE(self->rtcp.remote_ip); // reset default values @@ -1914,13 +1922,13 @@ static tsk_object_t* trtp_manager_dtor(tsk_object_t * self) /* rtp */ TSK_FREE(manager->rtp.remote_ip); - TSK_FREE(manager->rtp.public_ip); + TSK_FREE(manager->rtp.public_addr.ip); TSK_FREE(manager->rtp.serial_buffer.ptr); /* rtcp */ TSK_OBJECT_SAFE_FREE(manager->rtcp.session); TSK_FREE(manager->rtcp.remote_ip); - TSK_FREE(manager->rtcp.public_ip); + TSK_FREE(manager->rtcp.public_addr.ip); TSK_FREE(manager->rtcp.cname); TSK_OBJECT_SAFE_FREE(manager->rtcp.local_socket); diff --git a/tinySIP/src/transports/tsip_transport.c b/tinySIP/src/transports/tsip_transport.c index e9d2473c..feec0dfc 100755 --- a/tinySIP/src/transports/tsip_transport.c +++ b/tinySIP/src/transports/tsip_transport.c @@ -921,8 +921,8 @@ int tsip_transport_init(tsip_transport_t* self, tnet_socket_type_t type, const s } self->stack = stack; - self->type = type; self->net_transport = tnet_transport_create(host, port, type, description); + self->type = tnet_transport_get_type(self->net_transport); // Type could be "ipv46" or any fancy protocol. Update it using the transport master self->scheme = "sip"; diff --git a/tinySIP/src/transports/tsip_transport_layer.c b/tinySIP/src/transports/tsip_transport_layer.c index fc01c0ea..562f3951 100755 --- a/tinySIP/src/transports/tsip_transport_layer.c +++ b/tinySIP/src/transports/tsip_transport_layer.c @@ -865,7 +865,7 @@ clean_routes: transport = curr; break; } - if((curr->type & destNetType) == destNetType) { + if((curr->type & destNetType) == destNetType || (curr->type & destNetType) == curr->type) { transport_closest1 = curr; } if(self->stack->network.transport_idx_default>= 0 && curr->type == self->stack->network.transport_types[self->stack->network.transport_idx_default]) {