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 5034 : DeleteActor(XmppClient *client)
26 5034 : : LifetimeActor(client->lifetime_manager()), client_(client) { }
27 5034 : virtual bool MayDelete() const {
28 5034 : CHECK_CONCURRENCY("bgp::Config");
29 5034 : return (client_->GetSessionQueueSize() == 0);
30 : }
31 5034 : virtual void Shutdown() {
32 5034 : CHECK_CONCURRENCY("bgp::Config");
33 5034 : }
34 5034 : virtual void Destroy() {
35 5034 : CHECK_CONCURRENCY("bgp::Config");
36 5034 : }
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 4999 : XmppClient::XmppClient(EventManager *evm, const XmppChannelConfig *config)
53 : : XmppConnectionManager(
54 4999 : evm, ssl::context::sslv23_client, config->auth_enabled, true),
55 4999 : config_mgr_(new XmppConfigManager),
56 4999 : lifetime_manager_(new LifetimeManager(
57 9998 : TaskScheduler::GetInstance()->GetTaskId("bgp::Config"))),
58 4999 : deleter_(new DeleteActor(this)),
59 4999 : auth_enabled_(config->auth_enabled),
60 4999 : tcp_hold_time_(config->tcp_hold_time) {
61 :
62 4999 : 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 4999 : }
118 :
119 10030 : XmppClient::~XmppClient() {
120 10030 : }
121 :
122 0 : bool XmppClient::Initialize(short port) {
123 0 : TcpServer::Initialize(port);
124 0 : return true;
125 : }
126 :
127 5034 : LifetimeActor *XmppClient::deleter() {
128 5034 : return deleter_.get();
129 : }
130 :
131 10068 : LifetimeManager *XmppClient::lifetime_manager() {
132 10068 : return lifetime_manager_.get();
133 : }
134 :
135 7484 : TcpSession *XmppClient::CreateSession() {
136 : typedef boost::asio::detail::socket_option::boolean<
137 : SOL_SOCKET, SO_REUSEADDR> reuse_addr_t;
138 :
139 7484 : TcpSession *session = TcpServer::CreateSession();
140 7484 : Socket *socket = session->socket();
141 :
142 7484 : boost::system::error_code err;
143 7484 : socket->open(ip::tcp::v4(), err);
144 7484 : 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 7484 : socket->set_option(reuse_addr_t(true), err);
152 7484 : if (err) {
153 0 : XMPP_WARNING(SetSockOptFail, session->ToUVEKey(), XMPP_PEER_DIR_OUT,
154 : err.message());
155 0 : return session;
156 : }
157 :
158 7484 : err = session->SetSocketOptions();
159 7484 : if (err) {
160 0 : DeleteSession(session);
161 0 : assert(0);
162 : }
163 :
164 7484 : return session;
165 : }
166 :
167 5034 : void XmppClient::Shutdown() {
168 5034 : XmppConnectionManager::Shutdown();
169 5034 : deleter_->Delete();
170 5034 : }
171 :
172 : void
173 4998 : XmppClient::ProcessConfigUpdate(XmppConfigManager::DiffType delta,
174 : const XmppChannelConfig *current, const XmppChannelConfig *future) {
175 4998 : if (delta == XmppConfigManager::DF_ADD) {
176 4989 : XmppClientConnection *connection = CreateConnection(future);
177 4989 : connection->Initialize(); // trigger state-machine
178 : }
179 4998 : 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 4998 : }
186 :
187 : void
188 4998 : XmppClient::ConfigUpdate(const XmppConfigData *cfg) {
189 4998 : config_mgr_->SetFuture(cfg);
190 4998 : config_mgr_->PeerConfigDiff(
191 : boost::bind(&XmppClient::ProcessConfigUpdate, this, _1, _2, _3));
192 4998 : config_mgr_->AcceptFuture();
193 4998 : }
194 :
195 4978 : void XmppClient::RegisterConnectionEvent(xmps::PeerId id,
196 : ConnectionEventCb cb) {
197 4978 : std::scoped_lock lock(connection_event_map_mutex_);
198 4978 : connection_event_map_.insert(make_pair(id, cb));
199 4978 : }
200 :
201 0 : void XmppClient::UnRegisterConnectionEvent(xmps::PeerId id) {
202 0 : std::scoped_lock lock(connection_event_map_mutex_);
203 0 : ConnectionEventCbMap::iterator it = connection_event_map_.find(id);
204 0 : if (it != connection_event_map_.end())
205 0 : connection_event_map_.erase(it);
206 0 : }
207 :
208 12822 : void XmppClient::NotifyConnectionEvent(XmppChannelMux *mux,
209 : xmps::PeerState state) {
210 12822 : std::scoped_lock lock(connection_event_map_mutex_);
211 12822 : ConnectionEventCbMap::iterator iter = connection_event_map_.begin();
212 25563 : for (; iter != connection_event_map_.end(); ++iter) {
213 12741 : ConnectionEventCb cb = iter->second;
214 12741 : cb(mux, state);
215 12741 : }
216 12822 : }
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 7484 : SslSession *XmppClient::AllocSession(SslSocket *socket) {
227 7484 : SslSession *session = new XmppSession(this, socket);
228 7484 : return session;
229 : }
230 :
231 102522 : XmppClientConnection *XmppClient::FindConnection(const string &address) {
232 102522 : for (auto& value : connection_map_) {
233 102522 : if (value.second->ToString() == address)
234 102522 : return value.second;
235 : }
236 0 : return NULL;
237 : }
238 :
239 5007 : XmppClientConnection *XmppClient::CreateConnection(
240 : const XmppChannelConfig *config) {
241 : XmppClientConnection *connection =
242 5007 : XmppStaticObjectFactory::Create<XmppClientConnection>(this, config);
243 5007 : Endpoint endpoint = connection->endpoint();
244 5007 : ConnectionMap::iterator loc;
245 : bool result;
246 5007 : tie(loc, result) = connection_map_.insert(make_pair(endpoint, connection));
247 5007 : assert(result);
248 :
249 5007 : 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 5034 : void XmppClient::RemoveConnection(XmppClientConnection *connection) {
262 5034 : assert(connection->IsDeleted());
263 5034 : Endpoint endpoint = connection->endpoint();
264 5034 : ConnectionMap::iterator loc = connection_map_.find(endpoint);
265 5034 : assert(loc != connection_map_.end() && loc->second == connection);
266 5034 : connection_map_.erase(loc);
267 5034 : }
268 :
269 93566 : XmppChannel *XmppClient::FindChannel(const string &address) {
270 93566 : XmppClientConnection *connection = FindConnection(address);
271 93566 : 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 :
|