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