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