blob: 382a029b49289bb29828f9e116b335fb0efd4ba3 [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -08003 * Copyright (c) 2013-2017, Regents of the University of California.
Zhenkai Zhue42b4572013-01-22 15:57:54 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Zhenkai Zhue42b4572013-01-22 15:57:54 -08006 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08007 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
Zhenkai Zhue42b4572013-01-22 15:57:54 -080010 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080011 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Zhenkai Zhue42b4572013-01-22 15:57:54 -080014 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080015 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
Zhenkai Zhue42b4572013-01-22 15:57:54 -080019 */
20
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080021#include "content-server.hpp"
Lijing Wang6977ec42016-12-25 14:45:09 -080022#include "core/logging.hpp"
23
24#include <ndn-cxx/util/string-helper.hpp>
25#include <ndn-cxx/security/signing-helpers.hpp>
26
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080027#include <boost/lexical_cast.hpp>
Lijing Wang6977ec42016-12-25 14:45:09 -080028
29namespace ndn {
30namespace chronoshare {
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080031
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -080032_LOG_INIT(ContentServer);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080033
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080034static const int DB_CACHE_LIFETIME = 60;
35
Lijing Wang6977ec42016-12-25 14:45:09 -080036ContentServer::ContentServer(Face& face, ActionLogPtr actionLog,
37 const boost::filesystem::path& rootDir, const Name& userName,
Lijing Wang8e56d082016-12-25 14:45:23 -080038 const std::string& sharedFolderName, const name::Component& appName,
39 KeyChain& keyChain, time::milliseconds freshness)
Lijing Wang6977ec42016-12-25 14:45:09 -080040 : m_face(face)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080041 , m_actionLog(actionLog)
42 , m_dbFolder(rootDir / ".chronoshare")
43 , m_freshness(freshness)
Lijing Wang6977ec42016-12-25 14:45:09 -080044 , m_scheduler(face.getIoService())
45 , m_flushStateDbCacheEvent(m_scheduler)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080046 , m_userName(userName)
47 , m_sharedFolderName(sharedFolderName)
48 , m_appName(appName)
Lijing Wang6977ec42016-12-25 14:45:09 -080049 , m_keyChain(keyChain)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080050{
Lijing Wang6977ec42016-12-25 14:45:09 -080051 m_flushStateDbCacheEvent = m_scheduler.scheduleEvent(time::seconds(DB_CACHE_LIFETIME),
52 bind(&ContentServer::flushStaleDbCache, this));
Zhenkai Zhue42b4572013-01-22 15:57:54 -080053}
54
55ContentServer::~ContentServer()
56{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080057 ScopedLock lock(m_mutex);
Lijing Wang6977ec42016-12-25 14:45:09 -080058 for (FilterIdIt it = m_interestFilterIds.begin(); it != m_interestFilterIds.end(); ++it) {
59 m_face.unsetInterestFilter(it->second);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080060 }
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080061
Lijing Wang6977ec42016-12-25 14:45:09 -080062 m_interestFilterIds.clear();
Zhenkai Zhue42b4572013-01-22 15:57:54 -080063}
64
65void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080066ContentServer::registerPrefix(const Name& forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080067{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080068 // Format for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
Lijing Wang6977ec42016-12-25 14:45:09 -080069 // Format for actions:
70 // /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Zhenkai Zhub74e1e92013-01-25 14:36:18 -080071
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080072 _LOG_DEBUG(">> content server: register " << forwardingHint);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080073
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080074 ScopedLock lock(m_mutex);
Lijing Wang6977ec42016-12-25 14:45:09 -080075 m_interestFilterIds[forwardingHint] =
76 m_face.setInterestFilter(InterestFilter(forwardingHint),
77 bind(&ContentServer::filterAndServe, this, _1, _2),
78 RegisterPrefixSuccessCallback(), RegisterPrefixFailureCallback());
Zhenkai Zhue42b4572013-01-22 15:57:54 -080079}
80
81void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080082ContentServer::deregisterPrefix(const Name& forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080083{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080084 _LOG_DEBUG("<< content server: deregister " << forwardingHint);
Lijing Wang6977ec42016-12-25 14:45:09 -080085 m_face.unsetInterestFilter(m_interestFilterIds[forwardingHint]);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080086
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080087 ScopedLock lock(m_mutex);
Lijing Wang6977ec42016-12-25 14:45:09 -080088 m_interestFilterIds.erase(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080089}
90
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080091void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080092ContentServer::filterAndServeImpl(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080093{
94 // interest for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
Lijing Wang6977ec42016-12-25 14:45:09 -080095 // interest for actions:
96 // /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080097
Alexander Afanasyev4d086752013-02-07 13:06:04 -080098 // name for files: /<device_name>/<appname>/file/<hash>/<segment>
99 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
100
Lijing Wang8e56d082016-12-25 14:45:23 -0800101 if (name.size() >= 4 && name.get(-4) == m_appName) {
Lijing Wang6977ec42016-12-25 14:45:09 -0800102 std::string type = name.get(-3).toUri();
103 if (type == "file") {
104 serve_File(forwardingHint, name, interest);
105 }
106 else if (type == "action") {
107 std::string folder = name.get(-2).toUri();
108 if (folder == m_sharedFolderName) {
109 serve_Action(forwardingHint, name, interest);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800110 }
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800111 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800112 }
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800113}
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800114
115void
Lijing Wang6977ec42016-12-25 14:45:09 -0800116ContentServer::filterAndServe(const InterestFilter& interestFilter, const Interest& interestTrue)
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800117{
Lijing Wang6977ec42016-12-25 14:45:09 -0800118 Name forwardingHint = Name(interestFilter);
119 Name interest = interestTrue.getName();
120 _LOG_DEBUG("I'm serving ForwardingHint: " << forwardingHint << " Interest: " << interest);
121 if (forwardingHint.size() > 0 && m_userName.size() >= forwardingHint.size() &&
122 m_userName.getSubName(0, forwardingHint.size()) == forwardingHint) {
123 _LOG_DEBUG("Triggered without Forwardinghint!");
124 filterAndServeImpl(Name("/"), interest, interest); // try without forwarding hints
125 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800126
Lijing Wang6977ec42016-12-25 14:45:09 -0800127 _LOG_DEBUG("Triggered with Forwardinghint~!");
128 filterAndServeImpl(forwardingHint, interest.getSubName(forwardingHint.size()),
129 interest); // always try with hint... :( have to
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800130}
131
132void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800133ContentServer::serve_Action(const Name& forwardingHint, const Name& name, const Name& interest)
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800134{
Lijing Wang6977ec42016-12-25 14:45:09 -0800135 _LOG_DEBUG(
136 ">> content server serving ACTION, hint: " << forwardingHint << ", interest: " << interest);
137 m_scheduler.scheduleEvent(time::seconds(0),
138 bind(&ContentServer::serve_Action_Execute, this, forwardingHint, name,
139 interest));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800140 // need to unlock ccnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800141}
142
143void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800144ContentServer::serve_File(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800145{
Lijing Wang6977ec42016-12-25 14:45:09 -0800146 _LOG_DEBUG(">> content server serving FILE, hint: " << forwardingHint << ", interest: " << interest);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800147
Lijing Wang6977ec42016-12-25 14:45:09 -0800148 m_scheduler.scheduleEvent(time::seconds(0),
149 bind(&ContentServer::serve_File_Execute, this, forwardingHint, name,
150 interest));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800151 // need to unlock ccnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800152}
153
154void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800155ContentServer::serve_File_Execute(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800156{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800157 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800158 // interest: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800159 // name: /<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800160
Lijing Wang6977ec42016-12-25 14:45:09 -0800161 int64_t segment = name.get(-1).toNumber();
162 Name deviceName = name.getSubName(0, name.size() - 4);
163 Buffer hash(name.get(-2).value(), name.get(-2).value_size());
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800164
Lijing Wang6977ec42016-12-25 14:45:09 -0800165 _LOG_DEBUG(" server FILE for device: " << deviceName << ", file_hash: " << toHex(hash) << " segment: "
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800166 << segment);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800167
Lijing Wang6977ec42016-12-25 14:45:09 -0800168 std::string hashStr = toHex(hash);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800169
Lijing Wang6977ec42016-12-25 14:45:09 -0800170 shared_ptr<ObjectDb> db;
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800171
172 ScopedLock(m_dbCacheMutex);
173 {
174 DbCache::iterator it = m_dbCache.find(hash);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800175 if (it != m_dbCache.end()) {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800176 db = it->second;
177 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800178 else {
Lijing Wang6977ec42016-12-25 14:45:09 -0800179 if (ObjectDb::doesExist(m_dbFolder, deviceName,
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800180 hashStr)) // this is kind of overkill, as it counts available segments
181 {
Lijing Wang6977ec42016-12-25 14:45:09 -0800182 db = make_shared<ObjectDb>(m_dbFolder, hashStr);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800183 m_dbCache.insert(make_pair(hash, db));
184 }
185 else {
Lijing Wang6977ec42016-12-25 14:45:09 -0800186 _LOG_ERROR(
187 "ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << toHex(hash));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800188 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800189 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800190 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800191
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800192 if (db) {
Lijing Wang6977ec42016-12-25 14:45:09 -0800193 shared_ptr<Data> data = db->fetchSegment(deviceName, segment);
194 if (data) {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800195 if (forwardingHint.size() == 0) {
Lijing Wang6977ec42016-12-25 14:45:09 -0800196 m_face.put(*data);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800197 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800198 else {
Lijing Wang6977ec42016-12-25 14:45:09 -0800199 shared_ptr<Data> outerData = make_shared<Data>();
200
201 outerData->setContent(data->wireEncode());
Lijing Wang8e56d082016-12-25 14:45:23 -0800202 outerData->setFreshnessPeriod(m_freshness);
Lijing Wang6977ec42016-12-25 14:45:09 -0800203 outerData->setName(interest);
204
205 m_keyChain.sign(*outerData, signingWithSha256());;
206 m_face.put(*outerData);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800207 }
Lijing Wang6977ec42016-12-25 14:45:09 -0800208 _LOG_DEBUG("Send File Data Done!");
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800209 }
210 else {
211 _LOG_ERROR("ObjectDd exists, but no segment " << segment << " for device: " << deviceName
212 << ", file_hash: "
Lijing Wang6977ec42016-12-25 14:45:09 -0800213 << toHex(hash));
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800214 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800215 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800216}
217
218void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800219ContentServer::serve_Action_Execute(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800220{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800221 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800222 // interest: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800223 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800224
Lijing Wang6977ec42016-12-25 14:45:09 -0800225 int64_t seqno = name.get(-1).toNumber();
226 Name deviceName = name.getSubName(0, name.size() - 4);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800227
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800228 _LOG_DEBUG(" server ACTION for device: " << deviceName << " and seqno: " << seqno);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800229
Lijing Wang6977ec42016-12-25 14:45:09 -0800230 shared_ptr<Data> data = m_actionLog->LookupActionData(deviceName, seqno);
231 if (data) {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800232 if (forwardingHint.size() == 0) {
Lijing Wang6977ec42016-12-25 14:45:09 -0800233 m_keyChain.sign(*data);
234 m_face.put(*data);
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800235 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800236 else {
Lijing Wang6977ec42016-12-25 14:45:09 -0800237 data->setName(interest);
Lijing Wang8e56d082016-12-25 14:45:23 -0800238 data->setFreshnessPeriod(m_freshness);
Lijing Wang6977ec42016-12-25 14:45:09 -0800239 m_keyChain.sign(*data);
240 m_face.put(*data);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800241 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800242 }
243 else {
244 _LOG_ERROR("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
245 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800246}
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800247
248void
249ContentServer::flushStaleDbCache()
250{
251 ScopedLock(m_dbCacheMutex);
252 DbCache::iterator it = m_dbCache.begin();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800253 while (it != m_dbCache.end()) {
Lijing Wang6977ec42016-12-25 14:45:09 -0800254 shared_ptr<ObjectDb> db = it->second;
255 if (time::steady_clock::now() >= time::seconds(DB_CACHE_LIFETIME) + db->getLastUsed()) {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800256 m_dbCache.erase(it++);
257 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800258 else {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800259 ++it;
260 }
261 }
Lijing Wang6977ec42016-12-25 14:45:09 -0800262
263 m_flushStateDbCacheEvent = m_scheduler.scheduleEvent(time::seconds(DB_CACHE_LIFETIME),
264 bind(&ContentServer::flushStaleDbCache, this));
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800265}
Lijing Wang6977ec42016-12-25 14:45:09 -0800266
267} // namespace chronoshare
268} // namespace ndn