Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "base/util.h"
6 : #include "base/logging.h"
7 : #include "base/connection_info.h"
8 : #include "base/address_util.h"
9 : #include "cmn/agent_cmn.h"
10 : #include "controller/controller_dns.h"
11 : #include "controller/controller_init.h"
12 : #include "xmpp/xmpp_channel.h"
13 : #include "pugixml/pugixml.hpp"
14 : #include "xml/xml_pugi.h"
15 : #include "bind/xmpp_dns_agent.h"
16 :
17 : using process::ConnectionState;
18 : using process::ConnectionType;
19 : using process::ConnectionStatus;
20 :
21 : AgentDnsXmppChannel::DnsMessageHandler AgentDnsXmppChannel::dns_message_handler_cb_;
22 : AgentDnsXmppChannel::DnsXmppEventHandler AgentDnsXmppChannel::dns_xmpp_event_handler_cb_;
23 :
24 1 : AgentDnsXmppChannel::AgentDnsXmppChannel(Agent *agent,
25 1 : std::string xmpp_server, uint8_t xs_idx)
26 2 : : channel_(NULL), xmpp_server_(xmpp_server), xs_idx_(xs_idx),
27 1 : agent_(agent) {
28 1 : }
29 :
30 2 : AgentDnsXmppChannel::~AgentDnsXmppChannel() {
31 1 : if (channel_) {
32 1 : channel_->UnRegisterWriteReady(xmps::DNS);
33 1 : channel_->UnRegisterReceive(xmps::DNS);
34 : }
35 2 : }
36 :
37 1 : void AgentDnsXmppChannel::RegisterXmppChannel(XmppChannel *channel) {
38 1 : if (channel == NULL)
39 0 : return;
40 :
41 1 : channel_ = channel;
42 1 : channel->RegisterReceive(xmps::DNS,
43 : boost::bind(&AgentDnsXmppChannel::ReceiveInternal, this, _1));
44 : }
45 :
46 0 : bool AgentDnsXmppChannel::SendMsg(uint8_t *msg, std::size_t len) {
47 0 : if (!channel_ || channel_->GetPeerState() != xmps::READY)
48 0 : return false;
49 :
50 0 : return channel_->Send((const uint8_t *)msg, len, xmps::DNS,
51 0 : boost::bind(&AgentDnsXmppChannel::WriteReadyCb, this, _1));
52 : }
53 :
54 0 : void AgentDnsXmppChannel::ReceiveMsg(const XmppStanza::XmppMessage *msg) {
55 0 : if (msg && msg->type == XmppStanza::IQ_STANZA) {
56 0 : std::unique_ptr<XmlBase> impl(XmppXmlImplFactory::Instance()->GetXmlImpl());
57 0 : XmlPugi *pugi = reinterpret_cast<XmlPugi *>(impl.get());
58 0 : XmlPugi *msg_pugi = reinterpret_cast<XmlPugi *>(msg->dom.get());
59 0 : pugi->LoadXmlDoc(msg_pugi->doc()); //Verify Xmpp message format
60 : boost::shared_ptr<ControllerXmppData> data(new ControllerXmppData(xmps::DNS,
61 : xmps::UNKNOWN,
62 0 : xs_idx_,
63 0 : std::move(impl),
64 0 : true));
65 0 : agent_->controller()->Enqueue(data);
66 0 : }
67 0 : }
68 :
69 0 : void AgentDnsXmppChannel::ReceiveInternal(const XmppStanza::XmppMessage *msg) {
70 0 : ReceiveMsg(msg);
71 0 : }
72 :
73 0 : void AgentDnsXmppChannel::ReceiveDnsMessage(std::unique_ptr<XmlBase> impl) {
74 0 : XmlPugi *pugi = reinterpret_cast<XmlPugi *>(impl.get());
75 0 : pugi::xml_node node = pugi->FindNode("dns");
76 : DnsAgentXmpp::XmppType xmpp_type;
77 : uint32_t xid;
78 : uint16_t code;
79 0 : std::unique_ptr<DnsUpdateData> xmpp_data(new DnsUpdateData);
80 0 : if (DnsAgentXmpp::DnsAgentXmppDecode(node, xmpp_type, xid,
81 : code, xmpp_data.get())) {
82 0 : if (!dns_message_handler_cb_.empty())
83 0 : dns_message_handler_cb_(xmpp_data.release(), xmpp_type,
84 : NULL, false);
85 : }
86 0 : }
87 :
88 0 : std::string AgentDnsXmppChannel::ToString() const {
89 0 : return channel_->ToString();
90 : }
91 :
92 0 : void AgentDnsXmppChannel::WriteReadyCb(const boost::system::error_code &ec) {
93 0 : }
94 :
95 0 : void AgentDnsXmppChannel::XmppClientChannelEvent(AgentDnsXmppChannel *peer,
96 : xmps::PeerState state) {
97 0 : std::unique_ptr<XmlBase> dummy_dom;
98 : boost::shared_ptr<ControllerXmppData> data(new ControllerXmppData(xmps::DNS,
99 : state,
100 0 : peer->GetXmppServerIdx(),
101 0 : std::move(dummy_dom),
102 0 : false));
103 0 : peer->agent()->controller()->Enqueue(data);
104 0 : }
105 :
106 : /*
107 : * AgentDnsXmppChannel state TimedOut
108 : *
109 : * If there are more than two channels available in config, then try picking
110 : * other channel to replace this timed out channel. And push this channel at the
111 : * end of the channel list so that it is picked only in worst case.
112 : *
113 : * If there are only two channels configured, no action to be taken.
114 : */
115 0 : void AgentDnsXmppChannel::TimedOut() {
116 0 : bool update_list = false;
117 0 : std::vector<string>::iterator iter = agent_->GetDnslist().begin();
118 0 : std::vector<string>::iterator end = agent_->GetDnslist().end();
119 0 : for (; iter != end; iter++) {
120 0 : std::vector<string> server;
121 0 : boost::split(server, *iter, boost::is_any_of(":"));
122 0 : if (GetXmppServer().compare(server[0]) == 0) {
123 : // Add the TIMEDOUT server to the end.
124 0 : if (iter + 1 == end) break;
125 0 : std::rotate(iter, iter + 1, end);
126 0 : update_list = true;
127 0 : break;
128 : }
129 0 : }
130 0 : if (update_list) {
131 0 : agent_->controller()->ReConnectDnsServer();
132 : }
133 0 : }
134 :
135 0 : void AgentDnsXmppChannel::HandleXmppClientChannelEvent(AgentDnsXmppChannel *peer,
136 : xmps::PeerState state) {
137 0 : peer->UpdateConnectionInfo(state);
138 0 : if (state == xmps::READY) {
139 0 : if (!peer->dns_xmpp_event_handler_cb_.empty())
140 0 : peer->dns_xmpp_event_handler_cb_(peer);
141 0 : } else if (state == xmps::TIMEDOUT) {
142 0 : peer->TimedOut();
143 : }
144 0 : }
145 :
146 1 : void AgentDnsXmppChannel::set_dns_message_handler_cb(DnsMessageHandler cb) {
147 1 : dns_message_handler_cb_ = cb;
148 1 : }
149 :
150 1 : void AgentDnsXmppChannel::set_dns_xmpp_event_handler_cb(DnsXmppEventHandler cb){
151 1 : dns_xmpp_event_handler_cb_ = cb;
152 1 : }
153 :
154 1 : void AgentDnsXmppChannel::UpdateConnectionInfo(xmps::PeerState state) {
155 1 : if (agent_->connection_state() == NULL)
156 0 : return;
157 :
158 1 : boost::asio::ip::tcp::endpoint ep;
159 1 : boost::system::error_code ec;
160 1 : std::string last_state_name;
161 1 : ep.address(AddressFromString(agent_->dns_server(xs_idx_), &ec));
162 1 : ep.port(agent_->dns_server_port(xs_idx_));
163 1 : const std::string name = agent_->xmpp_dns_server_prefix() +
164 2 : ep.address().to_string();
165 1 : XmppChannel *xc = GetXmppChannel();
166 1 : if (xc) {
167 1 : last_state_name = xc->LastStateName();
168 : }
169 1 : if (state == xmps::READY) {
170 0 : agent_->connection_state()->Update(ConnectionType::XMPP, name,
171 : ConnectionStatus::UP, ep,
172 : last_state_name);
173 : } else {
174 1 : agent_->connection_state()->Update(ConnectionType::XMPP, name,
175 : ConnectionStatus::DOWN, ep,
176 : last_state_name);
177 : }
178 1 : }
|