⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rvmegacostack.c

📁 h.248协议源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/******************************************************************************
Filename:    rvmegacostack.c
Description: megaco stack class
*******************************************************************************
                Copyright (c) 2000 RADVision Inc.
*******************************************************************************
NOTICE:
This document contains information that is proprietary to RADVision Inc.
No part of this publication may be reproduced in any form whatsoever without
written prior approval by RADVision Inc.

RADVision Inc. reserves the right to revise this publication and make changes
without obligation to notify any person of such revisions or changes.
******************************************************************************/

#include "rvmegacostack.h"
#include "rvmegacoentity.h"
#include "rvmegacoauth.h"
#include "rvmegacoencode.h"
#include "rvmegacoerrors.h"
#include "rvtpkt.h"
#include "rvstr.h"
#include "rvlog.h"
#include "rvdefalloc.h"

#define RV_MEGACOSTACK_SENDDELAY_MIN        0
#define RV_MEGACOSTACK_SENDDELAY_DEFAULT   50
#define RV_MEGACOSTACK_SENDDELAY_MAX     1000
#define RV_MEGACOSTACK_INITRETRANSTIMEOUT_MIN     ((RvHrtime)  100 * RV_TIME_NSECPERMSEC)
#define RV_MEGACOSTACK_INITRETRANSTIMEOUT_DEFAULT ((RvHrtime) 2000 * RV_TIME_NSECPERMSEC)
#define RV_MEGACOSTACK_INITRETRANSTIMEOUT_MAX     ((RvHrtime)20000 * RV_TIME_NSECPERMSEC)
#define RV_MEGACOSTACK_MINRETRANSTIMEOUT_MIN     ((RvHrtime)   1 * RV_TIME_NSECPERMSEC)
#define RV_MEGACOSTACK_MINRETRANSTIMEOUT_DEFAULT ((RvHrtime) 100 * RV_TIME_NSECPERMSEC)
#define RV_MEGACOSTACK_MINRETRANSTIMEOUT_MAX     ((RvHrtime)1000 * RV_TIME_NSECPERMSEC)
#define RV_MEGACOSTACK_MAXRETRANSTIMEOUT_MIN     ((RvHrtime) 1 * RV_TIME_NSECPERSEC)
#define RV_MEGACOSTACK_MAXRETRANSTIMEOUT_DEFAULT ((RvHrtime) 8 * RV_TIME_NSECPERSEC)
#define RV_MEGACOSTACK_MAXRETRANSTIMEOUT_MAX     ((RvHrtime)20 * RV_TIME_NSECPERSEC)
#define RV_MEGACOSTACK_TMAX_MIN     ((RvHrtime)10 * RV_TIME_NSECPERSEC)
#define RV_MEGACOSTACK_TMAX_DEFAULT ((RvHrtime)30 * RV_TIME_NSECPERSEC)
#define RV_MEGACOSTACK_TMAX_MAX     ((RvHrtime)60 * RV_TIME_NSECPERSEC)
#define RV_MEGACOSTACK_MAXPACKET_DEFAULT 1400
#define RV_MEGACOSTACK_RECVBUFSIZE 2048
#define RV_MEGACOSTACK_IPHEADERLENGTH 10


static void rvMemToHexStr(char *dest, const void *src, size_t len)
{
	static const char *digs = "0123456789ABCDEF";
	const unsigned char *p = (const unsigned char *)src;
	const unsigned char *end = p + len;
	while(p < end)
	{
		*dest++ = digs[*p >> 4];
		*dest++ = digs[*p++ & 0x0F];
	}
	*dest = 0;
}


static void addIpHeader(char *hdr, const RvIpv4Addr *srcIp, const RvIpv4Addr *destIp, RvInetPort destPort)
{
	*(RvIpv4Addr *)hdr = *srcIp;
	*(RvIpv4Addr *)(hdr + sizeof(RvIpv4Addr)) = *destIp;
	hdr[2 * sizeof(RvIpv4Addr)] = destPort >> 8;
	hdr[2 * sizeof(RvIpv4Addr) + 1] = (char)destPort;
}


