diff --git a/CMake/Dependencies/libwebsockets-CMakeLists.txt b/CMake/Dependencies/libwebsockets-CMakeLists.txt index ebb4b390b5..01b61dbd5c 100644 --- a/CMake/Dependencies/libwebsockets-CMakeLists.txt +++ b/CMake/Dependencies/libwebsockets-CMakeLists.txt @@ -64,6 +64,7 @@ ExternalProject_Add(project_libwebsockets -DLWS_EXT_PTHREAD_LIBRARIES=${LWS_EXT_PTHREAD_LIBRARIES} -DLWS_OPENSSL_INCLUDE_DIRS=${LWS_OPENSSL_INCLUDE_DIRS} -DLWS_OPENSSL_LIBRARIES=${LWS_OPENSSL_LIBRARIES} + -DLWS_IPV6=1 BUILD_ALWAYS TRUE TEST_COMMAND "" ) diff --git a/src/source/Ice/IceAgent.c b/src/source/Ice/IceAgent.c index a9d3a066a8..0628bf1602 100644 --- a/src/source/Ice/IceAgent.c +++ b/src/source/Ice/IceAgent.c @@ -116,7 +116,7 @@ STATUS createIceAgent(PCHAR username, PCHAR password, PIceAgentCallbacks pIceAge if (doStatCalcs) { CHK(NULL != (pIceAgent->pRtcIceServerDiagnostics[i] = (PRtcIceServerDiagnostics) MEMCALLOC(1, SIZEOF(RtcIceServerDiagnostics))), STATUS_NOT_ENOUGH_MEMORY); - pIceAgent->pRtcIceServerDiagnostics[i]->port = (INT32) getInt16(pIceAgent->iceServers[i].ipAddress.port); + pIceAgent->pRtcIceServerDiagnostics[i]->port = (INT32) getInt16(pIceAgent->iceServers[i].ipAddresses.ipv4Address.port); switch (pIceAgent->iceServers[pIceAgent->iceServersCount].transport) { case KVS_SOCKET_PROTOCOL_UDP: STRCPY(pIceAgent->pRtcIceServerDiagnostics[i]->protocol, ICE_TRANSPORT_TYPE_UDP); @@ -1458,14 +1458,34 @@ STATUS iceAgentSendSrflxCandidateRequest(PIceAgent pIceAgent) switch (pCandidate->iceCandidateType) { case ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE: pIceServer = &(pIceAgent->iceServers[pCandidate->iceServerIndex]); - if (pIceServer->ipAddress.family == pCandidate->ipAddress.family) { + if (pIceServer->ipAddresses.ipv4Address.family == pCandidate->ipAddress.family) { // update transactionId CHK_STATUS( iceUtilsGenerateTransactionId(pBindingRequest->header.transactionId, ARRAY_SIZE(pBindingRequest->header.transactionId))); transactionIdStoreInsert(pIceAgent->pStunBindingRequestTransactionIdStore, pBindingRequest->header.transactionId); checkSum = COMPUTE_CRC32(pBindingRequest->header.transactionId, ARRAY_SIZE(pBindingRequest->header.transactionId)); - CHK_STATUS(iceAgentSendStunPacket(pBindingRequest, NULL, 0, pIceAgent, pCandidate, &pIceServer->ipAddress)); + + DLOGD("Sending STUN binding request to IPv4 STUN server: %u:%u", pIceServer->ipAddresses.ipv4Address.address, + pIceServer->ipAddresses.ipv4Address.port); + + CHK_STATUS(iceAgentSendStunPacket(pBindingRequest, NULL, 0, pIceAgent, pCandidate, &pIceServer->ipAddresses.ipv4Address)); + if (pIceAgent->pRtcIceServerDiagnostics[pCandidate->iceServerIndex] != NULL) { + pIceAgent->pRtcIceServerDiagnostics[pCandidate->iceServerIndex]->totalRequestsSent++; + CHK_STATUS(hashTableUpsert(pIceAgent->requestTimestampDiagnostics, checkSum, GETTIME())); + } + } else if (pIceServer->ipAddresses.ipv6Address.family == pCandidate->ipAddress.family) { + // update transactionId + CHK_STATUS( + iceUtilsGenerateTransactionId(pBindingRequest->header.transactionId, ARRAY_SIZE(pBindingRequest->header.transactionId))); + + transactionIdStoreInsert(pIceAgent->pStunBindingRequestTransactionIdStore, pBindingRequest->header.transactionId); + checkSum = COMPUTE_CRC32(pBindingRequest->header.transactionId, ARRAY_SIZE(pBindingRequest->header.transactionId)); + + DLOGD("Sending STUN binding request to IPv6 STUN server: %u:%u", pIceServer->ipAddresses.ipv6Address.address, + pIceServer->ipAddresses.ipv6Address.port); + + CHK_STATUS(iceAgentSendStunPacket(pBindingRequest, NULL, 0, pIceAgent, pCandidate, &pIceServer->ipAddresses.ipv6Address)); if (pIceAgent->pRtcIceServerDiagnostics[pCandidate->iceServerIndex] != NULL) { pIceAgent->pRtcIceServerDiagnostics[pCandidate->iceServerIndex]->totalRequestsSent++; CHK_STATUS(hashTableUpsert(pIceAgent->requestTimestampDiagnostics, checkSum, GETTIME())); @@ -1762,7 +1782,9 @@ STATUS iceAgentInitSrflxCandidate(PIceAgent pIceAgent) if (pCandidate->iceCandidateType == ICE_CANDIDATE_TYPE_HOST) { for (j = 0; j < pIceAgent->iceServersCount; j++) { pIceServer = &pIceAgent->iceServers[j]; - if (!pIceServer->isTurn && pIceServer->ipAddress.family == pCandidate->ipAddress.family) { + if (!pIceServer->isTurn && + (pIceServer->ipAddresses.ipv4Address.family == pCandidate->ipAddress.family || + pIceServer->ipAddresses.ipv6Address.family == pCandidate->ipAddress.family)) { CHK((pNewCandidate = (PIceCandidate) MEMCALLOC(1, SIZEOF(IceCandidate))) != NULL, STATUS_NOT_ENOUGH_MEMORY); generateJSONSafeString(pNewCandidate->id, ARRAY_SIZE(pNewCandidate->id)); pNewCandidate->isRemote = FALSE; @@ -1792,20 +1814,20 @@ STATUS iceAgentInitSrflxCandidate(PIceAgent pIceAgent) // Create and start the connection listener outside of the locks for (j = 0; j < srflxCount; j++) { pCandidate = srflxCandidates[j]; - // TODO: IPv6 STUN is not supported at the moment. Remove this check if the support is added in the future if (IS_IPV4_ADDR(&(pCandidate->ipAddress))) { - // open up a new socket at host candidate's ip address for server reflex candidate. - // the new port will be stored in pNewCandidate->ipAddress.port. And the Ip address will later be updated - // with the correct ip address once the STUN response is received. - CHK_STATUS(createSocketConnection(pCandidate->ipAddress.family, KVS_SOCKET_PROTOCOL_UDP, &pCandidate->ipAddress, NULL, (UINT64) pIceAgent, - incomingDataHandler, pIceAgent->kvsRtcConfiguration.sendBufSize, &pCandidate->pSocketConnection)); - ATOMIC_STORE_BOOL(&pCandidate->pSocketConnection->receiveData, TRUE); - // connectionListener will free the pSocketConnection at the end. - CHK_STATUS(connectionListenerAddConnection(pIceAgent->pConnectionListener, pCandidate->pSocketConnection)); - + DLOGI("Initializing an IPv4 STUN candidate..."); } else { - DLOGW("IPv6 candidate detected, ignoring...."); + DLOGI("Initializing an IPv6 STUN candidate..."); } + + // open up a new socket at host candidate's ip address for server reflex candidate. + // the new port will be stored in pNewCandidate->ipAddress.port. And the Ip address will later be updated + // with the correct ip address once the STUN response is received. + CHK_STATUS(createSocketConnection(pCandidate->ipAddress.family, KVS_SOCKET_PROTOCOL_UDP, &pCandidate->ipAddress, NULL, (UINT64) pIceAgent, + incomingDataHandler, pIceAgent->kvsRtcConfiguration.sendBufSize, &pCandidate->pSocketConnection)); + ATOMIC_STORE_BOOL(&pCandidate->pSocketConnection->receiveData, TRUE); + // connectionListener will free the pSocketConnection at the end. + CHK_STATUS(connectionListenerAddConnection(pIceAgent->pConnectionListener, pCandidate->pSocketConnection)); } CleanUp: @@ -1898,7 +1920,7 @@ STATUS iceAgentInitRelayCandidate(PIceAgent pIceAgent, UINT32 iceServerIndex, KV // open up a new socket without binding to any host address. The candidate Ip address will later be updated // with the correct relay ip address once the Allocation success response is received. Relay candidate's socket is managed // by TurnConnection struct. - CHK_STATUS(createSocketConnection(KVS_IP_FAMILY_TYPE_IPV4, protocol, NULL, &pIceAgent->iceServers[iceServerIndex].ipAddress, + CHK_STATUS(createSocketConnection(KVS_IP_FAMILY_TYPE_IPV4, protocol, NULL, &pIceAgent->iceServers[iceServerIndex].ipAddresses.ipv4Address, (UINT64) pNewCandidate, incomingRelayedDataHandler, pIceAgent->kvsRtcConfiguration.sendBufSize, &pNewCandidate->pSocketConnection)); // connectionListener will free the pSocketConnection at the end. diff --git a/src/source/Ice/IceUtils.c b/src/source/Ice/IceUtils.c index 444d2d025a..9209639aec 100644 --- a/src/source/Ice/IceUtils.c +++ b/src/source/Ice/IceUtils.c @@ -168,16 +168,18 @@ STATUS iceUtilsSendStunPacket(PStunPacket pStunPacket, PBYTE password, UINT32 pa UINT32 stunPacketSize = STUN_PACKET_ALLOCATION_SIZE; BYTE stunPacketBuffer[STUN_PACKET_ALLOCATION_SIZE]; + CHAR ipAddrStr[KVS_IP_ADDRESS_STRING_BUFFER_LEN]; + + CHK_STATUS(getIpAddrStr(pDest, ipAddrStr, ARRAY_SIZE(ipAddrStr))); + CHK_STATUS(iceUtilsPackageStunPacket(pStunPacket, password, passwordLen, stunPacketBuffer, &stunPacketSize)); CHK(pDest != NULL, STATUS_NULL_ARG); switch (pStunPacket->header.stunMessageType) { case STUN_PACKET_TYPE_BINDING_REQUEST: - DLOGD("Sending BINDING_REQUEST to ip:%u.%u.%u.%u, port:%u", pDest->address[0], pDest->address[1], pDest->address[2], pDest->address[3], - (UINT16) getInt16(pDest->port)); + DLOGD("Sending BINDING_REQUEST to ip:%s, port:%u", ipAddrStr, (UINT16) getInt16(pDest->port)); break; case STUN_PACKET_TYPE_BINDING_RESPONSE_SUCCESS: - DLOGD("Sending BINDING_RESPONSE_SUCCESS to ip:%u.%u.%u.%u, port:%u", pDest->address[0], pDest->address[1], pDest->address[2], - pDest->address[3], (UINT16) getInt16(pDest->port)); + DLOGD("Sending BINDING_RESPONSE_SUCCESS to ip:%s, port:%u", ipAddrStr, (UINT16) getInt16(pDest->port)); break; default: break; @@ -221,7 +223,8 @@ STATUS parseIceServer(PIceServer pIceServer, PCHAR url, PCHAR username, PCHAR cr STATUS retStatus = STATUS_SUCCESS; PCHAR separator = NULL, urlNoPrefix = NULL, paramStart = NULL; UINT32 port = ICE_STUN_DEFAULT_PORT; - CHAR addressResolved[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; + CHAR addressResolvedIPv4[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; + CHAR addressResolvedIPv6[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; // username and credential is only mandatory for turn server CHK(url != NULL && pIceServer != NULL, STATUS_NULL_ARG); @@ -264,7 +267,7 @@ STATUS parseIceServer(PIceServer pIceServer, PCHAR url, PCHAR username, PCHAR cr } if (pIceServer->setIpFn != NULL) { - retStatus = pIceServer->setIpFn(0, pIceServer->url, &pIceServer->ipAddress); + retStatus = pIceServer->setIpFn(0, pIceServer->url, &pIceServer->ipAddresses); } // Adding a NULL_ARG check specifically to cover for the case where early STUN @@ -274,12 +277,22 @@ STATUS parseIceServer(PIceServer pIceServer, PCHAR url, PCHAR username, PCHAR cr // Reset the retStatus to ensure the appropriate status code is returned from // getIpWithHostName retStatus = STATUS_SUCCESS; - CHK_STATUS(getIpWithHostName(pIceServer->url, &pIceServer->ipAddress)); + CHK_STATUS(getIpWithHostName(pIceServer->url, &pIceServer->ipAddresses)); } - pIceServer->ipAddress.port = (UINT16) getInt16((INT16) port); - getIpAddrStr(&pIceServer->ipAddress, addressResolved, ARRAY_SIZE(addressResolved)); - DLOGP("ICE Server address for %s: %s", pIceServer->url, addressResolved); + if (pIceServer->ipAddresses.ipv4Address.family != KVS_IP_FAMILY_TYPE_NOT_SET) { + pIceServer->ipAddresses.ipv4Address.port = (UINT16) getInt16((INT16) port); + CHK_STATUS(getIpAddrStr(&pIceServer->ipAddresses.ipv4Address, addressResolvedIPv4, ARRAY_SIZE(addressResolvedIPv4))); + DLOGP("Resolved ICE Server IPv4 address for %s: %s", pIceServer->url, addressResolvedIPv4); + DLOGP("...with port: %u", pIceServer->ipAddresses.ipv4Address.port); + } + + if (pIceServer->ipAddresses.ipv6Address.family != KVS_IP_FAMILY_TYPE_NOT_SET) { + pIceServer->ipAddresses.ipv6Address.port = (UINT16) getInt16((INT16) port); + CHK_STATUS(getIpAddrStr(&pIceServer->ipAddresses.ipv6Address, addressResolvedIPv6, ARRAY_SIZE(addressResolvedIPv6))); + DLOGP("Resolved ICE Server IPv6 address for %s: %s", pIceServer->url, addressResolvedIPv6); + DLOGP("...with port: %u", pIceServer->ipAddresses.ipv6Address.port); + } CleanUp: diff --git a/src/source/Ice/IceUtils.h b/src/source/Ice/IceUtils.h index c03b1f1d19..a9a18bfc1f 100644 --- a/src/source/Ice/IceUtils.h +++ b/src/source/Ice/IceUtils.h @@ -54,7 +54,7 @@ typedef struct { BOOL isTurn; BOOL isSecure; CHAR url[MAX_ICE_CONFIG_URI_LEN + 1]; - KvsIpAddress ipAddress; + DualKvsIpAddresses ipAddresses; CHAR username[MAX_ICE_CONFIG_USER_NAME_LEN + 1]; CHAR credential[MAX_ICE_CONFIG_CREDENTIAL_LEN + 1]; KVS_SOCKET_PROTOCOL transport; diff --git a/src/source/Ice/NatBehaviorDiscovery.c b/src/source/Ice/NatBehaviorDiscovery.c index a0b70e4721..b48d8dee3a 100644 --- a/src/source/Ice/NatBehaviorDiscovery.c +++ b/src/source/Ice/NatBehaviorDiscovery.c @@ -123,7 +123,7 @@ STATUS discoverNatMappingBehavior(PIceServer pStunServer, PNatTestData data, PSo /* execute test I */ DLOGD("Running mapping behavior test I. Send binding request"); - CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddress, pSocketConnection, testIndex++, data, &bindingResponse)); + CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddresses.ipv4Address, pSocketConnection, testIndex++, data, &bindingResponse)); if (bindingResponse == NULL) { natMappingBehavior = NAT_BEHAVIOR_NO_UDP_CONNECTIVITY; @@ -144,7 +144,7 @@ STATUS discoverNatMappingBehavior(PIceServer pStunServer, PNatTestData data, PSo /* execute test II */ DLOGD("Running mapping behavior test II. Send binding request to alternate address but primary port"); testDestAddress = otherAddress; - testDestAddress.port = pStunServer->ipAddress.port; + testDestAddress.port = pStunServer->ipAddresses.ipv4Address.port; CHK_STATUS(executeNatTest(bindingRequest, &testDestAddress, pSocketConnection, testIndex++, data, &bindingResponse)); CHK_ERR(bindingResponse != NULL, retStatus, "Expect to receive binding response"); @@ -208,7 +208,7 @@ STATUS discoverNatFilteringBehavior(PIceServer pStunServer, PNatTestData data, P /* execute test I */ DLOGD("Running filtering behavior test I. Send binding request"); - CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddress, pSocketConnection, testIndex++, data, &bindingResponse)); + CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddresses.ipv4Address, pSocketConnection, testIndex++, data, &bindingResponse)); if (bindingResponse == NULL) { natFilteringBehavior = NAT_BEHAVIOR_NO_UDP_CONNECTIVITY; CHK(FALSE, retStatus); @@ -219,7 +219,7 @@ STATUS discoverNatFilteringBehavior(PIceServer pStunServer, PNatTestData data, P CHK_STATUS(appendStunChangeRequestAttribute(bindingRequest, STUN_ATTRIBUTE_CHANGE_REQUEST_FLAG_CHANGE_IP | STUN_ATTRIBUTE_CHANGE_REQUEST_FLAG_CHANGE_PORT)); - CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddress, pSocketConnection, testIndex++, data, &bindingResponse)); + CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddresses.ipv4Address, pSocketConnection, testIndex++, data, &bindingResponse)); if (bindingResponse != NULL) { natFilteringBehavior = NAT_BEHAVIOR_ENDPOINT_INDEPENDENT; CHK(FALSE, retStatus); @@ -230,7 +230,7 @@ STATUS discoverNatFilteringBehavior(PIceServer pStunServer, PNatTestData data, P CHK_STATUS(getStunAttribute(bindingRequest, STUN_ATTRIBUTE_TYPE_CHANGE_REQUEST, (PStunAttributeHeader*) &pStunAttributeChangeRequest)); pStunAttributeChangeRequest->changeFlag = STUN_ATTRIBUTE_CHANGE_REQUEST_FLAG_CHANGE_PORT; - CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddress, pSocketConnection, testIndex++, data, &bindingResponse)); + CHK_STATUS(executeNatTest(bindingRequest, &pStunServer->ipAddresses.ipv4Address, pSocketConnection, testIndex++, data, &bindingResponse)); if (bindingResponse != NULL) { natFilteringBehavior = NAT_BEHAVIOR_ADDRESS_DEPENDENT; @@ -291,15 +291,15 @@ STATUS discoverNatBehavior(PCHAR stunServer, NAT_BEHAVIOR* pNatMappingBehavior, /* use the first usable local interface to create socket */ for (i = 0; i < localNetworkInterfaceCount; ++i) { - if (localNetworkInterfaces[i].family == iceServerStun.ipAddress.family) { + if (localNetworkInterfaces[i].family == iceServerStun.ipAddresses.ipv4Address.family) { pSelectedLocalInterface = &localNetworkInterfaces[i]; break; } } CHK_WARN(pSelectedLocalInterface != NULL, retStatus, "No usable local interface"); - CHK_STATUS(createSocketConnection(iceServerStun.ipAddress.family, KVS_SOCKET_PROTOCOL_UDP, pSelectedLocalInterface, NULL, (UINT64) &customData, - natTestIncomingDataHandler, 0, &pSocketConnection)); + CHK_STATUS(createSocketConnection(iceServerStun.ipAddresses.ipv4Address.family, KVS_SOCKET_PROTOCOL_UDP, pSelectedLocalInterface, NULL, + (UINT64) &customData, natTestIncomingDataHandler, 0, &pSocketConnection)); ATOMIC_STORE_BOOL(&pSocketConnection->receiveData, TRUE); CHK_STATUS(createConnectionListener(&pConnectionListener)); @@ -322,8 +322,8 @@ STATUS discoverNatBehavior(PCHAR stunServer, NAT_BEHAVIOR* pNatMappingBehavior, CHK_STATUS(connectionListenerRemoveAllConnection(pConnectionListener)); freeSocketConnection(&pSocketConnection); - CHK_STATUS(createSocketConnection(iceServerStun.ipAddress.family, KVS_SOCKET_PROTOCOL_UDP, pSelectedLocalInterface, NULL, (UINT64) &customData, - natTestIncomingDataHandler, 0, &pSocketConnection)); + CHK_STATUS(createSocketConnection(iceServerStun.ipAddresses.ipv4Address.family, KVS_SOCKET_PROTOCOL_UDP, pSelectedLocalInterface, NULL, + (UINT64) &customData, natTestIncomingDataHandler, 0, &pSocketConnection)); ATOMIC_STORE_BOOL(&pSocketConnection->receiveData, TRUE); CHK_STATUS(connectionListenerAddConnection(pConnectionListener, pSocketConnection)); diff --git a/src/source/Ice/Network.c b/src/source/Ice/Network.c index b5568bb97b..d900a9245f 100644 --- a/src/source/Ice/Network.c +++ b/src/source/Ice/Network.c @@ -393,17 +393,20 @@ STATUS getIpAddrFromDnsHostname(PCHAR hostname, PCHAR address, UINT16 lengthSrc, return retStatus; } -STATUS getIpWithHostName(PCHAR hostname, PKvsIpAddress destIp) +STATUS getIpWithHostName(PCHAR hostname, PDualKvsIpAddresses destIps) { STATUS retStatus = STATUS_SUCCESS; INT32 errCode; UINT16 hostnameLen, addrLen; PCHAR errStr; struct addrinfo *res, *rp; - BOOL resolved = FALSE; + BOOL ipv4Resolved = FALSE; + BOOL ipv6Resolved = FALSE; struct sockaddr_in* ipv4Addr; struct sockaddr_in6* ipv6Addr; struct in_addr inaddr; + CHAR ipv4AddrStr[KVS_IP_ADDRESS_STRING_BUFFER_LEN]; + CHAR ipv6AddrStr[KVS_IP_ADDRESS_STRING_BUFFER_LEN]; CHAR addr[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; @@ -430,27 +433,38 @@ STATUS getIpWithHostName(PCHAR hostname, PKvsIpAddress destIp) errStr = errCode == EAI_SYSTEM ? (strerror(errno)) : ((PCHAR) gai_strerror(errCode)); CHK_ERR(FALSE, STATUS_RESOLVE_HOSTNAME_FAILED, "getaddrinfo() with errno %s", errStr); } - for (rp = res; rp != NULL && !resolved; rp = rp->ai_next) { + for (rp = res; rp != NULL && !(ipv4Resolved && ipv6Resolved); rp = rp->ai_next) { if (rp->ai_family == AF_INET) { ipv4Addr = (struct sockaddr_in*) rp->ai_addr; - destIp->family = KVS_IP_FAMILY_TYPE_IPV4; - MEMCPY(destIp->address, &ipv4Addr->sin_addr, IPV4_ADDRESS_LENGTH); - resolved = TRUE; + destIps->ipv4Address.family = KVS_IP_FAMILY_TYPE_IPV4; + MEMCPY(destIps->ipv4Address.address, &ipv4Addr->sin_addr, IPV4_ADDRESS_LENGTH); + + CHK_STATUS(getIpAddrStr(&(destIps->ipv4Address), ipv4AddrStr, ARRAY_SIZE(ipv4AddrStr))); + DLOGD("Found an IPv4 ICE server addresss: %s", ipv4AddrStr); + + ipv4Resolved = TRUE; + } else if (rp->ai_family == AF_INET6) { ipv6Addr = (struct sockaddr_in6*) rp->ai_addr; - destIp->family = KVS_IP_FAMILY_TYPE_IPV6; - MEMCPY(destIp->address, &ipv6Addr->sin6_addr, IPV6_ADDRESS_LENGTH); - resolved = TRUE; + destIps->ipv6Address.family = KVS_IP_FAMILY_TYPE_IPV6; + MEMCPY(destIps->ipv6Address.address, &ipv6Addr->sin6_addr, IPV6_ADDRESS_LENGTH); + + CHK_STATUS(getIpAddrStr(&(destIps->ipv6Address), ipv6AddrStr, ARRAY_SIZE(ipv6AddrStr))); + DLOGD("Found an IPv6 ICE server addresss: %s", ipv6AddrStr); + + ipv6Resolved = TRUE; + + } else { + DLOGD("Found an invalid ICE server addresss family type - must be IPv4 or IPv6."); } } freeaddrinfo(res); - CHK_ERR(resolved, STATUS_HOSTNAME_NOT_FOUND, "Could not find network address of %s", hostname); - } - - else { + CHK_ERR(ipv4Resolved || ipv6Resolved, STATUS_HOSTNAME_NOT_FOUND, "Could not find network address of %s", hostname); + } else { + // TODO: The below is for TURN case, will need to do this based on IP family too... inet_pton(AF_INET, addr, &inaddr); - destIp->family = KVS_IP_FAMILY_TYPE_IPV4; - MEMCPY(destIp->address, &inaddr, IPV4_ADDRESS_LENGTH); + destIps->ipv4Address.family = KVS_IP_FAMILY_TYPE_IPV4; + MEMCPY(destIps->ipv4Address.address, &inaddr, IPV4_ADDRESS_LENGTH); } CleanUp: diff --git a/src/source/Ice/Network.h b/src/source/Ice/Network.h index 80fb745160..9a05e7a251 100644 --- a/src/source/Ice/Network.h +++ b/src/source/Ice/Network.h @@ -122,7 +122,7 @@ STATUS socketWrite(INT32, const void*, SIZE_T); * * @return - STATUS status of execution */ -STATUS getIpWithHostName(PCHAR, PKvsIpAddress); +STATUS getIpWithHostName(PCHAR, PDualKvsIpAddresses); /** * @param - PCHAR - IN - IP address string to verify if it is IPv4 or IPv6 format diff --git a/src/source/Ice/TurnConnection.c b/src/source/Ice/TurnConnection.c index 86dc365747..d2dc24ef17 100644 --- a/src/source/Ice/TurnConnection.c +++ b/src/source/Ice/TurnConnection.c @@ -674,7 +674,7 @@ STATUS turnConnectionAddPeer(PTurnConnection pTurnConnection, PKvsIpAddress pPee BOOL locked = FALSE; CHK(pTurnConnection != NULL && pPeerAddress != NULL, STATUS_NULL_ARG); - CHK(pTurnConnection->turnServer.ipAddress.family == pPeerAddress->family, STATUS_INVALID_ARG); + CHK(pTurnConnection->turnServer.ipAddresses.ipv4Address.family == pPeerAddress->family, STATUS_INVALID_ARG); CHK_WARN(IS_IPV4_ADDR(pPeerAddress), retStatus, "Drop IPv6 turn peer because only IPv4 turn peer is supported right now"); MUTEX_LOCK(pTurnConnection->lock); @@ -770,7 +770,7 @@ STATUS turnConnectionSendData(PTurnConnection pTurnConnection, PBYTE pBuf, UINT3 putInt16((PINT16) (pTurnConnection->sendDataBuffer + 2), (UINT16) bufLen); MEMCPY(pTurnConnection->sendDataBuffer + TURN_DATA_CHANNEL_SEND_OVERHEAD, pBuf, bufLen); - retStatus = iceUtilsSendData(pTurnConnection->sendDataBuffer, paddedDataLen, &pTurnConnection->turnServer.ipAddress, + retStatus = iceUtilsSendData(pTurnConnection->sendDataBuffer, paddedDataLen, &pTurnConnection->turnServer.ipAddresses.ipv4Address, pTurnConnection->pControlChannel, NULL, FALSE); if (STATUS_FAILED(retStatus)) { @@ -858,7 +858,7 @@ STATUS turnConnectionRefreshAllocation(PTurnConnection pTurnConnection) pStunAttributeLifetime->lifetime = DEFAULT_TURN_ALLOCATION_LIFETIME_SECONDS; CHK_STATUS(iceUtilsSendStunPacket(pTurnConnection->pTurnAllocationRefreshPacket, pTurnConnection->longTermKey, - ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddress, + ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddresses.ipv4Address, pTurnConnection->pControlChannel, NULL, FALSE)); pTurnConnection->nextAllocationRefreshTime = currTime + DEFAULT_TURN_SEND_REFRESH_INVERVAL; @@ -1056,7 +1056,7 @@ STATUS checkTurnPeerConnections(PTurnConnection pTurnConnection) CHK(pTurnPeer->pTransactionIdStore != NULL, STATUS_INVALID_OPERATION); transactionIdStoreInsert(pTurnPeer->pTransactionIdStore, pTurnConnection->pTurnCreatePermissionPacket->header.transactionId); sendStatus = iceUtilsSendStunPacket(pTurnConnection->pTurnCreatePermissionPacket, pTurnConnection->longTermKey, - ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddress, + ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddresses.ipv4Address, pTurnConnection->pControlChannel, NULL, FALSE); } else if (pTurnPeer->connectionState == TURN_PEER_CONN_STATE_BIND_CHANNEL) { @@ -1082,7 +1082,7 @@ STATUS checkTurnPeerConnections(PTurnConnection pTurnConnection) CHK(pTurnPeer->pTransactionIdStore != NULL, STATUS_INVALID_OPERATION); transactionIdStoreInsert(pTurnPeer->pTransactionIdStore, pTurnConnection->pTurnChannelBindPacket->header.transactionId); sendStatus = iceUtilsSendStunPacket(pTurnConnection->pTurnChannelBindPacket, pTurnConnection->longTermKey, - ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddress, + ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddresses.ipv4Address, pTurnConnection->pControlChannel, NULL, FALSE); } } diff --git a/src/source/Ice/TurnConnectionStateMachine.c b/src/source/Ice/TurnConnectionStateMachine.c index 6b7ba5775c..2963a9d36b 100644 --- a/src/source/Ice/TurnConnectionStateMachine.c +++ b/src/source/Ice/TurnConnectionStateMachine.c @@ -278,8 +278,8 @@ STATUS executeGetCredentialsTurnState(UINT64 customData, UINT64 time) } else { CHK(currentTime <= pTurnConnection->stateTimeoutTime, STATUS_TURN_CONNECTION_GET_CREDENTIALS_FAILED); } - CHK_STATUS(iceUtilsSendStunPacket(pTurnConnection->pTurnPacket, NULL, 0, &pTurnConnection->turnServer.ipAddress, pTurnConnection->pControlChannel, - NULL, FALSE)); + CHK_STATUS(iceUtilsSendStunPacket(pTurnConnection->pTurnPacket, NULL, 0, &pTurnConnection->turnServer.ipAddresses.ipv4Address, + pTurnConnection->pControlChannel, NULL, FALSE)); CleanUp: @@ -348,7 +348,7 @@ STATUS executeAllocationTurnState(UINT64 customData, UINT64 time) CHK(currentTime <= pTurnConnection->stateTimeoutTime, STATUS_TURN_CONNECTION_ALLOCATION_FAILED); } CHK_STATUS(iceUtilsSendStunPacket(pTurnConnection->pTurnPacket, pTurnConnection->longTermKey, ARRAY_SIZE(pTurnConnection->longTermKey), - &pTurnConnection->turnServer.ipAddress, pTurnConnection->pControlChannel, NULL, FALSE)); + &pTurnConnection->turnServer.ipAddresses.ipv4Address, pTurnConnection->pControlChannel, NULL, FALSE)); CleanUp: @@ -679,7 +679,7 @@ STATUS executeCleanUpTurnState(UINT64 customData, UINT64 time) CHK(pStunAttributeLifetime != NULL, STATUS_INTERNAL_ERROR); pStunAttributeLifetime->lifetime = 0; CHK_STATUS(iceUtilsSendStunPacket(pTurnConnection->pTurnAllocationRefreshPacket, pTurnConnection->longTermKey, - ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddress, + ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddresses.ipv4Address, pTurnConnection->pControlChannel, NULL, FALSE)); pTurnConnection->deallocatePacketSent = TRUE; } diff --git a/src/source/Include_i.h b/src/source/Include_i.h index b606165d8c..ffbd328dd2 100644 --- a/src/source/Include_i.h +++ b/src/source/Include_i.h @@ -92,6 +92,7 @@ extern "C" { #define MAX_UDP_PACKET_SIZE 65507 typedef enum { + KVS_IP_FAMILY_TYPE_NOT_SET = (UINT16) 0x0000, // Sentinel value for not yet set IP address. KVS_IP_FAMILY_TYPE_IPV4 = (UINT16) 0x0001, KVS_IP_FAMILY_TYPE_IPV6 = (UINT16) 0x0002, } KVS_IP_FAMILY_TYPE; @@ -103,12 +104,18 @@ typedef struct { BOOL isPointToPoint; } KvsIpAddress, *PKvsIpAddress; +// This structure stores both an IPv4 and IPv6 address (if applicable). +typedef struct { + KvsIpAddress ipv4Address; + KvsIpAddress ipv6Address; +} DualKvsIpAddresses, *PDualKvsIpAddresses; + #define IS_IPV4_ADDR(pAddress) ((pAddress)->family == KVS_IP_FAMILY_TYPE_IPV4) // Used for ensuring alignment #define ALIGN_UP_TO_MACHINE_WORD(x) ROUND_UP((x), SIZEOF(SIZE_T)) -typedef STATUS (*IceServerSetIpFunc)(UINT64, PCHAR, PKvsIpAddress); +typedef STATUS (*IceServerSetIpFunc)(UINT64, PCHAR, PDualKvsIpAddresses); STATUS getIpAddrStr(PKvsIpAddress pKvsIpAddress, PCHAR pBuffer, UINT32 bufferLen); //////////////////////////////////////////////////// diff --git a/src/source/PeerConnection/PeerConnection.c b/src/source/PeerConnection/PeerConnection.c index d25101cb38..1ade8d9a25 100644 --- a/src/source/PeerConnection/PeerConnection.c +++ b/src/source/PeerConnection/PeerConnection.c @@ -806,25 +806,44 @@ STATUS getStunAddr(PStunIpAddrContext pStunIpAddrCtx) STATUS retStatus = STATUS_SUCCESS; struct addrinfo *rp, *res; struct sockaddr_in* ipv4Addr; - BOOL resolved = FALSE; + struct sockaddr_in6* ipv6Addr; + BOOL ipv4Resolved = FALSE; + BOOL ipv6Resolved = FALSE; + + // Initialize IP address families to a sentinel value + // to indicate that they are not set. + pStunIpAddrCtx->kvsIpAddresses.ipv4Address.family = KVS_IP_FAMILY_TYPE_NOT_SET; + pStunIpAddrCtx->kvsIpAddresses.ipv6Address.family = KVS_IP_FAMILY_TYPE_NOT_SET; + pStunIpAddrCtx->kvsIpAddresses.ipv4Address.port = 0; + pStunIpAddrCtx->kvsIpAddresses.ipv6Address.port = 0; + + DLOGD("Resolving STUN server address for hostname: %s", pStunIpAddrCtx->hostname); errCode = getaddrinfo(pStunIpAddrCtx->hostname, NULL, NULL, &res); if (errCode != 0) { DLOGI("Failed to resolve hostname with errcode: %d", errCode); retStatus = STATUS_RESOLVE_HOSTNAME_FAILED; } else { - for (rp = res; rp != NULL && !resolved; rp = rp->ai_next) { - if (rp->ai_family == AF_INET) { + for (rp = res; rp != NULL && !(ipv4Resolved && ipv6Resolved); rp = rp->ai_next) { + if (!ipv4Resolved && rp->ai_family == AF_INET) { + DLOGD("Found an IPv4 STUN addresss for hostname: %s", pStunIpAddrCtx->hostname); ipv4Addr = (struct sockaddr_in*) rp->ai_addr; - pStunIpAddrCtx->kvsIpAddr.family = KVS_IP_FAMILY_TYPE_IPV4; - pStunIpAddrCtx->kvsIpAddr.port = 0; - MEMCPY(pStunIpAddrCtx->kvsIpAddr.address, &ipv4Addr->sin_addr, IPV4_ADDRESS_LENGTH); - resolved = TRUE; + pStunIpAddrCtx->kvsIpAddresses.ipv4Address.family = KVS_IP_FAMILY_TYPE_IPV4; + MEMCPY(pStunIpAddrCtx->kvsIpAddresses.ipv4Address.address, &ipv4Addr->sin_addr, IPV4_ADDRESS_LENGTH); + ipv4Resolved = TRUE; + } else if (!ipv6Resolved && rp->ai_family == AF_INET6) { + DLOGD("Found an IPv6 STUN addresss for hostname: %s", pStunIpAddrCtx->hostname); + ipv6Addr = (struct sockaddr_in6*) rp->ai_addr; + pStunIpAddrCtx->kvsIpAddresses.ipv6Address.family = KVS_IP_FAMILY_TYPE_IPV6; + MEMCPY(pStunIpAddrCtx->kvsIpAddresses.ipv6Address.address, &ipv6Addr->sin6_addr, IPV6_ADDRESS_LENGTH); + ipv6Resolved = TRUE; + } else { + DLOGD("Invalid family STUN addresss for hostname: %s", pStunIpAddrCtx->hostname); } } freeaddrinfo(res); } - if (!resolved) { + if (!(ipv4Resolved || ipv6Resolved)) { retStatus = STATUS_RESOLVE_HOSTNAME_FAILED; } @@ -833,7 +852,7 @@ STATUS getStunAddr(PStunIpAddrContext pStunIpAddrCtx) return retStatus; } -STATUS onSetStunServerIp(UINT64 customData, PCHAR url, PKvsIpAddress pIpAddr) +STATUS onSetStunServerIp(UINT64 customData, PCHAR url, PDualKvsIpAddresses pIpAddresses) { ENTERS(); UNUSED_PARAM(customData); @@ -863,7 +882,10 @@ STATUS onSetStunServerIp(UINT64 customData, PCHAR url, PKvsIpAddress pIpAddr) pWebRtcClientContext->pStunIpAddrCtx->startTime = 0; CHK_ERR(getStunAddr(pWebRtcClientContext->pStunIpAddrCtx) == STATUS_SUCCESS, retStatus, "Failed to resolve after cache expiry"); } - MEMCPY(pIpAddr, &pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddr, SIZEOF(pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddr)); + MEMCPY(pIpAddresses->ipv4Address.address, &pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv4Address, + SIZEOF(pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv4Address)); + MEMCPY(pIpAddresses->ipv6Address.address, &pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv6Address, + SIZEOF(pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv6Address)); } else { DLOGE("Initialization failed"); } @@ -886,7 +908,8 @@ PVOID resolveStunIceServerIp(PVOID args) UNUSED_PARAM(args); PWebRtcClientContext pWebRtcClientContext = getWebRtcClientInstance(); BOOL locked = FALSE; - CHAR addressResolved[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; + CHAR addressResolvedIPv4[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; + CHAR addressResolvedIPv6[KVS_IP_ADDRESS_STRING_BUFFER_LEN + 1] = {'\0'}; PCHAR pRegion; PCHAR pHostnamePostfix; UINT64 stunDnsResolutionStartTime = 0; @@ -912,9 +935,21 @@ PVOID resolveStunIceServerIp(PVOID args) KINESIS_VIDEO_STUN_URL_WITHOUT_PORT, pRegion, pHostnamePostfix); stunDnsResolutionStartTime = GETTIME(); if (getStunAddr(pWebRtcClientContext->pStunIpAddrCtx) == STATUS_SUCCESS) { - getIpAddrStr(&pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddr, addressResolved, ARRAY_SIZE(addressResolved)); - DLOGI("ICE Server address for %s with getaddrinfo: %s", pWebRtcClientContext->pStunIpAddrCtx->hostname, addressResolved); - pWebRtcClientContext->pStunIpAddrCtx->isIpInitialized = TRUE; + if (pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv4Address.family != KVS_IP_FAMILY_TYPE_NOT_SET) { + // If the IPv4 family is set, then there must have been an IPv4 address resolved. + getIpAddrStr(&pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv4Address, addressResolvedIPv4, + ARRAY_SIZE(addressResolvedIPv4)); + DLOGI("ICE Server address for %s with getaddrinfo: %s", pWebRtcClientContext->pStunIpAddrCtx->hostname, addressResolvedIPv4); + pWebRtcClientContext->pStunIpAddrCtx->isIpInitialized = TRUE; + } + if (pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv6Address.family != KVS_IP_FAMILY_TYPE_NOT_SET) { + // If the IPv6 family is set, then there must have been an IPv6 address resolved. + getIpAddrStr(&pWebRtcClientContext->pStunIpAddrCtx->kvsIpAddresses.ipv6Address, addressResolvedIPv6, + ARRAY_SIZE(addressResolvedIPv6)); + DLOGI("ICE Server address for %s with getaddrinfo: %s", pWebRtcClientContext->pStunIpAddrCtx->hostname, addressResolvedIPv6); + pWebRtcClientContext->pStunIpAddrCtx->isIpInitialized = TRUE; + } + } else { DLOGE("Failed to resolve %s", pWebRtcClientContext->pStunIpAddrCtx->hostname); } diff --git a/src/source/PeerConnection/PeerConnection.h b/src/source/PeerConnection/PeerConnection.h index 7311ec9794..20cec6e078 100644 --- a/src/source/PeerConnection/PeerConnection.h +++ b/src/source/PeerConnection/PeerConnection.h @@ -158,7 +158,7 @@ typedef struct { typedef struct { CHAR hostname[MAX_ICE_CONFIG_URI_LEN + 1]; - KvsIpAddress kvsIpAddr; + DualKvsIpAddresses kvsIpAddresses; BOOL isIpInitialized; UINT64 startTime; UINT64 stunDnsResolutionTime; diff --git a/tst/IceFunctionalityTest.cpp b/tst/IceFunctionalityTest.cpp index 3a27b6324b..1c9d5fc8cf 100644 --- a/tst/IceFunctionalityTest.cpp +++ b/tst/IceFunctionalityTest.cpp @@ -305,7 +305,7 @@ TEST_F(IceFunctionalityTest, IceAgentIceAgentAddIceServerUnitTest) EXPECT_EQ(STATUS_SUCCESS, parseIceServer(&iceServer, (PCHAR) "turn:54.202.170.151:443?transport=udp", (PCHAR) "username", (PCHAR) "password")); EXPECT_TRUE(!iceServer.isSecure); EXPECT_EQ(iceServer.transport, KVS_SOCKET_PROTOCOL_UDP); - EXPECT_EQ(443, (UINT16) getInt16(iceServer.ipAddress.port)); + EXPECT_EQ(443, (UINT16) getInt16(iceServer.ipAddresses.ipv4Address.port)); /* we are not doing full validation. Only parsing out what we know */ EXPECT_EQ(STATUS_SUCCESS, parseIceServer(&iceServer, (PCHAR) "turn:54.202.170.151:443?randomstuff", (PCHAR) "username", (PCHAR) "password")); diff --git a/tst/NetworkApiTest.cpp b/tst/NetworkApiTest.cpp index c5702a61c6..01697f3b3d 100644 --- a/tst/NetworkApiTest.cpp +++ b/tst/NetworkApiTest.cpp @@ -11,14 +11,14 @@ class NetworkApiTest : public WebRtcClientTestBase { TEST_F(NetworkApiTest, GetIpWithHostNameTest) { - KvsIpAddress ipAddress; - EXPECT_EQ(STATUS_NULL_ARG, getIpWithHostName(NULL, &ipAddress)); - EXPECT_EQ(STATUS_RESOLVE_HOSTNAME_FAILED, getIpWithHostName((PCHAR) "stun:stun.test.net:3478", &ipAddress)); - EXPECT_EQ(STATUS_SUCCESS, getIpWithHostName((PCHAR) "35-90-63-38.t-ae7dd61a.kinesisvideo.us-west-2.amazonaws.com", &ipAddress)); - EXPECT_EQ(STATUS_SUCCESS, getIpWithHostName((PCHAR) "12.34.45.40", &ipAddress)); - EXPECT_EQ(STATUS_SUCCESS, getIpWithHostName((PCHAR) "2001:0db8:85a3:0000:0000:8a2e:0370:7334", &ipAddress)); - EXPECT_EQ(STATUS_RESOLVE_HOSTNAME_FAILED, getIpWithHostName((PCHAR) ".12.34.45.40", &ipAddress)); - EXPECT_EQ(STATUS_RESOLVE_HOSTNAME_FAILED, getIpWithHostName((PCHAR) "...........", &ipAddress)); + DualKvsIpAddresses ipAddresses; + EXPECT_EQ(STATUS_NULL_ARG, getIpWithHostName(NULL, &ipAddresses)); + EXPECT_EQ(STATUS_RESOLVE_HOSTNAME_FAILED, getIpWithHostName((PCHAR) "stun:stun.test.net:3478", &ipAddresses)); + EXPECT_EQ(STATUS_SUCCESS, getIpWithHostName((PCHAR) "35-90-63-38.t-ae7dd61a.kinesisvideo.us-west-2.amazonaws.com", &ipAddresses)); + EXPECT_EQ(STATUS_SUCCESS, getIpWithHostName((PCHAR) "12.34.45.40", &ipAddresses)); + EXPECT_EQ(STATUS_SUCCESS, getIpWithHostName((PCHAR) "2001:0db8:85a3:0000:0000:8a2e:0370:7334", &ipAddresses)); + EXPECT_EQ(STATUS_RESOLVE_HOSTNAME_FAILED, getIpWithHostName((PCHAR) ".12.34.45.40", &ipAddresses)); + EXPECT_EQ(STATUS_RESOLVE_HOSTNAME_FAILED, getIpWithHostName((PCHAR) "...........", &ipAddresses)); } TEST_F(NetworkApiTest, ipIpAddrTest) diff --git a/tst/TurnConnectionFunctionalityTest.cpp b/tst/TurnConnectionFunctionalityTest.cpp index da2914cd63..42a158b42a 100644 --- a/tst/TurnConnectionFunctionalityTest.cpp +++ b/tst/TurnConnectionFunctionalityTest.cpp @@ -52,7 +52,7 @@ class TurnConnectionFunctionalityTest : public WebRtcClientTestBase { EXPECT_EQ(STATUS_SUCCESS, getLocalhostIpAddresses(localIpInterfaces, &localIpInterfaceCount, NULL, 0)); for (i = 0; i < localIpInterfaceCount; ++i) { - if (localIpInterfaces[i].family == pTurnServer->ipAddress.family && (pTurnSocketAddr == NULL || localIpInterfaces[i].isPointToPoint)) { + if (localIpInterfaces[i].family == pTurnServer->ipAddresses.ipv4Address.family && (pTurnSocketAddr == NULL || localIpInterfaces[i].isPointToPoint)) { pTurnSocketAddr = &localIpInterfaces[i]; } } @@ -69,8 +69,8 @@ class TurnConnectionFunctionalityTest : public WebRtcClientTestBase { return STATUS_SUCCESS; }; EXPECT_EQ(STATUS_SUCCESS, - createSocketConnection((KVS_IP_FAMILY_TYPE) pTurnServer->ipAddress.family, KVS_ICE_DEFAULT_TURN_PROTOCOL, NULL, - &pTurnServer->ipAddress, (UINT64) this, onDataHandler, 0, &pTurnSocket)); + createSocketConnection((KVS_IP_FAMILY_TYPE) pTurnServer->ipAddresses.ipv4Address.family, KVS_ICE_DEFAULT_TURN_PROTOCOL, NULL, + &pTurnServer->ipAddresses.ipv4Address, (UINT64) this, onDataHandler, 0, &pTurnSocket)); EXPECT_EQ(STATUS_SUCCESS, connectionListenerAddConnection(pConnectionListener, pTurnSocket)); ASSERT_EQ(STATUS_SUCCESS, createTurnConnection(pTurnServer, timerQueueHandle, TURN_CONNECTION_DATA_TRANSFER_MODE_DATA_CHANNEL, KVS_ICE_DEFAULT_TURN_PROTOCOL,