diff --git a/src/source/Ice/IceAgent.c b/src/source/Ice/IceAgent.c index ddc5492b0b..0b18439800 100644 --- a/src/source/Ice/IceAgent.c +++ b/src/source/Ice/IceAgent.c @@ -1801,25 +1801,6 @@ STATUS iceAgentInitRelayCandidates(PIceAgent pIceAgent) return retStatus; } -STATUS turnStateFailedFn(PSocketConnection pSocketConnection, UINT64 data) -{ - UNUSED_PARAM(pSocketConnection); - - STATUS retStatus = STATUS_SUCCESS; - - PIceCandidate pNewCandidate = (PIceCandidate) data; - CHK(pNewCandidate != NULL, STATUS_NULL_ARG); - MUTEX_LOCK(pNewCandidate->pIceAgent->lock); - - if (pNewCandidate->state == ICE_CANDIDATE_STATE_NEW) { - pNewCandidate->state = ICE_CANDIDATE_STATE_INVALID; - } - -CleanUp: - MUTEX_UNLOCK(pNewCandidate->pIceAgent->lock); - return retStatus; -} - STATUS iceAgentInitRelayCandidate(PIceAgent pIceAgent, UINT32 iceServerIndex, KVS_SOCKET_PROTOCOL protocol) { STATUS retStatus = STATUS_SUCCESS; diff --git a/src/source/Ice/TurnConnection.c b/src/source/Ice/TurnConnection.c index 2a2e184b1d..ef98ab3a38 100644 --- a/src/source/Ice/TurnConnection.c +++ b/src/source/Ice/TurnConnection.c @@ -896,249 +896,6 @@ STATUS turnConnectionFreePreAllocatedPackets(PTurnConnection pTurnConnection) return retStatus; } -STATUS turnConnectionStepState(PTurnConnection pTurnConnection) -{ - ENTERS(); - STATUS retStatus = STATUS_SUCCESS; - UINT32 readyPeerCount = 0, channelWithPermissionCount = 0; - UINT64 currentTime = GETTIME(); - CHAR ipAddrStr[KVS_IP_ADDRESS_STRING_BUFFER_LEN]; - TURN_CONNECTION_STATE previousState = TURN_STATE_NEW; - BOOL refreshPeerPermission = FALSE; - UINT32 i = 0; - - CHK(pTurnConnection != NULL, STATUS_NULL_ARG); - - previousState = pTurnConnection->state; - - switch (pTurnConnection->state) { - case TURN_STATE_NEW: - // create empty turn allocation request - CHK_STATUS(turnConnectionPackageTurnAllocationRequest(NULL, NULL, NULL, 0, DEFAULT_TURN_ALLOCATION_LIFETIME_SECONDS, - &pTurnConnection->pTurnPacket)); - - pTurnConnection->state = TURN_STATE_CHECK_SOCKET_CONNECTION; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_SOCKET_CONNECT_TIMEOUT; - break; - - case TURN_STATE_CHECK_SOCKET_CONNECTION: - if (socketConnectionIsConnected(pTurnConnection->pControlChannel)) { - /* initialize TLS once tcp connection is established */ - /* Start receiving data for TLS handshake */ - ATOMIC_STORE_BOOL(&pTurnConnection->pControlChannel->receiveData, TRUE); - - /* We dont support DTLS and TCP, so only options are TCP/TLS and UDP. */ - /* TODO: add plain TCP once it becomes available. */ - if (pTurnConnection->protocol == KVS_SOCKET_PROTOCOL_TCP && pTurnConnection->pControlChannel->pTlsSession == NULL) { - CHK_STATUS(socketConnectionInitSecureConnection(pTurnConnection->pControlChannel, FALSE)); - } - - pTurnConnection->state = TURN_STATE_GET_CREDENTIALS; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_GET_CREDENTIAL_TIMEOUT; - } else { - CHK(currentTime < pTurnConnection->stateTimeoutTime, STATUS_TURN_CONNECTION_STATE_TRANSITION_TIMEOUT); - } - break; - - // fallthrough here, missing break intended - case TURN_STATE_GET_CREDENTIALS: - - if (pTurnConnection->credentialObtained) { - DLOGV("Updated turn allocation request credential after receiving 401"); - - // update turn allocation packet with credentials - CHK_STATUS(freeStunPacket(&pTurnConnection->pTurnPacket)); - CHK_STATUS(turnConnectionGetLongTermKey(pTurnConnection->turnServer.username, pTurnConnection->turnRealm, - pTurnConnection->turnServer.credential, pTurnConnection->longTermKey, - SIZEOF(pTurnConnection->longTermKey))); - CHK_STATUS(turnConnectionPackageTurnAllocationRequest(pTurnConnection->turnServer.username, pTurnConnection->turnRealm, - pTurnConnection->turnNonce, pTurnConnection->nonceLen, - DEFAULT_TURN_ALLOCATION_LIFETIME_SECONDS, &pTurnConnection->pTurnPacket)); - - pTurnConnection->state = TURN_STATE_ALLOCATION; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_ALLOCATION_TIMEOUT; - } else { - CHK(currentTime < pTurnConnection->stateTimeoutTime, STATUS_TURN_CONNECTION_STATE_TRANSITION_TIMEOUT); - } - break; - - case TURN_STATE_ALLOCATION: - - if (ATOMIC_LOAD_BOOL(&pTurnConnection->hasAllocation)) { - CHK_STATUS(getIpAddrStr(&pTurnConnection->relayAddress, ipAddrStr, ARRAY_SIZE(ipAddrStr))); - DLOGD("Relay address received: %s, port: %u", ipAddrStr, (UINT16) getInt16(pTurnConnection->relayAddress.port)); - - if (pTurnConnection->pTurnCreatePermissionPacket != NULL) { - CHK_STATUS(freeStunPacket(&pTurnConnection->pTurnCreatePermissionPacket)); - } - CHK_STATUS(createStunPacket(STUN_PACKET_TYPE_CREATE_PERMISSION, NULL, &pTurnConnection->pTurnCreatePermissionPacket)); - // use host address as placeholder. hostAddress should have the same family as peer address - CHK_STATUS(appendStunAddressAttribute(pTurnConnection->pTurnCreatePermissionPacket, STUN_ATTRIBUTE_TYPE_XOR_PEER_ADDRESS, - &pTurnConnection->hostAddress)); - CHK_STATUS(appendStunUsernameAttribute(pTurnConnection->pTurnCreatePermissionPacket, pTurnConnection->turnServer.username)); - CHK_STATUS(appendStunRealmAttribute(pTurnConnection->pTurnCreatePermissionPacket, pTurnConnection->turnRealm)); - CHK_STATUS( - appendStunNonceAttribute(pTurnConnection->pTurnCreatePermissionPacket, pTurnConnection->turnNonce, pTurnConnection->nonceLen)); - - // create channel bind packet here too so for each peer as soon as permission is created, it can start - // sending chaneel bind request - if (pTurnConnection->pTurnChannelBindPacket != NULL) { - CHK_STATUS(freeStunPacket(&pTurnConnection->pTurnChannelBindPacket)); - } - CHK_STATUS(createStunPacket(STUN_PACKET_TYPE_CHANNEL_BIND_REQUEST, NULL, &pTurnConnection->pTurnChannelBindPacket)); - // use host address as placeholder - CHK_STATUS(appendStunAddressAttribute(pTurnConnection->pTurnChannelBindPacket, STUN_ATTRIBUTE_TYPE_XOR_PEER_ADDRESS, - &pTurnConnection->hostAddress)); - CHK_STATUS(appendStunChannelNumberAttribute(pTurnConnection->pTurnChannelBindPacket, 0)); - CHK_STATUS(appendStunUsernameAttribute(pTurnConnection->pTurnChannelBindPacket, pTurnConnection->turnServer.username)); - CHK_STATUS(appendStunRealmAttribute(pTurnConnection->pTurnChannelBindPacket, pTurnConnection->turnRealm)); - CHK_STATUS(appendStunNonceAttribute(pTurnConnection->pTurnChannelBindPacket, pTurnConnection->turnNonce, pTurnConnection->nonceLen)); - - if (pTurnConnection->pTurnAllocationRefreshPacket != NULL) { - CHK_STATUS(freeStunPacket(&pTurnConnection->pTurnAllocationRefreshPacket)); - } - CHK_STATUS(createStunPacket(STUN_PACKET_TYPE_REFRESH, NULL, &pTurnConnection->pTurnAllocationRefreshPacket)); - CHK_STATUS(appendStunLifetimeAttribute(pTurnConnection->pTurnAllocationRefreshPacket, DEFAULT_TURN_ALLOCATION_LIFETIME_SECONDS)); - CHK_STATUS(appendStunUsernameAttribute(pTurnConnection->pTurnAllocationRefreshPacket, pTurnConnection->turnServer.username)); - CHK_STATUS(appendStunRealmAttribute(pTurnConnection->pTurnAllocationRefreshPacket, pTurnConnection->turnRealm)); - CHK_STATUS( - appendStunNonceAttribute(pTurnConnection->pTurnAllocationRefreshPacket, pTurnConnection->turnNonce, pTurnConnection->nonceLen)); - - pTurnConnection->state = TURN_STATE_CREATE_PERMISSION; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_CREATE_PERMISSION_TIMEOUT; - - } else { - CHK(currentTime < pTurnConnection->stateTimeoutTime, STATUS_TURN_CONNECTION_STATE_TRANSITION_TIMEOUT); - } - break; - - case TURN_STATE_CREATE_PERMISSION: - - for (i = 0; i < pTurnConnection->turnPeerCount; ++i) { - // As soon as create permission succeeded, we start sending channel bind message. - // So connectionState could've already advanced to ready state. - if (pTurnConnection->turnPeerList[i].connectionState == TURN_PEER_CONN_STATE_BIND_CHANNEL || - pTurnConnection->turnPeerList[i].connectionState == TURN_PEER_CONN_STATE_READY) { - channelWithPermissionCount++; - } - } - - // push back timeout if no peer is available yet - if (pTurnConnection->turnPeerCount == 0) { - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_CREATE_PERMISSION_TIMEOUT; - CHK(FALSE, retStatus); - } - - if (currentTime >= pTurnConnection->stateTimeoutTime) { - CHK(channelWithPermissionCount > 0, STATUS_TURN_CONNECTION_FAILED_TO_CREATE_PERMISSION); - - // go to next state if we have at least one ready peer - pTurnConnection->state = TURN_STATE_BIND_CHANNEL; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_BIND_CHANNEL_TIMEOUT; - } - break; - - case TURN_STATE_BIND_CHANNEL: - - for (i = 0; i < pTurnConnection->turnPeerCount; ++i) { - if (pTurnConnection->turnPeerList[i].connectionState == TURN_PEER_CONN_STATE_READY) { - readyPeerCount++; - } - } - - if (currentTime >= pTurnConnection->stateTimeoutTime || readyPeerCount == pTurnConnection->turnPeerCount) { - CHK(readyPeerCount > 0, STATUS_TURN_CONNECTION_FAILED_TO_BIND_CHANNEL); - // go to next state if we have at least one ready peer - pTurnConnection->state = TURN_STATE_READY; - } - break; - - case TURN_STATE_READY: - - CHK_STATUS(turnConnectionRefreshPermission(pTurnConnection, &refreshPeerPermission)); - if (refreshPeerPermission) { - // reset pTurnPeer->connectionState to make them go through create permission and channel bind again - for (i = 0; i < pTurnConnection->turnPeerCount; ++i) { - pTurnConnection->turnPeerList[i].connectionState = TURN_PEER_CONN_STATE_CREATE_PERMISSION; - } - - pTurnConnection->currentTimerCallingPeriod = DEFAULT_TURN_TIMER_INTERVAL_BEFORE_READY; - CHK_STATUS(timerQueueUpdateTimerPeriod(pTurnConnection->timerQueueHandle, (UINT64) pTurnConnection, - (UINT32) ATOMIC_LOAD(&pTurnConnection->timerCallbackId), - pTurnConnection->currentTimerCallingPeriod)); - pTurnConnection->state = TURN_STATE_CREATE_PERMISSION; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_CREATE_PERMISSION_TIMEOUT; - } else if (pTurnConnection->currentTimerCallingPeriod != DEFAULT_TURN_TIMER_INTERVAL_AFTER_READY) { - // use longer timer interval as now it just needs to check disconnection and permission expiration. - pTurnConnection->currentTimerCallingPeriod = DEFAULT_TURN_TIMER_INTERVAL_AFTER_READY; - CHK_STATUS(timerQueueUpdateTimerPeriod(pTurnConnection->timerQueueHandle, (UINT64) pTurnConnection, - (UINT32) ATOMIC_LOAD(&pTurnConnection->timerCallbackId), - pTurnConnection->currentTimerCallingPeriod)); - } - - break; - - case TURN_STATE_CLEAN_UP: - /* start cleanning up even if we dont receive allocation freed response in time, or if connection is already closed, - * since we already sent multiple STUN refresh packets with 0 lifetime. */ - if (socketConnectionIsClosed(pTurnConnection->pControlChannel) || !ATOMIC_LOAD_BOOL(&pTurnConnection->hasAllocation) || - currentTime >= pTurnConnection->stateTimeoutTime) { - // clean transactionId store for each turn peer, preserving the peers - for (i = 0; i < pTurnConnection->turnPeerCount; ++i) { - transactionIdStoreClear(pTurnConnection->turnPeerList[i].pTransactionIdStore); - } - - CHK_STATUS(turnConnectionFreePreAllocatedPackets(pTurnConnection)); - CHK_STATUS(socketConnectionClosed(pTurnConnection->pControlChannel)); - pTurnConnection->state = STATUS_SUCCEEDED(pTurnConnection->errorStatus) ? TURN_STATE_NEW : TURN_STATE_FAILED; - ATOMIC_STORE_BOOL(&pTurnConnection->shutdownComplete, TRUE); - } - - break; - - case TURN_STATE_FAILED: - DLOGW("TurnConnection in TURN_STATE_FAILED due to 0x%08x. Aborting TurnConnection", pTurnConnection->errorStatus); - /* Since we are aborting, not gonna do cleanup */ - ATOMIC_STORE_BOOL(&pTurnConnection->hasAllocation, FALSE); - /* If we haven't done cleanup, go to cleanup state which will do the cleanup then go to failed state again. */ - if (!ATOMIC_LOAD_BOOL(&pTurnConnection->shutdownComplete)) { - pTurnConnection->state = TURN_STATE_CLEAN_UP; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_CLEAN_UP_TIMEOUT; - } - - break; - - default: - break; - } - -CleanUp: - - CHK_LOG_ERR(retStatus); - - if (STATUS_SUCCEEDED(retStatus) && ATOMIC_LOAD_BOOL(&pTurnConnection->stopTurnConnection) && pTurnConnection->state != TURN_STATE_CLEAN_UP && - pTurnConnection->state != TURN_STATE_NEW && !ATOMIC_LOAD_BOOL(&pTurnConnection->shutdownComplete)) { - pTurnConnection->state = TURN_STATE_CLEAN_UP; - pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_CLEAN_UP_TIMEOUT; - } - - /* move to failed state if retStatus is failed status and state is not yet TURN_STATE_FAILED */ - if (STATUS_FAILED(retStatus) && pTurnConnection->state != TURN_STATE_FAILED) { - pTurnConnection->errorStatus = retStatus; - pTurnConnection->state = TURN_STATE_FAILED; - /* fix up state to trigger transition into TURN_STATE_FAILED */ - retStatus = STATUS_SUCCESS; - } - - if (pTurnConnection != NULL && previousState != pTurnConnection->state) { - DLOGD("TurnConnection state changed from %s to %s", turnConnectionGetStateStr(previousState), - turnConnectionGetStateStr(pTurnConnection->state)); - } - - LEAVES(); - return retStatus; -} - STATUS turnConnectionUpdateNonce(PTurnConnection pTurnConnection) { STATUS retStatus = STATUS_SUCCESS; diff --git a/src/source/Ice/TurnConnectionStateMachine.c b/src/source/Ice/TurnConnectionStateMachine.c index 0bc54afd0b..0e0a1f2dd5 100644 --- a/src/source/Ice/TurnConnectionStateMachine.c +++ b/src/source/Ice/TurnConnectionStateMachine.c @@ -99,7 +99,7 @@ STATUS stepTurnConnectionStateMachine(PTurnConnection pTurnConnection) retStatus = stepStateMachine(pTurnConnection->pStateMachine); if (STATUS_SUCCEEDED(retStatus) && ATOMIC_LOAD_BOOL(&pTurnConnection->stopTurnConnection) && pTurnConnection->state != TURN_STATE_NEW && - pTurnConnection->state != TURN_STATE_CLEAN_UP) { + pTurnConnection->state != TURN_STATE_CLEAN_UP && !ATOMIC_LOAD_BOOL(&pTurnConnection->shutdownComplete)) { currentTime = GETTIME(); pTurnConnection->state = TURN_STATE_CLEAN_UP; pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_CLEAN_UP_TIMEOUT; @@ -111,18 +111,6 @@ STATUS stepTurnConnectionStateMachine(PTurnConnection pTurnConnection) pTurnConnection->errorStatus = retStatus; pTurnConnection->state = TURN_STATE_FAILED; - /* There is data race condition when editing the candidate state without holding - * the IceAgent lock. However holding the turn lock and then locking the ice agent lock - * can result in a dead lock. Ice must always be locked first, and then turn. - */ - - MUTEX_UNLOCK(pTurnConnection->lock); - if (pTurnConnection->turnConnectionCallbacks.turnStateFailedFn != NULL) { - pTurnConnection->turnConnectionCallbacks.turnStateFailedFn(pTurnConnection->pControlChannel, - pTurnConnection->turnConnectionCallbacks.customData); - } - MUTEX_LOCK(pTurnConnection->lock); - /* fix up state to trigger transition into TURN_STATE_FAILED */ retStatus = STATUS_SUCCESS; CHK_STATUS(stepStateMachine(pTurnConnection->pStateMachine)); @@ -261,8 +249,6 @@ STATUS fromGetCredentialsTurnState(UINT64 customData, PUINT64 pState) if (pTurnConnection->credentialObtained) { state = TURN_STATE_ALLOCATION; pTurnConnection->stateTimeoutTime = currentTime + DEFAULT_TURN_ALLOCATION_TIMEOUT; - pTurnConnection->stateTryCountMax = DEFAULT_TURN_ALLOCATION_MAX_TRY_COUNT; - pTurnConnection->stateTryCount = 0; } *pState = state; @@ -362,9 +348,6 @@ STATUS executeAllocationTurnState(UINT64 customData, UINT64 time) pTurnConnection->turnNonce, pTurnConnection->nonceLen, DEFAULT_TURN_ALLOCATION_LIFETIME_SECONDS, &pTurnConnection->pTurnPacket)); pTurnConnection->state = TURN_STATE_ALLOCATION; - } else { - pTurnConnection->stateTryCount++; - CHK(pTurnConnection->stateTryCount < pTurnConnection->stateTryCountMax, STATUS_TURN_CONNECTION_ALLOCAITON_FAILED); } CHK_STATUS(iceUtilsSendStunPacket(pTurnConnection->pTurnPacket, pTurnConnection->longTermKey, ARRAY_SIZE(pTurnConnection->longTermKey), &pTurnConnection->turnServer.ipAddress, pTurnConnection->pControlChannel, NULL, FALSE));