static void addIpHeaderTcp(char *hdr, RvSocket *socket, RvBool isSending)
{
	RvSocketAddr localAddr, remoteAddr;
	rvSocketAddrConstruct(&localAddr);
	rvSocketAddrConstruct(&remoteAddr);
	rvSocketGetLocalAddr(socket, &localAddr);
	rvSocketGetRemoteAddr(socket, &remoteAddr);
	if(isSending)
		addIpHeader(hdr, rvSocketAddrGetIpv4Addr(&localAddr), 
			rvSocketAddrGetIpv4Addr(&remoteAddr), rvSocketAddrGetInetPort(&remoteAddr));
	else
		addIpHeader(hdr, rvSocketAddrGetIpv4Addr(&remoteAddr), 
			rvSocketAddrGetIpv4Addr(&localAddr), rvSocketAddrGetInetPort(&localAddr));
	rvSocketAddrDestruct(&localAddr);
	rvSocketAddrDestruct(&remoteAddr);
}


RvBool rvMegacoStackSendMessage(RvMegacoStack *stack, RvStrStream *msgStream,
	RvSocket *socket, const RvSocketAddr *destAddr,	RvTransportType transportType)
{
	/* The stream must contain a buffer of length RV_MEGACOENTITY_SENDBUFHDRSIZE in front of the message to send.
	The buffer will first be used to hold the IP header required for authentication, then eventually
	it will hold the authentication header and the TPKT header. */

	const char *key;
	RvBool doAuthenticate;
	RvBool sendSuccessful = rvFalse;

	/* message must be null terminated, but don't count null terminator in length */
	char *message = rvStrStreamGetStr(msgStream) + RV_MEGACOENTITY_SENDBUFHDRSIZE;
	size_t length = rvStrStreamGetSize(msgStream) - RV_MEGACOENTITY_SENDBUFHDRSIZE - 1;  

	if(stack->rawSendCb != NULL)
	{
		if(!stack->rawSendCb(stack, message, length, stack->rawSendData))
			return rvFalse;
		length = strlen(message); /* length may have changed */
	}

	rvLogSend(&rvLog, message);

	doAuthenticate = stack->authenticate != NULL && stack->getKey != NULL &&
		(key = stack->getKey(destAddr, transportType, stack->getKeyData)) != NULL;
	
	if(doAuthenticate)
	{
		RvMegacoAuthenticationHeader ah;
		RvStrStream ahStream;
		size_t hashStrLength = 2 * stack->hashLength + 1; /* 2 hex digits per byte plus null terminator */
		char *hash = (char *)rvAllocAllocate(stack->genAlloc, stack->hashLength);
		char *hashStr = (char *)rvAllocAllocate(stack->genAlloc, hashStrLength);
		char *ipHeader = message - RV_MEGACOSTACK_IPHEADERLENGTH;
		size_t ahSize;

		if(transportType == RV_TRANSPORTTYPE_TCP)
		{
			addIpHeaderTcp(ipHeader, socket, rvTrue);
		}
		else
		{
			RvSocketAddr srcAddr;
			rvSocketAddrConstruct(&srcAddr);
			rvSocketGetLocalAddr(socket, &srcAddr);
			addIpHeader(ipHeader, rvSocketAddrGetIpv4Addr(&srcAddr), 
				rvSocketAddrGetIpv4Addr(destAddr), rvSocketAddrGetInetPort(destAddr));
			rvSocketAddrDestruct(&srcAddr);
		}

		stack->authenticate(ipHeader, length + RV_MEGACOSTACK_IPHEADERLENGTH, key, strlen(key), hash);
		rvMemToHexStr(hashStr, hash, stack->hashLength);

		rvStrStreamConstruct(&ahStream, RV_MEGACOENTITY_SENDBUFHDRSIZE + 1, stack->sendBufAlloc);
		rvMegacoAuthenticationHeaderConstruct(&ah, 0, 0, hashStr);
		rvMegacoAuthenticationHeaderEncode(&ah, &ahStream, stack->encodeCompact);

		ahSize = rvStrStreamGetSize(&ahStream);
		message -= ahSize;
		length += ahSize;
		memcpy(message, rvStrStreamGetStr(&ahStream), ahSize);

		rvMegacoAuthenticationHeaderDestruct(&ah);	
		rvStrStreamDestruct(&ahStream);

		rvAllocDeallocate(stack->genAlloc, hashStrLength, hashStr);
		rvAllocDeallocate(stack->genAlloc, stack->hashLength, hash);
	}

	if(transportType == RV_TRANSPORTTYPE_TCP)
	{
		RvTpkt *tpkt = (RvTpkt *)(message - sizeof(RvTpkt));
		rvTpktConstruct(tpkt, length);
		sendSuccessful = rvSocketSend(socket, tpkt, sizeof(RvTpkt) + length);
		rvTpktDestruct(&tpkt);
	}
	else if(transportType == RV_TRANSPORTTYPE_UDP)
	{
		sendSuccessful = rvSocketSendTo(socket, message, length, destAddr);
	}
	
	return sendSuccessful;
}


