Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #ifndef __XMPP_STATE_MC__ 7 : #define __XMPP_STATE_MC__ 8 : 9 : #include <mutex> 10 : 11 : #include <boost/asio.hpp> 12 : #include <boost/statechart/state_machine.hpp> 13 : 14 : #include "base/queue_task.h" 15 : #include "base/timer.h" 16 : #include "io/ssl_session.h" 17 : #include "xmpp/xmpp_proto.h" 18 : 19 : namespace sc = boost::statechart; 20 : 21 : namespace xmsm { 22 : struct Idle; 23 : struct Active; 24 : struct Connect; 25 : struct OpenSent; 26 : struct OpenConfirm; 27 : struct XmppStreamEstablished; 28 : } 29 : 30 : namespace xmsm { 31 : struct EvStart; 32 : struct Idle; 33 : 34 : typedef enum { 35 : IDLE = 0, 36 : ACTIVE = 1, 37 : CONNECT = 2, 38 : OPENSENT = 3, 39 : OPENCONFIRM = 4, 40 : ESTABLISHED = 5 41 : } XmState; 42 : 43 : typedef enum { 44 : OPENCONFIRM_INIT = 0, 45 : OPENCONFIRM_FEATURE_NEGOTIATION = 1, 46 : OPENCONFIRM_FEATURE_SUCCESS = 2 47 : } XmOpenConfirmState; 48 : 49 : 50 : typedef enum { 51 : EvTLSHANDSHAKE_FAILURE = 0, 52 : EvTLSHANDSHAKE_SUCCESS = 1 53 : } SslHandShakeResponse; 54 : 55 : } 56 : 57 : class XmppConnection; 58 : class XmppSession; 59 : class TcpSession; 60 : class XmppConnectionInfo; 61 : 62 : class XmppStateMachine : 63 : public sc::state_machine<XmppStateMachine, xmsm::Idle> { 64 : public: 65 : static const int kOpenTime = 15; // seconds 66 : static const int kConnectInterval = 30; // seconds 67 : static const int kHoldTime = 90; // seconds 68 : static const int kMaxAttempts = 4; 69 : static const int kJitter = 10; // percentage 70 : 71 : XmppStateMachine(XmppConnection *connection, bool active, bool auth_enabled = false, int config_hold_time = kHoldTime); 72 : ~XmppStateMachine(); 73 : 74 : void Initialize(); 75 : void Clear(); 76 : void SetAdminState(bool down); 77 : 78 : // State transitions 79 : void OnStart(const xmsm::EvStart &event); 80 : 81 : virtual void StartConnectTimer(int seconds); 82 : void CancelConnectTimer(); 83 : virtual void StartOpenTimer(int seconds); 84 : void CancelOpenTimer(); 85 : 86 : int GetConfiguredHoldTime() const; 87 : virtual void StartHoldTimer(); 88 : void CancelHoldTimer(); 89 : void ResetSession(); 90 : 91 21997 : bool IsAuthEnabled() { return auth_enabled_; } 92 : 93 : void TimerErrorHandler(std::string name, std::string error); 94 : 95 : // Feed session events into the state machine. 96 : virtual void OnSessionEvent(TcpSession *session, TcpSession::Event event); 97 : 98 : // Receive Passive Open. 99 : bool PassiveOpen(XmppSession *session); 100 : 101 : // Receive incoming message 102 : void OnMessage(XmppSession *session, const XmppStanza::XmppMessage *msg); 103 : void ProcessMessage(XmppSession *session, 104 : const XmppStanza::XmppMessage *msg); 105 : 106 : // Receive incoming ssl events 107 : //void OnEvent(XmppSession *session, xmsm::SslHandShakeResponse); 108 : void OnEvent(SslSession *session, xmsm::SslHandShakeResponse); 109 : 110 : //void OnSessionError(Error error); 111 : 112 : // transfer the ownership of the session to the connection. 113 : void AssignSession(); 114 : 115 : // Calculate Timer value for active to connect transition. 116 : int GetConnectTime() const; 117 : 118 33 : void SetHandShakeCbHandler(SslHandShakeCallbackHandler cb) { 119 33 : handshake_cb_ = cb; 120 33 : } 121 : 122 2931 : SslHandShakeCallbackHandler HandShakeCbHandler() { return handshake_cb_; } 123 : 124 : std::string StateName() const; 125 : std::string LastStateName() const; 126 : std::string LastStateChangeAt() const; 127 : xmsm::XmState StateType() const; 128 : xmsm::XmOpenConfirmState OpenConfirmStateType() const; 129 : 130 : // getters and setters 131 29893670 : XmppConnection *connection() { return connection_; } 132 : void set_connection(const XmppConnection *connection) { 133 : connection_ = const_cast<XmppConnection *>(connection); 134 : } 135 : void SwapXmppConnection(XmppStateMachine *other); 136 : bool IsActiveChannel(); 137 : bool logUVE(); 138 : const char *ChannelType(); 139 : void set_session(TcpSession *session); 140 : void clear_session(); 141 : void DeleteSession(XmppSession *session); 142 4171321 : XmppSession *session() { return session_; } 143 0 : void RemoveSession() { session_ = NULL; } 144 : void set_state(xmsm::XmState state); 145 37901 : xmsm::XmState get_state() { return state_; } 146 : void set_openconfirm_state(xmsm::XmOpenConfirmState state); 147 73 : xmsm::XmOpenConfirmState get_openconfirm_state() { 148 73 : return openconfirm_state_; 149 : } 150 : 151 7825 : void connect_attempts_inc() { attempts_++; } 152 3012 : void connect_attempts_clear() { attempts_ = 0; } 153 9276 : int get_connect_attempts() const { return attempts_; } 154 : 155 2472466 : void keepalive_count_inc() { keepalive_count_++; } 156 15978 : void keepalive_count_clear() { keepalive_count_ = 0; } 157 2472735 : int get_keepalive_count() const { return keepalive_count_; } 158 : 159 990 : int hold_time() const { return hold_time_; } 160 12389 : virtual int hold_time_msecs() const { return hold_time_ * 1000; } 161 6555 : void set_hold_time(int hold_time) { hold_time_ = hold_time; } 162 : 163 : void unconsumed_event(const sc::event_base &event); 164 : 165 : void SendConnectionInfo(const std::string &event, 166 : const std::string &nextstate = ""); 167 : 168 : void SendConnectionInfo(XmppConnectionInfo *info, const std::string &event, 169 : const std::string &nextstate = ""); 170 : void ResurrectOldConnection(XmppConnection *connection, 171 : XmppSession *session); 172 : 173 4166409 : void set_last_event(const std::string &event) { 174 4166409 : std::scoped_lock lock(mutex_); 175 4166411 : last_event_ = event; 176 4166404 : last_event_at_ = UTCTimestampUsec(); 177 4166412 : } 178 : 179 : void update_last_event(const std::string &event); 180 : 181 559 : const std::string last_event() const { 182 559 : std::scoped_lock lock(mutex_); 183 1118 : return last_event_; 184 559 : } 185 : 186 7747 : bool ConnectTimerCancelled() { return connect_timer_->cancelled(); } 187 1 : bool OpenTimerCancelled() { return open_timer_->cancelled(); } 188 13 : bool HoldTimerCancelled() { return hold_timer_->cancelled(); } 189 : void AssertOnHoldTimeout(); 190 : bool HoldTimerExpired(); 191 1420 : const Timer *hold_timer() const { return hold_timer_; } 192 : 193 : private: 194 : friend class XmppStateMachineTest; 195 : 196 : bool ConnectTimerExpired(); 197 : bool OpenTimerExpired(); 198 : bool Enqueue(const sc::event_base &ev); 199 : bool DequeueEvent(boost::intrusive_ptr<const sc::event_base> event); 200 : void ProcessEvent(const sc::event_base &event); 201 : void ProcessStreamHeaderMessage(XmppSession *session, 202 : const XmppStanza::XmppMessage *msg); 203 : 204 : WorkQueue<boost::intrusive_ptr<const sc::event_base> > work_queue_; 205 : XmppConnection *connection_; 206 : XmppSession *session_; 207 : TcpServer *server_; 208 : Timer *connect_timer_; 209 : Timer *open_timer_; 210 : Timer *hold_timer_; 211 : int config_hold_time_; 212 : int hold_time_; 213 : uint32_t attempts_; 214 : uint32_t keepalive_count_; 215 : bool deleted_; 216 : bool in_dequeue_; 217 : bool is_active_; 218 : bool auth_enabled_; 219 : xmsm::XmState state_; 220 : xmsm::XmState last_state_; 221 : xmsm::XmOpenConfirmState openconfirm_state_; 222 : uint64_t state_since_; 223 : std::string last_event_; 224 : uint64_t last_event_at_; 225 : SslHandShakeCallbackHandler handshake_cb_; 226 : mutable std::mutex mutex_; 227 : 228 : DISALLOW_COPY_AND_ASSIGN(XmppStateMachine); 229 : }; 230 : 231 : #endif