void ILibWrapper_WebRTC_ConnectionFactory_SetTurnServer(ILibWrapper_WebRTC_ConnectionFactory factory, struct sockaddr_in6* turnServer, char* username, int usernameLength, char* password, int passwordLength, ILibWebRTC_TURN_ConnectFlags turnSetting) { ILibWrapper_WebRTC_ConnectionFactoryStruct *cf = (ILibWrapper_WebRTC_ConnectionFactoryStruct*)factory; cf->mTurnSetting = turnSetting; if(turnServer != NULL) {memcpy(&(cf->mTurnServer), turnServer, INET_SOCKADDR_LENGTH(turnServer->sin6_family));} if(cf->mTurnServerUsername!=NULL) {free(cf->mTurnServerUsername);cf->mTurnServerUsername = NULL;} if(cf->mTurnServerPassword!=NULL) {free(cf->mTurnServerPassword);cf->mTurnServerPassword = NULL;} if(turnSetting == ILibWebRTC_TURN_DISABLED) { ILibWebRTC_SetTurnServer(cf->mStunModule, NULL, NULL, 0, NULL, 0, ILibWebRTC_TURN_DISABLED); } else { if((cf->mTurnServerUsername = (char*)malloc(usernameLength))==NULL){ILIBCRITICALEXIT(254);} cf->mTurnServerUsernameLen = usernameLength; memcpy(cf->mTurnServerUsername, username, usernameLength); if((cf->mTurnServerPassword = (char*)malloc(passwordLength))==NULL){ILIBCRITICALEXIT(254);} cf->mTurnServerPasswordLen = passwordLength; memcpy(cf->mTurnServerPassword, password, passwordLength); ILibWebRTC_SetTurnServer(cf->mStunModule, turnServer, username, usernameLength, password, passwordLength, turnSetting); } }
int ILibWrapper_WebRTC_OnDataChannel(void *StunModule, void* WebRTCModule, unsigned short StreamId, char* ChannelName, int ChannelNameLength) { ILibWrapper_WebRTC_ConnectionStruct *obj = (ILibWrapper_WebRTC_ConnectionStruct*) ILibWebRTC_GetUserObjectFromDtlsSession(WebRTCModule); ILibWrapper_WebRTC_DataChannel* dataChannel = NULL; ILibSparseArray_Lock(obj->DataChannels); if((dataChannel = (ILibWrapper_WebRTC_DataChannel*)ILibSparseArray_Get(obj->DataChannels, (int)StreamId))==NULL) { if((dataChannel = (ILibWrapper_WebRTC_DataChannel*)malloc(sizeof(ILibWrapper_WebRTC_DataChannel)))==NULL){ILIBCRITICALEXIT(254);} memset(dataChannel, 0, sizeof(ILibWrapper_WebRTC_DataChannel)); dataChannel->parent = obj; dataChannel->streamId = StreamId; if((dataChannel->channelName = (char*)malloc(ChannelNameLength+1))==NULL){ILIBCRITICALEXIT(254);} ChannelName[ChannelNameLength] = 0; dataChannel->channelName[ChannelNameLength] = 0; memcpy(dataChannel->channelName, ChannelName, ChannelNameLength); ILibSparseArray_Add(obj->DataChannels, (int)StreamId, dataChannel); ILibWrapper_InitializeDataChannel_Transport(dataChannel); } ILibSparseArray_UnLock(obj->DataChannels); if(obj->OnDataChannel!=NULL) { obj->OnDataChannel(obj, dataChannel); } return(0); // We always return 0, becuase we want the default ACK behavior that is handled underneath }
char* ILibWrapper_ReadString(char* buffer, int offset, int length) { char* retVal; if((retVal = (char*)malloc(length+1)) == NULL) {ILIBCRITICALEXIT(254);} memcpy(retVal, buffer+offset, length); retVal[length] = 0; return(retVal); }
__declspec(dllexport) void* ILibWrapper_SockAddr_FromBytes(char* buffer, int offset, int length) { struct sockaddr_in6* retVal = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6)); if(retVal==NULL){ILIBCRITICALEXIT(254);} memset(retVal, 0, sizeof(struct sockaddr_in6)); memcpy(retVal, buffer+offset, length); return(retVal); }
__declspec(dllexport) void* ILibWrapper_SockAddr_FromString6(char* buffer, unsigned short port) { struct sockaddr_in6* retVal = (struct sockaddr_in6*)malloc(sizeof(struct sockaddr_in6)); if(retVal==NULL){ILIBCRITICALEXIT(254);} memset(retVal,0,sizeof(struct sockaddr_in6)); retVal->sin6_family = AF_INET6; retVal->sin6_port = htons(port); ILibInet_pton(AF_INET6, buffer, &(retVal->sin6_addr)); return(retVal); }
ILibWrapper_WebRTC_DataChannel* ILibWrapper_WebRTC_DataChannel_CreateEx(ILibWrapper_WebRTC_Connection connection, char* channelName, int channelNameLen, unsigned short streamId, ILibWrapper_WebRTC_DataChannel_OnDataChannelAck OnAckHandler) { ILibWrapper_WebRTC_DataChannel *retVal = (ILibWrapper_WebRTC_DataChannel*)malloc(sizeof(ILibWrapper_WebRTC_DataChannel)); if(retVal==NULL){ILIBCRITICALEXIT(254);} memset(retVal, 0, sizeof(ILibWrapper_WebRTC_DataChannel)); retVal->parent = connection; if((retVal->channelName = (char*)malloc(channelNameLen+1))==NULL){ILIBCRITICALEXIT(254);} memcpy(retVal->channelName, channelName, channelNameLen); retVal->channelName[channelNameLen] = 0; retVal->streamId = streamId; retVal->OnAck = OnAckHandler; ILibSparseArray_Lock(((ILibWrapper_WebRTC_ConnectionStruct*)connection)->DataChannels); ILibSparseArray_Add(((ILibWrapper_WebRTC_ConnectionStruct*)connection)->DataChannels, retVal->streamId, retVal); ILibSparseArray_UnLock(((ILibWrapper_WebRTC_ConnectionStruct*)connection)->DataChannels); ILibWrapper_InitializeDataChannel_Transport(retVal); ILibWebRTC_OpenDataChannel(((ILibWrapper_WebRTC_ConnectionStruct*)connection)->dtlsSession, streamId, channelName, channelNameLen); return(retVal); }
void ILibWrapper_WebRTC_Connection_SetStunServers(ILibWrapper_WebRTC_Connection connection, char** serverList, int serverLength) { ILibWrapper_WebRTC_ConnectionStruct *obj = (ILibWrapper_WebRTC_ConnectionStruct*) connection; int i; if(serverLength<=0){return;} if((obj->stunServerFlags = (char*)malloc(serverLength))==NULL){ILIBCRITICALEXIT(254);} memset(obj->stunServerFlags, 0, serverLength); obj->stunServerList = (char**)malloc(serverLength * sizeof(char*)); obj->stunServerListLength = serverLength; for(i=0;i<serverLength;++i) { int sz = strlen(serverList[i]); obj->stunServerList[i] = (char*)malloc(sz+1); (obj->stunServerList[i])[sz] = 0; memcpy(obj->stunServerList[i], serverList[i], sz); } }
ILibWrapper_WebRTC_ConnectionFactory ILibWrapper_WebRTC_ConnectionFactory_CreateConnectionFactory(void* chain, unsigned short localPort) { ILibWrapper_WebRTC_ConnectionFactoryStruct *retVal = (ILibWrapper_WebRTC_ConnectionFactoryStruct*)malloc(sizeof(ILibWrapper_WebRTC_ConnectionFactoryStruct)); if(retVal==NULL){ILIBCRITICALEXIT(254);} memset(retVal, 0, sizeof(ILibWrapper_WebRTC_ConnectionFactoryStruct)); ILibAddToChain(chain, retVal); retVal->Destroy = &ILibWrapper_WebRTC_ConnectionFactory_OnDestroy; ILibWrapper_WebRTC_InitializeCrypto(retVal); retVal->mStunModule = ILibStunClient_Start(chain, localPort, &ILibWrapper_WebRTC_OnStunResult); ILibStunClient_SetOptions(retVal->mStunModule, retVal->ctx, retVal->tlsServerCertThumbprint); ILibSCTP_SetCallbacks(retVal->mStunModule, &ILibWrapper_WebRTC_OnConnectSink, &ILibWrapper_WebRTC_OnDataSink, &ILibWrapper_WebRTC_OnSendOKSink); ILibWebRTC_SetCallbacks(retVal->mStunModule, &ILibWrapper_WebRTC_OnDataChannel, &ILibWrapper_WebRTC_OnDataChannelClosed, &ILibWrapper_WebRTC_OnDataChannelAck, &ILibWrapper_WebRTC_OnOfferUpdated); retVal->Connections = ILibSparseArray_Create(ILibWrapper_WebRTC_ConnectionFactory_ConnectionBucketSize, &ILibWrapper_WebRTC_ConnectionFactory_Bucketizer); retVal->mChain = chain; return(retVal); }
ILibWrapper_WebRTC_Connection ILibWrapper_WebRTC_ConnectionFactory_CreateConnection(ILibWrapper_WebRTC_ConnectionFactory factory, ILibWrapper_WebRTC_Connection_OnConnect OnConnectHandler, ILibWrapper_WebRTC_Connection_OnDataChannel OnDataChannelHandler, ILibWrapper_WebRTC_Connection_OnSendOK OnConnectionSendOK) { ILibWrapper_WebRTC_ConnectionStruct *retVal = (ILibWrapper_WebRTC_ConnectionStruct*)malloc(sizeof(ILibWrapper_WebRTC_ConnectionStruct)); if(retVal==NULL){ILIBCRITICALEXIT(254);} memset(retVal, 0, sizeof(ILibWrapper_WebRTC_ConnectionStruct)); retVal->OnConnected = OnConnectHandler; retVal->OnDataChannel = OnDataChannelHandler; retVal->OnSendOK = OnConnectionSendOK; retVal->mFactory = (ILibWrapper_WebRTC_ConnectionFactoryStruct*)factory; ILibSparseArray_Lock(retVal->mFactory->Connections); retVal->id = (retVal->mFactory->NextConnectionID)++; ILibSparseArray_Add(retVal->mFactory->Connections, retVal->id, retVal); ILibSparseArray_UnLock(retVal->mFactory->Connections); retVal->DataChannels = ILibSparseArray_Create(ILibWrapper_WebRTC_Connection_DataChannelsBucketSize, &ILibWrapper_WebRTC_Connection_DataChannelBucketizer); return(retVal); }
// // Chain PostSelect handler // // <param name="socketModule"></param> // <param name="slct"></param> // <param name="readset"></param> // <param name="writeset"></param> // <param name="errorset"></param> void ILibAsyncServerSocket_PostSelect(void* socketModule, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset) { struct ILibAsyncServerSocket_Data *data; struct sockaddr_in6 addr; //struct sockaddr_in6 receivingAddress; #ifdef _POSIX socklen_t addrlen; //socklen_t receivingAddressLength = sizeof(struct sockaddr_in6); #else int addrlen; //int receivingAddressLength = sizeof(struct sockaddr_in6); #endif struct ILibAsyncServerSocketModule *module = (struct ILibAsyncServerSocketModule*)socketModule; int i,flags; #ifdef _WIN32_WCE SOCKET NewSocket; #elif WIN32 SOCKET NewSocket; #elif defined( _POSIX) int NewSocket; #endif UNREFERENCED_PARAMETER( slct ); UNREFERENCED_PARAMETER( writeset ); UNREFERENCED_PARAMETER( errorset ); if (FD_ISSET(module->ListenSocket, readset) != 0) { // // There are pending TCP connection requests // for(i = 0; i < module->MaxConnection; ++i) { // // Check to see if we have available resources to handle this connection request // if (ILibAsyncSocket_IsFree(module->AsyncSockets[i]) != 0) { addrlen = sizeof(addr); NewSocket = accept(module->ListenSocket, (struct sockaddr*)&addr, &addrlen); //printf("Accept NewSocket=%d\r\n", NewSocket); // This code rejects connections that are from out-of-scope addresses (Outside the subnet, outside local host...) // It needs to be updated to IPv6. /* if (NewSocket != ~0) { switch(module->scope) { case ILibServerScope_LocalLoopback: // Check that the caller ip address is the same as the receive IP address getsockname(NewSocket, (struct sockaddr*)&receivingAddress, &receivingAddressLength); if (((struct sockaddr_in*)&receivingAddress)->sin_addr.s_addr != ((struct sockaddr_in*)&addr)->sin_addr.s_addr) // TODO: NOT IPv6 COMPILANT!!!!!!!!!!!!!!!!!!!!!!!! { #if defined(WIN32) || defined(_WIN32_WCE) closesocket(NewSocket); #else close(NewSocket); #endif NewSocket = ~0; } break; case ILibServerScope_LocalSegment: getsockname(NewSocket, (struct sockaddr*)&receivingAddress, &receivingAddressLength); break; default: break; } } */ if (NewSocket != ~0) { //printf("Accepting new connection, socket = %d\r\n", NewSocket); // // Set this new socket to non-blocking mode, so we can play nice and share thread // #ifdef _WIN32_WCE flags = 1; ioctlsocket(NewSocket ,FIONBIO, &flags); #elif WIN32 flags = 1; ioctlsocket(NewSocket, FIONBIO, (u_long *)(&flags)); #elif _POSIX flags = fcntl(NewSocket, F_GETFL,0); fcntl(NewSocket, F_SETFL, O_NONBLOCK|flags); #endif // // Instantiate a module to contain all the data about this connection // if ((data = (struct ILibAsyncServerSocket_Data*)malloc(sizeof(struct ILibAsyncServerSocket_Data))) == NULL) ILIBCRITICALEXIT(254); memset(data, 0, sizeof(struct ILibAsyncServerSocket_Data)); data->module = socketModule; ILibAsyncSocket_UseThisSocket(module->AsyncSockets[i], &NewSocket, &ILibAsyncServerSocket_OnInterruptSink, data); ILibAsyncSocket_SetRemoteAddress(module->AsyncSockets[i], (struct sockaddr*)&addr); #ifndef MICROSTACK_NOTLS if (module->ssl_ctx != NULL) { // Accept a new TLS connection ILibAsyncSocket_SetSSLContext(module->AsyncSockets[i], module->ssl_ctx, 1); } else #endif if (module->OnConnect != NULL) { // Notify the user about this new connection module->OnConnect(module, module->AsyncSockets[i], &(data->user)); } } else {break;} } } } }
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); }
int ILibWrapper_SdpToBlock(char* sdp, int sdpLen, int *isActive, char **username, char **password, char **block) { struct parser_result *pr; struct parser_result_field *f; int ptr; int blockLen; void* candidates = NULL; char* lines; char* dtlshash = NULL; int dtlsHashLen = 0; int candidatecount = 0; int BlockFlags = 0; *isActive = 0; *username = NULL; *password = NULL; ILibCreateStack(&candidates); lines = ILibString_Replace(sdp, sdpLen, "\n", 1, "\r", 1); pr = ILibParseString(lines, 0, sdpLen, "\r", 1); f = pr->FirstResult; while(f!=NULL) { if(f->datalength == 0) { f = f->NextResult; continue; } f->data[f->datalength] = 0; if(strcmp(f->data, "a=setup:passive")==0) { BlockFlags |= ILibWebRTC_SDP_Flags_DTLS_SERVER; } else if(strcmp(f->data, "a=setup:active")==0 || strcmp(f->data, "a=setup:actpass")==0) { *isActive = 1; } if(f->datalength > 12 && strncmp(f->data, "a=ice-ufrag:", 12)==0) {*username = f->data + 12;} if(f->datalength > 10 && strncmp(f->data, "a=ice-pwd:", 10)==0) {*password = f->data + 10;} if(f->datalength > 22 && strncmp(f->data, "a=fingerprint:sha-256 ", 22)==0) { char* tmp = ILibString_Replace(f->data + 22, f->datalength - 22, ":", 1, "", 0); dtlsHashLen = util_hexToBuf(tmp, strlen(tmp), tmp); dtlshash = tmp; } if(f->datalength > 12 && strncmp(f->data, "a=candidate:", 12)==0) { struct parser_result* pr2 = ILibParseString(f->data, 0, f->datalength, " ", 1); if(pr2->FirstResult->NextResult->datalength == 1 && pr2->FirstResult->NextResult->data[0] == '1' && pr2->FirstResult->NextResult->NextResult->datalength == 3 && strncasecmp(pr2->FirstResult->NextResult->NextResult->data, "UDP", 3)==0) //if(pr2->FirstResult->NextResult->NextResult->datalength == 3 && strncasecmp(pr2->FirstResult->NextResult->NextResult->data, "UDP", 3)==0) { char* candidateData; struct parser_result *pr3; char *tmp = pr2->FirstResult->NextResult->NextResult->NextResult->NextResult->NextResult->data; unsigned short port; tmp[pr2->FirstResult->NextResult->NextResult->NextResult->NextResult->NextResult->datalength] = 0; port = atoi(tmp); pr3 = ILibParseString(pr2->FirstResult->NextResult->NextResult->NextResult->NextResult->data, 0, pr2->FirstResult->NextResult->NextResult->NextResult->NextResult->datalength, ".", 1); if (pr3->NumResults == 4) { candidateData = pr3->FirstResult->data; pr3->FirstResult->data[pr3->FirstResult->datalength] = 0; candidateData[0] = (char)atoi(pr3->FirstResult->data); pr3->FirstResult->NextResult->data[pr3->FirstResult->NextResult->datalength] = 0; candidateData[1] = (char)atoi(pr3->FirstResult->NextResult->data); pr3->FirstResult->NextResult->NextResult->data[pr3->FirstResult->NextResult->NextResult->datalength] = 0; candidateData[2] = (char)atoi(pr3->FirstResult->NextResult->NextResult->data); pr3->FirstResult->NextResult->NextResult->NextResult->data[pr3->FirstResult->NextResult->NextResult->NextResult->datalength] = 0; candidateData[3] = (char)atoi(pr3->FirstResult->NextResult->NextResult->NextResult->data); ((unsigned short*)candidateData)[2] = htons(port); candidateData[6] = 0; ILibPushStack(&candidates, candidateData); ++candidatecount; } ILibDestructParserResults(pr3); } ILibDestructParserResults(pr2); } f = f->NextResult; } if (*username == NULL || *password == NULL || dtlshash == NULL || candidatecount == 0) { *block = NULL; return(0); } blockLen = 6 + strlen(*username)+1 + strlen(*password)+1 + dtlsHashLen + 1 + (candidatecount*6)+1; if((*block = (char*)malloc(blockLen))==NULL){ILIBCRITICALEXIT(254);} ptr = 0; ((unsigned short*)*block+ptr)[0] = htons(1); ptr += 2; ((unsigned int*)(*block+ptr))[0] = htonl(BlockFlags); ptr += 4; (*block)[ptr] = (char)strlen(*username); ptr += 1; memcpy(*block+ptr, *username, strlen(*username)); ptr += strlen(*username); (*block)[ptr] = (char)strlen(*password); ptr += 1; memcpy(*block+ptr, *password, strlen(*password)); ptr += strlen(*password); (*block)[ptr] = (char)dtlsHashLen; ptr += 1; memcpy(*block+ptr, dtlshash, dtlsHashLen); ptr += dtlsHashLen; (*block)[ptr] = (char)candidatecount; ptr += 1; while(ILibPeekStack(&candidates)!=NULL) { memcpy(*block+ptr, ILibPopStack(&candidates), 6); ptr += 6; } ILibDestructParserResults(pr); free(lines); if(dtlshash!=NULL) {free(dtlshash);} return(ptr); }