static void rvMegacoEntitySendError(RvMegacoEntity *local,
	RvMegacoErrorDescriptor *error,	RvSocket *socket, const RvSocketAddr *destAddr)
{
	RvMegacoStack *stack = local->stack;
	RvStrStream msgStream;

	rvStrStreamConstruct(&msgStream, RV_MEGACOENTITY_ENCODEBUFINITSIZE, stack->sendBufAlloc);
	rvStrStreamSeekOffCur(&msgStream, RV_MEGACOENTITY_SENDBUFHDRSIZE);

	rvMegacoMessageHeaderEncode(rvMegacoEntityGetAddress(local), rvMegacoVersion, &msgStream, stack->encodeCompact);
	rvMegacoErrorEncode(error, &msgStream, stack->encodeCompact);
	rvStrStreamEnds(&msgStream);

	rvMegacoStackSendMessage(stack, &msgStream, socket, destAddr, rvMegacoEntityGetTransportType(local));
	
	rvStrStreamDestruct(&msgStream);
}


static RvBool rvMegacoStackAuthenticateMessage(RvMegacoStack *stack, RvMegacoAuthenticationHeader *ah,
	const char *message, RvSocket *socket, const RvSocketAddr *fromAddr, RvTransportType transportType)
{
	const char *key;
	size_t msgLength, dataLength, hashStrLength;
	char *buf, *hash, *hashStr;
	RvBool authentic;

	if(stack->authenticate == NULL || stack->getKey == NULL)
		return rvTrue; /* authentication not enabled for this stack */

	if((key = stack->getKey(fromAddr, transportType, stack->getKeyData)) == NULL)
		return rvTrue; /* authentication not required for this address */

	if(ah == NULL)
		return rvFalse; /* authentication required but missing */

	if(rvMegacoAuthenticationHeaderGetDataLength(ah) != 2 * stack->hashLength)
		return rvFalse; /* authentication data is not the correct length */

	msgLength = strlen(message);
	dataLength = msgLength + RV_MEGACOSTACK_IPHEADERLENGTH;
	hashStrLength = 2 * stack->hashLength + 1; /* 2 hex digits per byte plus null terminator */
	buf = (char *)rvAllocAllocate(stack->genAlloc, dataLength);
	hash = (char *)rvAllocAllocate(stack->genAlloc, stack->hashLength);
	hashStr = (char *)rvAllocAllocate(stack->genAlloc, hashStrLength); 

	if(transportType == RV_TRANSPORTTYPE_TCP)
	{
		addIpHeaderTcp(buf, socket, rvFalse);
	}
	else
	{
		RvSocketAddr destAddr;
		rvSocketAddrConstruct(&destAddr);
		rvSocketGetLocalAddr(socket, &destAddr);
		addIpHeader(buf, rvSocketAddrGetIpv4Addr(fromAddr), 
			rvSocketAddrGetIpv4Addr(&destAddr), rvSocketAddrGetInetPort(&destAddr));
		rvSocketAddrDestruct(&destAddr);
	}

	memcpy(buf + RV_MEGACOSTACK_IPHEADERLENGTH, message, msgLength);
	stack->authenticate(buf, dataLength, key, strlen(key), hash);
	rvMemToHexStr(hashStr, hash, stack->hashLength);

	authentic = rvStrIcmp(hashStr, rvMegacoAuthenticationHeaderGetData(ah)) == 0;
	
	rvAllocDeallocate(stack->genAlloc, hashStrLength, hashStr);
	rvAllocDeallocate(stack->genAlloc, stack->hashLength, hash);
	rvAllocDeallocate(stack->genAlloc, dataLength, buf);

	return authentic;
}

