Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
vc60er authored and disa6302 committed Dec 5, 2023
1 parent 50494cd commit 34fea94
Show file tree
Hide file tree
Showing 3 changed files with 1 addition and 280 deletions.
19 changes: 0 additions & 19 deletions src/source/Ice/IceAgent.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
243 changes: 0 additions & 243 deletions src/source/Ice/TurnConnection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
19 changes: 1 addition & 18 deletions src/source/Ice/TurnConnectionStateMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit 34fea94

Please sign in to comment.