/*!\file match_basic.c *\brief Implements the match function. * * The match function here is integrated here with an enabled() function. * It is also the basic match, so not suited for Constraint Logic Programming. */ #include #include #include "memory.h" #include "substitution.h" #include "system.h" #include "modelchecker.h" #include "match_basic.h" //! Get the candidates list for typeless basic stuff __inline__ Termlist candidates (const Knowledge know) { return knowledgeGetBasics (know); } struct fvpass { int (*solution) (); System sys; int run; Roledef roledef; int (*proceed) (System, int); }; //! Fix variables in a message, and check whether it can be accepted. /** * fp.sys is only accessed for the matching type. *@returns 1 (true) if there exists a message that can be accepted, fvpass returns 1 on it. */ int fixVariablelist (const struct fvpass fp, const Knowledge know, Termlist varlist, const Term message) { int flag = 0; Termlist tlscan; Termlist candlist; if (varlist != NULL) { if (!isTermVariable (varlist->term)) { while (varlist != NULL && !isTermVariable (varlist->term)) { varlist = varlist->next; } } } /* cond: varlist == NULL || isTermvariable(varlist->term) */ if (varlist == NULL) { /* there are no (more) variables to be fixed. */ /* actually trigger it if possible */ int copied; Knowledge tempknow; /* first we propagate the substitutions in the knowledge */ /* TODO this must also be done for all agent knowledge!! */ if (knowledgeSubstNeeded (know)) { copied = 1; tempknow = knowledgeSubstDo (know); } else { copied = 0; tempknow = know; } if (inKnowledge (tempknow, message)) { if (fp.solution != NULL) { flag = fp.solution (fp, tempknow); } else { /* signal that it was enabled, now we omit the pruning */ flag = 1; } } else { /* not enabled */ flag = 0; } /* restore state */ if (copied) { knowledgeDelete (tempknow); knowledgeSubstUndo (know); } return flag; } /* cond: isTermvariable(varlist->term) */ varlist->term = deVar (varlist->term); /* cond: realTermvariable(varlist->term) */ candlist = candidates (know); #ifdef DEBUG if (DEBUGL (5)) { indent (); printf ("Set "); termPrint (varlist->term); printf (" with type "); termlistPrint (varlist->term->stype); printf (" from candidates "); termlistPrint (candlist); printf ("\n"); } #endif /* Now check all candidates. Do they work as candidates? */ tlscan = candlist; while (tlscan != NULL && !(flag && fp.solution == NULL)) { if (!isTermEqual (varlist->term, tlscan->term)) { /* substitute */ varlist->term->subst = tlscan->term; if (validSubst (fp.sys->match, varlist->term)) { #ifdef DEBUG if (DEBUGL (5)) { indent (); printf ("Substituting "); termPrint (varlist->term); printf ("\n"); } #endif /* now we may need to substitute more */ flag = fixVariablelist (fp, know, varlist->next, message) || flag; } } tlscan = tlscan->next; } /* restore state: variable is not instantiated. */ varlist->term->subst = NULL; /* garbage collect */ termlistDelete (candlist); return flag; } /* * check whether a roledef, given some newer knowledge substitutions, can survive */ #define enabled_basic(sys,know,newterm) !inKnowledge(know,newterm) //! Try to execute a read event. /** * Try to execute a read event. It must be able to be construct it from the * current intruder knowledge (Inject), but not from the forbidden knowledge * set, which we tried earlier. * *@returns 0 if it is not enabled, 1 if it was enabled (and routes explored) *\sa explorify() */ int matchRead_basic (const System sys, const int run, int (*proceed) (System, int)) { Roledef rd; int flag = 0; struct fvpass fp; Termlist varlist; int solution (struct fvpass fp, Knowledge know) { Knowledge oldknow; Term newterm; /* remove variable linkages */ newterm = termDuplicateUV (fp.roledef->message); /* a candidate, but if this is a t4 traversal, is it also an old one? */ if (fp.sys->traverse < 4 || fp.roledef->forbidden == NULL || enabled_basic (fp.sys, fp.roledef->forbidden, newterm)) { /* it is possibly enabled, i.e. not forbidden */ int enabled; oldknow = fp.sys->know; fp.sys->know = know; #ifdef DEBUG if (DEBUGL (5)) { printf ("+"); } #endif enabled = fp.proceed (fp.sys, fp.run); // flag determines the enabled status now fp.sys->know = oldknow; termDelete (newterm); return enabled; } else { /* blocked */ #ifdef DEBUG if (DEBUGL (5)) { printf ("-"); } #endif termDelete (newterm); return 0; } } rd = runPointerGet (sys, run); varlist = termlistAddVariables (NULL, rd->message); fp.sys = sys; fp.run = run; fp.roledef = rd; fp.proceed = proceed; fp.solution = solution; #ifdef DEBUG if (DEBUGL (5)) { indent (); printf ("{\n"); } #endif flag = fixVariablelist (fp, sys->know, varlist, rd->message); termlistDelete (varlist); #ifdef DEBUG if (DEBUGL (5)) { indent (); printf ("} with flag %i\n", flag); } #endif return flag; } //! Skip an event /** * Skips over an event. Because the intruder knowledge is incremental, we can * just overwrite the old value of forbidden. *@returns 1 */ int block_basic (const System sys, const int run) { Knowledge pushKnow; Roledef rd; rd = runPointerGet (sys, run); pushKnow = rd->forbidden; rd->forbidden = sys->know; traverse (sys); rd->forbidden = pushKnow; return 1; } //! Execute a send /** *@returns 1 */ int send_basic (const System sys, const int run) { Roledef rd = runPointerGet (sys, run); /* execute send, push knowledge? */ if (inKnowledge (sys->know, rd->message)) { /* no new knowledge, so this remains */ explorify (sys, run); } else { /* new knowledge, must store old state */ Knowledge oldknow = sys->know; sys->know = knowledgeDuplicate (sys->know); sys->knowPhase++; knowledgeAddTerm (sys->know, rd->message); explorify (sys, run); sys->knowPhase--; knowledgeDelete (sys->know); sys->know = oldknow; } return 1; }