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