separate controller backend frontend
Change-Id: Ic4ba9c8154a600c978e75ea82ff36569270dd656
diff --git a/src/controller-backend.cpp b/src/controller-backend.cpp
new file mode 100644
index 0000000..af84cd7
--- /dev/null
+++ b/src/controller-backend.cpp
@@ -0,0 +1,360 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ * Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "controller-backend.hpp"
+
+#ifndef Q_MOC_RUN
+#include "invitation.hpp"
+#include "logging.h"
+#endif
+
+
+INIT_LOGGER("ControllerBackend");
+
+namespace chronos {
+
+using std::string;
+
+using ndn::Face;
+using ndn::IdentityCertificate;
+using ndn::OnInterestValidated;
+using ndn::OnInterestValidationFailed;
+
+
+static const uint8_t ROUTING_PREFIX_SEPARATOR[2] = {0xF0, 0x2E};
+
+ControllerBackend::ControllerBackend(QObject* parent)
+ : QThread(parent)
+ , m_contactManager(m_face)
+ , m_invitationListenerId(0)
+{
+ // connection to contact manager
+ connect(this, SIGNAL(identityUpdated(const QString&)),
+ &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
+
+ connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
+ this, SLOT(onContactIdListReady(const QStringList&)));
+
+}
+
+ControllerBackend::~ControllerBackend()
+{
+}
+
+void
+ControllerBackend::run()
+{
+ setInvitationListener();
+
+ m_face.processEvents();
+
+ std::cerr << "Bye!" << std::endl;
+}
+
+// private methods:
+
+void
+tmpOnInvitationInterest(const ndn::Name& prefix,
+ const ndn::Interest& interest)
+{
+ std::cerr << "tmpOnInvitationInterest" << std::endl;
+}
+
+void
+tmpOnInvitationRegisterFailed(const Name& prefix,
+ const string& failInfo)
+{
+ std::cerr << "tmpOnInvitationRegisterFailed" << std::endl;
+}
+
+void
+tmpUnregisterPrefixSuccessCallback()
+{
+ std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
+}
+
+void
+tmpUnregisterPrefixFailureCallback(const string& failInfo)
+{
+ std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
+}
+
+void
+ControllerBackend::setInvitationListener()
+{
+ QMutexLocker locker(&m_mutex);
+
+ Name invitationPrefix;
+ Name routingPrefix = getInvitationRoutingPrefix();
+ size_t offset = 0;
+ if (!routingPrefix.isPrefixOf(m_identity)) {
+ invitationPrefix.append(routingPrefix).append(ROUTING_PREFIX_SEPARATOR, 2);
+ offset = routingPrefix.size() + 1;
+ }
+ invitationPrefix.append(m_identity).append("CHRONOCHAT-INVITATION");
+
+ const ndn::RegisteredPrefixId* invitationListenerId =
+ m_face.setInterestFilter(invitationPrefix,
+ bind(&ControllerBackend::onInvitationInterest,
+ this, _1, _2, offset),
+ bind(&ControllerBackend::onInvitationRegisterFailed,
+ this, _1, _2));
+
+ if (m_invitationListenerId != 0) {
+ m_face.unregisterPrefix(m_invitationListenerId,
+ bind(&ControllerBackend::onInvitationPrefixReset, this),
+ bind(&ControllerBackend::onInvitationPrefixResetFailed, this, _1));
+ }
+
+ m_invitationListenerId = invitationListenerId;
+
+}
+
+ndn::Name
+ControllerBackend::getInvitationRoutingPrefix()
+{
+ return Name("/ndn/broadcast");
+}
+
+void
+ControllerBackend::onInvitationPrefixReset()
+{
+ // _LOG_DEBUG("ControllerBackend::onInvitationPrefixReset");
+}
+
+void
+ControllerBackend::onInvitationPrefixResetFailed(const std::string& failInfo)
+{
+ // _LOG_DEBUG("ControllerBackend::onInvitationPrefixResetFailed: " << failInfo);
+}
+
+
+void
+ControllerBackend::onInvitationInterest(const ndn::Name& prefix,
+ const ndn::Interest& interest,
+ size_t routingPrefixOffset)
+{
+ // _LOG_DEBUG("onInvitationInterest: " << interest.getName());
+ shared_ptr<Interest> invitationInterest =
+ make_shared<Interest>(boost::cref(interest.getName().getSubName(routingPrefixOffset)));
+
+ // check if the chatroom already exists;
+ try {
+ Invitation invitation(invitationInterest->getName());
+ if (m_chatDialogList.contains(QString::fromStdString(invitation.getChatroom())))
+ return;
+ }
+ catch (Invitation::Error& e) {
+ // Cannot parse the invitation;
+ return;
+ }
+
+ OnInterestValidated onValidated = bind(&ControllerBackend::onInvitationValidated, this, _1);
+ OnInterestValidationFailed onFailed = bind(&ControllerBackend::onInvitationValidationFailed,
+ this, _1, _2);
+
+ m_validator.validate(*invitationInterest, onValidated, onFailed);
+}
+
+void
+ControllerBackend::onInvitationRegisterFailed(const Name& prefix, const string& failInfo)
+{
+ // _LOG_DEBUG("ControllerBackend::onInvitationRegisterFailed: " << failInfo);
+}
+
+void
+ControllerBackend::onInvitationValidated(const shared_ptr<const Interest>& interest)
+{
+ Invitation invitation(interest->getName());
+ // Should be obtained via a method of ContactManager.
+ string alias = invitation.getInviterCertificate().getPublicKeyName().getPrefix(-1).toUri();
+
+ emit invitaionValidated(QString::fromStdString(alias),
+ QString::fromStdString(invitation.getChatroom()),
+ interest->getName());
+}
+
+void
+ControllerBackend::onInvitationValidationFailed(const shared_ptr<const Interest>& interest,
+ string failureInfo)
+{
+ // _LOG_DEBUG("Invitation: " << interest->getName() <<
+ // " cannot not be validated due to: " << failureInfo);
+}
+
+void
+ControllerBackend::onLocalPrefix(const Interest& interest, Data& data)
+{
+ Name prefix;
+
+ Block contentBlock = data.getContent();
+ try {
+ contentBlock.parse();
+
+ for (Block::element_const_iterator it = contentBlock.elements_begin();
+ it != contentBlock.elements_end(); it++) {
+ Name candidate;
+ candidate.wireDecode(*it);
+ if (candidate.isPrefixOf(m_identity)) {
+ prefix = candidate;
+ break;
+ }
+ }
+
+ if (prefix.empty()) {
+ if (contentBlock.elements_begin() != contentBlock.elements_end())
+ prefix.wireDecode(*contentBlock.elements_begin());
+ else
+ prefix = Name("/private/local");
+ }
+ }
+ catch (Block::Error& e) {
+ prefix = Name("/private/local");
+ }
+
+ updateLocalPrefix(prefix);
+}
+
+void
+ControllerBackend::onLocalPrefixTimeout(const Interest& interest)
+{
+ Name localPrefix("/private/local");
+ updateLocalPrefix(localPrefix);
+}
+
+void
+ControllerBackend::updateLocalPrefix(const Name& localPrefix)
+{
+ if (m_localPrefix.empty() || m_localPrefix != localPrefix) {
+ m_localPrefix = localPrefix;
+ emit localPrefixUpdated(QString::fromStdString(localPrefix.toUri()));
+ }
+}
+
+// public slots:
+void
+ControllerBackend::shutdown()
+{
+ m_face.getIoService().stop();
+}
+
+void
+ControllerBackend::addChatroom(QString chatroom)
+{
+ m_chatDialogList.append(chatroom);
+}
+
+void
+ControllerBackend::removeChatroom(QString chatroom)
+{
+ m_chatDialogList.removeAll(chatroom);
+}
+
+void
+ControllerBackend::onUpdateLocalPrefixAction()
+{
+ // Name interestName();
+ Interest interest("/localhop/ndn-autoconf/routable-prefixes");
+ interest.setInterestLifetime(time::milliseconds(1000));
+ interest.setMustBeFresh(true);
+
+ m_face.expressInterest(interest,
+ bind(&ControllerBackend::onLocalPrefix, this, _1, _2),
+ bind(&ControllerBackend::onLocalPrefixTimeout, this, _1));
+}
+
+void
+ControllerBackend::onIdentityChanged(const QString& identity)
+{
+ m_chatDialogList.clear();
+
+ m_identity = Name(identity.toStdString());
+
+ std::cerr << "ControllerBackend::onIdentityChanged: " << m_identity << std::endl;
+
+ m_keyChain.createIdentity(m_identity);
+
+ setInvitationListener();
+
+ emit identityUpdated(identity);
+}
+
+void
+ControllerBackend::onInvitationResponded(const ndn::Name& invitationName, bool accepted)
+{
+ shared_ptr<Data> response = make_shared<Data>();
+ shared_ptr<IdentityCertificate> chatroomCert;
+
+ // generate reply;
+ if (accepted) {
+ Name responseName = invitationName;
+ responseName.append(m_localPrefix.wireEncode());
+
+ response->setName(responseName);
+
+ // We should create a particular certificate for this chatroom,
+ //but let's use default one for now.
+ chatroomCert
+ = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
+
+ response->setContent(chatroomCert->wireEncode());
+ response->setFreshnessPeriod(time::milliseconds(1000));
+ }
+ else {
+ response->setName(invitationName);
+ response->setFreshnessPeriod(time::milliseconds(1000));
+ }
+
+ m_keyChain.signByIdentity(*response, m_identity);
+
+ // Check if we need a wrapper
+ Name invitationRoutingPrefix = getInvitationRoutingPrefix();
+ if (invitationRoutingPrefix.isPrefixOf(m_identity))
+ m_face.put(*response);
+ else {
+ Name wrappedName;
+ wrappedName.append(invitationRoutingPrefix)
+ .append(ROUTING_PREFIX_SEPARATOR, 2)
+ .append(response->getName());
+
+ // _LOG_DEBUG("onInvitationResponded: prepare reply " << wrappedName);
+
+ shared_ptr<Data> wrappedData = make_shared<Data>(wrappedName);
+ wrappedData->setContent(response->wireEncode());
+ wrappedData->setFreshnessPeriod(time::milliseconds(1000));
+
+ m_keyChain.signByIdentity(*wrappedData, m_identity);
+ m_face.put(*wrappedData);
+ }
+
+ Invitation invitation(invitationName);
+ emit startChatroomOnInvitation(invitation, true);
+}
+
+void
+ControllerBackend::onContactIdListReady(const QStringList& list)
+{
+ ContactList contactList;
+
+ m_contactManager.getContactList(contactList);
+ m_validator.cleanTrustAnchor();
+
+ for (ContactList::const_iterator it = contactList.begin(); it != contactList.end(); it++)
+ m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
+
+}
+
+
+} // namespace chronos
+
+#if WAF
+#include "controller-backend.moc"
+// #include "controller-backend.cpp.moc"
+#endif