blob: b795afef4a4a100e4ee23d53418d50ea3004f70f [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"
22#include "logging.hpp"
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080023#include "periodic-task.hpp"
24#include "simple-interval-generator.hpp"
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080025#include "task.hpp"
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080026#include <boost/lexical_cast.hpp>
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080027#include <boost/make_shared.hpp>
28#include <utility>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080029
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -080030_LOG_INIT(ContentServer);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080031
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070032using namespace Ndnx;
Zhenkai Zhue42b4572013-01-22 15:57:54 -080033using namespace std;
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080034using namespace boost;
Zhenkai Zhue42b4572013-01-22 15:57:54 -080035
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080036static const int DB_CACHE_LIFETIME = 60;
37
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080038ContentServer::ContentServer(CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
39 const boost::filesystem::path& rootDir, const Ccnx::Name& userName,
40 const std::string& sharedFolderName, const std::string& appName,
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080041 int freshness)
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070042 : m_ndnx(ndnx)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080043 , m_actionLog(actionLog)
44 , m_dbFolder(rootDir / ".chronoshare")
45 , m_freshness(freshness)
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080046 , m_scheduler(new Scheduler())
47 , m_userName(userName)
48 , m_sharedFolderName(sharedFolderName)
49 , m_appName(appName)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080050{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080051 m_scheduler->start();
52 TaskPtr flushStaleDbCacheTask =
53 boost::make_shared<PeriodicTask>(boost::bind(&ContentServer::flushStaleDbCache, this),
54 "flush-state-db-cache", m_scheduler,
55 boost::make_shared<SimpleIntervalGenerator>(DB_CACHE_LIFETIME));
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080056 m_scheduler->addTask(flushStaleDbCacheTask);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080057}
58
59ContentServer::~ContentServer()
60{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080061 m_scheduler->shutdown();
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080062
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080063 ScopedLock lock(m_mutex);
64 for (PrefixIt forwardingHint = m_prefixes.begin(); forwardingHint != m_prefixes.end();
65 ++forwardingHint) {
66 m_ccnx->clearInterestFilter(*forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080067 }
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080068
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080069 m_prefixes.clear();
Zhenkai Zhue42b4572013-01-22 15:57:54 -080070}
71
72void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080073ContentServer::registerPrefix(const Name& forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080074{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080075 // Format for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
76 // Format for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Zhenkai Zhub74e1e92013-01-25 14:36:18 -080077
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080078 _LOG_DEBUG(">> content server: register " << forwardingHint);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080079
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080080 m_ccnx->setInterestFilter(forwardingHint,
81 bind(&ContentServer::filterAndServe, this, forwardingHint, _1));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080082
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080083 ScopedLock lock(m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080084 m_prefixes.insert(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080085}
86
87void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080088ContentServer::deregisterPrefix(const Name& forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080089{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080090 _LOG_DEBUG("<< content server: deregister " << forwardingHint);
91 m_ccnx->clearInterestFilter(forwardingHint);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080092
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080093 ScopedLock lock(m_mutex);
94 m_prefixes.erase(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080095}
96
Zhenkai Zhuc3a27872013-01-25 19:21:25 -080097
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080098void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080099ContentServer::filterAndServeImpl(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800100{
101 // interest for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
102 // interest for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
103
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800104 // name for files: /<device_name>/<appname>/file/<hash>/<segment>
105 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
106
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800107 try {
108 if (name.size() >= 4 && name.getCompFromBackAsString(3) == m_appName) {
109 string type = name.getCompFromBackAsString(2);
110 if (type == "file") {
111 serve_File(forwardingHint, name, interest);
112 }
113 else if (type == "action") {
114 string folder = name.getCompFromBackAsString(1);
115 if (folder == m_sharedFolderName) {
116 serve_Action(forwardingHint, name, interest);
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800117 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800118 }
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800119 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800120 }
121 catch (Ccnx::NameException& ne) {
122 // ignore any unexpected interests and errors
123 _LOG_ERROR(boost::get_error_info<Ccnx::error_info_str>(ne));
124 }
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800125}
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800126
127void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800128ContentServer::filterAndServe(Name forwardingHint, const Name& interest)
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800129{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800130 try {
131 if (forwardingHint.size() > 0 && m_userName.size() >= forwardingHint.size() &&
132 m_userName.getPartialName(0, forwardingHint.size()) == forwardingHint) {
133 filterAndServeImpl(Name("/"), interest, interest); // try without forwarding hints
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800134 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800135
136 filterAndServeImpl(forwardingHint, interest.getPartialName(forwardingHint.size()),
137 interest); // always try with hint... :( have to
138 }
139 catch (Ccnx::NameException& ne) {
140 // ignore any unexpected interests and errors
141 _LOG_ERROR(boost::get_error_info<Ccnx::error_info_str>(ne));
142 }
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800143}
144
145void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800146ContentServer::serve_Action(const Name& forwardingHint, const Name& name, const Name& interest)
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800147{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800148 _LOG_DEBUG(">> content server serving ACTION, hint: " << forwardingHint
149 << ", interest: " << interest);
150 m_scheduler->scheduleOneTimeTask(m_scheduler, 0, bind(&ContentServer::serve_Action_Execute, this,
151 forwardingHint, name, interest),
152 boost::lexical_cast<string>(name));
153 // need to unlock ccnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800154}
155
156void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800157ContentServer::serve_File(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800158{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800159 _LOG_DEBUG(">> content server serving FILE, hint: " << forwardingHint
160 << ", interest: " << interest);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800161
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800162 m_scheduler->scheduleOneTimeTask(m_scheduler, 0, bind(&ContentServer::serve_File_Execute, this,
163 forwardingHint, name, interest),
164 boost::lexical_cast<string>(name));
165 // need to unlock ccnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800166}
167
168void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800169ContentServer::serve_File_Execute(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800170{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800171 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800172 // interest: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800173 // name: /<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800174
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800175 int64_t segment = name.getCompFromBackAsInt(0);
176 Name deviceName = name.getPartialName(0, name.size() - 4);
177 Hash hash(head(name.getCompFromBack(1)), name.getCompFromBack(1).size());
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800178
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800179 _LOG_DEBUG(" server FILE for device: " << deviceName << ", file_hash: " << hash.shortHash()
180 << " segment: "
181 << segment);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800182
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800183 string hashStr = lexical_cast<string>(hash);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800184
185 ObjectDbPtr db;
186
187 ScopedLock(m_dbCacheMutex);
188 {
189 DbCache::iterator it = m_dbCache.find(hash);
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800190 if (it != m_dbCache.end()) {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800191 db = it->second;
192 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800193 else {
194 if (ObjectDb::DoesExist(m_dbFolder, deviceName,
195 hashStr)) // this is kind of overkill, as it counts available segments
196 {
197 db = boost::make_shared<ObjectDb>(m_dbFolder, hashStr);
198 m_dbCache.insert(make_pair(hash, db));
199 }
200 else {
201 _LOG_ERROR("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: "
202 << hash.shortHash());
203 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800204 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800205 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800206
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800207 if (db) {
208 BytesPtr co = db->fetchSegment(deviceName, segment);
209 if (co) {
210 if (forwardingHint.size() == 0) {
211 _LOG_DEBUG(ParsedContentObject(*co).name());
212 m_ccnx->putToCcnd(*co);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800213 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800214 else {
215 if (m_freshness > 0) {
216 m_ccnx->publishData(interest, *co, m_freshness);
217 }
218 else {
219 m_ccnx->publishData(interest, *co);
220 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800221 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800222 }
223 else {
224 _LOG_ERROR("ObjectDd exists, but no segment " << segment << " for device: " << deviceName
225 << ", file_hash: "
226 << hash.shortHash());
227 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800228 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800229}
230
231void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800232ContentServer::serve_Action_Execute(const Name& forwardingHint, const Name& name, const Name& interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800233{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800234 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800235 // interest: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800236 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800237
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800238 int64_t seqno = name.getCompFromBackAsInt(0);
239 Name deviceName = name.getPartialName(0, name.size() - 4);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800240
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800241 _LOG_DEBUG(" server ACTION for device: " << deviceName << " and seqno: " << seqno);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800242
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800243 PcoPtr pco = m_actionLog->LookupActionPco(deviceName, seqno);
244 if (pco) {
245 if (forwardingHint.size() == 0) {
246 m_ccnx->putToCcnd(pco->buf());
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800247 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800248 else {
249 const Bytes& content = pco->buf();
250 if (m_freshness > 0) {
251 m_ccnx->publishData(interest, content, m_freshness);
252 }
253 else {
254 m_ccnx->publishData(interest, content);
255 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800256 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800257 }
258 else {
259 _LOG_ERROR("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
260 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800261}
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800262
263void
264ContentServer::flushStaleDbCache()
265{
266 ScopedLock(m_dbCacheMutex);
267 DbCache::iterator it = m_dbCache.begin();
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800268 while (it != m_dbCache.end()) {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800269 ObjectDbPtr db = it->second;
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800270 if (db->secondsSinceLastUse() >= DB_CACHE_LIFETIME) {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800271 m_dbCache.erase(it++);
272 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800273 else {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800274 ++it;
275 }
276 }
277}