typedef struct
{
	RvMegacoEntity *localEntity;
	RvSocket *socket;
	RvSocketAddr *fromAddr;
	RvTransportType transportType;
	RvMegacoEntity *remoteEntity;
} RvMegacoMessageInfo;

#define rvMegacoMessageInfoConstruct(msg, loc, sock, from, transport) \
	((msg)->localEntity = (loc), (msg)->socket = (sock), (msg)->fromAddr = (from), \
	(msg)->transportType = (transport), (msg)->remoteEntity = NULL, (msg))
#define rvMegacoMessageInfoDestruct

static void rvMegacoStackProcessParserError(const RvParseError *error, const char *text, void *data)
{
	RvMegacoMessageInfo *message = (RvMegacoMessageInfo *)data;
	RvMegacoEntity *localEntity = message->localEntity;
	RvMegacoStack *stack = localEntity->stack;
	RvStrStream errmsg;
	RvMegacoErrorDescriptor errdescr;

	stack->parseErrors++;

	rvLogError(&rvLog, rvParseErrorGetMessage(error));

	if(stack->parseErrorCb != NULL)
		stack->parseErrorCb(text, error, message->fromAddr);

	rvStrStreamConstruct(&errmsg, 60, stack->genAlloc);
	rvStrStreamWriteStr(&errmsg, "Syntax Error: Line ");
	rvStrStreamWriteUInt(&errmsg, rvParseErrorGetLine(error));
	rvStrStreamWriteStr(&errmsg, ", Column ");
	rvStrStreamWriteUInt(&errmsg, rvParseErrorGetColumn(error));
	rvStrStreamEnds(&errmsg);
	
	rvMegacoErrorDescriptorConstruct(&errdescr, RV_MEGACOERROR_PROTOCOL, rvStrStreamGetStr(&errmsg));
	rvMegacoEntitySendError(localEntity, &errdescr, message->socket, message->fromAddr);
	rvMegacoErrorDescriptorDestruct(&errdescr);
	
	rvStrStreamDestruct(&errmsg);
}

static RvBool rvMegacoStackProcessMessageHeader(const RvMegacoEntityAddress *sender, unsigned int version, void *data)
{
	RvMegacoMessageInfo *message = (RvMegacoMessageInfo *)data;
	RvMegacoEntity *localEntity = message->localEntity;
	RvMegacoStack *stack = localEntity->stack;

	message->remoteEntity = rvMegacoEntityFindRemote(localEntity, sender);

	if(message->remoteEntity != NULL && message->transportType == RV_TRANSPORTTYPE_UDP &&
		!rvSocketAddrEqual(message->fromAddr, rvMegacoEntityGetSocketAddr(message->remoteEntity)))
	{
		rvMegacoEntityRemoveRemote(localEntity, sender);
		if(message->remoteEntity->u.remote.deleteMe)
		{
			rvMegacoEntityDestruct(message->remoteEntity);
			rvAllocDeallocate(stack->entityAlloc, sizeof(RvMegacoEntity), message->remoteEntity);
		}
		message->remoteEntity = NULL;
	}

	if(message->remoteEntity == NULL)
	{
		message->remoteEntity = (RvMegacoEntity *)rvAllocAllocate(stack->entityAlloc, sizeof(RvMegacoEntity));
		if(rvMegacoEntityConstructRemoteEx(message->remoteEntity, sender, message->fromAddr, rvTrue, localEntity) == NULL)
		{
			rvAllocDeallocate(stack->entityAlloc, sizeof(RvMegacoEntity), message->remoteEntity);
			return rvFalse;
		}
		rvMegacoEntitySetDeleteFlag(message->remoteEntity);
	}

	if(!message->remoteEntity->dead)
	{
		if(message->transportType == RV_TRANSPORTTYPE_TCP)
			rvMegacoEntitySetSocket(message->remoteEntity, message->socket);
	}

	return rvTrue;
}

