OpenSDN source code
xmpp_state_machine.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
6 
7 #include <atomic>
8 #include <typeinfo>
9 #include <boost/bind.hpp>
10 #include <boost/date_time/posix_time/posix_time.hpp>
11 #include <boost/statechart/custom_reaction.hpp>
12 #include <boost/statechart/event.hpp>
13 #include <boost/statechart/simple_state.hpp>
14 #include <boost/statechart/state.hpp>
15 #include <boost/statechart/state_machine.hpp>
16 #include <boost/statechart/transition.hpp>
17 
18 #include "base/logging.h"
19 #include "base/task_annotations.h"
20 #include "io/event_manager.h"
21 #include "io/ssl_session.h"
22 #include "sandesh/sandesh_trace.h"
23 #include "sandesh/common/vns_types.h"
24 #include "sandesh/common/vns_constants.h"
25 #include "sandesh/xmpp_client_server_sandesh_types.h"
26 #include "sandesh/xmpp_peer_info_types.h"
27 #include "sandesh/xmpp_state_machine_sandesh_types.h"
28 #include "sandesh/xmpp_trace_sandesh_types.h"
29 #include "xmpp/xmpp_connection.h"
30 #include "xmpp/xmpp_factory.h"
31 #include "xmpp/xmpp_log.h"
32 #include "xmpp/xmpp_server.h"
33 #include "xmpp/xmpp_session.h"
34 
35 using namespace std;
36 
37 namespace mpl = boost::mpl;
38 namespace sc = boost::statechart;
39 
40 #define SM_LOG(_sm, _msg) do { \
41  XMPP_UTDEBUG(XmppStateMachineDebug, \
42  (_sm)->connection() ? (_sm)->connection()->ToUVEKey() : "", \
43  XMPP_PEER_DIR_NA, (_sm)->ChannelType(), _msg); \
44 } while (false)
45 
46 namespace xmsm {
47 // events
48 
49 struct EvStart : sc::event<EvStart> {
50  static const char *Name() {
51  return "EvStart";
52  }
53 };
54 
55 struct EvStop : sc::event<EvStop> {
56  static const char *Name() {
57  return "EvStop";
58  }
59 };
60 
61 struct EvAdminDown : sc::event<EvAdminDown> {
62  static const char *Name() {
63  return "EvAdminDown";
64  }
65 };
66 
67 struct EvConnectTimerExpired : sc::event<EvConnectTimerExpired> {
68  static const char *Name() {
69  return "EvConnectTimerExpired";
70  }
71 };
72 
73 struct EvOpenTimerExpired : sc::event<EvOpenTimerExpired> {
74  static const char *Name() {
75  return "EvOpenTimerExpired";
76  }
77 };
78 
79 struct EvHoldTimerExpired : sc::event<EvHoldTimerExpired> {
80  static const char *Name() {
81  return "EvHoldTimerExpired";
82  }
83 };
84 
85 struct EvTcpConnected : sc::event<EvTcpConnected> {
86  EvTcpConnected(XmppSession *session) : session(session) { };
87  static const char *Name() {
88  return "EvTcpConnected";
89  }
91 } ;
92 
93 struct EvTcpConnectFail : sc::event<EvTcpConnectFail> {
94  EvTcpConnectFail(XmppSession *session) : session(session) { };
95  static const char *Name() {
96  return "EvTcpConnectFail";
97  }
99 } ;
100 
101 struct EvTcpPassiveOpen : sc::event<EvTcpPassiveOpen> {
102  EvTcpPassiveOpen(XmppSession *session) : session(session) { };
103  static const char *Name() {
104  return "EvTcpPassiveOpen";
105  }
107 };
108 
109 struct EvTcpClose : sc::event<EvTcpClose> {
110  EvTcpClose(XmppSession *session) : session(session) { };
111  static const char *Name() {
112  return "EvTcpClose";
113  }
115 };
116 
117 struct EvTcpDeleteSession : sc::event<EvTcpDeleteSession> {
118  explicit EvTcpDeleteSession(TcpSession *session) : session(session) { }
119  static const char *Name() {
120  return "EvTcpDeleteSession";
121  }
123 };
124 
125 struct EvXmppMessage : sc::event<EvXmppMessage> {
126  explicit EvXmppMessage(XmppSession *session,
127  const XmppStanza::XmppMessage *msg) : session(session), msg(msg) { }
128  static const char *Name() {
129  return "EvXmppMessage";
130  }
133 };
134 
135 struct EvXmppOpen : public sc::event<EvXmppOpen> {
137  session(session),
138  msg(static_cast<const XmppStanza::XmppStreamMessage *>(msg)) {
139  }
140  static const char *Name() {
141  return "EvXmppOpen";
142  }
144  boost::shared_ptr<const XmppStanza::XmppStreamMessage> msg;
145 };
146 
147 struct EvStreamFeatureRequest : sc::event<EvStreamFeatureRequest> {
149  const XmppStanza::XmppMessage *msg) :
150  session(session),
151  msg(static_cast<const XmppStanza::XmppStreamMessage *>(msg)) {
152  }
153  static const char *Name() {
154  return "EvStreamFeatureRequest";
155  }
157  boost::shared_ptr<const XmppStanza::XmppMessage> msg;
158 };
159 
160 struct EvStartTls : sc::event<EvStartTls> {
162  const XmppStanza::XmppMessage *msg) :
163  session(session),
164  msg(static_cast<const XmppStanza::XmppStreamMessage *>(msg)) {
165  }
166  static const char *Name() {
167  return "EvStartTls";
168  }
170  boost::shared_ptr<const XmppStanza::XmppMessage> msg;
171 };
172 
173 struct EvTlsProceed : sc::event<EvTlsProceed> {
175  const XmppStanza::XmppMessage *msg) :
176  session(session),
177  msg(static_cast<const XmppStanza::XmppStreamMessage *>(msg)) {
178  }
179  static const char *Name() {
180  return "EvTlsProceed";
181  }
183  boost::shared_ptr<const XmppStanza::XmppMessage> msg;
184 };
185 
186 struct EvTlsHandShakeSuccess : sc::event<EvTlsHandShakeSuccess> {
187  explicit EvTlsHandShakeSuccess(XmppSession *session) :
188  session(session) { }
189  static const char *Name() {
190  return "EvTlsHandShakeSuccess";
191  }
193 };
194 
195 struct EvTlsHandShakeFailure : sc::event<EvTlsHandShakeFailure> {
196  explicit EvTlsHandShakeFailure(XmppSession *session) :
197  session(session) { }
198  static const char *Name() {
199  return "EvTlsHandShakeFailure";
200  }
202 };
203 
204 struct EvXmppKeepalive : sc::event<EvXmppKeepalive> {
206  const XmppStanza::XmppMessage *msg) :
207  session(session), msg(msg) {
208  }
209  static const char *Name() {
210  return "EvXmppKeepalive";
211  }
213  boost::shared_ptr<const XmppStanza::XmppMessage> msg;
214 };
215 
216 struct EvXmppMessageStanza : sc::event<EvXmppMessageStanza> {
218  const XmppStanza::XmppMessage *msg) :
219  session(session), msg(msg) {
220  }
221  static const char *Name() {
222  return "EvXmppMessageStanza";
223  }
225  boost::shared_ptr<const XmppStanza::XmppMessage> msg;
226 };
227 
228 struct EvXmppIqStanza : sc::event<EvXmppIqStanza> {
230  const XmppStanza::XmppMessage *msg)
231  : session(session), msg(msg) {
232  }
233  static const char *Name() {
234  return "EvXmppIqStanza";
235  }
237  boost::shared_ptr<const XmppStanza::XmppMessage> msg;
238 };
239 
240 struct EvXmppOpenReceive : sc::event<EvXmppOpenReceive> {
241  EvXmppOpenReceive(XmppSession *session) : session(session) {
242  }
243  static const char *Name() {
244  return "EvXmppOpenReceive";
245  }
247 };
248 
249 struct Idle : public sc::state<Idle, XmppStateMachine> {
250  typedef sc::transition<EvStart, Active,
252  Idle(my_context ctx) : my_base(ctx) {
253  XmppStateMachine *state_machine = &context<XmppStateMachine>();
254  bool flap = (state_machine->get_state() == ESTABLISHED);
255  state_machine->set_state(IDLE);
256  state_machine->SendConnectionInfo("Start", "Active");
257  if (flap) {
258  state_machine->connection()->increment_flap_count();
259  }
260  }
261 };
262 
263 struct Active : public sc::state<Active, XmppStateMachine> {
264  typedef mpl::list<
265  sc::custom_reaction<EvAdminDown>,
266  sc::custom_reaction<EvConnectTimerExpired>,
267  sc::custom_reaction<EvOpenTimerExpired>,
268  sc::custom_reaction<EvTcpPassiveOpen>,
269  sc::custom_reaction<EvTcpClose>,
270  sc::custom_reaction<EvXmppOpen>,
271  sc::custom_reaction<EvStop>
273 
274  Active(my_context ctx) : my_base(ctx) {
275  XmppStateMachine *state_machine = &context<XmppStateMachine>();
276  state_machine->keepalive_count_clear();
277  bool flap = (state_machine->get_state() == ESTABLISHED);
278  state_machine->set_state(ACTIVE);
279  if (flap) {
280  state_machine->connection()->increment_flap_count();
281  }
282  if (state_machine->IsActiveChannel() ) {
283  if (state_machine->get_connect_attempts() >=
285  XmppConnection *connection = state_machine->connection();
286  if (connection) {
287  state_machine->SendConnectionInfo(
288  "Connect failed after retries");
289  // Notify clients if any action to be taken
290  connection->ChannelMux()->HandleStateEvent(xmsm::ACTIVE);
291  }
292  }
293  state_machine->StartConnectTimer(state_machine->GetConnectTime());
294  }
295  }
297  XmppStateMachine *state_machine = &context<XmppStateMachine>();
298  state_machine->CancelConnectTimer();
299  state_machine->CancelOpenTimer();
300  }
301 
302  //event on client only
303  sc::result react(const EvConnectTimerExpired &event) {
304  XmppStateMachine *state_machine = &context<XmppStateMachine>();
305  if (state_machine->ConnectTimerCancelled()) {
306  SM_LOG(state_machine, "Discard EvConnectTimerExpired in (Active) State");
307  return discard_event();
308  } else {
309  state_machine->SendConnectionInfo(event.Name(), "Connect");
310  SM_LOG(state_machine, "EvConnectTimerExpired in (Active) State");
311  return transit<Connect>();
312  }
313  }
314 
315  // event on server only
316  sc::result react(const EvTcpPassiveOpen &event) {
317  XmppStateMachine *state_machine = &context<XmppStateMachine>();
318  event.session->AsyncReadStart();
319  assert(state_machine->session() == event.session);
320  event.session->set_observer(
322  state_machine, _1, _2));
324  XmppConnectionInfo info;
325  info.set_local_port(event.session->local_port());
326  info.set_remote_port(event.session->remote_port());
327  state_machine->SendConnectionInfo(&info, event.Name());
328  return discard_event();
329  }
330 
331  // event on server only
332  sc::result react(const EvTcpClose &event) {
333  XmppStateMachine *state_machine = &context<XmppStateMachine>();
334  if (event.session != state_machine->session()) {
335  return discard_event();
336  }
337  state_machine->CancelOpenTimer();
338  state_machine->ResetSession();
339  state_machine->SendConnectionInfo(event.Name(), "Idle");
340  return transit<Idle>();
341  }
342 
343  //event on server only
344  sc::result react(const EvOpenTimerExpired &event) {
345  XmppStateMachine *state_machine = &context<XmppStateMachine>();
346  if (state_machine->OpenTimerCancelled()) {
347  SM_LOG(state_machine,
348  "Discard EvOpenTimerExpired in (Active) State");
349  return discard_event();
350  }
351 
352  // At this point session on connection is not set, hence SendClose
353  // using session on the state_machine.
354  XmppSession *session = state_machine->session();
355  XmppConnection *connection = state_machine->connection();
356  connection->SendClose(session);
357  state_machine->ResetSession();
358  state_machine->SendConnectionInfo(event.Name(), "Idle");
359  return transit<Idle>();
360  }
361 
362  //event on server only
363  sc::result react(const EvXmppOpen &event) {
364  XmppStateMachine *state_machine = &context<XmppStateMachine>();
365  if (event.session != state_machine->session()) {
366  return discard_event();
367  }
368  state_machine->AssignSession();
369 
370  XmppConnection *connection = state_machine->connection();
371  if (connection->IsDeleted()) {
372  state_machine->ResetSession();
373  return discard_event();
374  }
375 
376  XmppSession *session = state_machine->session();
377  if (!state_machine->IsAuthEnabled())
378  state_machine->ResurrectOldConnection(connection, session);
379 
380  // Get the possibly updated XmppConnection information.
381  connection = state_machine->connection();
382  state_machine->CancelOpenTimer();
383  if (!connection->SendOpenConfirm(session)) {
384  connection->SendClose(session);
385  state_machine->ResetSession();
386  state_machine->SendConnectionInfo("Send Open Confirm Failed",
387  "Idle");
388  return transit<Idle>();
389  } else {
390  XmppConnectionInfo info;
391  info.set_identifier(event.msg->from);
392  if (state_machine->IsAuthEnabled()) {
393  state_machine->SendConnectionInfo(&info, event.Name(),
394  "Open Confirm");
395  return transit<OpenConfirm>();
396  } else {
397  connection->StartKeepAliveTimer();
398  state_machine->SendConnectionInfo(&info, event.Name(),
399  "Established");
400  return transit<XmppStreamEstablished>();
401  }
402  }
403  }
404 
405  sc::result react(const EvStop &event) {
406  XmppStateMachine *state_machine = &context<XmppStateMachine>();
407  XmppConnection *connection = state_machine->connection();
408  state_machine->CancelOpenTimer();
409  state_machine->CancelConnectTimer();
410  connection->StopKeepAliveTimer();
411 
412  if (state_machine->IsActiveChannel() ) {
413  state_machine->set_session(NULL);
414  state_machine->SendConnectionInfo(event.Name(), "Active");
415  return transit<Active>();
416  } else {
417  state_machine->ResetSession();
418  state_machine->SendConnectionInfo(event.Name(), "Idle");
419  return transit<Idle>();
420  }
421  }
422 
423  sc::result react(const EvAdminDown &event) {
424  XmppStateMachine *state_machine = &context<XmppStateMachine>();
425  XmppConnectionInfo info;
426  info.set_close_reason("Administratively down");
427  state_machine->connection()->set_close_reason("Administratively down");
428  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
429  return transit<Idle>();
430  }
431 
432 };
433 
434 //State valid only for client side, connection in Active state
435 struct Connect : public sc::state<Connect, XmppStateMachine> {
436  typedef mpl::list<
437  sc::custom_reaction<EvAdminDown>,
438  sc::custom_reaction<EvConnectTimerExpired>,
439  sc::custom_reaction<EvTcpConnected>,
440  sc::custom_reaction<EvTcpConnectFail>,
441  sc::custom_reaction<EvTcpClose>,
442  sc::custom_reaction<EvStop>
444 
445  static const int kConnectTimeout = 60; // seconds
446 
447  Connect(my_context ctx) : my_base(ctx) {
448  XmppStateMachine *state_machine = &context<XmppStateMachine>();
449  StartSession(state_machine);
450  state_machine->connect_attempts_inc();
451  state_machine->set_state(CONNECT);
452  state_machine->StartConnectTimer(state_machine->GetConnectTime());
453  XmppSession *session = state_machine->session();
454  if (session != NULL) {
455  XmppConnectionInfo info;
456  info.set_local_port(session->local_port());
457  info.set_remote_port(session->remote_port());
458  state_machine->SendConnectionInfo(&info, "Connect Event");
459  }
460  }
462  XmppStateMachine *state_machine = &context<XmppStateMachine>();
463  state_machine->CancelConnectTimer();
464  }
465 
466  sc::result react(const EvConnectTimerExpired &event) {
467  XmppStateMachine *state_machine = &context<XmppStateMachine>();
468  if (state_machine->ConnectTimerCancelled()) {
469  SM_LOG(state_machine,
470  "Discard EvConnectTimerExpired in (Connect) State");
471  return discard_event();
472  }
473  CloseSession(state_machine);
474  XmppConnectionInfo info;
475  info.set_close_reason("Connect timer expired");
476  state_machine->connection()->set_close_reason("Connect timer expired");
477  state_machine->SendConnectionInfo(&info, event.Name(), "Active");
478  return transit<Active>();
479  }
480 
481  sc::result react(const EvTcpConnected &event) {
482  XmppStateMachine *state_machine = &context<XmppStateMachine>();
483  if (event.session != state_machine->session()) {
484  return discard_event();
485  }
486  XmppConnection *connection = state_machine->connection();
487  state_machine->CancelConnectTimer();
488  XmppSession *session = state_machine->session();
489  XmppConnectionInfo info;
490  info.set_local_port(session->local_port());
491  info.set_remote_port(session->remote_port());
492  if (connection->SendOpen(session)) {
493  state_machine->StartHoldTimer();
494  state_machine->SendConnectionInfo(&info, event.Name(), "OpenSent");
495  return transit<OpenSent>();
496  } else {
497  SM_LOG(state_machine, "SendOpen failed in (Connect) State");
498  CloseSession(state_machine);
499  info.set_close_reason("SendOpen failed");
500  state_machine->connection()->set_close_reason("Send Open failed");
501  state_machine->SendConnectionInfo(&info, "Send Open failed",
502  "Active");
503  return transit<Active>();
504  }
505  }
506 
507  sc::result react(const EvTcpConnectFail &event) {
508  // delete session; restart connect timer.
509  XmppStateMachine *state_machine = &context<XmppStateMachine>();
510  if (event.session != state_machine->session()) {
511  return discard_event();
512  }
513  state_machine->set_session(NULL);
514  state_machine->CancelConnectTimer();
515  state_machine->SendConnectionInfo(event.Name(), "Active");
516  return transit<Active>();
517  }
518 
519  sc::result react(const EvTcpClose &event) {
520  XmppStateMachine *state_machine = &context<XmppStateMachine>();
521  if (event.session != state_machine->session()) {
522  return discard_event();
523  }
524  // close the tcp sessions.
525  CloseSession(state_machine);
526  state_machine->CancelConnectTimer();
527  state_machine->SendConnectionInfo(event.Name(), "Active");
528  return transit<Active>();
529  }
530 
531  sc::result react(const EvStop &event) {
532  XmppStateMachine *state_machine = &context<XmppStateMachine>();
533  CloseSession(state_machine);
534  state_machine->CancelConnectTimer();
535  XmppConnectionInfo info;
536  info.set_close_reason("EvStop received");
537  state_machine->connection()->set_close_reason("EvStop received");
538  state_machine->SendConnectionInfo(&info, event.Name(), "Active");
539  return transit<Active>();
540  }
541 
542  sc::result react(const EvAdminDown &event) {
543  XmppStateMachine *state_machine = &context<XmppStateMachine>();
544  CloseSession(state_machine);
545  XmppConnectionInfo info;
546  info.set_close_reason("Administratively down");
547  state_machine->connection()->set_close_reason("Administratively down");
548  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
549  return transit<Idle>();
550  }
551 
552  // Create an active connection request.
553  void StartSession(XmppStateMachine *state_machine) {
554  XmppConnection *connection = state_machine->connection();
555  XmppSession *session = connection->CreateSession();
556  state_machine->set_session(session);
557  session->set_observer(boost::bind(&XmppStateMachine::OnSessionEvent,
558  state_machine, _1, _2));
559  boost::system::error_code err;
560  session->socket()->bind(connection->local_endpoint(), err);
561  if (err) {
562  LOG(WARN, "Bind failure for local address " <<
563  connection->local_endpoint() << " : " << err.message());
564  assert(false);
565  }
566  connection->server()->Connect(session, connection->endpoint());
567  }
568 
569  void CloseSession(XmppStateMachine *state_machine) {
570  state_machine->set_session(NULL);
571  }
572 };
573 
574 // The client reaches OpenSent after sending an immediate OPEN on a active
575 // connection. Server should not come in this state.
576 struct OpenSent : public sc::state<OpenSent, XmppStateMachine> {
577  typedef mpl::list<
578  sc::custom_reaction<EvAdminDown>,
579  sc::custom_reaction<EvTcpClose>,
580  sc::custom_reaction<EvXmppOpen>,
581  sc::custom_reaction<EvHoldTimerExpired>,
582  sc::custom_reaction<EvStop>
584 
585  OpenSent(my_context ctx) : my_base(ctx) {
586  XmppStateMachine *state_machine = &context<XmppStateMachine>();
587  state_machine->set_state(OPENSENT);
588  }
590  XmppStateMachine *state_machine = &context<XmppStateMachine>();
591  state_machine->CancelHoldTimer();
592  }
593 
594  sc::result react(const EvTcpClose &event) {
595  XmppStateMachine *state_machine = &context<XmppStateMachine>();
596  if (event.session != state_machine->session()) {
597  return discard_event();
598  }
599  state_machine->CancelHoldTimer();
600  if (event.session) {
601  state_machine->set_session(NULL);
602  state_machine->SendConnectionInfo(event.Name(), "Active");
603  return transit<Active>();
604  }
605  return discard_event();
606  }
607 
608  sc::result react(const EvXmppOpen &event) {
609  XmppStateMachine *state_machine = &context<XmppStateMachine>();
610  XmppConnection *connection = state_machine->connection();
611  if (event.session == state_machine->session()) {
612  state_machine->AssignSession();
613  XmppConnectionInfo info;
614  info.set_identifier(event.msg->from);
615  if (state_machine->IsAuthEnabled()) {
616  state_machine->SendConnectionInfo(&info, event.Name(),
617  "Open Confirm");
618  return transit<OpenConfirm>();
619  } else {
620  connection->SendKeepAlive();
621  connection->StartKeepAliveTimer();
622  state_machine->StartHoldTimer();
623  state_machine->SendConnectionInfo(&info, event.Name(),
624  "Established");
625  return transit<XmppStreamEstablished>();
626  }
627  }
628  return discard_event();
629  }
630 
631  sc::result react(const EvHoldTimerExpired &event) {
632  XmppStateMachine *state_machine = &context<XmppStateMachine>();
633  if (state_machine->HoldTimerCancelled()) {
634  SM_LOG(state_machine,
635  "Discard EvHoldTimerExpired in (OpenSent) State");
636  return discard_event();
637  }
638  CloseSession(state_machine);
639  XmppConnectionInfo info;
640  info.set_close_reason("Hold timer expired");
641  state_machine->connection()->set_close_reason("Hold timer expired");
642  state_machine->SendConnectionInfo(&info, event.Name(), "Active");
643  return transit<Active>();
644  }
645 
646  sc::result react(const EvStop &event) {
647  XmppStateMachine *state_machine = &context<XmppStateMachine>();
648  state_machine->CancelHoldTimer();
649  CloseSession(state_machine);
650  XmppConnectionInfo info;
651  info.set_close_reason("EvStop received");
652  state_machine->connection()->set_close_reason("EvStop received");
653  state_machine->SendConnectionInfo(&info, event.Name(), "Active");
654  return transit<Active>();
655  }
656 
657  sc::result react(const EvAdminDown &event) {
658  XmppStateMachine *state_machine = &context<XmppStateMachine>();
659  CloseSession(state_machine);
660  XmppConnectionInfo info;
661  info.set_close_reason("Administratively down");
662  state_machine->connection()->set_close_reason("Administratively down");
663  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
664  return transit<Idle>();
665  }
666 
667  void CloseSession(XmppStateMachine *state_machine) {
668  state_machine->set_session(NULL);
669  }
670 };
671 
672 struct OpenConfirm : public sc::state<OpenConfirm, XmppStateMachine> {
673  typedef mpl::list<
674  sc::custom_reaction<EvAdminDown>,
675  sc::custom_reaction<EvTcpClose>,
676  sc::custom_reaction<EvHoldTimerExpired>,
677  sc::custom_reaction<EvStreamFeatureRequest>, //received by client
678  sc::custom_reaction<EvStartTls>, //received by server
679  sc::custom_reaction<EvTlsProceed>, //received by client
680  sc::custom_reaction<EvTlsHandShakeSuccess>,
681  sc::custom_reaction<EvTlsHandShakeFailure>,
682  sc::custom_reaction<EvXmppOpen>, //received by server
683  sc::custom_reaction<EvStop>
685 
686  OpenConfirm(my_context ctx) : my_base(ctx) {
687  XmppStateMachine *state_machine = &context<XmppStateMachine>();
688  state_machine->StartHoldTimer();
689  XmppConnectionInfo info;
690  if (!state_machine->IsActiveChannel()) { //server
691  if (state_machine->IsAuthEnabled()) {
692  XmppConnection *connection = state_machine->connection();
693  XmppSession *session = state_machine->session();
694  if (!connection->SendStreamFeatureRequest(session)) {
695  connection->SendClose(session);
696  SM_LOG(state_machine,
697  "Xmpp Send Stream Feature Request Failed, IDLE");
698  state_machine->ResetSession();
699  info.set_close_reason("Send Stream Feature Request Failed");
700  state_machine->connection()->set_close_reason(
701  "Send Stream Feature Request Failed");
702  state_machine->SendConnectionInfo(&info,
703  "Send Stream Feature Request failed", "Idle");
704  // cannot transition state as this is the constructor
705  // of new state
706  }
707  }
708  }
709  state_machine->set_state(OPENCONFIRM);
710  state_machine->set_openconfirm_state(OPENCONFIRM_INIT);
711  }
712 
713  sc::result react(const EvTcpClose &event) {
714  XmppStateMachine *state_machine = &context<XmppStateMachine>();
715  state_machine->CancelHoldTimer();
716  if (state_machine->IsActiveChannel() ) {
717  CloseSession(state_machine);
718  state_machine->SendConnectionInfo(event.Name(), "Active");
719  return transit<Active>();
720  } else {
721  state_machine->ResetSession();
722  state_machine->SendConnectionInfo(event.Name(), "Idle");
723  return transit<Idle>();
724  }
725  }
726 
727  sc::result react(const EvHoldTimerExpired &event) {
728  XmppStateMachine *state_machine = &context<XmppStateMachine>();
729  if (state_machine->HoldTimerCancelled()) {
730  SM_LOG(state_machine,
731  "Discard EvHoldTimerExpired in (OpenConfirm) State");
732  return discard_event();
733  }
734  XmppConnectionInfo info;
735  info.set_close_reason("Hold timer expired");
736  state_machine->connection()->set_close_reason("Hold timer expired");
737  if (state_machine->IsActiveChannel() ) {
738  CloseSession(state_machine);
739  state_machine->SendConnectionInfo(&info, event.Name(), "Active");
740  return transit<Active>();
741  } else {
742  state_machine->ResetSession();
743  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
744  return transit<Idle>();
745  }
746  }
747 
748  // received by the client
749  sc::result react(const EvStreamFeatureRequest &event) {
750  XmppStateMachine *state_machine = &context<XmppStateMachine>();
751  XmppConnection *connection = state_machine->connection();
752  XmppSession *session = state_machine->session();
753  // TODO, we need to have a supported stream feature list
754  // and compare against the requested stream feature list
755  // which will enable us to send start of various features
756  if (!connection->SendStartTls(session)) {
757  connection->SendClose(session);
758  state_machine->ResetSession();
759  XmppConnectionInfo info;
760  info.set_close_reason("Send Start Tls Failed");
761  state_machine->SendConnectionInfo(&info, event.Name(), "Active");
762  return transit<Active>();
763  } else {
764  state_machine->StartHoldTimer();
765  state_machine->SendConnectionInfo(event.Name(),
766  "Sent Start Tls, OpenConfirm Feature Negotiation");
767  state_machine->set_openconfirm_state(
769  return discard_event();
770  }
771  }
772 
773  // received by client
774  sc::result react(const EvTlsProceed &event) {
775  XmppStateMachine *state_machine = &context<XmppStateMachine>();
776  XmppConnection *connection = state_machine->connection();
777  XmppSession *session = state_machine->session();
778  state_machine->StartHoldTimer();
779  XmppConnectionInfo info;
780  info.set_identifier(connection->GetTo());
781  // Trigger Ssl Handshake on client side
782  session->TriggerSslHandShake(state_machine->HandShakeCbHandler());
783  state_machine->SendConnectionInfo( &info, event.Name(),
784  "Trigger Client Ssl Handshake");
785  return discard_event();
786  }
787 
788  //received by server
789  sc::result react(const EvStartTls &event) {
790  XmppStateMachine *state_machine = &context<XmppStateMachine>();
791  if (event.session != state_machine->session()) {
792  return discard_event();
793  }
794  XmppConnection *connection = state_machine->connection();
795  XmppSession *session = state_machine->session();
796  XmppConnectionInfo info;
797  info.set_identifier(connection->GetTo());
798  if (!connection->SendProceedTls(session)) {
799  connection->SendClose(session);
800  state_machine->ResetSession();
801  info.set_close_reason("Send Proceed Tls Failed");
802  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
803  return transit<Idle>();
804  } else {
805  state_machine->StartHoldTimer();
806  // Trigger Ssl Handshake on server side
807  session->TriggerSslHandShake(state_machine->HandShakeCbHandler());
808  state_machine->SendConnectionInfo(&info, event.Name(),
809  "Trigger Server Ssl Handshake");
810  return discard_event();
811  }
812  }
813 
814  sc::result react(const EvStop &event) {
815  XmppStateMachine *state_machine = &context<XmppStateMachine>();
816  state_machine->CancelHoldTimer();
817  if (state_machine->IsActiveChannel() ) {
818  CloseSession(state_machine);
819  state_machine->SendConnectionInfo(event.Name(), "Active");
820  return transit<Active>();
821  } else {
822  state_machine->ResetSession();
823  state_machine->SendConnectionInfo(event.Name(), "Idle");
824  return transit<Idle>();
825  }
826  }
827 
828  sc::result react(const EvTlsHandShakeSuccess &event) {
829  XmppStateMachine *state_machine = &context<XmppStateMachine>();
830  if (event.session != state_machine->session()) {
831  return discard_event();
832  }
833  XmppConnection *connection = state_machine->connection();
834  XmppSession *session = state_machine->session();
835  session->AsyncReadStart();
837  if (state_machine->IsActiveChannel()) { //client
838  if (!connection->SendOpen(session)) {
839  connection->SendClose(session);
840  state_machine->ResetSession();
841  XmppConnectionInfo info;
842  info.set_close_reason("Open send failed in OpenConfirm State");
843  state_machine->SendConnectionInfo(event.Name(), "Active");
844  return transit<Active>();
845  }
846  }
847  // both server and client
848  state_machine->StartHoldTimer();
849  state_machine->SendConnectionInfo(event.Name(),
850  "OpenConfirm Feature Negotiation Success");
851  return discard_event();
852  }
853 
854  sc::result react(const EvTlsHandShakeFailure &event) {
855  XmppStateMachine *state_machine = &context<XmppStateMachine>();
856  if (event.session != state_machine->session()) {
857  return discard_event();
858  }
859  // Do not send stream close as error occured at TLS layer
860  state_machine->ResetSession();
861  if (state_machine->IsActiveChannel()) { // client
862  state_machine->SendConnectionInfo(event.Name(), "Active");
863  return transit<Active>();
864  } else {
865  state_machine->SendConnectionInfo(event.Name(), "Idle");
866  return transit<Idle>();
867  }
868  }
869 
870  //event on server and client
871  sc::result react(const EvXmppOpen &event) {
872  XmppStateMachine *state_machine = &context<XmppStateMachine>();
873  if (event.session != state_machine->session()) {
874  return discard_event();
875  }
876  XmppConnectionInfo info;
877  info.set_identifier(event.msg->from);
878  XmppConnection *connection = state_machine->connection();
879  XmppSession *session = state_machine->session();
880  if (connection->IsActiveChannel()) { //client
881  connection->SendKeepAlive();
882  connection->StartKeepAliveTimer();
883  state_machine->StartHoldTimer();
884  state_machine->SendConnectionInfo(&info, event.Name(),
885  "Established");
886  return transit<XmppStreamEstablished>();
887  } else { //server
888  if (!connection->SendOpenConfirm(session)) {
889  connection->SendClose(session);
890  SM_LOG(state_machine,
891  "Xmpp Send Open Confirm Failed, IDLE");
892  state_machine->ResetSession();
893  info.set_close_reason("Send Open Confirm Failed");
894  state_machine->connection()->set_close_reason(
895  "Send Open Confirm Failed");
896  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
897  return transit<Idle>();
898  } else {
899  if (state_machine->IsAuthEnabled())
900  state_machine->ResurrectOldConnection(connection, session);
901  connection = state_machine->connection();
902  connection->StartKeepAliveTimer();
903  state_machine->StartHoldTimer();
904  state_machine->SendConnectionInfo(&info, event.Name(),
905  "Established");
906  return transit<XmppStreamEstablished>();
907  }
908  }
909  }
910 
911  sc::result react(const EvAdminDown &event) {
912  XmppStateMachine *state_machine = &context<XmppStateMachine>();
913  CloseSession(state_machine);
914  XmppConnectionInfo info;
915  info.set_close_reason("Administratively down");
916  state_machine->connection()->set_close_reason("Administratively down");
917  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
918  return transit<Idle>();
919  }
920 
921  void CloseSession(XmppStateMachine *state_machine) {
922  XmppConnection *connection = state_machine->connection();
923  if (connection != NULL) connection->StopKeepAliveTimer();
924  state_machine->set_session(NULL);
925  }
926 };
927 
929  public sc::state<XmppStreamEstablished, XmppStateMachine> {
930  typedef mpl::list<
931  sc::custom_reaction<EvAdminDown>,
932  sc::custom_reaction<EvTcpClose>,
933  sc::custom_reaction<EvXmppKeepalive>,
934  sc::custom_reaction<EvXmppMessageStanza>,
935  sc::custom_reaction<EvXmppIqStanza>,
936  sc::custom_reaction<EvHoldTimerExpired>,
937  sc::custom_reaction<EvStop>
939 
940  XmppStreamEstablished(my_context ctx) : my_base(ctx) {
941  XmppStateMachine *state_machine = &context<XmppStateMachine>();
942  XmppConnection *connection = state_machine->connection();
943  state_machine->StartHoldTimer();
944  state_machine->set_state(ESTABLISHED);
946  }
948  XmppStateMachine *state_machine = &context<XmppStateMachine>();
949  state_machine->CancelHoldTimer();
950  }
951 
952  sc::result react(const EvTcpClose &event) {
953  XmppStateMachine *state_machine = &context<XmppStateMachine>();
954  if (event.session != state_machine->session()) {
955  return discard_event();
956  }
957  state_machine->ResetSession();
958  if (state_machine->IsActiveChannel()) {
959  state_machine->SendConnectionInfo(event.Name(), "Active");
960  return transit<Active>();
961  } else {
962  state_machine->SendConnectionInfo(event.Name(), "Idle");
963  return transit<Idle>();
964  }
965  }
966 
967  sc::result react(const EvXmppKeepalive &event) {
968  XmppStateMachine *state_machine = &context<XmppStateMachine>();
969  if (event.session != state_machine->session()) {
970  return discard_event();
971  }
972  state_machine->keepalive_count_inc();
973  if (state_machine->get_keepalive_count() == 3) {
974  state_machine->connect_attempts_clear();
975  }
976  state_machine->StartHoldTimer();
977  return discard_event();
978  }
979 
980  sc::result react(const EvXmppMessageStanza &event) {
981  XmppStateMachine *state_machine = &context<XmppStateMachine>();
982  if (event.session != state_machine->session()) {
983  return discard_event();
984  }
985  state_machine->StartHoldTimer();
986  state_machine->connection()->ProcessXmppChatMessage(
987  static_cast<const XmppStanza::XmppChatMessage *>(event.msg.get()));
988  return discard_event();
989  }
990 
991  sc::result react(const EvXmppIqStanza &event) {
992  XmppStateMachine *state_machine = &context<XmppStateMachine>();
993  if (event.session != state_machine->session()) {
994  return discard_event();
995  }
996  state_machine->StartHoldTimer();
997  state_machine->connection()->ProcessXmppIqMessage(
998  static_cast<const XmppStanza::XmppMessage *>(event.msg.get()));
999  return discard_event();
1000  }
1001 
1002  sc::result react(const EvHoldTimerExpired &event) {
1003  XmppStateMachine *state_machine = &context<XmppStateMachine>();
1004  if (state_machine->HoldTimerCancelled()) {
1005  SM_LOG(state_machine,
1006  "Discard EvHoldTimerExpired in (Established) State");
1007  return discard_event();
1008  }
1009  XMPP_NOTICE(XmppStateMachineNotice,
1010  state_machine->connection()->ToUVEKey(),
1012  state_machine->ChannelType(),
1013  "EvHoldTimerExpired in (Established) State. Transit to IDLE");
1014  state_machine->SendConnectionInfo(event.Name());
1015  state_machine->AssertOnHoldTimeout();
1016  state_machine->ResetSession();
1017  if (state_machine->IsActiveChannel()) {
1018  return transit<Active>();
1019  } else {
1020  return transit<Idle>();
1021  }
1022  }
1023 
1024  sc::result react(const EvStop &event) {
1025  XmppStateMachine *state_machine = &context<XmppStateMachine>();
1026  state_machine->SendConnectionInfo(event.Name());
1027  state_machine->ResetSession();
1028  if (state_machine->IsActiveChannel()) {
1029  return transit<Active>();
1030  } else {
1031  return transit<Idle>();
1032  }
1033  }
1034 
1035  sc::result react(const EvAdminDown &event) {
1036  XmppStateMachine *state_machine = &context<XmppStateMachine>();
1037  state_machine->ResetSession();
1038  XmppConnectionInfo info;
1039  info.set_close_reason("Administratively down");
1040  state_machine->connection()->set_close_reason("Administratively down");
1041  state_machine->SendConnectionInfo(&info, event.Name(), "Idle");
1042  return transit<Idle>();
1043  }
1044 };
1045 
1046 } // namespace xmsm
1047 
1049  static bool init_ = false;
1050  static bool assert_ = false;
1051 
1052  if (!init_) {
1053  char *str = getenv("XMPP_ASSERT_ON_HOLD_TIMEOUT");
1054  if (str && strtoul(str, NULL, 0) != 0) assert_ = true;
1055  init_ = true;
1056  }
1057 
1058  if (!assert_) return;
1059 
1060  if (connection()) {
1061  connection()->LogMsg("HOLD TIMER EXPIRED: ");
1062  } else {
1063  LOG4CPLUS_DEBUG(log4cplus::Logger::getRoot(), "HOLD TIMER EXPIRED: ");
1064  }
1065 
1066  assert(!assert_);
1067 }
1068 
1070  XmppConnection *connection = this->connection();
1071  set_session(NULL);
1072  CancelHoldTimer();
1073 
1074  if (!connection)
1075  return;
1076 
1077  // Stop keepalives, transition to IDLE and notify registered entities.
1078  connection->StopKeepAliveTimer();
1079  connection->ChannelMux()->HandleStateEvent(xmsm::IDLE);
1080  if (IsActiveChannel())
1081  return;
1082 
1083  // Retain the connection if graceful restart is supported.
1084  XmppServer *server = dynamic_cast<XmppServer *>(connection->server());
1085  if (!server->IsPeerCloseGraceful())
1086  connection->ManagedDelete();
1087 }
1088 
1090  bool auth_enabled, int config_hold_time)
1091  : work_queue_(TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
1092  connection->GetTaskInstance(),
1093  boost::bind(&XmppStateMachine::DequeueEvent, this, _1)),
1094  connection_(connection),
1095  session_(NULL),
1096  server_(connection->server()),
1097  connect_timer_(
1098  TimerManager::CreateTimer(*server_->event_manager()->io_service(),
1099  "Connect timer",
1100  TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
1101  connection->GetTaskInstance())),
1102  open_timer_(
1103  TimerManager::CreateTimer(*server_->event_manager()->io_service(),
1104  "Open timer",
1105  TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
1106  connection->GetTaskInstance())),
1107  hold_timer_(
1108  TimerManager::CreateTimer(*server_->event_manager()->io_service(),
1109  "Hold timer",
1110  TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
1111  connection->GetTaskInstance())),
1112  config_hold_time_(config_hold_time),
1113  hold_time_(GetConfiguredHoldTime()),
1114  attempts_(0),
1115  keepalive_count_(0),
1116  deleted_(false),
1117  in_dequeue_(false),
1118  is_active_(active),
1119  auth_enabled_(auth_enabled),
1120  state_(xmsm::IDLE),
1121  last_state_(xmsm::IDLE),
1122  openconfirm_state_(xmsm::OPENCONFIRM_INIT) {
1123  handshake_cb_ = boost::bind(
1125 }
1126 
1128  assert(!deleted_);
1129  deleted_ = true;
1131  set_session(NULL);
1132 
1133  // Explicitly call the state destructor before the state machine itself.
1134  // This is needed because some of the destructors access the state machine
1135  // context.
1136  terminate();
1137 
1138  // Delete timer after state machine is terminated so that there is no
1139  // possible reference to the timers being deleted any more
1143 }
1144 
1146  initiate();
1148 }
1149 
1150 // Note this api does not enqueue the deletion of TCP session
1152  if (session_ != NULL) {
1153  session_->set_observer(NULL);
1155  session_->Close();
1157  session_ = NULL;
1158  }
1159 }
1160 
1162  // If there is a session assigned to this state machine, reset the observer
1163  // so that tcp does not have a reference to 'this' which is going away
1164  if (session != NULL) {
1165  session->set_observer(NULL);
1167  session->Close();
1169  }
1170 }
1171 
1173  if (session_ != NULL) {
1176  }
1177  session_ = static_cast<XmppSession *>(session);
1178 }
1179 
1180 void XmppStateMachine::TimerErrorHandler(std::string name, std::string error) {
1181 }
1182 
1185 
1186  // Add up to +/- kJitter percentage to reduce connection collisions.
1187  int ms = ((seconds)? seconds * 1000 : 50);
1188  ms = (ms * (100 - kJitter)) / 100;
1189  ms += (ms * (rand() % (kJitter * 2))) / 100;
1190  connect_timer_->Start(ms,
1191  boost::bind(&XmppStateMachine::ConnectTimerExpired, this),
1192  boost::bind(&XmppStateMachine::TimerErrorHandler, this, _1, _2));
1193 }
1194 
1197 }
1198 
1200  CancelOpenTimer();
1201  open_timer_->Start(seconds * 1000,
1202  boost::bind(&XmppStateMachine::OpenTimerExpired, this),
1203  boost::bind(&XmppStateMachine::TimerErrorHandler, this, _1, _2));
1204 }
1205 
1207  open_timer_->Cancel();
1208 }
1209 
1211  static std::atomic<bool> env_checked = std::atomic<bool>();
1212  static std::atomic<int> env_hold_time = std::atomic<int>();
1213 
1214  // For testing only - configure through environment variable.
1215  if (!env_checked) {
1216  char *keepalive_time_str = getenv("XMPP_KEEPALIVE_SECONDS");
1217  if (keepalive_time_str) {
1218  env_hold_time = strtoul(keepalive_time_str, NULL, 0) * 3;
1219  env_checked = true;
1220  return env_hold_time;
1221  } else {
1222  env_checked = true;
1223  }
1224  } else if (env_hold_time) {
1225  return env_hold_time;
1226  } else if (config_hold_time_) {
1227  return config_hold_time_;
1228  }
1229 
1230  // Use hard coded default.
1231  return kHoldTime;
1232 }
1233 
1235  CancelHoldTimer();
1236 
1237  if (hold_time_ <= 0)
1238  return;
1239 
1240  hold_timer_->Start(hold_time_ * 1000,
1241  boost::bind(&XmppStateMachine::HoldTimerExpired, this),
1242  boost::bind(&XmppStateMachine::TimerErrorHandler, this, _1, _2));
1243 }
1244 
1246  hold_timer_->Cancel();
1247 }
1248 
1250 }
1251 
1253  XMPP_UTDEBUG(XmppStateMachineTimerExpire,
1254  connection() ? connection()->ToUVEKey() : "",
1255  XMPP_PEER_DIR_NA, this->ChannelType(), "Connect", StateName());
1257  return false;
1258 }
1259 
1261  XMPP_NOTICE(XmppEventLog, connection()->ToUVEKey(), XMPP_PEER_DIR_NA,
1262  this->ChannelType(),
1263  "Event: OpenTimer Expired ",
1264  connection()->endpoint().address().to_string(),
1265  connection()->GetTo());
1267  return false;
1268 }
1269 
1270 
1272  boost::system::error_code error;
1273 
1274  // Reset hold timer if there is data already present in the socket.
1275  if (session() && session()->socket() &&
1276  session()->socket()->available(error) > 0) {
1277  return true;
1278  }
1279  XMPP_NOTICE(XmppEventLog, connection()->ToUVEKey(), XMPP_PEER_DIR_NA,
1280  this->ChannelType(), "Event: HoldTimer Expired ",
1281  connection()->endpoint().address().to_string(),
1282  connection()->GetTo());
1284  return false;
1285 }
1286 
1288  TcpSession *session, TcpSession::Event event) {
1289  switch (event) {
1290  case TcpSession::ACCEPT:
1291  break;
1293  XMPP_NOTICE(XmppEventLog, session->ToUVEKey(), XMPP_PEER_DIR_IN,
1294  this->ChannelType(), "Event: Tcp Connected ",
1295  connection()->endpoint().address().to_string(),
1296  connection()->GetTo());
1297  Enqueue(xmsm::EvTcpConnected(static_cast<XmppSession *>(session)));
1298  break;
1300  XMPP_NOTICE(XmppEventLog, session->ToUVEKey(), XMPP_PEER_DIR_IN,
1301  this->ChannelType(), "Event: Tcp Connect Fail ",
1302  connection()->endpoint().address().to_string(),
1303  connection()->GetTo());
1306  break;
1307  case TcpSession::CLOSE:
1308  XMPP_NOTICE(XmppEventLog, session->ToUVEKey(), XMPP_PEER_DIR_IN,
1309  this->ChannelType(), "Event: Tcp Connection Closed ",
1310  connection()->endpoint().address().to_string(),
1311  connection()->GetTo());
1312  Enqueue(xmsm::EvTcpClose(static_cast<XmppSession *>(session)));
1314  break;
1315  default:
1316  XMPP_WARNING(XmppUnknownEvent, session->ToUVEKey(), XMPP_PEER_DIR_IN,
1317  this->ChannelType(), event);
1318  break;
1319  }
1320 }
1321 
1323  string state = "PassiveOpen in state: " + StateName();
1324  XMPP_NOTICE(XmppEventLog, session->ToUVEKey(), XMPP_PEER_DIR_IN,
1325  this->ChannelType(), state,
1326  session->Connection()->endpoint().address().to_string(), "");
1328 }
1329 
1330 // Process XmppStream header message received over a session. Close the stream
1331 // if an old session is still present and undergoing graceful restart.
1332 //
1333 // Return true if msg is enqueued for further processing, false otherwise.
1335  const XmppStanza::XmppMessage *msg) {
1336  XmppConnectionManager *connection_manager =
1337  dynamic_cast<XmppConnectionManager *>(connection_->server());
1338  std::scoped_lock lock(connection_manager->mutex());
1339 
1340  // Update "To" information which can be used to map an older session
1341  session->Connection()->SetTo(msg->from);
1342 
1343  XmppServer *xmpp_server = dynamic_cast<XmppServer *>(server_);
1344  XmppConnectionEndpoint *endpoint = NULL;
1345 
1346  // Look for an endpoint which may already exist
1347  if (xmpp_server) {
1348  endpoint =
1349  xmpp_server->FindConnectionEndpoint(connection_->ToString());
1350 
1351  if (!xmpp_server->subcluster_name().empty() &&
1352  xmpp_server->subcluster_name() != msg->xmlns) {
1353  string reason = "Subcluster mismatch: Agent subcluster " +
1354  msg->xmlns + ", Control subcluster " +
1355  xmpp_server->subcluster_name();
1356  XMPP_WARNING(XmppDeleteConnection, session->ToUVEKey(),
1358  "Drop new xmpp connection " + session->ToString() +
1359  " as " + reason);
1360  session->Connection()->set_close_reason(reason);
1362  delete msg;
1363  return;
1364  }
1365  }
1366 
1367  // If there is no connection already associated with the end-point,
1368  // process the incoming open message and move forward with the session
1369  // establishment.
1370  if (!endpoint || !endpoint->connection() ||
1371  connection_ == endpoint->connection()) {
1373  return;
1374  }
1375 
1376  // Check if the IP addresses match.
1377  boost::asio::ip::address addr =
1378  endpoint->connection()->endpoint().address();
1379  if (connection_->endpoint().address() != addr) {
1380  XMPP_WARNING(XmppDeleteConnection, session->ToUVEKey(),
1382  "Drop new xmpp connection " + session->ToString() +
1383  " as another connection with same name " + msg->from +
1384  " but with different IP address " + addr.to_string() +
1385  " already exists");
1387  delete msg;
1388  return;
1389  }
1390 
1391  XmppChannelMux *channel = endpoint->connection()->ChannelMux();
1392 
1393  // If GR Helper mode is not enabled, ignore the new connection request.
1394  // Existing connection, if down will get cleaned up eventually. If it is
1395  // up, it shall remain intact.
1396  if (!xmpp_server->IsPeerCloseGraceful()) {
1397  XMPP_NOTICE(XmppDeleteConnection, session->ToUVEKey(),
1399  "Drop new xmpp connection " + session->ToString() +
1400  " as another connection is alreready present");
1402  delete msg;
1403  return;
1404  }
1405 
1406  XmppStateMachine *old_sm = endpoint->connection()->state_machine();
1407 
1408  // Bring down old session if connection is already up and ready. This is
1409  // the scenario in which old session's TCP did not learn the session down
1410  // event, possibly due to compute cold reboot. In that case, trigger
1411  // closure (and possibly GR) process for the old session.
1412  if (channel->GetPeerState() == xmps::READY) {
1413  XMPP_NOTICE(XmppDeleteConnection, old_sm->session()->ToUVEKey(),
1414  XMPP_PEER_DIR_IN, "Delete old xmpp connection " +
1415  old_sm->session()->ToString() +
1416  " as a new connection as been initiated (GR Helper is active)");
1417  old_sm->Enqueue(xmsm::EvTcpClose(old_sm->session()));
1418 
1419  // Drop the new session until old one is deleted or marked stale.
1421  delete msg;
1422  return;
1423  }
1424 
1425  // If previous closure is still in progress, drop the new connection.
1426  if (channel->ReceiverCount()) {
1427  XMPP_NOTICE(XmppDeleteConnection, session->ToUVEKey(),
1429  "Drop new xmpp connection " + session->ToString() +
1430  " as current connection is still under deletion");
1432  delete msg;
1433  return;
1434  }
1435 
1436  // Now we reach for the classic GR case, in which existing session stale
1437  // process is complete, (peer is in GR/LLGR timer wait state).
1438  // In this case, we should process the open message, and later switch to
1439  // the new connection and state machine, retaining the old XmppPeer,
1440  // BgpXmppChannel, routes, etc.
1442 }
1443 
1445  const XmppStanza::XmppMessage *msg) {
1446  if (!Enqueue(xmsm::EvXmppMessage(session, msg)))
1447  delete msg;
1448 }
1449 
1451  const XmppStanza::XmppMessage *msg) {
1452  // Bail if session is already reset and disassociated from the connection.
1453  if (!session->Connection()) {
1454  delete msg;
1455  return;
1456  }
1457 
1458  const XmppStanza::XmppStreamMessage *stream_msg =
1459  static_cast<const XmppStanza::XmppStreamMessage *>(msg);
1460 
1461  switch (msg->type) {
1463  if (stream_msg->strmtype ==
1465 
1466  switch (stream_msg->strmtlstype) {
1469  msg));
1470  break;
1473  break;
1476  break;
1477  default:
1478  break;
1479  }
1480 
1481  } else if (stream_msg->strmtype ==
1483  stream_msg->strmtype ==
1486  break;
1489  break;
1490  case XmppStanza::IQ_STANZA:
1492  break;
1495  break;
1496  default:
1497  if (!msg->IsValidType(msg->type)) {
1498  XMPP_NOTICE(XmppStateMachineUnsupportedMessage,
1500  ChannelType(), (int)msg->type);
1501  }
1502  delete msg;
1503  break;
1504  }
1505 
1506 }
1507 
1509  Enqueue(xmsm::EvStop());
1510 }
1511 
1513  assert(IsActiveChannel());
1514  if (down) {
1516  } else {
1518  }
1519 }
1520 
1523  XmppSession *sess = static_cast<XmppSession *>(session);
1524  switch(resp) {
1527  break;
1530  break;
1531  default:
1532  break;
1533  }
1534 }
1535 
1537  last_state_ = state_;
1538  state_ = state;
1540 
1541  if (!logUVE()) return;
1542 
1543  XmppPeerInfoData peer_info;
1544  peer_info.set_name(connection()->ToUVEKey());
1545  PeerStateInfo state_info;
1546  state_info.set_state(StateName());
1547  state_info.set_last_state(LastStateName());
1548  state_info.set_last_state_at(state_since_);
1549  peer_info.set_state_info(state_info);
1550  assert(!peer_info.get_name().empty());
1551  XMPPPeerInfo::Send(peer_info);
1552 }
1553 
1554 
1556  openconfirm_state_ = state;
1557 }
1558 
1559 static const char *state_names[] = {
1560  "Idle",
1561  "Active",
1562  "Connect",
1563  "OpenSent",
1564  "OpenConfirm",
1565  "Established" };
1566 
1568  return state_names[state_];
1569 }
1570 
1572  return state_names[last_state_];
1573 }
1574 
1577 }
1578 
1580  return state_;
1581 }
1582 
1584  return openconfirm_state_;
1585 }
1586 
1588  connection_->set_session(static_cast<XmppSession *>(session_));
1589 }
1590 
1592 
1594  int backoff = attempts_ > 6 ? 6 : attempts_;
1595  return std::min(backoff ? 1 << (backoff - 1) : 0, kConnectInterval);
1596 }
1597 
1599  return is_active_;
1600 }
1601 
1603  return connection()->logUVE();
1604 }
1605 
1607  return (IsActiveChannel() ? " Mode Client: " : " Mode Server: " );
1608 }
1609 
1611  boost::intrusive_ptr<const sc::event_base> event) {
1612  // Process message event and enqueue additional events as necessary.
1613  const xmsm::EvXmppMessage *ev_xmpp_message =
1614  dynamic_cast<const xmsm::EvXmppMessage *>(event.get());
1615  if (ev_xmpp_message) {
1616  ProcessMessage(ev_xmpp_message->session, ev_xmpp_message->msg);
1617  } else {
1618  ProcessEvent(*event);
1619  event.reset();
1620  }
1621  return true;
1622 }
1623 
1624 void XmppStateMachine::ProcessEvent(const sc::event_base &event) {
1625  const xmsm::EvTcpDeleteSession *deferred_delete =
1626  dynamic_cast<const xmsm::EvTcpDeleteSession *>(&event);
1627  XMPP_UTDEBUG(XmppStateMachineDequeueEvent,
1628  connection() ? connection()->ToUVEKey() : "",
1630  connection() ?
1631  connection()->endpoint().address().to_string() : "",
1632  connection() ? connection()->GetTo() : "");
1633  if (deferred_delete) {
1634  TcpSession *session = deferred_delete->session;
1636  return;
1637  }
1638  if (deleted_) {
1639  return;
1640  }
1641 
1642  update_last_event(TYPE_NAME(event));
1643  in_dequeue_ = true;
1644  process_event(event);
1645  in_dequeue_ = false;
1646 }
1647 
1648 void XmppStateMachine::unconsumed_event(const sc::event_base &event) {
1649  XMPP_INFO(XmppUnconsumedEvent, connection() ? connection()->ToUVEKey() : "",
1651 }
1652 
1653 void XmppStateMachine::update_last_event(const std::string &event) {
1654  set_last_event(event);
1655 
1656  if (!logUVE()) return;
1657 
1658  // Skip iq and message events.
1659  if (event == "xmsm::EvXmppIqStanza" ||
1660  event == "xmsm::EvXmppMessageStanza") {
1661  return;
1662  }
1663 
1664  // Skip keepalive events after we've reached established state.
1665  if (state_ == xmsm::ESTABLISHED && event == "xmsm::EvXmppKeepalive") {
1666  return;
1667  }
1668 
1669  XmppPeerInfoData peer_info;
1670  peer_info.set_name(connection()->ToUVEKey());
1671  PeerEventInfo event_info;
1672  event_info.set_last_event(last_event_);
1673  event_info.set_last_event_at(last_event_at_);
1674  peer_info.set_event_info(event_info);
1675 
1676  assert(!peer_info.get_name().empty());
1677  XMPPPeerInfo::Send(peer_info);
1678 }
1679 
1680 //
1681 // Enqueue an event to xmpp state machine.
1682 // Return false if the event is not enqueued.
1683 //
1684 bool XmppStateMachine::Enqueue(const sc::event_base &event) {
1685  if (!deleted_) {
1686  work_queue_.Enqueue(event.intrusive_from_this());
1687  return true;
1688  }
1689 
1690  return false;
1691 }
1692 
1693 // Object trace routines.
1694 void XmppStateMachine::SendConnectionInfo(const string &event,
1695  const string &nextstate) {
1696  XmppConnectionInfo info;
1697  SendConnectionInfo(&info, event, nextstate);
1698  return;
1699 }
1700 
1701 void XmppStateMachine::SendConnectionInfo(XmppConnectionInfo *info,
1702  const string &event, const string &nextstate) {
1703 
1704  info->set_ip_address(this->connection()->endpoint().address().to_string());
1705  info->set_state(StateName());
1706  info->set_event(event);
1707  if (!nextstate.empty()) {
1708  info->set_next_state(nextstate);
1709  }
1710  XMPP_CONNECTION_LOG_MSG(*info);
1711  return;
1712 }
1713 
1714 // Resurrect an old xmpp connection if present (when under GracefulRestart)
1715 //
1716 // During Graceful Restart (or otherwise), new connections are rejected in
1717 // ProcessStreamHeaderMessage() itself until old one's cleanup process is
1718 // complete and the system is ready to start a new session.
1719 //
1720 // Hence in here, when called upon receipt of OpenMessage, we can try to reuse
1721 // old XmppConnection if present and there by complete any pending GR process
1722 //
1723 // We do so by reusing XmppConnection, XmppChannel, etc. from the old connection
1724 // and only use the XmppSession and XmppStateMachine from the new session
1725 //
1726 // New connection is instead associated with the old state machine and session,
1727 // and their deletion is triggered
1729  XmppSession *new_session) {
1730 
1731  // Look for an endpoint (which is a persistent data structure) across
1732  // xmpp session flips
1733  bool created;
1734  XmppConnectionEndpoint *connection_endpoint =
1735  static_cast<XmppServer *>(
1736  new_connection->server())->LocateConnectionEndpoint(
1737  static_cast<XmppServerConnection *>(new_connection), created);
1738 
1739  // If this is a new endpoint, then there is no older connection to manage.
1740  if (created)
1741  return;
1742 
1743  // GR Helper must be enabled when we are trying to resurrect connection.
1744  XmppServer *server = dynamic_cast<XmppServer *>(new_connection->server());
1745  assert(server->IsPeerCloseGraceful());
1746 
1747  XMPP_NOTICE(XmppCreateConnection, new_session->ToUVEKey(),
1749  "Resurrect xmpp connection " + new_session->ToString());
1750 
1751  // Retrieve old XmppConnection and XmppStateMachine (to reuse)
1752  XmppConnection *old_xmpp_connection = connection_endpoint->connection();
1753  assert(old_xmpp_connection);
1754 
1755  XmppStateMachine *old_state_machine = old_xmpp_connection->state_machine();
1756  assert(old_state_machine);
1757 
1758  // Swap Old and New connections and state machines linkages
1759  new_connection->SwapXmppStateMachine(old_xmpp_connection);
1760  this->SwapXmppConnection(old_state_machine);
1761 
1762  // Update XmppConnection in the old session.
1763  XmppSession *old_xmpp_session = old_state_machine->session();
1764  if (old_xmpp_session)
1765  old_xmpp_session->SetConnection(new_connection);
1766  new_session->SetConnection(old_xmpp_connection);
1767 
1768  // Set new session with the old connection as it would be the current active
1769  // connection from now on.
1770  old_xmpp_connection->set_session(new_session);
1771 
1772  // Trigger deletion of the new connection which now is associated wth the
1773  // the old_state_machine
1774  new_connection->Shutdown();
1775 }
1776 
1778  swap(connection_, other->connection_);
1780 }
virtual Socket * socket() const
Definition: ssl_session.cc:97
void TriggerSslHandShake(SslHandShakeCallbackHandler)
Definition: ssl_session.cc:199
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:304
virtual void Connect(TcpSession *session, Endpoint remote)
Definition: tcp_server.cc:475
virtual void DeleteSession(TcpSession *session)
Definition: tcp_server.cc:198
@ CONNECT_COMPLETE
Definition: tcp_session.h:46
@ CONNECT_FAILED
Definition: tcp_session.h:47
TcpServer * server()
Definition: tcp_session.h:84
const std::string & ToUVEKey() const
Definition: tcp_session.h:174
int32_t remote_port() const
Definition: tcp_session.cc:547
virtual std::string ToString() const
Definition: tcp_session.h:79
void set_observer(EventObserver observer)
Definition: tcp_session.cc:218
virtual void AsyncReadStart()
Definition: tcp_session.cc:174
int32_t local_port() const
Definition: tcp_session.cc:535
void Close()
Definition: tcp_session.cc:354
static bool DeleteTimer(Timer *Timer)
Definition: timer.cc:221
bool Cancel()
Definition: timer.cc:149
bool Start(int time, Handler handler, ErrorHandler error_handler=NULL)
Definition: timer.cc:107
bool Enqueue(QueueEntryT entry)
Definition: queue_task.h:248
void Shutdown(bool delete_entries=true)
Definition: queue_task.h:152
void HandleStateEvent(xmsm::XmState state)
virtual xmps::PeerState GetPeerState() const
size_t ReceiverCount() const
XmppConnection * connection()
std::mutex & mutex() const
virtual void increment_flap_count()=0
bool IsActiveChannel() const
XmppChannelMux * ChannelMux()
virtual bool SendStreamFeatureRequest(XmppSession *session)
int ProcessXmppIqMessage(const XmppStanza::XmppMessage *)
XmppSession * CreateSession()
std::string & GetTo()
bool IsDeleted() const
void SwapContents(XmppConnection *other)
virtual boost::asio::ip::tcp::endpoint local_endpoint() const
virtual bool SendOpen(XmppSession *session)
virtual void ManagedDelete()=0
virtual bool SendStartTls(XmppSession *session)
virtual boost::asio::ip::tcp::endpoint endpoint() const
TcpServer * server()
virtual bool SendProceedTls(XmppSession *session)
int ProcessXmppChatMessage(const XmppStanza::XmppChatMessage *)
bool logUVE() const
void SetTo(const std::string &)
void SwapXmppStateMachine(XmppConnection *other)
void StartKeepAliveTimer()
void SendClose(XmppSession *session)
XmppStateMachine * state_machine()
virtual bool SendOpenConfirm(XmppSession *session)
void ProcessSslHandShakeResponse(SslSessionPtr session, const boost::system::error_code &error)
const std::string & ToString() const
void set_session(XmppSession *session)
const std::string & ToUVEKey() const
virtual void set_close_reason(const std::string &reason)=0
virtual bool IsPeerCloseGraceful() const
Definition: xmpp_server.cc:280
XmppConnectionEndpoint * FindConnectionEndpoint(const std::string &endpoint_name)
Definition: xmpp_server.cc:675
const std::string subcluster_name() const
Definition: xmpp_server.h:105
XmppConnection * Connection()
Definition: xmpp_session.h:26
void SetConnection(XmppConnection *connection)
Definition: xmpp_session.cc:52
void ClearConnection()
Definition: xmpp_session.cc:63
XmppMessageType type
Definition: xmpp_proto.h:57
bool IsValidType(XmppMessageType type) const
Definition: xmpp_proto.h:64
@ WHITESPACE_MESSAGE_STANZA
Definition: xmpp_proto.h:20
@ MESSAGE_STANZA
Definition: xmpp_proto.h:18
@ STREAM_HEADER
Definition: xmpp_proto.h:17
void update_last_event(const std::string &event)
xmsm::XmOpenConfirmState OpenConfirmStateType() const
void set_state(xmsm::XmState state)
void ProcessEvent(const sc::event_base &event)
xmsm::XmState get_state()
virtual void StartHoldTimer()
void SetAdminState(bool down)
XmppSession * session_
XmppStateMachine(XmppConnection *connection, bool active, bool auth_enabled=false, int config_hold_time=kHoldTime)
void DeleteSession(XmppSession *session)
std::string StateName() const
virtual void StartOpenTimer(int seconds)
static const int kConnectInterval
bool DequeueEvent(boost::intrusive_ptr< const sc::event_base > event)
void OnStart(const xmsm::EvStart &event)
SslHandShakeCallbackHandler HandShakeCbHandler()
void ProcessStreamHeaderMessage(XmppSession *session, const XmppStanza::XmppMessage *msg)
xmsm::XmState StateType() const
XmppConnection * connection()
const char * ChannelType()
WorkQueue< boost::intrusive_ptr< const sc::event_base > > work_queue_
void set_last_event(const std::string &event)
void TimerErrorHandler(std::string name, std::string error)
std::string LastStateName() const
bool PassiveOpen(XmppSession *session)
virtual void StartConnectTimer(int seconds)
void SwapXmppConnection(XmppStateMachine *other)
XmppConnection * connection_
std::string LastStateChangeAt() const
void ProcessMessage(XmppSession *session, const XmppStanza::XmppMessage *msg)
xmsm::XmOpenConfirmState openconfirm_state_
void OnEvent(SslSession *session, xmsm::SslHandShakeResponse)
bool Enqueue(const sc::event_base &ev)
void OnMessage(XmppSession *session, const XmppStanza::XmppMessage *msg)
void set_session(TcpSession *session)
int get_keepalive_count() const
xmsm::XmState state_
XmppSession * session()
void set_openconfirm_state(xmsm::XmOpenConfirmState state)
int GetConfiguredHoldTime() const
void SendConnectionInfo(const std::string &event, const std::string &nextstate="")
int get_connect_attempts() const
xmsm::XmState last_state_
static const int kMaxAttempts
void ResurrectOldConnection(XmppConnection *connection, XmppSession *session)
static const int kHoldTime
static const int kOpenTime
static const int kJitter
virtual void OnSessionEvent(TcpSession *session, TcpSession::Event event)
void unconsumed_event(const sc::event_base &event)
SslHandShakeCallbackHandler handshake_cb_
#define TYPE_NAME(_type)
Definition: logging.h:32
#define LOG(_Level, _Msg)
Definition: logging.h:34
@ READY
Definition: xmpp_channel.h:17
@ EvTLSHANDSHAKE_SUCCESS
@ EvTLSHANDSHAKE_FAILURE
@ OPENCONFIRM_FEATURE_NEGOTIATION
@ OPENCONFIRM_FEATURE_SUCCESS
@ OPENCONFIRM_INIT
static const std::string integerToString(const NumberType &num)
Definition: string_util.h:19
XmppStreamTlsType strmtlstype
Definition: xmpp_proto.h:99
XmppStreamMsgType strmtype
Definition: xmpp_proto.h:98
Active(my_context ctx)
sc::result react(const EvXmppOpen &event)
mpl::list< sc::custom_reaction< EvAdminDown >, sc::custom_reaction< EvConnectTimerExpired >, sc::custom_reaction< EvOpenTimerExpired >, sc::custom_reaction< EvTcpPassiveOpen >, sc::custom_reaction< EvTcpClose >, sc::custom_reaction< EvXmppOpen >, sc::custom_reaction< EvStop > > reactions
sc::result react(const EvConnectTimerExpired &event)
sc::result react(const EvAdminDown &event)
sc::result react(const EvStop &event)
sc::result react(const EvTcpPassiveOpen &event)
sc::result react(const EvOpenTimerExpired &event)
sc::result react(const EvTcpClose &event)
void StartSession(XmppStateMachine *state_machine)
void CloseSession(XmppStateMachine *state_machine)
sc::result react(const EvAdminDown &event)
sc::result react(const EvTcpConnectFail &event)
mpl::list< sc::custom_reaction< EvAdminDown >, sc::custom_reaction< EvConnectTimerExpired >, sc::custom_reaction< EvTcpConnected >, sc::custom_reaction< EvTcpConnectFail >, sc::custom_reaction< EvTcpClose >, sc::custom_reaction< EvStop > > reactions
sc::result react(const EvTcpClose &event)
sc::result react(const EvStop &event)
sc::result react(const EvTcpConnected &event)
Connect(my_context ctx)
sc::result react(const EvConnectTimerExpired &event)
static const char * Name()
static const char * Name()
static const char * Name()
static const char * Name()
static const char * Name()
boost::shared_ptr< const XmppStanza::XmppMessage > msg
EvStartTls(XmppSession *session, const XmppStanza::XmppMessage *msg)
static const char * Name()
static const char * Name()
boost::shared_ptr< const XmppStanza::XmppMessage > msg
EvStreamFeatureRequest(XmppSession *session, const XmppStanza::XmppMessage *msg)
static const char * Name()
EvTcpClose(XmppSession *session)
EvTcpConnectFail(XmppSession *session)
static const char * Name()
static const char * Name()
EvTcpConnected(XmppSession *session)
EvTcpDeleteSession(TcpSession *session)
static const char * Name()
EvTcpPassiveOpen(XmppSession *session)
static const char * Name()
EvTlsHandShakeFailure(XmppSession *session)
EvTlsHandShakeSuccess(XmppSession *session)
EvTlsProceed(XmppSession *session, const XmppStanza::XmppMessage *msg)
boost::shared_ptr< const XmppStanza::XmppMessage > msg
static const char * Name()
EvXmppIqStanza(XmppSession *session, const XmppStanza::XmppMessage *msg)
static const char * Name()
boost::shared_ptr< const XmppStanza::XmppMessage > msg
static const char * Name()
EvXmppKeepalive(XmppSession *session, const XmppStanza::XmppMessage *msg)
boost::shared_ptr< const XmppStanza::XmppMessage > msg
boost::shared_ptr< const XmppStanza::XmppMessage > msg
static const char * Name()
EvXmppMessageStanza(XmppSession *session, const XmppStanza::XmppMessage *msg)
static const char * Name()
EvXmppMessage(XmppSession *session, const XmppStanza::XmppMessage *msg)
const XmppStanza::XmppMessage * msg
static const char * Name()
EvXmppOpenReceive(XmppSession *session)
boost::shared_ptr< const XmppStanza::XmppStreamMessage > msg
EvXmppOpen(XmppSession *session, const XmppStanza::XmppMessage *msg)
static const char * Name()
sc::transition< EvStart, Active, XmppStateMachine, &XmppStateMachine::OnStart > reactions
Idle(my_context ctx)
sc::result react(const EvStartTls &event)
sc::result react(const EvStop &event)
sc::result react(const EvHoldTimerExpired &event)
mpl::list< sc::custom_reaction< EvAdminDown >, sc::custom_reaction< EvTcpClose >, sc::custom_reaction< EvHoldTimerExpired >, sc::custom_reaction< EvStreamFeatureRequest >, sc::custom_reaction< EvStartTls >, sc::custom_reaction< EvTlsProceed >, sc::custom_reaction< EvTlsHandShakeSuccess >, sc::custom_reaction< EvTlsHandShakeFailure >, sc::custom_reaction< EvXmppOpen >, sc::custom_reaction< EvStop > > reactions
sc::result react(const EvTlsHandShakeSuccess &event)
OpenConfirm(my_context ctx)
void CloseSession(XmppStateMachine *state_machine)
sc::result react(const EvTcpClose &event)
sc::result react(const EvTlsHandShakeFailure &event)
sc::result react(const EvTlsProceed &event)
sc::result react(const EvAdminDown &event)
sc::result react(const EvXmppOpen &event)
sc::result react(const EvStreamFeatureRequest &event)
sc::result react(const EvAdminDown &event)
sc::result react(const EvStop &event)
mpl::list< sc::custom_reaction< EvAdminDown >, sc::custom_reaction< EvTcpClose >, sc::custom_reaction< EvXmppOpen >, sc::custom_reaction< EvHoldTimerExpired >, sc::custom_reaction< EvStop > > reactions
OpenSent(my_context ctx)
sc::result react(const EvTcpClose &event)
sc::result react(const EvXmppOpen &event)
void CloseSession(XmppStateMachine *state_machine)
sc::result react(const EvHoldTimerExpired &event)
sc::result react(const EvXmppMessageStanza &event)
sc::result react(const EvTcpClose &event)
sc::result react(const EvXmppIqStanza &event)
sc::result react(const EvStop &event)
sc::result react(const EvHoldTimerExpired &event)
sc::result react(const EvAdminDown &event)
sc::result react(const EvXmppKeepalive &event)
mpl::list< sc::custom_reaction< EvAdminDown >, sc::custom_reaction< EvTcpClose >, sc::custom_reaction< EvXmppKeepalive >, sc::custom_reaction< EvXmppMessageStanza >, sc::custom_reaction< EvXmppIqStanza >, sc::custom_reaction< EvHoldTimerExpired >, sc::custom_reaction< EvStop > > reactions
static boost::posix_time::ptime UTCUsecToPTime(uint64_t tusec)
Definition: time_util.h:38
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13
#define XMPP_PEER_DIR_NA
Definition: xmpp_log.h:16
#define XMPP_UTDEBUG(obj,...)
Definition: xmpp_log.h:67
#define XMPP_WARNING(obj,...)
Definition: xmpp_log.h:35
#define XMPP_INFO(obj,...)
Definition: xmpp_log.h:51
#define XMPP_CONNECTION_LOG_MSG(info)
Definition: xmpp_log.h:83
#define XMPP_NOTICE(obj,...)
Definition: xmpp_log.h:43
#define XMPP_PEER_DIR_IN
Definition: xmpp_log.h:15
#define SM_LOG(_sm, _msg)
static const char * state_names[]