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;
}