blob: 4a1ee9487e08984acbd37558bcda0a04e6f3acde [file] [log] [blame]
Zhenkai Zhue42b4572013-01-22 15:57:54 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
19 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
20 */
21
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080022#include "content-server.hpp"
23#include "logging.hpp"
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080024#include <boost/make_shared.hpp>
25#include <utility>
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080026#include "task.hpp"
27#include "periodic-task.hpp"
28#include "simple-interval-generator.hpp"
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080029#include <boost/lexical_cast.hpp>
30
31INIT_LOGGER ("ContentServer");
Zhenkai Zhue42b4572013-01-22 15:57:54 -080032
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070033using namespace Ndnx;
Zhenkai Zhue42b4572013-01-22 15:57:54 -080034using namespace std;
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080035using namespace boost;
Zhenkai Zhue42b4572013-01-22 15:57:54 -080036
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080037static const int DB_CACHE_LIFETIME = 60;
38
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070039ContentServer::ContentServer(NdnxWrapperPtr ndnx, ActionLogPtr actionLog,
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080040 const boost::filesystem::path &rootDir,
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070041 const Ndnx::Name &userName, const std::string &sharedFolderName,
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080042 const std::string &appName,
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080043 int freshness)
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070044 : m_ndnx(ndnx)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080045 , m_actionLog(actionLog)
46 , m_dbFolder(rootDir / ".chronoshare")
47 , m_freshness(freshness)
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080048 , m_scheduler (new Scheduler())
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080049 , m_userName (userName)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080050 , m_sharedFolderName (sharedFolderName)
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080051 , m_appName (appName)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080052{
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080053 m_scheduler->start ();
54 TaskPtr flushStaleDbCacheTask = boost::make_shared<PeriodicTask>(boost::bind(&ContentServer::flushStaleDbCache, this), "flush-state-db-cache", m_scheduler, boost::make_shared<SimpleIntervalGenerator>(DB_CACHE_LIFETIME));
55 m_scheduler->addTask(flushStaleDbCacheTask);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080056}
57
58ContentServer::~ContentServer()
59{
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080060 m_scheduler->shutdown ();
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080061
62 ScopedLock lock (m_mutex);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080063 for (PrefixIt forwardingHint = m_prefixes.begin(); forwardingHint != m_prefixes.end(); ++forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080064 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070065 m_ndnx->clearInterestFilter (*forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080066 }
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080067
68 m_prefixes.clear ();
Zhenkai Zhue42b4572013-01-22 15:57:54 -080069}
70
71void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080072ContentServer::registerPrefix(const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080073{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080074 // Format for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
75 // Format for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Zhenkai Zhub74e1e92013-01-25 14:36:18 -080076
Alexander Afanasyev4d086752013-02-07 13:06:04 -080077 _LOG_DEBUG (">> content server: register " << forwardingHint);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080078
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070079 m_ndnx->setInterestFilter (forwardingHint, bind(&ContentServer::filterAndServe, this, forwardingHint, _1));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080080
81 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080082 m_prefixes.insert(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080083}
84
85void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080086ContentServer::deregisterPrefix (const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080087{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080088 _LOG_DEBUG ("<< content server: deregister " << forwardingHint);
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070089 m_ndnx->clearInterestFilter(forwardingHint);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080090
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080091 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080092 m_prefixes.erase (forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080093}
94
Zhenkai Zhuc3a27872013-01-25 19:21:25 -080095
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -080096void
97ContentServer::filterAndServeImpl (const Name &forwardingHint, const Name &name, const Name &interest)
98{
99 // interest for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
100 // interest for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
101
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800102 // name for files: /<device_name>/<appname>/file/<hash>/<segment>
103 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
104
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800105 try
106 {
107 if (name.size() >= 4 && name.getCompFromBackAsString (3) == m_appName)
108 {
109 string type = name.getCompFromBackAsString (2);
110 if (type == "file")
111 {
112 serve_File (forwardingHint, name, interest);
113 }
114 else if (type == "action")
115 {
Zhenkai Zhu555c4f12013-02-13 16:57:36 -0800116 string folder = name.getCompFromBackAsString (1);
117 if (folder == m_sharedFolderName)
118 {
119 serve_Action (forwardingHint, name, interest);
120 }
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800121 }
122 }
123 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700124 catch (Ndnx::NameException &ne)
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800125 {
126 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700127 _LOG_ERROR(boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800128 }
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800129}
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800130
131void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800132ContentServer::filterAndServe (Name forwardingHint, const Name &interest)
133{
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800134 try
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800135 {
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800136 if (forwardingHint.size () > 0 &&
137 m_userName.size () >= forwardingHint.size () &&
138 m_userName.getPartialName (0, forwardingHint.size ()) == forwardingHint)
139 {
140 filterAndServeImpl (Name ("/"), interest, interest); // try without forwarding hints
141 }
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800142
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800143 filterAndServeImpl (forwardingHint, interest.getPartialName (forwardingHint.size()), interest); // always try with hint... :( have to
144 }
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700145 catch (Ndnx::NameException &ne)
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800146 {
147 // ignore any unexpected interests and errors
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700148 _LOG_ERROR(boost::get_error_info<Ndnx::error_info_str>(ne));
Alexander Afanasyevc87e8012013-02-12 14:24:24 -0800149 }
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800150}
151
152void
153ContentServer::serve_Action (const Name &forwardingHint, const Name &name, const Name &interest)
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800154{
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800155 _LOG_DEBUG (">> content server serving ACTION, hint: " << forwardingHint << ", interest: " << interest);
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800156 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 -0700157 // need to unlock ndnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800158}
159
160void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800161ContentServer::serve_File (const Name &forwardingHint, const Name &name, const Name &interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800162{
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800163 _LOG_DEBUG (">> content server serving FILE, hint: " << forwardingHint << ", interest: " << interest);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800164
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800165 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 -0700166 // need to unlock ndnx mutex... or at least don't lock it
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800167}
168
169void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800170ContentServer::serve_File_Execute (const Name &forwardingHint, const Name &name, const Name &interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800171{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800172 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800173 // interest: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800174 // name: /<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800175
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800176 int64_t segment = name.getCompFromBackAsInt (0);
177 Name deviceName = name.getPartialName (0, name.size () - 4);
178 Hash hash (head(name.getCompFromBack (1)), name.getCompFromBack (1).size());
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800179
180 _LOG_DEBUG (" server FILE for device: " << deviceName << ", file_hash: " << hash.shortHash () << " segment: " << segment);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800181
182 string hashStr = lexical_cast<string> (hash);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800183
184 ObjectDbPtr db;
185
186 ScopedLock(m_dbCacheMutex);
187 {
188 DbCache::iterator it = m_dbCache.find(hash);
189 if (it != m_dbCache.end())
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800190 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800191 db = it->second;
192 }
193 else
194 {
195 if (ObjectDb::DoesExist (m_dbFolder, deviceName, hashStr)) // this is kind of overkill, as it counts available segments
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800196 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800197 db = boost::make_shared<ObjectDb>(m_dbFolder, hashStr);
198 m_dbCache.insert(make_pair(hash, db));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800199 }
200 else
201 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800202 _LOG_ERROR ("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << hash.shortHash ());
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800203 }
204 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800205 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800206
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800207 if (db)
208 {
209 BytesPtr co = db->fetchSegment (deviceName, segment);
210 if (co)
211 {
212 if (forwardingHint.size () == 0)
213 {
214 _LOG_DEBUG (ParsedContentObject (*co).name ());
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700215 m_ndnx->putToNdnd (*co);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800216 }
217 else
218 {
219 if (m_freshness > 0)
220 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700221 m_ndnx->publishData(interest, *co, m_freshness);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800222 }
223 else
224 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700225 m_ndnx->publishData(interest, *co);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800226 }
227 }
228
229 }
230 else
231 {
232 _LOG_ERROR ("ObjectDd exists, but no segment " << segment << " for device: " << deviceName << ", file_hash: " << hash.shortHash ());
233 }
234
235 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800236}
237
238void
Alexander Afanasyev3cca13f2013-02-07 16:06:46 -0800239ContentServer::serve_Action_Execute (const Name &forwardingHint, const Name &name, const Name &interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800240{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800241 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800242 // interest: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800243 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800244
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800245 int64_t seqno = name.getCompFromBackAsInt (0);
246 Name deviceName = name.getPartialName (0, name.size () - 4);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800247
248 _LOG_DEBUG (" server ACTION for device: " << deviceName << " and seqno: " << seqno);
249
250 PcoPtr pco = m_actionLog->LookupActionPco (deviceName, seqno);
251 if (pco)
252 {
253 if (forwardingHint.size () == 0)
254 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700255 m_ndnx->putToNdnd (pco->buf ());
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800256 }
257 else
258 {
259 const Bytes &content = pco->buf ();
260 if (m_freshness > 0)
Zhenkai Zhubc738572013-01-23 22:46:11 -0800261 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700262 m_ndnx->publishData(interest, content, m_freshness);
Zhenkai Zhubc738572013-01-23 22:46:11 -0800263 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800264 else
Zhenkai Zhubc738572013-01-23 22:46:11 -0800265 {
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700266 m_ndnx->publishData(interest, content);
Zhenkai Zhubc738572013-01-23 22:46:11 -0800267 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800268 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800269 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800270 else
271 {
272 _LOG_ERROR ("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
273 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800274}
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800275
276void
277ContentServer::flushStaleDbCache()
278{
279 ScopedLock(m_dbCacheMutex);
280 DbCache::iterator it = m_dbCache.begin();
281 while (it != m_dbCache.end())
282 {
283 ObjectDbPtr db = it->second;
284 if (db->secondsSinceLastUse() >= DB_CACHE_LIFETIME)
285 {
286 m_dbCache.erase(it++);
287 }
288 else
289 {
290 ++it;
291 }
292 }
293}