blob: bbe17da7a7bceb4e2e89e80c0a4823e7fb658c8a [file] [log] [blame]
Yingdi Yud45777b2014-10-16 23:54:11 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
Yingdi Yuf3401182015-02-02 20:21:07 -08009 * Qiuhan Ding <qiuhanding@cs.ucla.edu>
Yingdi Yud45777b2014-10-16 23:54:11 -070010 */
11
12#include "chat-dialog-backend.hpp"
13
Yingdi Yu45da92a2015-02-02 13:17:03 -080014#include <QFile>
15
Yingdi Yud45777b2014-10-16 23:54:11 -070016#ifndef Q_MOC_RUN
17#include <ndn-cxx/util/io.hpp>
Yingdi Yu45da92a2015-02-02 13:17:03 -080018#include <ndn-cxx/security/validator-regex.hpp>
Yingdi Yud45777b2014-10-16 23:54:11 -070019#include "logging.h"
20#endif
21
22
23INIT_LOGGER("ChatDialogBackend");
24
Yingdi Yueb692ac2015-02-10 18:46:18 -080025namespace chronochat {
Yingdi Yud45777b2014-10-16 23:54:11 -070026
27static const time::milliseconds FRESHNESS_PERIOD(60000);
28static const time::seconds HELLO_INTERVAL(60);
Qiuhan Dingba3e57a2015-01-08 19:07:39 -080029static const ndn::Name::Component ROUTING_HINT_SEPARATOR =
30 ndn::name::Component::fromEscapedString("%F0%2E");
Qiuhan Ding43c8e162015-02-02 15:16:48 -080031static const int IDENTITY_OFFSET = -3;
Yingdi Yuf3401182015-02-02 20:21:07 -080032static const int CONNECTION_RETRY_TIMER = 3;
Yingdi Yud45777b2014-10-16 23:54:11 -070033
34ChatDialogBackend::ChatDialogBackend(const Name& chatroomPrefix,
35 const Name& userChatPrefix,
36 const Name& routingPrefix,
37 const std::string& chatroomName,
38 const std::string& nick,
Yingdi Yu45da92a2015-02-02 13:17:03 -080039 const Name& signingId,
Yingdi Yud45777b2014-10-16 23:54:11 -070040 QObject* parent)
41 : QThread(parent)
Yingdi Yuf3401182015-02-02 20:21:07 -080042 , m_shouldResume(false)
Yingdi Yud45777b2014-10-16 23:54:11 -070043 , m_localRoutingPrefix(routingPrefix)
44 , m_chatroomPrefix(chatroomPrefix)
45 , m_userChatPrefix(userChatPrefix)
46 , m_chatroomName(chatroomName)
47 , m_nick(nick)
Yingdi Yu45da92a2015-02-02 13:17:03 -080048 , m_signingId(signingId)
Yingdi Yud45777b2014-10-16 23:54:11 -070049{
50 updatePrefixes();
51}
52
53
54ChatDialogBackend::~ChatDialogBackend()
55{
56}
57
58// protected methods:
59void
60ChatDialogBackend::run()
61{
Yingdi Yu4647f022015-02-01 00:26:38 -080062 bool shouldResume = false;
63 do {
64 initializeSync();
Yingdi Yud45777b2014-10-16 23:54:11 -070065
Yingdi Yu4647f022015-02-01 00:26:38 -080066 if (m_face == nullptr)
67 break;
68
Yingdi Yuf3401182015-02-02 20:21:07 -080069 try {
70 m_face->getIoService().run();
71 }
72 catch (std::runtime_error& e) {
73 {
74 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
75 m_isNfdConnected = false;
76 }
77 emit nfdError();
78 {
79 std::lock_guard<std::mutex>lock(m_resumeMutex);
80 m_shouldResume = true;
81 }
82#ifdef BOOST_THREAD_USES_CHRONO
83 time::seconds reconnectTimer = time::seconds(CONNECTION_RETRY_TIMER);
84#else
85 boost::posix_time::time_duration reconnectTimer;
86 reconnectTimer = boost::posix_time::seconds(CONNECTION_RETRY_TIMER);
87#endif
88 while (!m_isNfdConnected) {
89#ifdef BOOST_THREAD_USES_CHRONO
90 boost::this_thread::sleep_for(reconnectTimer);
91#else
92 boost::this_thread::sleep(reconnectTimer);
93#endif
94 }
95 emit refreshChatDialog(m_routableUserChatPrefix);
96 }
Qiuhan Dingf22c41b2015-03-11 13:19:01 -070097 {
Yingdi Yuf3401182015-02-02 20:21:07 -080098 std::lock_guard<std::mutex>lock(m_resumeMutex);
Qiuhan Dingf22c41b2015-03-11 13:19:01 -070099 shouldResume = m_shouldResume;
100 m_shouldResume = false;
101 }
Yingdi Yuf3401182015-02-02 20:21:07 -0800102 close();
Yingdi Yu4647f022015-02-01 00:26:38 -0800103
104 } while (shouldResume);
Yingdi Yud45777b2014-10-16 23:54:11 -0700105
106 std::cerr << "Bye!" << std::endl;
107}
108
109// private methods:
110void
111ChatDialogBackend::initializeSync()
112{
Yingdi Yu4647f022015-02-01 00:26:38 -0800113 BOOST_ASSERT(m_sock == nullptr);
Yingdi Yud45777b2014-10-16 23:54:11 -0700114
Yingdi Yu45da92a2015-02-02 13:17:03 -0800115 m_face = make_shared<ndn::Face>();
Yingdi Yu4647f022015-02-01 00:26:38 -0800116 m_scheduler = unique_ptr<ndn::Scheduler>(new ndn::Scheduler(m_face->getIoService()));
Yingdi Yud45777b2014-10-16 23:54:11 -0700117
Yingdi Yu45da92a2015-02-02 13:17:03 -0800118 // initialize validator
119 shared_ptr<ndn::IdentityCertificate> anchor = loadTrustAnchor();
120
121 if (static_cast<bool>(anchor)) {
122 shared_ptr<ndn::ValidatorRegex> validator =
123 make_shared<ndn::ValidatorRegex>(m_face.get()); // TODO: Change to Face*
124 validator->addDataVerificationRule(
125 make_shared<ndn::SecRuleRelative>("^<>*<%F0.>(<>*)$",
126 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
127 ">", "\\1", "\\1\\2", true));
128 validator->addDataVerificationRule(
129 make_shared<ndn::SecRuleRelative>("(<>*)$",
130 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
131 ">", "\\1", "\\1\\2", true));
132 validator->addTrustAnchor(anchor);
133
134 m_validator = validator;
135 }
136 else
137 m_validator = shared_ptr<ndn::Validator>();
138
139
Yingdi Yud45777b2014-10-16 23:54:11 -0700140 // create a new SyncSocket
141 m_sock = make_shared<chronosync::Socket>(m_chatroomPrefix,
142 m_routableUserChatPrefix,
Yingdi Yu4647f022015-02-01 00:26:38 -0800143 ref(*m_face),
Yingdi Yu45da92a2015-02-02 13:17:03 -0800144 bind(&ChatDialogBackend::processSyncUpdate, this, _1),
145 m_signingId,
146 m_validator);
Yingdi Yud45777b2014-10-16 23:54:11 -0700147
148 // schedule a new join event
Yingdi Yu4647f022015-02-01 00:26:38 -0800149 m_scheduler->scheduleEvent(time::milliseconds(600),
150 bind(&ChatDialogBackend::sendJoin, this));
Yingdi Yud45777b2014-10-16 23:54:11 -0700151
152 // cancel existing hello event if it exists
Yingdi Yu4647f022015-02-01 00:26:38 -0800153 if (m_helloEventId != nullptr) {
154 m_scheduler->cancelEvent(m_helloEventId);
Yingdi Yud45777b2014-10-16 23:54:11 -0700155 m_helloEventId.reset();
156 }
157}
158
Yingdi Yu45da92a2015-02-02 13:17:03 -0800159class IoDeviceSource
160{
161public:
162 typedef char char_type;
163 typedef boost::iostreams::source_tag category;
164
165 explicit
166 IoDeviceSource(QIODevice& source)
167 : m_source(source)
168 {
169 }
170
171 std::streamsize
172 read(char* buffer, std::streamsize n)
173 {
174 return m_source.read(buffer, n);
175 }
176private:
177 QIODevice& m_source;
178};
179
180shared_ptr<ndn::IdentityCertificate>
181ChatDialogBackend::loadTrustAnchor()
182{
183 QFile anchorFile(":/security/anchor.cert");
184
185 if (!anchorFile.open(QIODevice::ReadOnly)) {
186 return {};
187 }
188
189 boost::iostreams::stream<IoDeviceSource> anchorFileStream(anchorFile);
190 return ndn::io::load<ndn::IdentityCertificate>(anchorFileStream);
191}
192
Yingdi Yud45777b2014-10-16 23:54:11 -0700193void
Yingdi Yuf3401182015-02-02 20:21:07 -0800194ChatDialogBackend::exitChatroom() {
Yingdi Yu4647f022015-02-01 00:26:38 -0800195 if (m_joined)
196 sendLeave();
197
198 usleep(100000);
Yingdi Yuf3401182015-02-02 20:21:07 -0800199}
Yingdi Yu4647f022015-02-01 00:26:38 -0800200
Yingdi Yuf3401182015-02-02 20:21:07 -0800201void
202ChatDialogBackend::close()
203{
Yingdi Yu4647f022015-02-01 00:26:38 -0800204 m_scheduler->cancelAllEvents();
205 m_helloEventId.reset();
206 m_roster.clear();
Yingdi Yu45da92a2015-02-02 13:17:03 -0800207 m_validator.reset();
Yingdi Yu4647f022015-02-01 00:26:38 -0800208 m_sock.reset();
209}
210
211void
Yingdi Yud45777b2014-10-16 23:54:11 -0700212ChatDialogBackend::processSyncUpdate(const std::vector<chronosync::MissingDataInfo>& updates)
213{
214 _LOG_DEBUG("<<< processing Tree Update");
215
216 if (updates.empty()) {
217 return;
218 }
219
220 std::vector<NodeInfo> nodeInfos;
221
222
Yingdi Yu1cc45d92015-02-09 14:19:54 -0800223 for (size_t i = 0; i < updates.size(); i++) {
Yingdi Yud45777b2014-10-16 23:54:11 -0700224 // update roster
225 if (m_roster.find(updates[i].session) == m_roster.end()) {
226 m_roster[updates[i].session].sessionPrefix = updates[i].session;
227 m_roster[updates[i].session].hasNick = false;
228 }
229
230 // fetch missing chat data
231 if (updates[i].high - updates[i].low < 3) {
232 for (chronosync::SeqNo seq = updates[i].low; seq <= updates[i].high; ++seq) {
233 m_sock->fetchData(updates[i].session, seq,
Yingdi Yu45da92a2015-02-02 13:17:03 -0800234 [this] (const shared_ptr<const ndn::Data>& data) {
235 this->processChatData(data, true, true);
236 },
237 [this] (const shared_ptr<const ndn::Data>& data, const std::string& msg) {
238 this->processChatData(data, true, false);
239 },
240 ndn::OnTimeout(),
Yingdi Yud45777b2014-10-16 23:54:11 -0700241 2);
242 _LOG_DEBUG("<<< Fetching " << updates[i].session << "/" << seq);
243 }
244 }
245 else {
246 // There are too many msgs to fetch, let's just fetch the latest one
247 m_sock->fetchData(updates[i].session, updates[i].high,
Yingdi Yu45da92a2015-02-02 13:17:03 -0800248 [this] (const shared_ptr<const ndn::Data>& data) {
249 this->processChatData(data, false, true);
250 },
251 [this] (const shared_ptr<const ndn::Data>& data, const std::string& msg) {
252 this->processChatData(data, false, false);
253 },
254 ndn::OnTimeout(),
Yingdi Yud45777b2014-10-16 23:54:11 -0700255 2);
256 }
257
Yingdi Yud45777b2014-10-16 23:54:11 -0700258 }
259
260 // reflect the changes on GUI
261 emit syncTreeUpdated(nodeInfos,
262 QString::fromStdString(getHexEncodedDigest(m_sock->getRootDigest())));
263}
264
265void
Yingdi Yu45da92a2015-02-02 13:17:03 -0800266ChatDialogBackend::processChatData(const ndn::shared_ptr<const ndn::Data>& data,
267 bool needDisplay,
268 bool isValidated)
Yingdi Yud45777b2014-10-16 23:54:11 -0700269{
270 SyncDemo::ChatMessage msg;
271
272 if (!msg.ParseFromArray(data->getContent().value(), data->getContent().value_size())) {
273 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " <<
274 data->getName() << ". what is happening?");
275 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
276 msg.set_from("inconnu");
277 msg.set_type(SyncDemo::ChatMessage::OTHER);
278 return;
279 }
280
281 Name remoteSessionPrefix = data->getName().getPrefix(-1);
282
283 if (msg.type() == SyncDemo::ChatMessage::LEAVE) {
284 BackendRoster::iterator it = m_roster.find(remoteSessionPrefix);
285
286 if (it != m_roster.end()) {
287 // cancel timeout event
288 if (static_cast<bool>(it->second.timeoutEventId))
Yingdi Yu4647f022015-02-01 00:26:38 -0800289 m_scheduler->cancelEvent(it->second.timeoutEventId);
Yingdi Yud45777b2014-10-16 23:54:11 -0700290
291 // notify frontend to remove the remote session (node)
292 emit sessionRemoved(QString::fromStdString(remoteSessionPrefix.toUri()),
293 QString::fromStdString(msg.from()),
294 msg.timestamp());
295
296 // remove roster entry
297 m_roster.erase(remoteSessionPrefix);
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800298
299 emit eraseInRoster(remoteSessionPrefix.getPrefix(IDENTITY_OFFSET),
300 Name::Component(m_chatroomName));
Yingdi Yud45777b2014-10-16 23:54:11 -0700301 }
302 }
303 else {
304 BackendRoster::iterator it = m_roster.find(remoteSessionPrefix);
305
306 if (it == m_roster.end()) {
307 // Should not happen
308 BOOST_ASSERT(false);
309 }
310
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800311 uint64_t seqNo = data->getName().get(-1).toNumber();
Yingdi Yud45777b2014-10-16 23:54:11 -0700312
313 // If a timeout event has been scheduled, cancel it.
314 if (static_cast<bool>(it->second.timeoutEventId))
Yingdi Yu4647f022015-02-01 00:26:38 -0800315 m_scheduler->cancelEvent(it->second.timeoutEventId);
Yingdi Yud45777b2014-10-16 23:54:11 -0700316
317 // (Re)schedule another timeout event after 3 HELLO_INTERVAL;
318 it->second.timeoutEventId =
Yingdi Yu4647f022015-02-01 00:26:38 -0800319 m_scheduler->scheduleEvent(HELLO_INTERVAL * 3,
320 bind(&ChatDialogBackend::remoteSessionTimeout,
321 this, remoteSessionPrefix));
Yingdi Yud45777b2014-10-16 23:54:11 -0700322
323 // If chat message, notify the frontend
Yingdi Yu45da92a2015-02-02 13:17:03 -0800324 if (msg.type() == SyncDemo::ChatMessage::CHAT) {
325 if (isValidated)
326 emit chatMessageReceived(QString::fromStdString(msg.from()),
327 QString::fromStdString(msg.data()),
328 msg.timestamp());
329 else
330 emit chatMessageReceived(QString::fromStdString(msg.from() + " (Unverified)"),
331 QString::fromStdString(msg.data()),
332 msg.timestamp());
333 }
Yingdi Yud45777b2014-10-16 23:54:11 -0700334
335 // Notify frontend to plot notification on DigestTree.
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800336
337 // If we haven't got any message from this session yet.
338 if (m_roster[remoteSessionPrefix].hasNick == false) {
339 m_roster[remoteSessionPrefix].userNick = msg.from();
340 m_roster[remoteSessionPrefix].hasNick = true;
341
342 emit messageReceived(QString::fromStdString(remoteSessionPrefix.toUri()),
343 QString::fromStdString(msg.from()),
344 seqNo,
345 msg.timestamp(),
346 true);
347
348 emit addInRoster(remoteSessionPrefix.getPrefix(IDENTITY_OFFSET),
349 Name::Component(m_chatroomName));
350 }
351 else
352 emit messageReceived(QString::fromStdString(remoteSessionPrefix.toUri()),
353 QString::fromStdString(msg.from()),
354 seqNo,
355 msg.timestamp(),
356 false);
Yingdi Yud45777b2014-10-16 23:54:11 -0700357 }
358}
359
360void
361ChatDialogBackend::remoteSessionTimeout(const Name& sessionPrefix)
362{
363 time_t timestamp =
364 static_cast<time_t>(time::toUnixTimestamp(time::system_clock::now()).count() / 1000);
365
366 // notify frontend
367 emit sessionRemoved(QString::fromStdString(sessionPrefix.toUri()),
368 QString::fromStdString(m_roster[sessionPrefix].userNick),
369 timestamp);
370
371 // remove roster entry
372 m_roster.erase(sessionPrefix);
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800373
374 emit eraseInRoster(sessionPrefix.getPrefix(IDENTITY_OFFSET),
375 Name::Component(m_chatroomName));
Yingdi Yud45777b2014-10-16 23:54:11 -0700376}
377
378void
379ChatDialogBackend::sendMsg(SyncDemo::ChatMessage& msg)
380{
381 // send msg
382 ndn::OBufferStream os;
383 msg.SerializeToOstream(&os);
384
385 if (!msg.IsInitialized()) {
386 _LOG_DEBUG("Errrrr.. msg was not probally initialized " << __FILE__ <<
387 ":" << __LINE__ << ". what is happening?");
388 abort();
389 }
390
391 uint64_t nextSequence = m_sock->getLogic().getSeqNo() + 1;
392
393 m_sock->publishData(os.buf()->buf(), os.buf()->size(), FRESHNESS_PERIOD);
394
395 std::vector<NodeInfo> nodeInfos;
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800396 Name sessionName = m_sock->getLogic().getSessionName();
397 NodeInfo nodeInfo = {QString::fromStdString(sessionName.toUri()),
Yingdi Yud45777b2014-10-16 23:54:11 -0700398 nextSequence};
399 nodeInfos.push_back(nodeInfo);
400
401 emit syncTreeUpdated(nodeInfos,
402 QString::fromStdString(getHexEncodedDigest(m_sock->getRootDigest())));
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800403
404 emit messageReceived(QString::fromStdString(sessionName.toUri()),
405 QString::fromStdString(msg.from()),
406 nextSequence,
407 msg.timestamp(),
408 msg.type() == SyncDemo::ChatMessage::JOIN);
Yingdi Yud45777b2014-10-16 23:54:11 -0700409}
410
411void
412ChatDialogBackend::sendJoin()
413{
414 m_joined = true;
415
416 SyncDemo::ChatMessage msg;
417 prepareControlMessage(msg, SyncDemo::ChatMessage::JOIN);
418 sendMsg(msg);
419
Yingdi Yu4647f022015-02-01 00:26:38 -0800420 m_helloEventId = m_scheduler->scheduleEvent(HELLO_INTERVAL,
421 bind(&ChatDialogBackend::sendHello, this));
Yingdi Yuf3401182015-02-02 20:21:07 -0800422 emit newChatroomForDiscovery(Name::Component(m_chatroomName));
Yingdi Yud45777b2014-10-16 23:54:11 -0700423}
424
425void
426ChatDialogBackend::sendHello()
427{
428 SyncDemo::ChatMessage msg;
429 prepareControlMessage(msg, SyncDemo::ChatMessage::HELLO);
430 sendMsg(msg);
431
Yingdi Yu4647f022015-02-01 00:26:38 -0800432 m_helloEventId = m_scheduler->scheduleEvent(HELLO_INTERVAL,
433 bind(&ChatDialogBackend::sendHello, this));
Yingdi Yud45777b2014-10-16 23:54:11 -0700434}
435
436void
437ChatDialogBackend::sendLeave()
438{
439 SyncDemo::ChatMessage msg;
440 prepareControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
441 sendMsg(msg);
442
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800443 // get my own identity with routable prefix by getPrefix(-2)
444 emit eraseInRoster(m_routableUserChatPrefix.getPrefix(-2),
445 Name::Component(m_chatroomName));
446
Yingdi Yud45777b2014-10-16 23:54:11 -0700447 usleep(5000);
448 m_joined = false;
449}
450
451void
452ChatDialogBackend::prepareControlMessage(SyncDemo::ChatMessage& msg,
453 SyncDemo::ChatMessage::ChatMessageType type)
454{
455 msg.set_from(m_nick);
456 msg.set_to(m_chatroomName);
457 int32_t seconds =
458 static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count() / 1000);
459 msg.set_timestamp(seconds);
460 msg.set_type(type);
461}
462
463void
464ChatDialogBackend::prepareChatMessage(const QString& text,
465 time_t timestamp,
466 SyncDemo::ChatMessage &msg)
467{
468 msg.set_from(m_nick);
469 msg.set_to(m_chatroomName);
470 msg.set_data(text.toStdString());
471 msg.set_timestamp(timestamp);
472 msg.set_type(SyncDemo::ChatMessage::CHAT);
473}
474
475void
476ChatDialogBackend::updatePrefixes()
477{
478 m_routableUserChatPrefix.clear();
479
480 if (m_localRoutingPrefix.isPrefixOf(m_userChatPrefix))
481 m_routableUserChatPrefix = m_userChatPrefix;
482 else
483 m_routableUserChatPrefix.append(m_localRoutingPrefix)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800484 .append(ROUTING_HINT_SEPARATOR)
Yingdi Yud45777b2014-10-16 23:54:11 -0700485 .append(m_userChatPrefix);
486
487 emit chatPrefixChanged(m_routableUserChatPrefix);
488}
489
490std::string
491ChatDialogBackend::getHexEncodedDigest(ndn::ConstBufferPtr digest)
492{
493 std::stringstream os;
494
495 CryptoPP::StringSource(digest->buf(), digest->size(), true,
496 new CryptoPP::HexEncoder(new CryptoPP::FileSink(os), false));
497 return os.str();
498}
499
500
501// public slots:
502void
503ChatDialogBackend::sendChatMessage(QString text, time_t timestamp)
504{
505 SyncDemo::ChatMessage msg;
506 prepareChatMessage(text, timestamp, msg);
507 sendMsg(msg);
508
509 emit chatMessageReceived(QString::fromStdString(msg.from()),
510 QString::fromStdString(msg.data()),
511 msg.timestamp());
512}
513
514void
515ChatDialogBackend::updateRoutingPrefix(const QString& localRoutingPrefix)
516{
517 Name newLocalRoutingPrefix(localRoutingPrefix.toStdString());
518
519 if (!newLocalRoutingPrefix.empty() && newLocalRoutingPrefix != m_localRoutingPrefix) {
520 // Update localPrefix
521 m_localRoutingPrefix = newLocalRoutingPrefix;
522
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700523 {
Yingdi Yuf3401182015-02-02 20:21:07 -0800524 std::lock_guard<std::mutex>lock(m_resumeMutex);
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700525 m_shouldResume = true;
526 }
Yingdi Yu4647f022015-02-01 00:26:38 -0800527
Yingdi Yuf3401182015-02-02 20:21:07 -0800528 exitChatroom();
Yingdi Yu4647f022015-02-01 00:26:38 -0800529
Qiuhan Ding112ee482015-03-11 11:54:11 -0700530 updatePrefixes();
531
Yingdi Yu4647f022015-02-01 00:26:38 -0800532 m_face->getIoService().stop();
Yingdi Yud45777b2014-10-16 23:54:11 -0700533 }
534}
535
536void
537ChatDialogBackend::shutdown()
538{
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700539 {
Yingdi Yuf3401182015-02-02 20:21:07 -0800540 std::lock_guard<std::mutex>lock(m_resumeMutex);
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700541 m_shouldResume = false;
542 }
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700543
Yingdi Yuf3401182015-02-02 20:21:07 -0800544 {
545 // In this case, we just stop checking the nfd connection and exit
546 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
547 m_isNfdConnected = true;
548 }
549
550 exitChatroom();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700551
Yingdi Yu4647f022015-02-01 00:26:38 -0800552 m_face->getIoService().stop();
Yingdi Yud45777b2014-10-16 23:54:11 -0700553}
554
Yingdi Yuf3401182015-02-02 20:21:07 -0800555void
556ChatDialogBackend::onNfdReconnect()
557{
558 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
559 m_isNfdConnected = true;
560}
561
Yingdi Yueb692ac2015-02-10 18:46:18 -0800562} // namespace chronochat
Yingdi Yud45777b2014-10-16 23:54:11 -0700563
564#if WAF
565#include "chat-dialog-backend.moc"
566// #include "chat-dialog-backend.cpp.moc"
567#endif