blob: fb97f25a35f3f3ce360ae7388130b77c33880410 [file] [log] [blame]
Yingdi Yu2c9e7712014-10-20 11:55:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
Varun Patilb3d03b92021-01-08 17:09:32 +05303 * Copyright (c) 2013-2021, Regents of the University of California
Junxiao Shi9887fd12016-07-23 02:09:00 +00004 * Yingdi Yu
Yingdi Yu2c9e7712014-10-20 11:55:05 -07005 *
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 Yu2c9e7712014-10-20 11:55:05 -070010 */
11
12#include "controller-backend.hpp"
13
14#ifndef Q_MOC_RUN
Varun Patila24bd3e2020-11-24 10:08:33 +053015#include <iostream>
16#include <boost/asio.hpp>
17
Yingdi Yu7ff31f02015-02-05 11:21:07 -080018#include <ndn-cxx/util/segment-fetcher.hpp>
Varun Patil3d850902020-11-23 12:19:14 +053019#include <ndn-cxx/security/signing-helpers.hpp>
20#include <ndn-cxx/security/certificate-fetcher-offline.hpp>
Varun Patila24bd3e2020-11-24 10:08:33 +053021
Yingdi Yu2c9e7712014-10-20 11:55:05 -070022#include "invitation.hpp"
Yingdi Yu2c9e7712014-10-20 11:55:05 -070023#endif
24
Yingdi Yueb692ac2015-02-10 18:46:18 -080025namespace chronochat {
Yingdi Yu2c9e7712014-10-20 11:55:05 -070026
27using std::string;
28
29using ndn::Face;
Yingdi Yu2c9e7712014-10-20 11:55:05 -070030
Qiuhan Dingba3e57a2015-01-08 19:07:39 -080031static const ndn::Name::Component ROUTING_HINT_SEPARATOR =
32 ndn::name::Component::fromEscapedString("%F0%2E");
33static const int MAXIMUM_REQUEST = 3;
Yingdi Yuf3401182015-02-02 20:21:07 -080034static const int CONNECTION_RETRY_TIMER = 3;
Yingdi Yu2c9e7712014-10-20 11:55:05 -070035
36ControllerBackend::ControllerBackend(QObject* parent)
37 : QThread(parent)
Yingdi Yuf3401182015-02-02 20:21:07 -080038 , m_shouldResume(false)
Varun Patil074e38d2021-01-05 17:38:53 +053039 , m_face(nullptr, m_keyChain)
40 , m_contactManager(m_face, m_keyChain)
Yingdi Yu2c9e7712014-10-20 11:55:05 -070041{
42 // connection to contact manager
43 connect(this, SIGNAL(identityUpdated(const QString&)),
44 &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
45
46 connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
47 this, SLOT(onContactIdListReady(const QStringList&)));
48
Varun Patilb3d03b92021-01-08 17:09:32 +053049 m_validator = std::make_shared<ndn::security::ValidatorNull>();
Yingdi Yu2c9e7712014-10-20 11:55:05 -070050}
51
Varun Patilb3d03b92021-01-08 17:09:32 +053052ControllerBackend::~ControllerBackend() = default;
Yingdi Yu2c9e7712014-10-20 11:55:05 -070053
54void
55ControllerBackend::run()
56{
Yingdi Yuf3401182015-02-02 20:21:07 -080057 bool shouldResume = false;
58 do {
59 try {
60 setInvitationListener();
61 m_face.processEvents();
62 }
Varun Patila24bd3e2020-11-24 10:08:33 +053063 catch (const std::runtime_error& e) {
Yingdi Yuf3401182015-02-02 20:21:07 -080064 {
65 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
66 m_isNfdConnected = false;
67 }
68 emit nfdError();
69 {
70 std::lock_guard<std::mutex>lock(m_resumeMutex);
71 m_shouldResume = true;
72 }
73#ifdef BOOST_THREAD_USES_CHRONO
74 time::seconds reconnectTimer = time::seconds(CONNECTION_RETRY_TIMER);
75#else
76 boost::posix_time::time_duration reconnectTimer;
77 reconnectTimer = boost::posix_time::seconds(CONNECTION_RETRY_TIMER);
78#endif
79 while (!m_isNfdConnected) {
80#ifdef BOOST_THREAD_USES_CHRONO
81 boost::this_thread::sleep_for(reconnectTimer);
82#else
83 boost::this_thread::sleep(reconnectTimer);
84#endif
85 }
86 }
87 {
88 std::lock_guard<std::mutex>lock(m_resumeMutex);
89 shouldResume = m_shouldResume;
90 m_shouldResume = false;
91 }
92 } while (shouldResume);
Yingdi Yu2c9e7712014-10-20 11:55:05 -070093 std::cerr << "Bye!" << std::endl;
94}
95
96// private methods:
97
98void
99tmpOnInvitationInterest(const ndn::Name& prefix,
100 const ndn::Interest& interest)
101{
102 std::cerr << "tmpOnInvitationInterest" << std::endl;
103}
104
105void
106tmpOnInvitationRegisterFailed(const Name& prefix,
107 const string& failInfo)
108{
109 std::cerr << "tmpOnInvitationRegisterFailed" << std::endl;
110}
111
112void
113tmpUnregisterPrefixSuccessCallback()
114{
115 std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
116}
117
118void
119tmpUnregisterPrefixFailureCallback(const string& failInfo)
120{
121 std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
122}
123
124void
125ControllerBackend::setInvitationListener()
126{
127 QMutexLocker locker(&m_mutex);
128
129 Name invitationPrefix;
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800130 Name requestPrefix;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700131 Name routingPrefix = getInvitationRoutingPrefix();
132 size_t offset = 0;
133 if (!routingPrefix.isPrefixOf(m_identity)) {
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800134 invitationPrefix.append(routingPrefix).append(ROUTING_HINT_SEPARATOR);
135 requestPrefix.append(routingPrefix).append(ROUTING_HINT_SEPARATOR);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700136 offset = routingPrefix.size() + 1;
137 }
138 invitationPrefix.append(m_identity).append("CHRONOCHAT-INVITATION");
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800139 requestPrefix.append(m_identity).append("CHRONOCHAT-INVITATION-REQUEST");
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700140
Varun Patila24bd3e2020-11-24 10:08:33 +0530141 m_invitationListenerHandle = m_face.setInterestFilter(invitationPrefix,
142 bind(&ControllerBackend::onInvitationInterest, this, _1, _2, offset),
143 bind(&ControllerBackend::onInvitationRegisterFailed, this, _1, _2));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700144
Varun Patila24bd3e2020-11-24 10:08:33 +0530145 m_requestListenerHandle = m_face.setInterestFilter(requestPrefix,
146 bind(&ControllerBackend::onInvitationRequestInterest, this, _1, _2, offset),
147 [] (const Name& prefix, const std::string& failInfo) {});
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700148}
149
150ndn::Name
151ControllerBackend::getInvitationRoutingPrefix()
152{
153 return Name("/ndn/broadcast");
154}
155
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700156
157void
158ControllerBackend::onInvitationInterest(const ndn::Name& prefix,
159 const ndn::Interest& interest,
160 size_t routingPrefixOffset)
161{
Varun Patilb3d03b92021-01-08 17:09:32 +0530162 auto invitationInterest = std::make_shared<Interest>(interest.getName().getSubName(routingPrefixOffset));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700163
164 // check if the chatroom already exists;
165 try {
166 Invitation invitation(invitationInterest->getName());
167 if (m_chatDialogList.contains(QString::fromStdString(invitation.getChatroom())))
168 return;
169 }
Varun Patila24bd3e2020-11-24 10:08:33 +0530170 catch (const Invitation::Error& e) {
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700171 // Cannot parse the invitation;
172 return;
173 }
174
Varun Patil3d850902020-11-23 12:19:14 +0530175 m_validator->validate(
176 *invitationInterest,
177 bind(&ControllerBackend::onInvitationValidated, this, _1),
178 bind(&ControllerBackend::onInvitationValidationFailed, this, _1, _2));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700179}
180
181void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800182ControllerBackend::onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700183{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700184}
185
186void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800187ControllerBackend::onInvitationRequestInterest(const ndn::Name& prefix,
188 const ndn::Interest& interest,
189 size_t routingPrefixOffset)
190{
191 shared_ptr<const Data> data = m_ims.find(interest);
192 if (data != nullptr) {
193 m_face.put(*data);
194 return;
195 }
196 Name interestName = interest.getName();
197 size_t i;
198 for (i = 0; i < interestName.size(); i++)
199 if (interestName.at(i) == Name::Component("CHRONOCHAT-INVITATION-REQUEST"))
200 break;
201 if (i < interestName.size()) {
202 string chatroom = interestName.at(i+1).toUri();
203 string alias = interestName.getSubName(i+2).getPrefix(-1).toUri();
204 emit invitationRequestReceived(QString::fromStdString(alias),
205 QString::fromStdString(chatroom),
206 interestName);
207 }
208}
209
210void
Varun Patil3d850902020-11-23 12:19:14 +0530211ControllerBackend::onInvitationValidated(const Interest& interest)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700212{
Varun Patil3d850902020-11-23 12:19:14 +0530213 Invitation invitation(interest.getName());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700214 // Should be obtained via a method of ContactManager.
Varun Patil3d850902020-11-23 12:19:14 +0530215 string alias = invitation.getInviterCertificate().getKeyName().getPrefix(-1).toUri();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700216
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800217 emit invitationValidated(QString::fromStdString(alias),
218 QString::fromStdString(invitation.getChatroom()),
Varun Patil3d850902020-11-23 12:19:14 +0530219 interest.getName());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700220}
221
222void
Varun Patil3d850902020-11-23 12:19:14 +0530223ControllerBackend::onInvitationValidationFailed(const Interest& interest,
224 const ndn::security::ValidationError& failureInfo)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700225{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700226}
227
228void
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800229ControllerBackend::onLocalPrefix(const ndn::ConstBufferPtr& data)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700230{
231 Name prefix;
232
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800233 Block contentBlock(tlv::Content, data);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700234 try {
235 contentBlock.parse();
236
237 for (Block::element_const_iterator it = contentBlock.elements_begin();
238 it != contentBlock.elements_end(); it++) {
239 Name candidate;
240 candidate.wireDecode(*it);
241 if (candidate.isPrefixOf(m_identity)) {
242 prefix = candidate;
243 break;
244 }
245 }
246
247 if (prefix.empty()) {
248 if (contentBlock.elements_begin() != contentBlock.elements_end())
249 prefix.wireDecode(*contentBlock.elements_begin());
250 else
251 prefix = Name("/private/local");
252 }
253 }
Varun Patila24bd3e2020-11-24 10:08:33 +0530254 catch (const Block::Error& e) {
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700255 prefix = Name("/private/local");
256 }
257
258 updateLocalPrefix(prefix);
259}
260
261void
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800262ControllerBackend::onLocalPrefixError(uint32_t code, const std::string& msg)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700263{
264 Name localPrefix("/private/local");
265 updateLocalPrefix(localPrefix);
266}
267
268void
269ControllerBackend::updateLocalPrefix(const Name& localPrefix)
270{
271 if (m_localPrefix.empty() || m_localPrefix != localPrefix) {
272 m_localPrefix = localPrefix;
273 emit localPrefixUpdated(QString::fromStdString(localPrefix.toUri()));
274 }
275}
276
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800277void
Varun Patil3d850902020-11-23 12:19:14 +0530278ControllerBackend::onRequestResponse(const Interest& interest, const Data& data)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800279{
280 size_t i;
281 Name interestName = interest.getName();
282 for (i = 0; i < interestName.size(); i++) {
283 if (interestName.at(i) == Name::Component("CHRONOCHAT-INVITATION-REQUEST"))
284 break;
285 }
286 Name::Component chatroomName = interestName.at(i+1);
287 Block contentBlock = data.getContent();
288 int res = ndn::readNonNegativeInteger(contentBlock);
Qiuhan Ding59c45432015-04-01 18:15:03 -0700289 if (m_chatDialogList.contains(QString::fromStdString(chatroomName.toUri())))
290 return;
291
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800292 // if data is true,
293 if (res == 1)
294 emit startChatroom(QString::fromStdString(chatroomName.toUri()), false);
295 else
296 emit invitationRequestResult("You are rejected to enter chatroom: " + chatroomName.toUri());
297}
298
299void
300ControllerBackend::onRequestTimeout(const Interest& interest, int& resendTimes)
301{
302 if (resendTimes < MAXIMUM_REQUEST)
303 m_face.expressInterest(interest,
304 bind(&ControllerBackend::onRequestResponse, this, _1, _2),
Varun Patil3d850902020-11-23 12:19:14 +0530305 bind(&ControllerBackend::onRequestTimeout, this, _1, resendTimes + 1),
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800306 bind(&ControllerBackend::onRequestTimeout, this, _1, resendTimes + 1));
307 else
308 emit invitationRequestResult("Invitation request times out.");
309}
310
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700311// public slots:
312void
313ControllerBackend::shutdown()
314{
Yingdi Yuf3401182015-02-02 20:21:07 -0800315 {
316 std::lock_guard<std::mutex>lock(m_resumeMutex);
317 m_shouldResume = false;
318 }
319 {
320 // In this case, we just stop checking the nfd connection and exit
321 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
322 m_isNfdConnected = true;
323 }
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700324 m_face.getIoService().stop();
325}
326
327void
328ControllerBackend::addChatroom(QString chatroom)
329{
330 m_chatDialogList.append(chatroom);
331}
332
333void
334ControllerBackend::removeChatroom(QString chatroom)
335{
336 m_chatDialogList.removeAll(chatroom);
337}
338
339void
340ControllerBackend::onUpdateLocalPrefixAction()
341{
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800342 Interest interest("/localhop/nfd/rib/routable-prefixes");
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700343 interest.setInterestLifetime(time::milliseconds(1000));
344 interest.setMustBeFresh(true);
345
Varun Patil3d850902020-11-23 12:19:14 +0530346 auto fetcher = ndn::util::SegmentFetcher::start(m_face,
347 interest,
348 m_nullValidator);
349 fetcher->onComplete.connect(bind(&ControllerBackend::onLocalPrefix, this, _1));
350 fetcher->onError.connect(bind(&ControllerBackend::onLocalPrefixError, this, _1, _2));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700351}
352
353void
354ControllerBackend::onIdentityChanged(const QString& identity)
355{
356 m_chatDialogList.clear();
357
358 m_identity = Name(identity.toStdString());
359
360 std::cerr << "ControllerBackend::onIdentityChanged: " << m_identity << std::endl;
361
362 m_keyChain.createIdentity(m_identity);
363
364 setInvitationListener();
365
366 emit identityUpdated(identity);
367}
368
369void
370ControllerBackend::onInvitationResponded(const ndn::Name& invitationName, bool accepted)
371{
Varun Patilb3d03b92021-01-08 17:09:32 +0530372 auto response = std::make_shared<Data>();
Varun Patil3d850902020-11-23 12:19:14 +0530373 shared_ptr<ndn::security::Certificate> chatroomCert;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700374
375 // generate reply;
376 if (accepted) {
377 Name responseName = invitationName;
378 responseName.append(m_localPrefix.wireEncode());
379
380 response->setName(responseName);
381
382 // We should create a particular certificate for this chatroom,
383 //but let's use default one for now.
Varun Patilb3d03b92021-01-08 17:09:32 +0530384 chatroomCert = std::make_shared<ndn::security::Certificate>(
Varun Patil3d850902020-11-23 12:19:14 +0530385 m_keyChain.createIdentity(m_identity).getDefaultKey().getDefaultCertificate());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700386
387 response->setContent(chatroomCert->wireEncode());
388 response->setFreshnessPeriod(time::milliseconds(1000));
389 }
390 else {
391 response->setName(invitationName);
392 response->setFreshnessPeriod(time::milliseconds(1000));
393 }
394
Varun Patil3d850902020-11-23 12:19:14 +0530395 m_keyChain.sign(*response, ndn::security::signingByIdentity(m_identity));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700396
397 // Check if we need a wrapper
398 Name invitationRoutingPrefix = getInvitationRoutingPrefix();
399 if (invitationRoutingPrefix.isPrefixOf(m_identity))
400 m_face.put(*response);
401 else {
402 Name wrappedName;
403 wrappedName.append(invitationRoutingPrefix)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800404 .append(ROUTING_HINT_SEPARATOR)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700405 .append(response->getName());
406
Varun Patilb3d03b92021-01-08 17:09:32 +0530407 auto wrappedData = std::make_shared<Data>(wrappedName);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700408 wrappedData->setContent(response->wireEncode());
409 wrappedData->setFreshnessPeriod(time::milliseconds(1000));
410
Varun Patil3d850902020-11-23 12:19:14 +0530411 m_keyChain.sign(*wrappedData, ndn::security::signingByIdentity(m_identity));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700412 m_face.put(*wrappedData);
413 }
414
415 Invitation invitation(invitationName);
416 emit startChatroomOnInvitation(invitation, true);
417}
418
419void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800420ControllerBackend::onInvitationRequestResponded(const ndn::Name& invitationResponseName,
421 bool accepted)
422{
Varun Patilb3d03b92021-01-08 17:09:32 +0530423 auto response = std::make_shared<Data>(invitationResponseName);
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800424 if (accepted)
Junxiao Shi9887fd12016-07-23 02:09:00 +0000425 response->setContent(ndn::makeNonNegativeIntegerBlock(tlv::Content, 1));
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800426 else
Junxiao Shi9887fd12016-07-23 02:09:00 +0000427 response->setContent(ndn::makeNonNegativeIntegerBlock(tlv::Content, 0));
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800428
Varun Patil3d850902020-11-23 12:19:14 +0530429 response->setFreshnessPeriod(time::milliseconds(1000));
430 m_keyChain.sign(*response, ndn::security::signingByIdentity(m_identity));
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800431 m_ims.insert(*response);
432 m_face.put(*response);
433}
434
435void
436ControllerBackend::onSendInvitationRequest(const QString& chatroomName, const QString& prefix)
437{
438 if (prefix.length() == 0)
439 return;
440 Name interestName = getInvitationRoutingPrefix();
441 interestName.append(ROUTING_HINT_SEPARATOR).append(prefix.toStdString());
442 interestName.append("CHRONOCHAT-INVITATION-REQUEST");
443 interestName.append(chatroomName.toStdString());
444 interestName.append(m_identity);
445 interestName.appendTimestamp();
446 Interest interest(interestName);
447 interest.setInterestLifetime(time::milliseconds(10000));
448 interest.setMustBeFresh(true);
Varun Patila24bd3e2020-11-24 10:08:33 +0530449 interest.setCanBePrefix(true);
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800450 interest.getNonce();
451 m_face.expressInterest(interest,
452 bind(&ControllerBackend::onRequestResponse, this, _1, _2),
Varun Patil3d850902020-11-23 12:19:14 +0530453 bind(&ControllerBackend::onRequestTimeout, this, _1, 0),
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800454 bind(&ControllerBackend::onRequestTimeout, this, _1, 0));
455}
456
457void
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700458ControllerBackend::onContactIdListReady(const QStringList& list)
459{
460 ContactList contactList;
461
462 m_contactManager.getContactList(contactList);
Varun Patil3d850902020-11-23 12:19:14 +0530463 // m_validator.cleanTrustAnchor();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700464
Varun Patil3d850902020-11-23 12:19:14 +0530465 // for (ContactList::const_iterator it = contactList.begin(); it != contactList.end(); it++)
466 // m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700467}
468
Yingdi Yuf3401182015-02-02 20:21:07 -0800469void
470ControllerBackend::onNfdReconnect()
471{
472 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
473 m_isNfdConnected = true;
474}
475
Yingdi Yueb692ac2015-02-10 18:46:18 -0800476} // namespace chronochat
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700477
478#if WAF
479#include "controller-backend.moc"
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700480#endif