blob: 26c45f857c8d15117ac91b0bfddd27386cf9f45d [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016, 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"
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080023#include <boost/make_shared.hpp>
24#include <utility>
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080025#include "task.hpp"
26#include "periodic-task.hpp"
27#include "simple-interval-generator.hpp"
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080028#include <boost/lexical_cast.hpp>
29
30INIT_LOGGER ("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 Afanasyev1dd37ed2013-08-14 18:08:09 -070038ContentServer::ContentServer(NdnxWrapperPtr ndnx, ActionLogPtr actionLog,
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080039 const boost::filesystem::path &rootDir,
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070040 const Ndnx::Name &userName, const std::string &sharedFolderName,
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080041 const std::string &appName,
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080042 int freshness)
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070043 : m_ndnx(ndnx)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080044 , m_actionLog(actionLog)
45 , m_dbFolder(rootDir / ".chronoshare")
46 , m_freshness(freshness)
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080047 , m_scheduler (new Scheduler())
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080048 , m_userName (userName)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080049 , m_sharedFolderName (sharedFolderName)
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080050 , m_appName (appName)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080051{
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080052 m_scheduler->start ();
53 TaskPtr flushStaleDbCacheTask = boost::make_shared<PeriodicTask>(boost::bind(&ContentServer::flushStaleDbCache, this), "flush-state-db-cache", m_scheduler, boost::make_shared<SimpleIntervalGenerator>(DB_CACHE_LIFETIME));
54 m_scheduler->addTask(flushStaleDbCacheTask);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080055}
56
57ContentServer::~ContentServer()
58{
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080059 m_scheduler->shutdown ();
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080060
61 ScopedLock lock (m_mutex);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080062 for (PrefixIt forwardingHint = m_prefixes.begin(); forwardingHint != m_prefixes.end(); ++forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080063 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070064 m_ndnx->clearInterestFilter (*forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080065 }
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080066
67 m_prefixes.clear ();
Zhenkai Zhue42b4572013-01-22 15:57:54 -080068}
69
70void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080071ContentServer::registerPrefix(const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080072{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080073 // Format for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
74 // Format for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Zhenkai Zhub74e1e92013-01-25 14:36:18 -080075
Alexander Afanasyev4d086752013-02-07 13:06:04 -080076 _LOG_DEBUG (">> content server: register " << forwardingHint);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080077
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070078 m_ndnx->setInterestFilter (forwardingHint, bind(&ContentServer::filterAndServe, this, forwardingHint, _1));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080079
80 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080081 m_prefixes.insert(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080082}
83
84void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080085ContentServer::deregisterPrefix (const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080086{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080087 _LOG_DEBUG ("<< content server: deregister " << forwardingHint);
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070088 m_ndnx->clearInterestFilter(forwardingHint);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080089
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080090 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080091 m_prefixes.erase (forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080092}
93
Zhenkai Zhuc3a27872013-01-25 19:21:25 -080094
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080095void
96ContentServer::filterAndServeImpl (const Name &forwardingHint, const Name &name, const Name &interest)
97{
98 // interest for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
99 // interest for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
100
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800101 // name for files: /<device_name>/<appname>/file/<hash>/<segment>
102 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
103
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800104 try
105 {
106 if (name.size() >= 4 && name.getCompFromBackAsString (3) == m_appName)
107 {
108 string type = name.getCompFromBackAsString (2);
109 if (type == "file")
110 {
111 serve_File (forwardingHint, name, interest);
112 }
113 else if (type == "action")
114 {
Zhenkai Zhu555c4f12013-02-13 16:57:36 -0800115 string folder = name.getCompFromBackAsString (1);
116 if (folder == m_sharedFolderName)
117 {
118 serve_Action (forwardingHint, name, interest);
119 }
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800120 }
121 }
122 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700123 catch (Ndnx::NameException &ne)
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800124 {
125 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700126 _LOG_ERROR(boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800127 }
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800128}
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800129
130void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800131ContentServer::filterAndServe (Name forwardingHint, const Name &interest)
132{
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800133 try
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800134 {
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800135 if (forwardingHint.size () > 0 &&
136 m_userName.size () >= forwardingHint.size () &&
137 m_userName.getPartialName (0, forwardingHint.size ()) == forwardingHint)
138 {
139 filterAndServeImpl (Name ("/"), interest, interest); // try without forwarding hints
140 }
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800141
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800142 filterAndServeImpl (forwardingHint, interest.getPartialName (forwardingHint.size()), interest); // always try with hint... :( have to
143 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700144 catch (Ndnx::NameException &ne)
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800145 {
146 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700147 _LOG_ERROR(boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800148 }
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800149}
150
151void
152ContentServer::serve_Action (const Name &forwardingHint, const Name &name, const Name &interest)
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800153{
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800154 _LOG_DEBUG (">> content server serving ACTION, hint: " << forwardingHint << ", interest: " << interest);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800155 m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_Action_Execute, this, forwardingHint, name, interest), boost::lexical_cast<string>(name));
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700156 // need to unlock ndnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800157}
158
159void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800160ContentServer::serve_File (const Name &forwardingHint, const Name &name, const Name &interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800161{
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800162 _LOG_DEBUG (">> content server serving FILE, hint: " << forwardingHint << ", interest: " << interest);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800163
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800164 m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_File_Execute, this, forwardingHint, name, interest), boost::lexical_cast<string>(name));
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700165 // need to unlock ndnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800166}
167
168void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -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 Afanasyev4d086752013-02-07 13:06:04 -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
179 _LOG_DEBUG (" server FILE for device: " << deviceName << ", file_hash: " << hash.shortHash () << " segment: " << segment);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800180
181 string hashStr = lexical_cast<string> (hash);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800182
183 ObjectDbPtr db;
184
185 ScopedLock(m_dbCacheMutex);
186 {
187 DbCache::iterator it = m_dbCache.find(hash);
188 if (it != m_dbCache.end())
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800189 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800190 db = it->second;
191 }
192 else
193 {
194 if (ObjectDb::DoesExist (m_dbFolder, deviceName, hashStr)) // this is kind of overkill, as it counts available segments
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800195 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800196 db = boost::make_shared<ObjectDb>(m_dbFolder, hashStr);
197 m_dbCache.insert(make_pair(hash, db));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800198 }
199 else
200 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800201 _LOG_ERROR ("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << hash.shortHash ());
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800202 }
203 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800204 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800205
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800206 if (db)
207 {
208 BytesPtr co = db->fetchSegment (deviceName, segment);
209 if (co)
210 {
211 if (forwardingHint.size () == 0)
212 {
213 _LOG_DEBUG (ParsedContentObject (*co).name ());
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700214 m_ndnx->putToNdnd (*co);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800215 }
216 else
217 {
218 if (m_freshness > 0)
219 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700220 m_ndnx->publishData(interest, *co, m_freshness);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800221 }
222 else
223 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700224 m_ndnx->publishData(interest, *co);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800225 }
226 }
227
228 }
229 else
230 {
231 _LOG_ERROR ("ObjectDd exists, but no segment " << segment << " for device: " << deviceName << ", file_hash: " << hash.shortHash ());
232 }
233
234 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800235}
236
237void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800238ContentServer::serve_Action_Execute (const Name &forwardingHint, const Name &name, const Name &interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800239{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800240 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800241 // interest: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800242 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800243
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800244 int64_t seqno = name.getCompFromBackAsInt (0);
245 Name deviceName = name.getPartialName (0, name.size () - 4);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800246
247 _LOG_DEBUG (" server ACTION for device: " << deviceName << " and seqno: " << seqno);
248
249 PcoPtr pco = m_actionLog->LookupActionPco (deviceName, seqno);
250 if (pco)
251 {
252 if (forwardingHint.size () == 0)
253 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700254 m_ndnx->putToNdnd (pco->buf ());
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800255 }
256 else
257 {
258 const Bytes &content = pco->buf ();
259 if (m_freshness > 0)
Zhenkai Zhubc738572013-01-23 22:46:11 -0800260 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700261 m_ndnx->publishData(interest, content, m_freshness);
Zhenkai Zhubc738572013-01-23 22:46:11 -0800262 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800263 else
Zhenkai Zhubc738572013-01-23 22:46:11 -0800264 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700265 m_ndnx->publishData(interest, content);
Zhenkai Zhubc738572013-01-23 22:46:11 -0800266 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800267 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800268 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800269 else
270 {
271 _LOG_ERROR ("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
272 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800273}
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800274
275void
276ContentServer::flushStaleDbCache()
277{
278 ScopedLock(m_dbCacheMutex);
279 DbCache::iterator it = m_dbCache.begin();
280 while (it != m_dbCache.end())
281 {
282 ObjectDbPtr db = it->second;
283 if (db->secondsSinceLastUse() >= DB_CACHE_LIFETIME)
284 {
285 m_dbCache.erase(it++);
286 }
287 else
288 {
289 ++it;
290 }
291 }
292}