📄 rvmegacotrans.c
字号:
#if (0)
******************************************************************************
Filename :rvmegacotrans.c
Description :This file contains the structures used for the Transaction
Manager Control Blocks
******************************************************************************
Copyright (c) 2000 RADVision Inc.
************************************************************************
NOTICE:
This document contains information that is proprietary to RADVision LTD.
No part of this publication may be reproduced in any form whatsoever
without written prior approval by RADVision LTD..
RADVision LTD. reserves the right to revise this publication and make
changes without obligation to notify any person of such revisions or
changes.
******************************************************************************
$Revision:$
$Date:$
$Author:L.Amberger$
******************************************************************************
#endif
#include "rvmegacotrans.h"
#include "rvmegacoentity.h"
#include "rvmegacostack.h"
#include "rvmegacoencode.h"
#include "rvmegacoerrors.h"
#include "rvlog.h"
#define RV_MEGACOTM_DFLT_TMR_VAL 1000
#define RV_MEGACOTM_SHORTINACTIVE_TO 1
#define RV_MEGACOTM_INACTIVE_TO 30000
#define RV_MEGACOTM_PROCESSING_TO 1000
#define RV_MEGACOTM_RESPONDED_TO 30000
#define RV_MEGACOTM_CMD_TO 1000
static void rvTransMgrTimerProc(RvTimer *timer, void *data);
static void rvMegacoTcbStopNStartTimer(RvMegacoTcbPtr t, int tValue);
RvMegacoTcb *rvMegacoTcbConstruct(RvMegacoTcb *tcb,RvMegacoStack *stack, RvMegacoEntity *localEntity,RvMegacoEntity *remoteEntity, RvBool useLocal, const RvMegacoTransaction *trans)
{
rvLogEnter(&rvLog, "rvMegacoTcbConstruct");
rvMutexConstruct(&tcb->lock);
tcb->useLocal = useLocal;
tcb->tId = rvMegacoTransactionGetId(trans);
tcb->state = RV_MEGACOTCB_STATE_IDLE;
rvTimerConstruct(&tcb->Timer[0], RV_MEGACOTM_DFLT_TMR_VAL, rvTransMgrTimerProc, tcb);
rvTimerConstruct(&tcb->Timer[1], RV_MEGACOTM_DFLT_TMR_VAL, rvTransMgrTimerProc, tcb);
tcb->CurrentTimer = 0;
rvStrStreamConstruct(&tcb->encodedTransaction, RV_MEGACOTCB_ENCODEBUFINITSIZE, stack->sendBufAlloc);
tcb->stack = stack;
tcb->localEntity = localEntity;
tcb->destEntity = remoteEntity;
tcb->firstSend = rvTrue;
tcb->msgFreed= rvFalse;
tcb->replyReceived = rvFalse;
tcb->data = NULL;
tcb->SentPending = rvFalse;
tcb->EntityDestructed = rvFalse;
rvMutexLock(&stack->mutex);
stack->totalTransactions++;
stack->curTransactions++;
rvMutexUnlock(&stack->mutex);
rvLogLeave(&rvLog, "rvMegacoTcbConstruct");
return tcb;
}
/* Note: This function is ONLY called by the entity destruct function to remove TCBs */
/* IT MARKS THE ENTITY AS HAVING BEEN DESTRUCTED */
void rvMegacoTcbMarkForDestruct(RvMegacoTcb *tcbPtr,RvTransactionStatus reason)
{
rvLogEnter(&rvLog, "rvMegacoTcbMarkForDestruct");
rvMutexLock(&tcbPtr->lock);
switch (tcbPtr->state)
{
/* If the state is one that indicates this was a command that was received */
case RV_MEGACOTCB_STATE_RESP_TO_SEND:
case RV_MEGACOTCB_STATE_RESPONDED:
case RV_MEGACOTCB_STATE_RESP_SEND_FAIL:
case RV_MEGACOTCB_STATE_WAITAPPLRESPONSE:
if (tcbPtr->AckCallBack != NULL)
tcbPtr->AckCallBack(tcbPtr,tcbPtr->data, reason);
break;
/* If the state is one that indicates this was a command that was sent */
case RV_MEGACOTCB_STATE_CMD_TO_SEND:
case RV_MEGACOTCB_STATE_CMDSENT:
case RV_MEGACOTCB_STATE_CMD_SEND_FAIL:
if(tcbPtr->ReplyCallBack != NULL)
tcbPtr->ReplyCallBack(tcbPtr,NULL,tcbPtr->data,reason);
break;
}
tcbPtr->EntityDestructed = rvTrue;
tcbPtr->state = RV_MEGACOTCB_STATE_INACTIVE;
rvMegacoTcbStopNStartTimer(tcbPtr,RV_MEGACOTM_SHORTINACTIVE_TO);
rvMutexUnlock(&tcbPtr->lock);
rvLogLeave(&rvLog, "rvMegacoTcbMarkForDestruct");
}
void rvMegacoTcbDestruct(RvMegacoTcb *tcb)
{
rvLogEnter(&rvLog, "rvMegacoTcbDestruct");
rvMutexLock(&tcb->stack->mutex);
tcb->stack->curTransactions--;
rvMutexUnlock(&tcb->stack->mutex);
rvMutexDestruct(&tcb->lock);
rvTimerDestruct(&tcb->Timer[0]);
rvTimerDestruct(&tcb->Timer[1]);
if(tcb->msgFreed != rvTrue)
rvStrStreamDestruct(&tcb->encodedTransaction);
rvLogLeave(&rvLog, "rvMegacoTcbDestruct");
}
static void rvMegacoTcbStopCurrentTimer(RvMegacoTcbPtr t)
{
rvLogEnter(&rvLog, "rvMegacoTcbStopCurrentTimer");
rvTimerStop(&t->Timer[t->CurrentTimer]);
if(t->CurrentTimer == 0)
t->CurrentTimer = 1;
else
t->CurrentTimer = 0;
rvLogLeave(&rvLog, "rvMegacoTcbStopCurrentTimer");
}
static void rvMegacoTcbStopNStartTimer(RvMegacoTcbPtr t, int tValue)
{
rvLogEnter(&rvLog, "rvMegacoTcbStopNStartTimer");
rvTimerStop(&t->Timer[t->CurrentTimer]);
if(t->CurrentTimer == 0)
t->CurrentTimer = 1;
else
t->CurrentTimer = 0;
rvTimerReset(&t->Timer[t->CurrentTimer],tValue);
rvLogLeave(&rvLog, "rvMegacoTcbStopNStartTimer");
}
void rvTransMgrTimerProc(RvTimer *timer,void * data)
{
RvHrtime totalTimeInNs;
RvHrtime currTime;
RvMegacoTcb *tcbPtr = (RvMegacoTcb *)data;
RvMegacoStack *stack = tcbPtr->stack;
RvBool doUnlock = rvTrue;
RvMegacoEntity *destEntity;
rvLogEnter(&rvLog, "rvTransMgrTimerProc");
if (tcbPtr->EntityDestructed == rvFalse)
rvLogStr2(&rvLog, "tcb timer exp", rvMegacoEntityAddressGetAddress(&tcbPtr->destEntity->mId));
if (timer != &tcbPtr->Timer[tcbPtr->CurrentTimer])
return;
rvMutexLock(&tcbPtr->lock);
if (tcbPtr->EntityDestructed == rvTrue) /* If the entity was destructed then there's nothing else to do */
{
rvMutexUnlock(&tcbPtr->lock);
rvMegacoTcbDestruct(tcbPtr);
rvAllocDeallocate(stack->tcbAlloc, sizeof(RvMegacoTcb), tcbPtr);
return;
}
/* Get the entity */
destEntity = rvMegacoTcbGetRemoteEntity(tcbPtr);
rvMutexUnlock(&tcbPtr->lock);
/* Must Lock the entity first */
rvMutexLock(&destEntity->mutex);
rvMutexLock(&tcbPtr->lock);
if (rvTimerGetId(timer) != rvTimerGetId(&tcbPtr->Timer[tcbPtr->CurrentTimer]))
{ /* Ignore this timer it is not the current one! */
rvLogInt2(&rvLog, "This is not the Current TCB Timer", rvTimerGetId(timer), 10);
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
rvLogLeave(&rvLog, "rvTransMgrTimerProc");
return;
}
switch (tcbPtr->state)
{
case RV_MEGACOTCB_STATE_IDLE:
/* ignore this */
break;
case RV_MEGACOTCB_STATE_RESP_TO_SEND:
/* This shouldn't happen - ignore it */
break;
case RV_MEGACOTCB_STATE_RESPONDED:
/* Mark the block for release */
tcbPtr->state = RV_MEGACOTCB_STATE_INACTIVE;
rvTimerReset(timer,RV_MEGACOTM_INACTIVE_TO);
if (tcbPtr->AckCallBack != NULL)
{
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
doUnlock = rvFalse;
tcbPtr->AckCallBack(tcbPtr,tcbPtr->data, RVTRANSACTIONSTATUS_SENDREPLY_TIMEOUT);
}
break;
case RV_MEGACOTCB_STATE_RESP_SEND_FAIL:
tcbPtr->state = RV_MEGACOTCB_STATE_INACTIVE;
rvTimerReset(timer,RV_MEGACOTM_INACTIVE_TO);
if (tcbPtr->AckCallBack != NULL)
{
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
doUnlock = rvFalse;
tcbPtr->AckCallBack(tcbPtr,tcbPtr->data, RVTRANSACTIONSTATUS_SENDREPLY_LLFAIL);
}
break;
case RV_MEGACOTCB_STATE_WAITAPPLRESPONSE: /* The application didn't respond */
tcbPtr->state = RV_MEGACOTCB_STATE_INACTIVE;
rvTimerReset(timer,RV_MEGACOTM_INACTIVE_TO);
break;
case RV_MEGACOTCB_STATE_CMD_TO_SEND:
/* This should never happen since the timer doesn't get set until */
/* the command is actually sent */
break;
case RV_MEGACOTCB_STATE_CMDSENT:
currTime = rvTimeGetHrtime();
totalTimeInNs = rvTimeHrSubtract(currTime,tcbPtr->OrigSendTime);
if (totalTimeInNs < stack->tMax)
{
tcbPtr->firstSend = rvFalse;
tcbPtr->state = RV_MEGACOTCB_STATE_CMD_TO_SEND;
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
doUnlock = rvFalse;
rvMegacoEntitySendListInsert(tcbPtr->destEntity,tcbPtr);
}
else
{/* report an error */
tcbPtr->state = RV_MEGACOTCB_STATE_INACTIVE;
rvTimerReset(timer,RV_MEGACOTM_INACTIVE_TO);
if (tcbPtr->ReplyCallBack != NULL)
{
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
doUnlock = rvFalse;
tcbPtr->ReplyCallBack(tcbPtr,NULL,tcbPtr->data,RVTRANSACTIONSTATUS_SENDREQ_FAIL );
}
}
break;
case RV_MEGACOTCB_STATE_CMD_SEND_FAIL:
tcbPtr->state = RV_MEGACOTCB_STATE_INACTIVE;
rvTimerReset(timer,RV_MEGACOTM_INACTIVE_TO);
if (tcbPtr->ReplyCallBack != NULL)
{
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
doUnlock = rvFalse;
tcbPtr->ReplyCallBack(tcbPtr,NULL,tcbPtr->data, RVTRANSACTIONSTATUS_SENDREQ_LLFAIL );
}
break;
case RV_MEGACOTCB_STATE_INACTIVE:
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
/* release all memory associated with this TCB and then free the TCB */
if (tcbPtr->EntityDestructed == rvFalse)
{
/* only remove from hash if entity has not been destructed */
if (tcbPtr->useLocal == rvTrue)
rvMegacoEntityRemoveTcb(tcbPtr->localEntity, tcbPtr->tId);
else
rvMegacoEntityRemoveTcb(tcbPtr->destEntity, tcbPtr->tId);
}
rvMegacoTcbDestruct(tcbPtr);
rvAllocDeallocate(stack->tcbAlloc, sizeof(RvMegacoTcb), tcbPtr);
doUnlock = rvFalse;
break;
}
if( doUnlock == rvTrue)
{
rvMutexUnlock(&tcbPtr->lock);
rvMutexUnlock(&destEntity->mutex);
}
rvLogLeave(&rvLog, "rvTransMgrTimerProc");
}
void rvMegacoTransMgrRecvRequest( RvMegacoEntity *remoteEntity, const RvMegacoTransaction *trans)
{
RvMegacoTcbPtr tcbPtr;
RvMegacoErrorDescriptor errorDesc;
RvMegacoTransactionReply transReply;
RvBool alreadyUnlocked = rvFalse;
RvMegacoTransactionId tId = rvMegacoTransactionGetId(trans);
RvMegacoStack* stack = remoteEntity->stack;
RvMegacoEntity* localEntity;
rvLogEnter(&rvLog, "rvMegacoTransMgrRecvRequest");
localEntity = rvMegacoEntityGetLocalEntity(remoteEntity);
/* Find the TCB using the transaction Id */
rvMutexLock(&localEntity->mutex);
tcbPtr = rvMegacoEntityFindTcb(remoteEntity, tId);
/* Or, add it to the hash table if it's a new transaction */
if (tcbPtr == NULL)
{
tcbPtr = (RvMegacoTcb *)rvAllocAllocate(stack->tcbAlloc, sizeof(RvMegacoTcb));
rvMegacoTcbConstruct(tcbPtr, stack,localEntity, remoteEntity, rvFalse, trans);
rvMegacoEntityAddTcb(remoteEntity, tcbPtr);
}
rvMutexLock(&tcbPtr->lock);
rvMutexUnlock(&localEntity->mutex);
switch (tcbPtr->state)
{
case RV_MEGACOTCB_STATE_IDLE:
tcbPtr->state = RV_MEGACOTCB_STATE_WAITAPPLRESPONSE;
rvTimerReset(&tcbPtr->Timer[tcbPtr->CurrentTimer],RV_MEGACOTM_PROCESSING_TO);
/* Invoke application callback */
rvMutexUnlock(&tcbPtr->lock);
alreadyUnlocked = rvTrue;
if (localEntity->u.local.processRequest != NULL)
localEntity->u.local.processRequest(tcbPtr,trans,localEntity->u.local.processRequestData);
break;
case RV_MEGACOTCB_STATE_RESP_TO_SEND:
/* Trigger the enitity to do a send */
rvMegacoEntitySendNow(remoteEntity);
break;
case RV_MEGACOTCB_STATE_RESPONDED:
/* resend the response */
tcbPtr->state = RV_MEGACOTCB_STATE_RESP_TO_SEND;
rvMegacoEntitySendListInsert(tcbPtr->destEntity,tcbPtr);
break;
case RV_MEGACOTCB_STATE_WAITAPPLRESPONSE:
/* send a provisional response */
rvMegacoTcbStopCurrentTimer( tcbPtr);
rvMutexUnlock(&tcbPtr->lock);
alreadyUnlocked = rvTrue;
rvMegacoTcbSendPending(tcbPtr,NULL,NULL);
break;
case RV_MEGACOTCB_STATE_CMDSENT:/* This is an error - we sent a command with this Id*/
case RV_MEGACOTCB_STATE_CMD_TO_SEND:/* This is an error - we are about to send a command with this Id*/
rvMegacoErrorDescriptorConstructA(&errorDesc, RV_MEGACOERROR_BAD_ID, "Incorrect ID", stack->msgAlloc);
rvMegacoTransactionReplyConstructA(&transReply, trans, stack->msgAlloc);
rvMegacoTransactionReplySetError(&transReply, &errorDesc);
rvMegacoTcbStopCurrentTimer( tcbPtr);
rvMutexUnlock(&tcbPtr->lock);
alreadyUnlocked = rvTrue;
rvMegacoTcbSendReply(tcbPtr,&transReply,NULL,NULL);
rvMegacoErrorDescriptorDestruct(&errorDesc);
rvMegacoTransactionReplyDestruct(&transReply);
break;
case RV_MEGACOTCB_STATE_INACTIVE:/* This transaction is waiting to be released don't respond to it */
break;
}
if (!alreadyUnlocked)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -