blob: 9078cf2c02ccf502a7efa80b5a241344da3a1f5b [file] [log] [blame]
Yingdi Yu2c9e7712014-10-20 11:55:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
Varun Patila24bd3e2020-11-24 10:08:33 +05303 * Copyright (c) 2013-2020, 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)
Yingdi Yu2c9e7712014-10-20 11:55:05 -070039 , m_contactManager(m_face)
Yingdi Yu2c9e7712014-10-20 11:55:05 -070040{
41 // connection to contact manager
42 connect(this, SIGNAL(identityUpdated(const QString&)),
43 &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
44
45 connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
46 this, SLOT(onContactIdListReady(const QStringList&)));
47
Varun Patil3d850902020-11-23 12:19:14 +053048 m_validator = make_shared<ndn::security::ValidatorNull>();
Yingdi Yu2c9e7712014-10-20 11:55:05 -070049}
50
51ControllerBackend::~ControllerBackend()
52{
53}
54
55void
56ControllerBackend::run()
57{
Yingdi Yuf3401182015-02-02 20:21:07 -080058 bool shouldResume = false;
59 do {
60 try {
61 setInvitationListener();
62 m_face.processEvents();
63 }
Varun Patila24bd3e2020-11-24 10:08:33 +053064 catch (const std::runtime_error& e) {
Yingdi Yuf3401182015-02-02 20:21:07 -080065 {
66 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
67 m_isNfdConnected = false;
68 }
69 emit nfdError();
70 {
71 std::lock_guard<std::mutex>lock(m_resumeMutex);
72 m_shouldResume = true;
73 }
74#ifdef BOOST_THREAD_USES_CHRONO
75 time::seconds reconnectTimer = time::seconds(CONNECTION_RETRY_TIMER);
76#else
77 boost::posix_time::time_duration reconnectTimer;
78 reconnectTimer = boost::posix_time::seconds(CONNECTION_RETRY_TIMER);
79#endif
80 while (!m_isNfdConnected) {
81#ifdef BOOST_THREAD_USES_CHRONO
82 boost::this_thread::sleep_for(reconnectTimer);
83#else
84 boost::this_thread::sleep(reconnectTimer);
85#endif
86 }
87 }
88 {
89 std::lock_guard<std::mutex>lock(m_resumeMutex);
90 shouldResume = m_shouldResume;
91 m_shouldResume = false;
92 }
93 } while (shouldResume);
Yingdi Yu2c9e7712014-10-20 11:55:05 -070094 std::cerr << "Bye!" << std::endl;
95}
96
97// private methods:
98
99void
100tmpOnInvitationInterest(const ndn::Name& prefix,
101 const ndn::Interest& interest)
102{
103 std::cerr << "tmpOnInvitationInterest" << std::endl;
104}
105
106void
107tmpOnInvitationRegisterFailed(const Name& prefix,
108 const string& failInfo)
109{
110 std::cerr << "tmpOnInvitationRegisterFailed" << std::endl;
111}
112
113void
114tmpUnregisterPrefixSuccessCallback()
115{
116 std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
117}
118
119void
120tmpUnregisterPrefixFailureCallback(const string& failInfo)
121{
122 std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
123}
124
125void
126ControllerBackend::setInvitationListener()
127{
128 QMutexLocker locker(&m_mutex);
129
130 Name invitationPrefix;
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800131 Name requestPrefix;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700132 Name routingPrefix = getInvitationRoutingPrefix();
133 size_t offset = 0;
134 if (!routingPrefix.isPrefixOf(m_identity)) {
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800135 invitationPrefix.append(routingPrefix).append(ROUTING_HINT_SEPARATOR);
136 requestPrefix.append(routingPrefix).append(ROUTING_HINT_SEPARATOR);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700137 offset = routingPrefix.size() + 1;
138 }
139 invitationPrefix.append(m_identity).append("CHRONOCHAT-INVITATION");
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800140 requestPrefix.append(m_identity).append("CHRONOCHAT-INVITATION-REQUEST");
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700141
Varun Patila24bd3e2020-11-24 10:08:33 +0530142 m_invitationListenerHandle = m_face.setInterestFilter(invitationPrefix,
143 bind(&ControllerBackend::onInvitationInterest, this, _1, _2, offset),
144 bind(&ControllerBackend::onInvitationRegisterFailed, this, _1, _2));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700145
Varun Patila24bd3e2020-11-24 10:08:33 +0530146 m_requestListenerHandle = m_face.setInterestFilter(requestPrefix,
147 bind(&ControllerBackend::onInvitationRequestInterest, this, _1, _2, offset),
148 [] (const Name& prefix, const std::string& failInfo) {});
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700149}
150
151ndn::Name
152ControllerBackend::getInvitationRoutingPrefix()
153{
154 return Name("/ndn/broadcast");
155}
156
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700157
158void
159ControllerBackend::onInvitationInterest(const ndn::Name& prefix,
160 const ndn::Interest& interest,
161 size_t routingPrefixOffset)
162{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700163 shared_ptr<Interest> invitationInterest =
Yingdi Yu6a614442014-10-31 17:42:43 -0700164 make_shared<Interest>(interest.getName().getSubName(routingPrefixOffset));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700165
166 // check if the chatroom already exists;
167 try {
168 Invitation invitation(invitationInterest->getName());
169 if (m_chatDialogList.contains(QString::fromStdString(invitation.getChatroom())))
170 return;
171 }
Varun Patila24bd3e2020-11-24 10:08:33 +0530172 catch (const Invitation::Error& e) {
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700173 // Cannot parse the invitation;
174 return;
175 }
176
Varun Patil3d850902020-11-23 12:19:14 +0530177 m_validator->validate(
178 *invitationInterest,
179 bind(&ControllerBackend::onInvitationValidated, this, _1),
180 bind(&ControllerBackend::onInvitationValidationFailed, this, _1, _2));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700181}
182
183void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800184ControllerBackend::onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700185{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700186}
187
188void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800189ControllerBackend::onInvitationRequestInterest(const ndn::Name& prefix,
190 const ndn::Interest& interest,
191 size_t routingPrefixOffset)
192{
193 shared_ptr<const Data> data = m_ims.find(interest);
194 if (data != nullptr) {
195 m_face.put(*data);
196 return;
197 }
198 Name interestName = interest.getName();
199 size_t i;
200 for (i = 0; i < interestName.size(); i++)
201 if (interestName.at(i) == Name::Component("CHRONOCHAT-INVITATION-REQUEST"))
202 break;
203 if (i < interestName.size()) {
204 string chatroom = interestName.at(i+1).toUri();
205 string alias = interestName.getSubName(i+2).getPrefix(-1).toUri();
206 emit invitationRequestReceived(QString::fromStdString(alias),
207 QString::fromStdString(chatroom),
208 interestName);
209 }
210}
211
212void
Varun Patil3d850902020-11-23 12:19:14 +0530213ControllerBackend::onInvitationValidated(const Interest& interest)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700214{
Varun Patil3d850902020-11-23 12:19:14 +0530215 Invitation invitation(interest.getName());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700216 // Should be obtained via a method of ContactManager.
Varun Patil3d850902020-11-23 12:19:14 +0530217 string alias = invitation.getInviterCertificate().getKeyName().getPrefix(-1).toUri();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700218
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800219 emit invitationValidated(QString::fromStdString(alias),
220 QString::fromStdString(invitation.getChatroom()),
Varun Patil3d850902020-11-23 12:19:14 +0530221 interest.getName());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700222}
223
224void
Varun Patil3d850902020-11-23 12:19:14 +0530225ControllerBackend::onInvitationValidationFailed(const Interest& interest,
226 const ndn::security::ValidationError& failureInfo)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700227{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700228}
229
230void
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800231ControllerBackend::onLocalPrefix(const ndn::ConstBufferPtr& data)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700232{
233 Name prefix;
234
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800235 Block contentBlock(tlv::Content, data);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700236 try {
237 contentBlock.parse();
238
239 for (Block::element_const_iterator it = contentBlock.elements_begin();
240 it != contentBlock.elements_end(); it++) {
241 Name candidate;
242 candidate.wireDecode(*it);
243 if (candidate.isPrefixOf(m_identity)) {
244 prefix = candidate;
245 break;
246 }
247 }
248
249 if (prefix.empty()) {
250 if (contentBlock.elements_begin() != contentBlock.elements_end())
251 prefix.wireDecode(*contentBlock.elements_begin());
252 else
253 prefix = Name("/private/local");
254 }
255 }
Varun Patila24bd3e2020-11-24 10:08:33 +0530256 catch (const Block::Error& e) {
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700257 prefix = Name("/private/local");
258 }
259
260 updateLocalPrefix(prefix);
261}
262
263void
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800264ControllerBackend::onLocalPrefixError(uint32_t code, const std::string& msg)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700265{
266 Name localPrefix("/private/local");
267 updateLocalPrefix(localPrefix);
268}
269
270void
271ControllerBackend::updateLocalPrefix(const Name& localPrefix)
272{
273 if (m_localPrefix.empty() || m_localPrefix != localPrefix) {
274 m_localPrefix = localPrefix;
275 emit localPrefixUpdated(QString::fromStdString(localPrefix.toUri()));
276 }
277}
278
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800279void
Varun Patil3d850902020-11-23 12:19:14 +0530280ControllerBackend::onRequestResponse(const Interest& interest, const Data& data)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800281{
282 size_t i;
283 Name interestName = interest.getName();
284 for (i = 0; i < interestName.size(); i++) {
285 if (interestName.at(i) == Name::Component("CHRONOCHAT-INVITATION-REQUEST"))
286 break;
287 }
288 Name::Component chatroomName = interestName.at(i+1);
289 Block contentBlock = data.getContent();
290 int res = ndn::readNonNegativeInteger(contentBlock);
Qiuhan Ding59c45432015-04-01 18:15:03 -0700291 if (m_chatDialogList.contains(QString::fromStdString(chatroomName.toUri())))
292 return;
293
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800294 // if data is true,
295 if (res == 1)
296 emit startChatroom(QString::fromStdString(chatroomName.toUri()), false);
297 else
298 emit invitationRequestResult("You are rejected to enter chatroom: " + chatroomName.toUri());
299}
300
301void
302ControllerBackend::onRequestTimeout(const Interest& interest, int& resendTimes)
303{
304 if (resendTimes < MAXIMUM_REQUEST)
305 m_face.expressInterest(interest,
306 bind(&ControllerBackend::onRequestResponse, this, _1, _2),
Varun Patil3d850902020-11-23 12:19:14 +0530307 bind(&ControllerBackend::onRequestTimeout, this, _1, resendTimes + 1),
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800308 bind(&ControllerBackend::onRequestTimeout, this, _1, resendTimes + 1));
309 else
310 emit invitationRequestResult("Invitation request times out.");
311}
312
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700313// public slots:
314void
315ControllerBackend::shutdown()
316{
Yingdi Yuf3401182015-02-02 20:21:07 -0800317 {
318 std::lock_guard<std::mutex>lock(m_resumeMutex);
319 m_shouldResume = false;
320 }
321 {
322 // In this case, we just stop checking the nfd connection and exit
323 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
324 m_isNfdConnected = true;
325 }
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700326 m_face.getIoService().stop();
327}
328
329void
330ControllerBackend::addChatroom(QString chatroom)
331{
332 m_chatDialogList.append(chatroom);
333}
334
335void
336ControllerBackend::removeChatroom(QString chatroom)
337{
338 m_chatDialogList.removeAll(chatroom);
339}
340
341void
342ControllerBackend::onUpdateLocalPrefixAction()
343{
Yingdi Yu7ff31f02015-02-05 11:21:07 -0800344 Interest interest("/localhop/nfd/rib/routable-prefixes");
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700345 interest.setInterestLifetime(time::milliseconds(1000));
346 interest.setMustBeFresh(true);
347
Varun Patil3d850902020-11-23 12:19:14 +0530348 auto fetcher = ndn::util::SegmentFetcher::start(m_face,
349 interest,
350 m_nullValidator);
351 fetcher->onComplete.connect(bind(&ControllerBackend::onLocalPrefix, this, _1));
352 fetcher->onError.connect(bind(&ControllerBackend::onLocalPrefixError, this, _1, _2));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700353}
354
355void
356ControllerBackend::onIdentityChanged(const QString& identity)
357{
358 m_chatDialogList.clear();
359
360 m_identity = Name(identity.toStdString());
361
362 std::cerr << "ControllerBackend::onIdentityChanged: " << m_identity << std::endl;
363
364 m_keyChain.createIdentity(m_identity);
365
366 setInvitationListener();
367
368 emit identityUpdated(identity);
369}
370
371void
372ControllerBackend::onInvitationResponded(const ndn::Name& invitationName, bool accepted)
373{
374 shared_ptr<Data> response = make_shared<Data>();
Varun Patil3d850902020-11-23 12:19:14 +0530375 shared_ptr<ndn::security::Certificate> chatroomCert;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700376
377 // generate reply;
378 if (accepted) {
379 Name responseName = invitationName;
380 responseName.append(m_localPrefix.wireEncode());
381
382 response->setName(responseName);
383
384 // We should create a particular certificate for this chatroom,
385 //but let's use default one for now.
Varun Patil3d850902020-11-23 12:19:14 +0530386 chatroomCert = make_shared<ndn::security::Certificate>(
387 m_keyChain.createIdentity(m_identity).getDefaultKey().getDefaultCertificate());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700388
389 response->setContent(chatroomCert->wireEncode());
390 response->setFreshnessPeriod(time::milliseconds(1000));
391 }
392 else {
393 response->setName(invitationName);
394 response->setFreshnessPeriod(time::milliseconds(1000));
395 }
396
Varun Patil3d850902020-11-23 12:19:14 +0530397 m_keyChain.sign(*response, ndn::security::signingByIdentity(m_identity));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700398
399 // Check if we need a wrapper
400 Name invitationRoutingPrefix = getInvitationRoutingPrefix();
401 if (invitationRoutingPrefix.isPrefixOf(m_identity))
402 m_face.put(*response);
403 else {
404 Name wrappedName;
405 wrappedName.append(invitationRoutingPrefix)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800406 .append(ROUTING_HINT_SEPARATOR)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700407 .append(response->getName());
408
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700409 shared_ptr<Data> wrappedData = make_shared<Data>(wrappedName);
410 wrappedData->setContent(response->wireEncode());
411 wrappedData->setFreshnessPeriod(time::milliseconds(1000));
412
Varun Patil3d850902020-11-23 12:19:14 +0530413 m_keyChain.sign(*wrappedData, ndn::security::signingByIdentity(m_identity));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700414 m_face.put(*wrappedData);
415 }
416
417 Invitation invitation(invitationName);
418 emit startChatroomOnInvitation(invitation, true);
419}
420
421void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800422ControllerBackend::onInvitationRequestResponded(const ndn::Name& invitationResponseName,
423 bool accepted)
424{
425 shared_ptr<Data> response = make_shared<Data>(invitationResponseName);
426 if (accepted)
Junxiao Shi9887fd12016-07-23 02:09:00 +0000427 response->setContent(ndn::makeNonNegativeIntegerBlock(tlv::Content, 1));
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800428 else
Junxiao Shi9887fd12016-07-23 02:09:00 +0000429 response->setContent(ndn::makeNonNegativeIntegerBlock(tlv::Content, 0));
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800430
Varun Patil3d850902020-11-23 12:19:14 +0530431 response->setFreshnessPeriod(time::milliseconds(1000));
432 m_keyChain.sign(*response, ndn::security::signingByIdentity(m_identity));
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800433 m_ims.insert(*response);
434 m_face.put(*response);
435}
436
437void
438ControllerBackend::onSendInvitationRequest(const QString& chatroomName, const QString& prefix)
439{
440 if (prefix.length() == 0)
441 return;
442 Name interestName = getInvitationRoutingPrefix();
443 interestName.append(ROUTING_HINT_SEPARATOR).append(prefix.toStdString());
444 interestName.append("CHRONOCHAT-INVITATION-REQUEST");
445 interestName.append(chatroomName.toStdString());
446 interestName.append(m_identity);
447 interestName.appendTimestamp();
448 Interest interest(interestName);
449 interest.setInterestLifetime(time::milliseconds(10000));
450 interest.setMustBeFresh(true);
Varun Patila24bd3e2020-11-24 10:08:33 +0530451 interest.setCanBePrefix(true);
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800452 interest.getNonce();
453 m_face.expressInterest(interest,
454 bind(&ControllerBackend::onRequestResponse, this, _1, _2),
Varun Patil3d850902020-11-23 12:19:14 +0530455 bind(&ControllerBackend::onRequestTimeout, this, _1, 0),
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800456 bind(&ControllerBackend::onRequestTimeout, this, _1, 0));
457}
458
459void
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700460ControllerBackend::onContactIdListReady(const QStringList& list)
461{
462 ContactList contactList;
463
464 m_contactManager.getContactList(contactList);
Varun Patil3d850902020-11-23 12:19:14 +0530465 // m_validator.cleanTrustAnchor();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700466
Varun Patil3d850902020-11-23 12:19:14 +0530467 // for (ContactList::const_iterator it = contactList.begin(); it != contactList.end(); it++)
468 // m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700469
470}
471
Yingdi Yuf3401182015-02-02 20:21:07 -0800472void
473ControllerBackend::onNfdReconnect()
474{
475 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
476 m_isNfdConnected = true;
477}
478
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700479
Yingdi Yueb692ac2015-02-10 18:46:18 -0800480} // namespace chronochat
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700481
482#if WAF
483#include "controller-backend.moc"
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700484#endif