/* * Copyright (C) 2008 iptego GmbH * * This file is part of SEMS, a free SIP media server. * * SEMS is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. This program is released under * the GPL with the additional exemption that compiling, linking, * and/or using OpenSSL is allowed. * * For a license to use the SEMS software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * SEMS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _STATE_ENGINE_H #define _STATE_ENGINE_H #include "DSMElemContainer.h" #include "AmSipMsg.h" #include "AmArg.h" #include "AmSdp.h" class AmSession; class DSMSession; #include using std::map; #include using std::vector; #include using std::string; using std::pair; #include "log.h" class DSMElement { public: DSMElement() { } virtual ~DSMElement() { } string name; // documentary only }; class DSMCondition : public DSMElement { public: enum EventType { Any, Start, Invite, SessionStart, Ringing, EarlySession, FailedCall, SipRequest, SipReply, BeforeDestroy, Hangup, Hold, UnHold, B2BOtherRequest, B2BOtherReply, B2BOtherBye, SessionTimeout, RtpTimeout, RemoteDisappeared, Key, Timer, NoAudio, PlaylistSeparator, DSMEvent, B2BEvent, DSMException, XmlrpcResponse, JsonRpcResponse, JsonRpcRequest, Startup, Reload, System, SIPSubscription, RTPTimeout, // SBC related LegStateChange, BLegRefused, PutOnHold, ResumeHeld, CreateHoldRequest, HandleHoldReply, RelayInit, RelayInitUAC, RelayInitUAS, RelayFinalize, RelayOnSipRequest, RelayOnSipReply, RelayOnB2BRequest, RelayOnB2BReply #ifdef WITH_ZRTP , ZRTPProtocolEvent, ZRTPSecurityEvent #endif }; static const char* type2str(EventType event); bool invert; DSMCondition() : invert(false) { } virtual ~DSMCondition() { } EventType type; map params; bool _match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params); virtual bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params); }; class DSMAction : public DSMElement { public: /** modifies State Engine operation */ enum SEAction { None, // no modification Repost, // repost current event Jump, // jump FSM Call, // call FSM Return // return from FSM call }; DSMAction() { /* DBG("const action\n"); */ } virtual ~DSMAction() { /* DBG("dest action\n"); */ } /** @return whether state engine is to be modified (via getSEAction) */ virtual bool execute(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params) = 0; /** @return state engine modification */ virtual SEAction getSEAction(string& param, AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params) { return None; } }; class DSMTransition; class State : public DSMElement { public: State(); ~State(); vector pre_actions; vector post_actions; vector transitions; }; class DSMTransition : public DSMElement { public: DSMTransition(); ~DSMTransition(); vector precond; vector actions; string from_state; string to_state; bool is_exception; }; class DSMConditionTree : public DSMElement { public: vector conditions; vector run_if_true; vector run_if_false; bool is_exception; }; class DSMFunction : public DSMElement { public: string name; vector actions; }; class DSMArrayFor : public DSMElement { public: DSMArrayFor() { } ~DSMArrayFor() { } enum DSMForType { Range, Array, Struct } for_type; string k; // for(k in array) string v; // for(k,v in struct), or range lower bound string array_struct; // array or struct name, or range upper bound vector actions; }; class DSMModule; class DSMStateDiagram { vector states; string name; string initial_state; bool checkInitialState(string& report); bool checkDestinationStates(string& report); bool checkHangupHandled(string& report); public: DSMStateDiagram(const string& name); ~DSMStateDiagram(); State* getInitialState(); State* getState(const string& s_name); void addState(const State& state, bool is_initial = false); bool addTransition(const DSMTransition& trans); const string& getName() { return name; } bool checkConsistency(string& report); }; class DSMException { public: DSMException(const string& e_type) { params["type"] = e_type; } DSMException(const string& e_type, const string& key1, const string& val1) { params["type"] = e_type; params[key1] = val1; } DSMException(const string& e_type, const string& key1, const string& val1, const string& key2, const string& val2) { params["type"] = e_type; params[key1] = val1; params[key2] = val2; } DSMException(map& params) : params(params) { } ~DSMException() { } map params; }; struct DSMStackElement { DSMStateDiagram* diag; State* state; vector actions; DSMStackElement(DSMStateDiagram* diag, State* state) : diag(diag), state(state) { } DSMStackElement(DSMStateDiagram* diag, State* state, const vector& actions) : diag(diag), state(state), actions(actions) { } }; class DSMStateEngine { State* current; DSMStateDiagram* current_diag; vector diags; // vector > stack; vector stack; bool callDiag(const string& diag_name, AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params, vector::iterator actions_from, vector::iterator actions_to); bool jumpDiag(const string& diag_name, AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params); bool returnDiag(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params); bool runactions(vector::iterator from, vector::iterator to, AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params, bool& is_consumed); vector mods; public: DSMStateEngine() : current(NULL), current_diag(NULL) {}; ~DSMStateEngine() {}; void addDiagram(DSMStateDiagram* diag); void addModules(vector modules); bool init(AmSession* sess, DSMSession* sc_sess, const string& startDiagram, DSMCondition::EventType init_event); void runEvent(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, map* event_params, bool run_exception = false); /** @return whether call should be accepted */ bool onInvite(const AmSipRequest& req, DSMSession* sess); void onBeforeDestroy(DSMSession* sc_sess, AmSession* sess); void processSdpOffer(AmSdp& offer); void processSdpAnswer(const AmSdp& offer, AmSdp& answer); }; extern void varPrintArg(const AmArg& a, map& dst, const string& name); #endif