// this is called for each ice candidate. if candidate is null, no additional candidates could be found. void WebRTCOnIceCandidate(ILibWrapper_WebRTC_Connection webRTCConnection, struct sockaddr_in6* candidate) { assert(webRTCConnection != NULL); void* user_data = NULL; libwebrtc_context* ctx = NULL; libwebrtc_connection* conn = (libwebrtc_connection*)webRTCConnection; ILibWrapper_WebRTC_Connection_GetUserData(webRTCConnection, (void**)&ctx, NULL, &user_data); // no additional candidates found. if( candidate == NULL ) return; char* offer = ILibWrapper_WebRTC_Connection_AddServerReflexiveCandidateToLocalSDP( webRTCConnection, candidate ); if( offer == NULL ) { ctx->callback(ctx, conn, NULL, LWRTC_CALLBACK_ERROR, user_data, NULL, 0 ); LOG("Offer failed, closing socket\n"); return; } free(offer); char address[225]; ILibInet_ntop2((struct sockaddr*)candidate, address, 255); const char* candidateFormat = "candidate:%d %d UDP %d %s %u typ host"; char buf[255] = {0}; snprintf(buf, sizeof(buf), candidateFormat, 0, 1, 2128609535-1, address, ntohs(candidate->sin6_port)); buf[sizeof(buf)-1] = 0; ctx->callback(ctx, conn, NULL, LWRTC_CALLBACK_ICE_CANDIDATE, user_data, buf, strlen(buf) ); }
char* ILibWrapper_WebRTC_Connection_AddServerReflexiveCandidateToLocalSDP(ILibWrapper_WebRTC_Connection connection, struct sockaddr_in6* candidate) { ILibWrapper_WebRTC_ConnectionStruct *obj = (ILibWrapper_WebRTC_ConnectionStruct*) connection; char *sdp; char *username; char *password; char address[255]; if(candidate!=NULL) { ILibInet_ntop2((struct sockaddr*)candidate, address, 255); ILibWrapper_BlockToSDPEx(obj->offerBlock, obj->offerBlockLen, &username, &password, &sdp, address, ntohs(candidate->sin6_port)); } else { ILibWrapper_BlockToSDPEx(obj->offerBlock, obj->offerBlockLen, &username, &password, &sdp, NULL, 0); } free(username); free(password); return(sdp); }
// // IPAddress Helper // __declspec(dllexport) char* ILibWrapper_SockAddr_GetAddressString(struct sockaddr* addr, char* buffer, int bufferLength) { return(ILibInet_ntop2(addr, buffer, bufferLength)); }
int ILibWrapper_BlockToSDPEx(char* block, int blockLen, char** username, char** password, char **sdp, char* serverReflexiveCandidateAddress, unsigned short serverReflexiveCandidatePort) { char* sdpTemplate1 = "v=0\r\no=MeshAgent %u 0 IN IP4 0.0.0.0\r\ns=SIP Call\r\nt=0 0\r\na=ice-ufrag:%s\r\na=ice-pwd:%s\r\na=fingerprint:sha-256 %s\r\nm=application 1 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\na=sctpmap:5000 webrtc-datachannel 16\r\na=setup:%s\r\n"; char* sdpTemplateRelay = "a=candidate:%d %d UDP %d %s %d typ relay raddr %u.%u.%u.%u %d\r\n"; char* sdpTemplateLocalCand = "a=candidate:%d %d UDP %d %u.%u.%u.%u %u typ host\r\n"; char* sdpTemplateSrflxCand = "a=candidate:%d %d UDP %d %s %u typ srflx raddr %u.%u.%u.%u rport %u\r\n"; int sdpLen; int c,x,i,ptr; char junk[4]; struct sockaddr_in6 *relayEndPoint = NULL; char relayAddressString[128]; unsigned short relayAddressPort = 0; // Decode the block //This value is commented out to prevent a compiler warning for unused variables, but I left it here to show how to fetch it // //short blockversion = ILibWrapper_ReadShort(block, 0); // int blockflags = ILibWrapper_ReadInt(block, 2); int isActive = (blockflags & ILibWebRTC_SDP_Flags_DTLS_SERVER) == ILibWebRTC_SDP_Flags_DTLS_SERVER ? 0:1; int usernamelen = (int)block[6]; int passwordlen = (int)block[7 + usernamelen]; int dtlshashlen = (int)block[8 + usernamelen + passwordlen]; int candidatecount = (int)block[9 + usernamelen + passwordlen + dtlshashlen]; char dtlshash[128]; int rlen = 10 + usernamelen + passwordlen + dtlshashlen + (candidatecount * 6); char* candidates = block + 10 + usernamelen + passwordlen + dtlshashlen; *username = ILibWrapper_ReadString(block, 7, usernamelen); *password = ILibWrapper_ReadString(block, 8 + usernamelen, passwordlen); util_tohex2(block + 9 + usernamelen + passwordlen, dtlshashlen, dtlshash); if (rlen < blockLen) { relayEndPoint = (struct sockaddr_in6*)(block+rlen+1); ILibInet_ntop2((struct sockaddr*)relayEndPoint, relayAddressString, 128); switch(((struct sockaddr_in*)relayEndPoint)->sin_family) { case AF_INET: relayAddressPort = ntohs(((struct sockaddr_in*)relayEndPoint)->sin_port); break; case AF_INET6: relayAddressPort = ntohs(relayEndPoint->sin6_port); break; } } // Build the sdp sdpLen = 2 + strlen(sdpTemplate1) + usernamelen + passwordlen + 7 + (dtlshashlen*3) + 7 + (2 * (candidatecount * (12 + 21 + strlen(sdpTemplateLocalCand))) ); if(serverReflexiveCandidateAddress!=NULL) { sdpLen += (2* (12 + 21 + strlen(sdpTemplateSrflxCand))); } if(relayEndPoint!=NULL) { sdpLen += (2* (12 + 21 + strlen(sdpTemplateRelay))); } if((*sdp = (char*)malloc(sdpLen))==NULL){ILIBCRITICALEXIT(254);} util_random(4, junk); x = snprintf(*sdp, sdpLen, sdpTemplate1, ((unsigned int*)junk)[0]%1000000, *username, *password, dtlshash, isActive==0?"passive":"actpass"); for(c = 1; c <= 2; ++c) { for (i = 0; i < candidatecount; i++) { ptr = i*6; x += snprintf(*sdp+x, sdpLen-x, sdpTemplateLocalCand, i, c, 2128609535-i, (unsigned char)candidates[ptr], (unsigned char)candidates[ptr+1], (unsigned char)candidates[ptr+2], (unsigned char)candidates[ptr+3], ntohs(((unsigned short*)(candidates+ptr+4))[0])); } if(serverReflexiveCandidateAddress!=NULL) { x += snprintf(*sdp+x, sdpLen-x, sdpTemplateSrflxCand, i, c, 2128609535-i, serverReflexiveCandidateAddress, serverReflexiveCandidatePort, (unsigned char)candidates[0], (unsigned char)candidates[1], (unsigned char)candidates[2], (unsigned char)candidates[3], ntohs(((unsigned short*)(candidates+4))[0])); ++i; } if(relayEndPoint!=NULL) { x += snprintf(*sdp+x, sdpLen-x, sdpTemplateRelay, i, c, 2128609535-i, relayAddressString, relayAddressPort, (unsigned char)candidates[0], (unsigned char)candidates[1], (unsigned char)candidates[2], (unsigned char)candidates[3]); } } return(x); }