static void rvMegacoStackProcessRequest(const RvMegacoTransaction *request, void *data)
{
	RvMegacoEntity *remoteEntity = ((RvMegacoMessageInfo *)data)->remoteEntity;
	if(!remoteEntity->dead)
		rvMegacoTransMgrRecvRequest(remoteEntity, request);
}

static void rvMegacoStackProcessReply(const RvMegacoTransactionReply *reply, void *data)
{
	RvMegacoEntity *remoteEntity = ((RvMegacoMessageInfo *)data)->remoteEntity;
	if(!remoteEntity->dead)
		rvMegacoTransMgrRecvReply(remoteEntity,	reply);
}

static void rvMegacoStackProcessPending(RvMegacoTransactionId id, void *data)
{
	RvMegacoEntity *remoteEntity = ((RvMegacoMessageInfo *)data)->remoteEntity;
	if(!remoteEntity->dead)
		rvMegacoTransMgrRecvPending(remoteEntity, id);
}

static void rvMegacoStackProcessResponseAck(RvMegacoTransactionId lo, RvMegacoTransactionId hi, void *data)
{
	RvMegacoEntity *remoteEntity = ((RvMegacoMessageInfo *)data)->remoteEntity;
	if(!remoteEntity->dead)
	{
		while(lo <= hi)
		{
			rvMegacoTransMgrRecvRespAck(remoteEntity, lo);
			++lo;
		}
	}
}

static void rvMegacoStackProcessErrorTransaction(const RvMegacoErrorDescriptor *error, void *data)
{
	RvMegacoEntity *localEntity = ((RvMegacoMessageInfo *)data)->localEntity;
	RvMegacoEntity *remoteEntity = ((RvMegacoMessageInfo *)data)->remoteEntity;

	if(localEntity->u.local.processError != NULL)
		localEntity->u.local.processError(remoteEntity, error, localEntity->u.local.processErrorData);
}

static void rvMegacoStackProcessPackets(char *packet, size_t length, RvSocket *socket, RvSocketAddr *fromAddr, RvTransportType transportType, void *data)
{
	RvMegacoEntity *localEntity = (RvMegacoEntity *)data;
	RvMegacoStack *stack = localEntity->stack;
	RvMegacoAuthenticationHeader ah, *ahPtr;
	RvBool authenticated;

	if(localEntity->dead)
		return;

	ahPtr = rvMegacoAuthenticationHeaderConstructParse(&ah, (const char **)&packet, stack->genAlloc);
	authenticated = rvMegacoStackAuthenticateMessage(stack, ahPtr, packet, socket, fromAddr, transportType);
	if(ahPtr != NULL)
		rvMegacoAuthenticationHeaderDestruct(&ah);
	
	if(!authenticated)
	{
		stack->authenticationFailures++;
		return;
	}

	rvLogReceive(&rvLog, packet);

	if(stack->rawRecvCb != NULL && !stack->rawRecvCb(stack, packet, length, stack->rawRecvData))
		return; 

	if(rvMegacoEntityGetEncoding(localEntity) == RV_MEGACOENCODING_BINARY)
	{
		rvLogError(&rvLog, "binary parser not implemented");
		return;
	}

	{
	static const RvMegacoParserHandlers rvMegacoStackParserHandlers = 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -