STATUS iceAgentAddRemoteCandidate()

in src/source/Ice/IceAgent.c [314:452]


STATUS iceAgentAddRemoteCandidate(PIceAgent pIceAgent, PCHAR pIceCandidateString)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS;
    BOOL locked = FALSE;
    PIceCandidate pIceCandidate = NULL, pDuplicatedIceCandidate = NULL, pLocalIceCandidate = NULL;
    PCHAR curr, tail, next;
    UINT32 tokenLen = 0, portValue = 0, remoteCandidateCount = 0, len = 0, priority = 0;
    BOOL freeIceCandidateIfFail = TRUE;
    BOOL foundIp = FALSE;
    BOOL foundType = FALSE;
    CHAR ipBuf[KVS_IP_ADDRESS_STRING_BUFFER_LEN];
    KvsIpAddress candidateIpAddr;
    PDoubleListNode pCurNode = NULL;
    SDP_ICE_CANDIDATE_PARSER_STATE state;
    ICE_CANDIDATE_TYPE iceCandidateType = ICE_CANDIDATE_TYPE_HOST;
    KVS_SOCKET_PROTOCOL remoteProtocol = KVS_SOCKET_PROTOCOL_NONE;

    CHK(pIceAgent != NULL && pIceCandidateString != NULL, STATUS_NULL_ARG);
    CHK(!IS_EMPTY_STRING(pIceCandidateString), STATUS_INVALID_ARG);

    MEMSET(&candidateIpAddr, 0x00, SIZEOF(KvsIpAddress));

    MUTEX_LOCK(pIceAgent->lock);
    locked = TRUE;

    CHK_STATUS(doubleListGetNodeCount(pIceAgent->remoteCandidates, &remoteCandidateCount));
    CHK(remoteCandidateCount < KVS_ICE_MAX_REMOTE_CANDIDATE_COUNT, STATUS_ICE_MAX_REMOTE_CANDIDATE_COUNT_EXCEEDED);
    // a=candidate:4234997325 1 udp 2043278322 192.168.0.56 44323 typ host
    curr = pIceCandidateString;
    tail = pIceCandidateString + STRLEN(pIceCandidateString);
    state = SDP_ICE_CANDIDATE_PARSER_STATE_FOUNDATION;

    while ((next = STRNCHR(curr, tail - curr, ' ')) != NULL && !foundType) {
        tokenLen = (UINT32) (next - curr);

        switch (state) {
            case SDP_ICE_CANDIDATE_PARSER_STATE_FOUNDATION:
            case SDP_ICE_CANDIDATE_PARSER_STATE_COMPONENT:
                break;
            case SDP_ICE_CANDIDATE_PARSER_STATE_PRIORITY:
                STRTOUI32(curr, next, 10, &priority);
                break;
            case SDP_ICE_CANDIDATE_PARSER_STATE_PROTOCOL:
                if (STRNCMPI(ICE_TRANSPORT_TYPE_TCP, curr, tokenLen) == 0) {
                    remoteProtocol = KVS_SOCKET_PROTOCOL_TCP;
                } else if (STRNCMPI(ICE_TRANSPORT_TYPE_UDP, curr, tokenLen) == 0) {
                    remoteProtocol = KVS_SOCKET_PROTOCOL_UDP;
                }
                CHK(STRNCMPI(ICE_TRANSPORT_TYPE_TCP, curr, tokenLen) != 0, STATUS_ICE_CANDIDATE_STRING_IS_TCP);
                break;
            case SDP_ICE_CANDIDATE_PARSER_STATE_IP:
                len = MIN(next - curr, KVS_IP_ADDRESS_STRING_BUFFER_LEN - 1);
                STRNCPY(ipBuf, curr, len);
                ipBuf[len] = '\0';
                if ((foundIp = inet_pton(AF_INET, ipBuf, candidateIpAddr.address) == 1 ? TRUE : FALSE)) {
                    candidateIpAddr.family = KVS_IP_FAMILY_TYPE_IPV4;
                } else if ((foundIp = inet_pton(AF_INET6, ipBuf, candidateIpAddr.address) == 1 ? TRUE : FALSE)) {
                    candidateIpAddr.family = KVS_IP_FAMILY_TYPE_IPV6;
                }
                CHK(foundIp, STATUS_ICE_CANDIDATE_STRING_MISSING_IP);
                break;
            case SDP_ICE_CANDIDATE_PARSER_STATE_PORT:
                CHK_STATUS(STRTOUI32(curr, curr + tokenLen, 10, &portValue));
                candidateIpAddr.port = htons(portValue);
                break;
            case SDP_ICE_CANDIDATE_PARSER_STATE_TYPE_ID:
                if (STRNCMPI("typ", curr, tokenLen) != 0) {
                    DLOGE("Can not find candidate typ.");
                    CHK(FALSE, STATUS_ICE_CANDIDATE_STRING_MISSING_TYPE);
                }
                break;
            case SDP_ICE_CANDIDATE_PARSER_STATE_TYPE_VAL:
                if (STRNCMPI("host", curr, tokenLen) == 0) {
                    iceCandidateType = ICE_CANDIDATE_TYPE_HOST;
                } else if (STRNCMPI("srflx", curr, tokenLen) == 0) {
                    iceCandidateType = ICE_CANDIDATE_TYPE_SERVER_REFLEXIVE;
                } else if (STRNCMPI("prflx", curr, tokenLen) == 0) {
                    iceCandidateType = ICE_CANDIDATE_TYPE_PEER_REFLEXIVE;
                } else if (STRNCMPI("relay", curr, tokenLen) == 0) {
                    iceCandidateType = ICE_CANDIDATE_TYPE_RELAYED;
                } else {
                    DLOGW("unknown candidate type.");
                }
                foundType = TRUE;
                break;
            default:
                DLOGW("supposedly does not happen.");
                break;
        }
        state++;
        curr = next + 1;
    }

    CHK(foundIp, STATUS_ICE_CANDIDATE_STRING_MISSING_IP);

    CHK_STATUS(findCandidateWithIp(&candidateIpAddr, pIceAgent->remoteCandidates, &pDuplicatedIceCandidate));
    CHK(pDuplicatedIceCandidate == NULL, retStatus);

    CHK((pIceCandidate = MEMCALLOC(1, SIZEOF(IceCandidate))) != NULL, STATUS_NOT_ENOUGH_MEMORY);
    generateJSONSafeString(pIceCandidate->id, ARRAY_SIZE(pIceCandidate->id));
    pIceCandidate->isRemote = TRUE;
    pIceCandidate->ipAddress = candidateIpAddr;
    pIceCandidate->state = ICE_CANDIDATE_STATE_VALID;
    pIceCandidate->priority = priority;
    pIceCandidate->iceCandidateType = iceCandidateType;
    pIceCandidate->remoteProtocol = remoteProtocol;

    CHK_STATUS(doubleListInsertItemHead(pIceAgent->remoteCandidates, (UINT64) pIceCandidate));
    freeIceCandidateIfFail = FALSE;

    CHK_STATUS(createIceCandidatePairs(pIceAgent, pIceCandidate, TRUE));
    iceAgentLogNewCandidate(pIceCandidate);

    /* pass remote candidate to each turnConnection */
    CHK_STATUS(doubleListGetHeadNode(pIceAgent->localCandidates, &pCurNode));
    while (pCurNode != NULL) {
        pLocalIceCandidate = (PIceCandidate) pCurNode->data;
        pCurNode = pCurNode->pNext;

        if (pLocalIceCandidate->iceCandidateType == ICE_CANDIDATE_TYPE_RELAYED) {
            CHK_STATUS(turnConnectionAddPeer(pLocalIceCandidate->pTurnConnection, &pIceCandidate->ipAddress));
        }
    }

CleanUp:
    if (locked) {
        MUTEX_UNLOCK(pIceAgent->lock);
    }

    if (STATUS_FAILED(retStatus) && freeIceCandidateIfFail) {
        SAFE_MEMFREE(pIceCandidate);
    }

    CHK_LOG_ERR(retStatus);

    LEAVES();
    return retStatus;
}