blob: 217228e24b418b20a3a402c857ffe68d0b9190d0 [file] [log] [blame]
Yingdi Yu2c9e7712014-10-20 11:55:05 -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>
9 */
10
11#include "controller-backend.hpp"
12
13#ifndef Q_MOC_RUN
14#include "invitation.hpp"
15#include "logging.h"
16#endif
17
18
19INIT_LOGGER("ControllerBackend");
20
Yingdi Yueb692ac2015-02-10 18:46:18 -080021namespace chronochat {
Yingdi Yu2c9e7712014-10-20 11:55:05 -070022
23using std::string;
24
25using ndn::Face;
26using ndn::IdentityCertificate;
27using ndn::OnInterestValidated;
28using ndn::OnInterestValidationFailed;
29
30
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 Yu2c9e7712014-10-20 11:55:05 -070034
35ControllerBackend::ControllerBackend(QObject* parent)
36 : QThread(parent)
37 , m_contactManager(m_face)
38 , m_invitationListenerId(0)
39{
40 // connection to contact manager
41 connect(this, SIGNAL(identityUpdated(const QString&)),
42 &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
43
44 connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
45 this, SLOT(onContactIdListReady(const QStringList&)));
46
47}
48
49ControllerBackend::~ControllerBackend()
50{
51}
52
53void
54ControllerBackend::run()
55{
56 setInvitationListener();
57
58 m_face.processEvents();
59
60 std::cerr << "Bye!" << std::endl;
61}
62
63// private methods:
64
65void
66tmpOnInvitationInterest(const ndn::Name& prefix,
67 const ndn::Interest& interest)
68{
69 std::cerr << "tmpOnInvitationInterest" << std::endl;
70}
71
72void
73tmpOnInvitationRegisterFailed(const Name& prefix,
74 const string& failInfo)
75{
76 std::cerr << "tmpOnInvitationRegisterFailed" << std::endl;
77}
78
79void
80tmpUnregisterPrefixSuccessCallback()
81{
82 std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
83}
84
85void
86tmpUnregisterPrefixFailureCallback(const string& failInfo)
87{
88 std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
89}
90
91void
92ControllerBackend::setInvitationListener()
93{
94 QMutexLocker locker(&m_mutex);
95
96 Name invitationPrefix;
Qiuhan Dingba3e57a2015-01-08 19:07:39 -080097 Name requestPrefix;
Yingdi Yu2c9e7712014-10-20 11:55:05 -070098 Name routingPrefix = getInvitationRoutingPrefix();
99 size_t offset = 0;
100 if (!routingPrefix.isPrefixOf(m_identity)) {
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800101 invitationPrefix.append(routingPrefix).append(ROUTING_HINT_SEPARATOR);
102 requestPrefix.append(routingPrefix).append(ROUTING_HINT_SEPARATOR);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700103 offset = routingPrefix.size() + 1;
104 }
105 invitationPrefix.append(m_identity).append("CHRONOCHAT-INVITATION");
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800106 requestPrefix.append(m_identity).append("CHRONOCHAT-INVITATION-REQUEST");
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700107
108 const ndn::RegisteredPrefixId* invitationListenerId =
109 m_face.setInterestFilter(invitationPrefix,
110 bind(&ControllerBackend::onInvitationInterest,
111 this, _1, _2, offset),
112 bind(&ControllerBackend::onInvitationRegisterFailed,
113 this, _1, _2));
114
115 if (m_invitationListenerId != 0) {
116 m_face.unregisterPrefix(m_invitationListenerId,
117 bind(&ControllerBackend::onInvitationPrefixReset, this),
118 bind(&ControllerBackend::onInvitationPrefixResetFailed, this, _1));
119 }
120
121 m_invitationListenerId = invitationListenerId;
122
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800123 const ndn::RegisteredPrefixId* requestListenerId =
124 m_face.setInterestFilter(requestPrefix,
125 bind(&ControllerBackend::onInvitationRequestInterest,
126 this, _1, _2, offset),
127 [] (const Name& prefix, const std::string& failInfo) {});
128
129 if (m_requestListenerId != 0) {
130 m_face.unregisterPrefix(m_requestListenerId,
131 []{},
132 [] (const std::string& failInfo) {});
133 }
134
135 m_requestListenerId = requestListenerId;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700136}
137
138ndn::Name
139ControllerBackend::getInvitationRoutingPrefix()
140{
141 return Name("/ndn/broadcast");
142}
143
144void
145ControllerBackend::onInvitationPrefixReset()
146{
147 // _LOG_DEBUG("ControllerBackend::onInvitationPrefixReset");
148}
149
150void
151ControllerBackend::onInvitationPrefixResetFailed(const std::string& failInfo)
152{
153 // _LOG_DEBUG("ControllerBackend::onInvitationPrefixResetFailed: " << failInfo);
154}
155
156
157void
158ControllerBackend::onInvitationInterest(const ndn::Name& prefix,
159 const ndn::Interest& interest,
160 size_t routingPrefixOffset)
161{
162 // _LOG_DEBUG("onInvitationInterest: " << interest.getName());
163 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 }
172 catch (Invitation::Error& e) {
173 // Cannot parse the invitation;
174 return;
175 }
176
177 OnInterestValidated onValidated = bind(&ControllerBackend::onInvitationValidated, this, _1);
178 OnInterestValidationFailed onFailed = bind(&ControllerBackend::onInvitationValidationFailed,
179 this, _1, _2);
180
181 m_validator.validate(*invitationInterest, onValidated, onFailed);
182}
183
184void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800185ControllerBackend::onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700186{
187 // _LOG_DEBUG("ControllerBackend::onInvitationRegisterFailed: " << failInfo);
188}
189
190void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800191ControllerBackend::onInvitationRequestInterest(const ndn::Name& prefix,
192 const ndn::Interest& interest,
193 size_t routingPrefixOffset)
194{
195 shared_ptr<const Data> data = m_ims.find(interest);
196 if (data != nullptr) {
197 m_face.put(*data);
198 return;
199 }
200 Name interestName = interest.getName();
201 size_t i;
202 for (i = 0; i < interestName.size(); i++)
203 if (interestName.at(i) == Name::Component("CHRONOCHAT-INVITATION-REQUEST"))
204 break;
205 if (i < interestName.size()) {
206 string chatroom = interestName.at(i+1).toUri();
207 string alias = interestName.getSubName(i+2).getPrefix(-1).toUri();
208 emit invitationRequestReceived(QString::fromStdString(alias),
209 QString::fromStdString(chatroom),
210 interestName);
211 }
212}
213
214void
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700215ControllerBackend::onInvitationValidated(const shared_ptr<const Interest>& interest)
216{
217 Invitation invitation(interest->getName());
218 // Should be obtained via a method of ContactManager.
219 string alias = invitation.getInviterCertificate().getPublicKeyName().getPrefix(-1).toUri();
220
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800221 emit invitationValidated(QString::fromStdString(alias),
222 QString::fromStdString(invitation.getChatroom()),
223 interest->getName());
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700224}
225
226void
227ControllerBackend::onInvitationValidationFailed(const shared_ptr<const Interest>& interest,
228 string failureInfo)
229{
230 // _LOG_DEBUG("Invitation: " << interest->getName() <<
231 // " cannot not be validated due to: " << failureInfo);
232}
233
234void
235ControllerBackend::onLocalPrefix(const Interest& interest, Data& data)
236{
237 Name prefix;
238
239 Block contentBlock = data.getContent();
240 try {
241 contentBlock.parse();
242
243 for (Block::element_const_iterator it = contentBlock.elements_begin();
244 it != contentBlock.elements_end(); it++) {
245 Name candidate;
246 candidate.wireDecode(*it);
247 if (candidate.isPrefixOf(m_identity)) {
248 prefix = candidate;
249 break;
250 }
251 }
252
253 if (prefix.empty()) {
254 if (contentBlock.elements_begin() != contentBlock.elements_end())
255 prefix.wireDecode(*contentBlock.elements_begin());
256 else
257 prefix = Name("/private/local");
258 }
259 }
260 catch (Block::Error& e) {
261 prefix = Name("/private/local");
262 }
263
264 updateLocalPrefix(prefix);
265}
266
267void
268ControllerBackend::onLocalPrefixTimeout(const Interest& interest)
269{
270 Name localPrefix("/private/local");
271 updateLocalPrefix(localPrefix);
272}
273
274void
275ControllerBackend::updateLocalPrefix(const Name& localPrefix)
276{
277 if (m_localPrefix.empty() || m_localPrefix != localPrefix) {
278 m_localPrefix = localPrefix;
279 emit localPrefixUpdated(QString::fromStdString(localPrefix.toUri()));
280 }
281}
282
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800283void
284ControllerBackend::onRequestResponse(const Interest& interest, Data& data)
285{
286 size_t i;
287 Name interestName = interest.getName();
288 for (i = 0; i < interestName.size(); i++) {
289 if (interestName.at(i) == Name::Component("CHRONOCHAT-INVITATION-REQUEST"))
290 break;
291 }
292 Name::Component chatroomName = interestName.at(i+1);
293 Block contentBlock = data.getContent();
294 int res = ndn::readNonNegativeInteger(contentBlock);
295 // if data is true,
296 if (res == 1)
297 emit startChatroom(QString::fromStdString(chatroomName.toUri()), false);
298 else
299 emit invitationRequestResult("You are rejected to enter chatroom: " + chatroomName.toUri());
300}
301
302void
303ControllerBackend::onRequestTimeout(const Interest& interest, int& resendTimes)
304{
305 if (resendTimes < MAXIMUM_REQUEST)
306 m_face.expressInterest(interest,
307 bind(&ControllerBackend::onRequestResponse, this, _1, _2),
308 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{
317 m_face.getIoService().stop();
318}
319
320void
321ControllerBackend::addChatroom(QString chatroom)
322{
323 m_chatDialogList.append(chatroom);
324}
325
326void
327ControllerBackend::removeChatroom(QString chatroom)
328{
329 m_chatDialogList.removeAll(chatroom);
330}
331
332void
333ControllerBackend::onUpdateLocalPrefixAction()
334{
335 // Name interestName();
336 Interest interest("/localhop/ndn-autoconf/routable-prefixes");
337 interest.setInterestLifetime(time::milliseconds(1000));
338 interest.setMustBeFresh(true);
339
340 m_face.expressInterest(interest,
341 bind(&ControllerBackend::onLocalPrefix, this, _1, _2),
342 bind(&ControllerBackend::onLocalPrefixTimeout, this, _1));
343}
344
345void
346ControllerBackend::onIdentityChanged(const QString& identity)
347{
348 m_chatDialogList.clear();
349
350 m_identity = Name(identity.toStdString());
351
352 std::cerr << "ControllerBackend::onIdentityChanged: " << m_identity << std::endl;
353
354 m_keyChain.createIdentity(m_identity);
355
356 setInvitationListener();
357
358 emit identityUpdated(identity);
359}
360
361void
362ControllerBackend::onInvitationResponded(const ndn::Name& invitationName, bool accepted)
363{
364 shared_ptr<Data> response = make_shared<Data>();
365 shared_ptr<IdentityCertificate> chatroomCert;
366
367 // generate reply;
368 if (accepted) {
369 Name responseName = invitationName;
370 responseName.append(m_localPrefix.wireEncode());
371
372 response->setName(responseName);
373
374 // We should create a particular certificate for this chatroom,
375 //but let's use default one for now.
376 chatroomCert
377 = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
378
379 response->setContent(chatroomCert->wireEncode());
380 response->setFreshnessPeriod(time::milliseconds(1000));
381 }
382 else {
383 response->setName(invitationName);
384 response->setFreshnessPeriod(time::milliseconds(1000));
385 }
386
387 m_keyChain.signByIdentity(*response, m_identity);
388
389 // Check if we need a wrapper
390 Name invitationRoutingPrefix = getInvitationRoutingPrefix();
391 if (invitationRoutingPrefix.isPrefixOf(m_identity))
392 m_face.put(*response);
393 else {
394 Name wrappedName;
395 wrappedName.append(invitationRoutingPrefix)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800396 .append(ROUTING_HINT_SEPARATOR)
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700397 .append(response->getName());
398
399 // _LOG_DEBUG("onInvitationResponded: prepare reply " << wrappedName);
400
401 shared_ptr<Data> wrappedData = make_shared<Data>(wrappedName);
402 wrappedData->setContent(response->wireEncode());
403 wrappedData->setFreshnessPeriod(time::milliseconds(1000));
404
405 m_keyChain.signByIdentity(*wrappedData, m_identity);
406 m_face.put(*wrappedData);
407 }
408
409 Invitation invitation(invitationName);
410 emit startChatroomOnInvitation(invitation, true);
411}
412
413void
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800414ControllerBackend::onInvitationRequestResponded(const ndn::Name& invitationResponseName,
415 bool accepted)
416{
417 shared_ptr<Data> response = make_shared<Data>(invitationResponseName);
418 if (accepted)
419 response->setContent(ndn::nonNegativeIntegerBlock(tlv::Content, 1));
420 else
421 response->setContent(ndn::nonNegativeIntegerBlock(tlv::Content, 0));
422
423 m_keyChain.signByIdentity(*response, m_identity);
424 m_ims.insert(*response);
425 m_face.put(*response);
426}
427
428void
429ControllerBackend::onSendInvitationRequest(const QString& chatroomName, const QString& prefix)
430{
431 if (prefix.length() == 0)
432 return;
433 Name interestName = getInvitationRoutingPrefix();
434 interestName.append(ROUTING_HINT_SEPARATOR).append(prefix.toStdString());
435 interestName.append("CHRONOCHAT-INVITATION-REQUEST");
436 interestName.append(chatroomName.toStdString());
437 interestName.append(m_identity);
438 interestName.appendTimestamp();
439 Interest interest(interestName);
440 interest.setInterestLifetime(time::milliseconds(10000));
441 interest.setMustBeFresh(true);
442 interest.getNonce();
443 m_face.expressInterest(interest,
444 bind(&ControllerBackend::onRequestResponse, this, _1, _2),
445 bind(&ControllerBackend::onRequestTimeout, this, _1, 0));
446}
447
448void
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700449ControllerBackend::onContactIdListReady(const QStringList& list)
450{
451 ContactList contactList;
452
453 m_contactManager.getContactList(contactList);
454 m_validator.cleanTrustAnchor();
455
456 for (ContactList::const_iterator it = contactList.begin(); it != contactList.end(); it++)
457 m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
458
459}
460
461
Yingdi Yueb692ac2015-02-10 18:46:18 -0800462} // namespace chronochat
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700463
464#if WAF
465#include "controller-backend.moc"
466// #include "controller-backend.cpp.moc"
467#endif