📄 rvmegacocontext.c
字号:
rvPtrVectorConstruct(&tClasses,x->alloc);
/* Loop over matching terminations, add a reply for each one unless is
a wildcarded response or termination list is required */
while((term=getNextMatchingTerm(x,command,&i,&j))!=NULL) {
/* The action reply will be added only if there is at least one command reply */
matchedTerm++;
addActionReply(x,actionReply,transReply);
/* Add the first command reply */
if(matchedTerm==1) {
/* Add the wildcarded id */
commReply = addCommandReply(x,rvMegacoTerminationIdGetId(termId),command,*actionReply);
}
stat = processCommandPerTermWild(x,term,command,commReply,&pkgs,&tClasses);
/* Stop processing on error unless the command is optional */
if(stat!=rvTrue && !rvMegacoCommandIsOptional(command))
break;
}
rvPtrVectorDestruct(&pkgs);
rvPtrVectorDestruct(&tClasses);
if(stat!=rvTrue)
return stat;
/* Return an error message if no terminations were matched, unless the context is ALL */
/* If there is already an action response return an error anyway (for consistency) */
if(!matchedTerm && (!contextAll || *actionReply!=NULL ) ) {
addActionReply(x,actionReply,transReply);
commReply = addCommandReply(x,rvMegacoTerminationIdGetId(termId),command,*actionReply);
setCommandError(x,commReply,RV_MEGACOERROR_NOMATCH_TERMID,"No TerminationID matched a wildcard");
return rvFalse;
}
return stat;
}
static RvBool processCommandSingleTerm(RvMegacoContext * x,const RvMegacoCommand * command,
RvMegacoActionReply** actionReply,
RvMegacoTransactionReply * transReply,
RvBool contextAll) {
RvMegacoTerm * term;
RvMegacoCommandReply * commReply;
const RvMegacoTerminationId * termId = rvMegacoCommandGetTerminationId(command);
int errCode = 0;
/* Get a valid termination to apply the command. If it can't, return with error */
term = getCommandTerm(x,command,&errCode,contextAll);
if(term==NULL) {
/* If context is all don't set an error for term not found except in case that there is already an action
reply,meaning that a previous command generated a response or when some other error happens */
if(!contextAll || *actionReply!=NULL || errCode!=0 ) {
addActionReply(x,actionReply,transReply);
commReply = addCommandReply(x,rvMegacoTerminationIdGetId(termId),command,*actionReply);
setTermError(x,commReply,errCode);
}
return rvFalse;
}
addActionReply(x,actionReply,transReply);
commReply = addCommandReply(x,rvMegacoTermGetId(term),command,*actionReply);
return processCommandPerTerm(x,term,command,commReply);
}
/* If the MG has been disabled by the MGC , still need to accept SVC so it can
come up again */
static RvBool checkTermMgrAvailable(RvMegacoContext * x,const RvMegacoCommand * command,
RvMegacoCommandType commType,
RvMegacoActionReply** actionReply,
RvMegacoTransactionReply * transReply) {
/* If the termination manager is disabled, accept only SVC */
if(rvMegacoTermMgrIsDisabled(x->termMgr) && commType!=RV_MEGACOCOMMANDTYPE_SVCCHANGE ) {
RvMegacoCommandReply reply;
addActionReply(x,actionReply,transReply);
rvMegacoCommandReplyConstructA(&reply,command,x->alloc);
setCommandError(x,&reply,RV_MEGACOERROR_NOTAVAIL_SRVC,"Service Unavailable");
rvMegacoActionReplyAddReply(*actionReply,&reply);
rvMegacoCommandReplyDestruct(&reply);
return rvFalse;
}
return rvTrue;
}
static RvBool processCommand(RvMegacoContext * x,const RvMegacoCommand * command,
RvMegacoActionReply** actionReply,
RvMegacoTransactionReply * transReply,
RvBool contextAll) {
const RvMegacoTerminationId * termId = rvMegacoCommandGetTerminationId(command);
RvMegacoCommandType commType = rvMegacoCommandGetType(command);
/* RvBool idIsWild = rvMegacoTerminationIdIsWild(termId);*/
/* RvBool idIsChoose = rvMegacoTerminationIdIsChoose(termId);*/
RvBool isWildRsp = rvMegacoCommandGetWildResponseFlag(command);
/* Have to check at this level to be able to accept a SVC */
if(!checkTermMgrAvailable(x,command,commType,actionReply,transReply))
return rvFalse;
if(!rvMegacoTerminationIdIsWild(termId) )
return processCommandSingleTerm(x,command,actionReply,transReply,contextAll);
switch(commType) {
case RV_MEGACOCOMMANDTYPE_ADD:
case RV_MEGACOCOMMANDTYPE_MOVE:
return processCommTermInOtherContext(x,command,actionReply,transReply,contextAll);
case RV_MEGACOCOMMANDTYPE_MODIFY:
case RV_MEGACOCOMMANDTYPE_SUBTRACT:
case RV_MEGACOCOMMANDTYPE_AUDITVAL:
if(isWildRsp)
return processCommTermInContextWildRsp(x,command,actionReply,transReply,contextAll);
else
return processCommTermInContext(x,command,actionReply,transReply,contextAll);
case RV_MEGACOCOMMANDTYPE_SVCCHANGE:
return processCommTermInContext(x,command,actionReply,transReply,contextAll);
case RV_MEGACOCOMMANDTYPE_AUDITCAP:
/* Special case: Audit all capabilities in null context with wildcard response */
/* Termination must be "*" and context must be NULL */
if( isNullContext(x) && isWildRsp &&
!strcmp(rvMegacoTerminationIdGetId(termId),"*") && !contextAll )
return processAuditAll(x,command,rvMegacoTerminationIdGetId(termId),
actionReply,transReply);
else if(isWildRsp)
return processCommTermInContextWildRsp(x,command,actionReply,transReply,contextAll);
else
return processCommTermInContext(x,command,actionReply,transReply,contextAll);
default:
return rvTrue;
}
}
/* Find a termination by id */
RvMegacoTerm * rvMegacoContextGetTerm(RvMegacoContext * x,const char * id) {
RvMegacoTerm * term = NULL;
rvMutexLock(&x->mutex);
term = rvMegacoTopologyGetTerm(&x->topology,id);
/* Check if the termination is really in the null context */
if(term!=NULL && isNullContext(x) && !rvMegacoTermIsInNullCtxt(term) )
term = NULL;
rvMutexUnlock(&x->mutex);
return term;
}
/* Find a termination by id in null context */
RvMegacoTerm * rvMegacoContextGetTermInNull(RvMegacoContext * x,const char * id) {
RvMegacoTerm * term = NULL;
rvMutexLock(&x->mutex);
term = rvMegacoTopologyGetTerm(&x->topology,id);
rvMutexUnlock(&x->mutex);
return term;
}
/* Note: this may be changed later to allow allocating the terminations from
a pool, or use some special allocator for terminations */
RvMegacoTerm * rvMegacoContextAddNewTerm(RvMegacoContext * x,const char * id) {
RvMegacoTerm * term;
rvMutexLock(&x->mutex);
term = rvAllocAllocate(x->alloc,sizeof(RvMegacoTerm));
rvMegacoTermConstruct(term,id,x,x->alloc);
/* If context is NULL or Ephemeral, don't create links */
if(x->id==0)
rvMegacoTopologyAddTerm(&x->topology,term,NULL);
else
rvMegacoTopologyAddTerm(&x->topology,term,x->alloc);
rvMutexUnlock(&x->mutex);
return term;
}
static RvMegacoTerm * addUnknownTerm(RvMegacoContext * x,const char * partialName) {
RvMegacoTerm * term = rvMegacoContextAddNewTerm(x,partialName);
rvMegacoTermSetType(term,RV_MDMTERMTYPE_UNKNOWN);
/* Construct the mdmTerm */
rvMdmTermConstruct_(rvMegacoTermGetMdmTerm(term),NULL,rvMegacoTmpTermMdmXClbks,term);
return term;
}
/* Find and validate the command termination */
static RvMegacoTerm* getSelectedTerm(RvMegacoContext * x,const RvMegacoCommand * command,
int* errCode) {
/* RvMegacoTerm * term = NULL; */
RvMdmTerm* selectTerm;
RvMegacoTerm * tmpTerm = NULL;
const RvMegacoTerminationId * termId = rvMegacoCommandGetTerminationId(command);
/* Save in case that it fails later */
x->chooseId = termId;
/* A "temporary" term is created to hold the rigth topology
and the command. This will be later replaced by the term selected
by the application (physical or ephemeral)
*/
tmpTerm = addUnknownTerm(x,rvMegacoTerminationIdGetId(termId));
if(tmpTerm==NULL) {
*errCode = RV_MEGACOERROR_NOTAVAIL_TERMID;
return NULL;
}
/* Note: the temporary termination must provide access to topology,
requested media and partial (or total) name */
rvMdmTermSetRequestedMedia_(rvMegacoTermGetMdmTerm(tmpTerm),rvMegacoAddCommandGetMedia(command));
selectTerm = rvMdmTermMgrSelectTermination_(x->termMgr->mdmTermMgr,rvMegacoTermGetMdmTerm(tmpTerm));
if( selectTerm==NULL ) {
*errCode = RV_MEGACOERROR_NOTAVAIL_TERMID;
}
/* Not required because topology will be set later
else { // Duplicate the temporary term topology,
term = (RvMegacoTerm *)rvMdmTermGetXTerm_(selectTerm);
rvMegacoTopologyDuplicate(&x->topology,tmpTerm,term);
}
*/
/* Release temporary termination */
rvMegacoTopologyRemoveTerm(&x->topology,tmpTerm,x->alloc);
rvMegacoTermDestruct(tmpTerm);
rvAllocDeallocate(x->alloc,sizeof(RvMegacoTerm),tmpTerm);
return (RvMegacoTerm *)rvMdmTermGetXTerm_(selectTerm);
}
/* Only for not wildcarded commands */
/* If errCode is set in return,the error should be returned even for context ALL */
/* (some commands require error even in this case: ADD and MOVE */
static RvMegacoTerm* getCommandTerm(RvMegacoContext * x,const RvMegacoCommand * command,
int* errCode,RvBool contextAll) {
const RvMegacoTerminationId * termId = rvMegacoCommandGetTerminationId(command);
const char * id = rvMegacoTerminationIdGetId(termId);
RvMegacoTerm * term = NULL;
RvMegacoCommandType type = rvMegacoCommandGetType(command);
if(rvMegacoTerminationIdIsChoose(termId) && type==RV_MEGACOCOMMANDTYPE_ADD) {
term = getSelectedTerm(x,command,errCode);
/* Save first selected term for topology */
if(x->chosenTerm==NULL)
x->chosenTerm = term;
}
else if(rvMegacoTerminationIdIsNormal(termId)) {
switch(type) {
case RV_MEGACOCOMMANDTYPE_ADD:
term = rvMegacoTermMgrFindInNullContext(x->termMgr,id);
if( term!=NULL && !rvMegacoTermIsInNullCtxt(term) ) {
term = NULL;
*errCode = RV_MEGACOERROR_INUSE_TERMID;
}
break;
case RV_MEGACOCOMMANDTYPE_MODIFY:
case RV_MEGACOCOMMANDTYPE_AUDITVAL:
case RV_MEGACOCOMMANDTYPE_AUDITCAP:
case RV_MEGACOCOMMANDTYPE_SVCCHANGE:
/* If some command is addressed at a termination in the NULL
context, but it is already active, set correct error code */
if( isNullContext(x) ) {
term = rvMegacoTermMgrFindInNullContext(x->termMgr,id);
if( term!=NULL && !rvMegacoTermIsInNullCtxt(term) ) {
term = NULL;
*errCode = RV_MEGACOERROR_INUSE_TERMID;
}
}
else /* Termination must be in active context */
term = rvMegacoContextGetTerm(x,id); break;
case RV_MEGACOCOMMANDTYPE_SUBTRACT:
term = rvMegacoContextGetTerm(x,id); break;
case RV_MEGACOCOMMANDTYPE_MOVE:
term = rvMegacoTermMgrFindInActiveContexts(x->termMgr,id); break;
}
}
/* Root termination is allowed only for certain commands and only
for the null context */
/* For audit is allowed for other contexts for the special case
that audit of context id */
else if(rvMegacoTerminationIdIsRoot(termId) ) {
switch(type) {
case RV_MEGACOCOMMANDTYPE_AUDITVAL:
case RV_MEGACOCOMMANDTYPE_AUDITCAP:
if(contextAll || isNullContext(x) )
term = rvMegacoTermMgrGetRootTermination(x->termMgr); break;
case RV_MEGACOCOMMANDTYPE_MODIFY:
case RV_MEGACOCOMMANDTYPE_SVCCHANGE:
if( isNullContext(x) )
term = rvMegacoTermMgrGetRootTermination(x->termMgr);
break;
}
}
return term;
}
/* Add an action reply if it doesn't exist */
static void addActionReply(RvMegacoContext * x,RvMegacoActionReply ** actionReply_,RvMegacoTransactionReply * transReply) {
RvMegacoContextId contextId;
RvMegacoActionReply actionReply,* newReply;
unsigned int id = rvMegacoContextGetId(x);
if(*actionReply_!=NULL)
return;
if(id==0)
rvMegacoContextIdConstructSpecial(&contextId,RV_MEGACOCONTEXTID_NULL);
else
rvMegacoContextIdConstruct(&contextId,id);
rvMegacoActionReplyConstructExA(&actionReply,&contextId,x->alloc);
rvMegacoContextIdDestruct(&contextId);
rvMegacoTransactionReplyAddReply(transReply,&actionReply);
rvMegacoActionReplyDestruct(&actionReply);
newReply = (RvMegacoActionReply*)rvMegacoTransactionReplyGetReply(transReply,rvMegacoTransactionReplyGetNumReplies(transReply)-1);
*actionReply_ = newReply;
}
RvBool rvMegacoContextProcessAction(RvMegacoContext * x,const RvMegacoAction * action,
RvMegacoTransactionReply * transReply,
RvBool contextAll) {
size_t i;
RvMegacoActionReply * actionReply = NULL;
RvBool stat = rvTrue;
const RvMegacoContextProperties* contextProperties;
RvMdmError error;
rvMdmErrorConstruct_(&error);
rvMutexLock(&x->mutex);
contextProperties = rvMegacoActionGetContextProperties(action);
if(!rvMegacoContextPropertiesIsEmpty(contextProperties)) {
/* Set context properties */
rvMegacoContextSetEmergency(x,rvMegacoContextPropertiesIsEmergency(contextProperties));
rvMegacoContextSetPriority(x,rvMegacoContextPropertiesGetPriority(contextProperties));
x->topologyDescr = rvMegacoContextPropertiesGetTopology(contextProperties);
}
else
x->topologyDescr = NULL;
/* There is no choose termination at the beginning */
x->chosenTerm=NULL;
/* Get the commands from the list and process them */
/* TODO: Rollback preprocessed commands if a processCommand fails ?? */
for(i=0;i<rvMegacoActionGetNumCommands(action);i++) {
if(!processCommand(x,rvMegacoActionGetCommand(action,i),&actionReply,transReply,contextAll)) {
stat = rvFalse;
break;
}
}
/* Avoid the case that a empty context is left 'dangling'
because there is no way to explicitly clean it */
if(contextIsEmpty(x)) {
rvMegacoTermMgrDeleteContext(x->termMgr,x);
return stat;
}
/* There is no topology in the null context */
if( stat && !isNullContext(x) ) {
const RvMegacoTopologyDescriptor * topology = rvMegacoContextPropertiesGetTopology(contextProperties);
rvMegacoTopologyUpdate(&x->topology,x->chosenTerm,topology);
/* Call callbacks to connect media streams created before */
rvMegacoTopologyUpdateMediaConnections(&x->topology,&error);
/* If there is no response, create one with the topology */
/* Note: maybe this is always required if there is a topology descriptor? */
/* Note: Is not clear what to encode in the topology argumments,by echo the input */
if( rvMegacoTopologyDescriptorGetNumTriples(topology) && actionReply == NULL) {
addActionReply(x,&actionReply,transReply);
rvMegacoActionReplySetContextProperties(actionReply,contextProperties);
}
}
rvMutexUnlock(&x->mutex);
return stat;
}
/***************************************************************************/
/* Process commands */
/***************************************************************************/
static void processMoveCommand(RvMegacoContext * x,RvMegacoTerm * term,
const RvMegacoCommand * command,RvMegacoCommandReply * commReply) {
/* Termination can't be moved to the NULL context */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -