Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "xmpp/xmpp_client.h"
6 :
7 : #include <boost/foreach.hpp>
8 : #include <boost/tuple/tuple.hpp>
9 :
10 : #include "base/task_annotations.h"
11 : #include "xmpp/xmpp_factory.h"
12 : #include "xmpp/xmpp_log.h"
13 : #include "xmpp/xmpp_session.h"
14 :
15 : #include "sandesh/common/vns_types.h"
16 : #include "sandesh/common/vns_constants.h"
17 : #include "sandesh/xmpp_client_server_sandesh_types.h"
18 :
19 : using namespace std;
20 : using namespace boost::asio;
21 : using boost::tie;
22 :
23 : class XmppClient::DeleteActor : public LifetimeActor {
24 : public:
25 5036 : DeleteActor(XmppClient *client)
26 5036 : : LifetimeActor(client->lifetime_manager()), client_(client) { }
27 5036 : virtual bool MayDelete() const {
28 5036 : CHECK_CONCURRENCY("bgp::Config");
29 5036 : return (client_->GetSessionQueueSize() == 0);
30 : }
31 5036 : virtual void Shutdown() {
32 5036 : CHECK_CONCURRENCY("bgp::Config");
33 5036 : }
34 5036 : virtual void Destroy() {
35 5036 : CHECK_CONCURRENCY("bgp::Config");
36 5036 : }
37 :
38 : private:
39 : XmppClient *client_;
40 : };
41 :
42 35 : XmppClient::XmppClient(EventManager *evm)
43 : : XmppConnectionManager(evm, ssl::context::sslv23_client, false, false),
44 35 : config_mgr_(new XmppConfigManager),
45 35 : lifetime_manager_(new LifetimeManager(
46 70 : TaskScheduler::GetInstance()->GetTaskId("bgp::Config"))),
47 35 : deleter_(new DeleteActor(this)),
48 35 : auth_enabled_(false),
49 35 : tcp_hold_time_(XmppChannelConfig::kTcpHoldTime) {
50 35 : }
51 :
52 5001 : XmppClient::XmppClient(EventManager *evm, const XmppChannelConfig *config)
53 : : XmppConnectionManager(
54 5001 : evm, ssl::context::sslv23_client, config->auth_enabled, true),
55 5001 : config_mgr_(new XmppConfigManager),
56 5001 : lifetime_manager_(new LifetimeManager(
57 10002 : TaskScheduler::GetInstance()->GetTaskId("bgp::Config"))),
58 5001 : deleter_(new DeleteActor(this)),
59 5001 : auth_enabled_(config->auth_enabled),
60 5001 : tcp_hold_time_(config->tcp_hold_time) {
61 :
62 5001 : if (config->auth_enabled) {
63 :
64 : // Get SSL context from base class and update
65 901 : boost::asio::ssl::context *ctx = context();
66 901 : boost::system::error_code ec;
67 :
68 : //set mode
69 901 : ctx->set_options(ssl::context::default_workarounds |
70 : ssl::context::no_sslv3 | ssl::context::no_sslv2 | ssl::context::no_tlsv1, ec);
71 901 : if (ec.value() != 0) {
72 0 : LOG(ERROR, "Error : " << ec.message() << ", setting ssl options");
73 0 : exit(EINVAL);
74 : }
75 :
76 : // CA certificate, used to verify if the peer certificate
77 : // is signed by a trusted CA
78 901 : std::string ca_cert_filename = config->path_to_ca_cert;
79 901 : if (!ca_cert_filename.empty()) {
80 :
81 : // Verify peer has CA signed certificate
82 0 : ctx->set_verify_mode(boost::asio::ssl::verify_peer, ec);
83 0 : if (ec.value() != 0) {
84 0 : LOG(ERROR, "Error : " << ec.message()
85 : << ", while setting ssl verification mode");
86 0 : exit(EINVAL);
87 : }
88 :
89 0 : ctx->load_verify_file(config->path_to_ca_cert, ec);
90 0 : if (ec.value() != 0) {
91 0 : LOG(ERROR, "Error : " << ec.message()
92 : << ", while using cacert file : "
93 : << config->path_to_ca_cert);
94 0 : exit(EINVAL);
95 : }
96 : }
97 :
98 : // server certificate
99 901 : ctx->use_certificate_chain_file(config->path_to_server_cert, ec);
100 901 : if (ec.value() != 0) {
101 0 : LOG(ERROR, "Error : " << ec.message() <<
102 : ", while using server cert file : "
103 : << config->path_to_server_cert);
104 0 : exit(EINVAL);
105 : }
106 :
107 : // server private key
108 901 : ctx->use_private_key_file(config->path_to_server_priv_key,
109 : boost::asio::ssl::context::pem, ec);
110 901 : if (ec.value() != 0) {
111 0 : LOG(ERROR, "Error : " << ec.message()
112 : << ", while using privkey file : "
113 : << config->path_to_server_priv_key);
114 0 : exit(EINVAL);
115 : }
116 901 : }
117 5001 : }
118 :
119 10034 : XmppClient::~XmppClient() {
120 10034 : }
121 :
122 0 : bool XmppClient::Initialize(short port) {
123 0 : TcpServer::Initialize(port);
124 0 : return true;
125 : }
126 :
127 5036 : LifetimeActor *XmppClient::deleter() {
128 5036 : return deleter_.get();
129 : }
130 :
131 10072 : LifetimeManager *XmppClient::lifetime_manager() {
132 10072 : return lifetime_manager_.get();
133 : }
134 :
135 7506 : TcpSession *XmppClient::CreateSession() {
136 : typedef boost::asio::detail::socket_option::boolean<
137 : SOL_SOCKET, SO_REUSEADDR> reuse_addr_t;
138 :
139 7506 : TcpSession *session = TcpServer::CreateSession();
140 7506 : Socket *socket = session->socket();
141 :
142 7506 : boost::system::error_code err;
143 7506 : socket->open(ip::tcp::v4(), err);
144 7506 : if (err) {
145 0 : XMPP_WARNING(ClientOpenFail, session->ToUVEKey(), XMPP_PEER_DIR_OUT,
146 : err.message());
147 0 : DeleteSession(session);
148 0 : return NULL;
149 : }
150 :
151 7506 : socket->set_option(reuse_addr_t(true), err);
152 7506 : if (err) {
153 0 : XMPP_WARNING(SetSockOptFail, session->ToUVEKey(), XMPP_PEER_DIR_OUT,
154 : err.message());
155 0 : return session;
156 : }
157 :
158 7506 : err = session->SetSocketOptions();
159 7506 : if (err) {
160 0 : DeleteSession(session);
161 0 : assert(0);
162 : }
163 :
164 7506 : return session;
165 : }
166 :
167 5036 : void XmppClient::Shutdown() {
168 5036 : XmppConnectionManager::Shutdown();
169 5036 : deleter_->Delete();
170 5036 : }
171 :
172 : void
173 5000 : XmppClient::ProcessConfigUpdate(XmppConfigManager::DiffType delta,
174 : const XmppChannelConfig *current, const XmppChannelConfig *future) {
175 5000 : if (delta == XmppConfigManager::DF_ADD) {
176 4991 : XmppClientConnection *connection = CreateConnection(future);
177 4991 : connection->Initialize(); // trigger state-machine
178 : }
179 5000 : if (delta == XmppConfigManager::DF_DELETE) {
180 9 : ConnectionMap::iterator loc = connection_map_.find(current->endpoint);
181 9 : if (loc != connection_map_.end()) {
182 9 : loc->second->ManagedDelete();
183 : }
184 : }
185 5000 : }
186 :
187 : void
188 5000 : XmppClient::ConfigUpdate(const XmppConfigData *cfg) {
189 5000 : config_mgr_->SetFuture(cfg);
190 5000 : config_mgr_->PeerConfigDiff(
191 : boost::bind(&XmppClient::ProcessConfigUpdate, this, _1, _2, _3));
192 5000 : config_mgr_->AcceptFuture();
193 5000 : }
194 :
195 4980 : void XmppClient::RegisterConnectionEvent(xmps::PeerId id,
196 : ConnectionEventCb cb) {
197 4980 : std::scoped_lock lock(connection_event_map_mutex_);
198 4980 : connection_event_map_.insert(make_pair(id, cb));
199 4980 : }
200 :
201 2 : void XmppClient::UnRegisterConnectionEvent(xmps::PeerId id) {
202 2 : std::scoped_lock lock(connection_event_map_mutex_);
203 2 : ConnectionEventCbMap::iterator it = connection_event_map_.find(id);
204 2 : if (it != connection_event_map_.end())
205 2 : connection_event_map_.erase(it);
206 2 : }
207 :
208 12833 : void XmppClient::NotifyConnectionEvent(XmppChannelMux *mux,
209 : xmps::PeerState state) {
210 12833 : std::scoped_lock lock(connection_event_map_mutex_);
211 12833 : ConnectionEventCbMap::iterator iter = connection_event_map_.begin();
212 25585 : for (; iter != connection_event_map_.end(); ++iter) {
213 12752 : ConnectionEventCb cb = iter->second;
214 12752 : cb(mux, state);
215 12752 : }
216 12833 : }
217 :
218 0 : size_t XmppClient::ConnectionEventCount() const {
219 0 : return connection_event_map_.size();
220 : }
221 :
222 9956 : size_t XmppClient::ConnectionCount() const {
223 9956 : return connection_map_.size();
224 : }
225 :
226 7506 : SslSession *XmppClient::AllocSession(SslSocket *socket) {
227 7506 : SslSession *session = new XmppSession(this, socket);
228 7506 : return session;
229 : }
230 :
231 102614 : XmppClientConnection *XmppClient::FindConnection(const string &address) {
232 102614 : for (auto& value : connection_map_) {
233 102614 : if (value.second->ToString() == address)
234 102614 : return value.second;
235 : }
236 0 : return NULL;
237 : }
238 :
239 5009 : XmppClientConnection *XmppClient::CreateConnection(
240 : const XmppChannelConfig *config) {
241 : XmppClientConnection *connection =
242 5009 : XmppStaticObjectFactory::Create<XmppClientConnection>(this, config);
243 5009 : Endpoint endpoint = connection->endpoint();
244 5009 : ConnectionMap::iterator loc;
245 : bool result;
246 5009 : tie(loc, result) = connection_map_.insert(make_pair(endpoint, connection));
247 5009 : assert(result);
248 :
249 5009 : return connection;
250 : }
251 :
252 27 : void XmppClient::InsertConnection(XmppClientConnection *connection) {
253 27 : assert(!connection->IsDeleted());
254 27 : Endpoint endpoint = connection->endpoint();
255 27 : ConnectionMap::iterator loc;
256 : bool result;
257 27 : tie(loc, result) = connection_map_.insert(make_pair(endpoint, connection));
258 27 : assert(result);
259 27 : }
260 :
261 5036 : void XmppClient::RemoveConnection(XmppClientConnection *connection) {
262 5036 : assert(connection->IsDeleted());
263 5036 : Endpoint endpoint = connection->endpoint();
264 5036 : ConnectionMap::iterator loc = connection_map_.find(endpoint);
265 5036 : assert(loc != connection_map_.end() && loc->second == connection);
266 5036 : connection_map_.erase(loc);
267 5036 : }
268 :
269 93715 : XmppChannel *XmppClient::FindChannel(const string &address) {
270 93715 : XmppClientConnection *connection = FindConnection(address);
271 93715 : return (connection ? connection->ChannelMux() : NULL);
272 : }
273 :
274 0 : int XmppClient::SetDscpValue(uint8_t value, const char *conn_id) {
275 0 : XmppClientConnection *connection = FindConnection(conn_id);
276 0 : if (connection) {
277 0 : return connection->SetDscpValue(value);
278 : }
279 0 : return 0;
280 : }
281 :
282 0 : void XmppClient::UpdateTimeOut(uint8_t time_out, const char *conn_id) {
283 0 : XmppClientConnection *connection = FindConnection(conn_id);
284 0 : if (connection) {
285 0 : return connection->UpdateKeepAliveTimer(time_out);
286 : }
287 : }
288 :
289 0 : uint32_t XmppClient::XmppTimeOut(const char *conn_id) {
290 0 : XmppClientConnection *connection = FindConnection(conn_id);
291 0 : if (connection) {
292 0 : return connection->state_machine()->hold_time();
293 : }
294 0 : return 0;
295 : }
296 :
|