예제 #1
0
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);
	}
}
예제 #2
0
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
}
예제 #3
0
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);
}
예제 #4
0
	__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);
	}
예제 #5
0
	__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);
	}
예제 #6
0
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);
}
예제 #7
0
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);
	}
}
예제 #8
0
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); 
}
예제 #9
0
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;}
			}
		}
	}
}
예제 #11
0
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);
}
예제 #12
0
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);
}