blob: 637b9af458cc9fc2ac11e9ecb32638f7e6c51504 [file] [log] [blame]
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -08001#include "ccnx-wrapper.h"
Zhenkai Zhu43eb2732012-12-28 00:48:26 -08002extern "C" {
3#include <ccn/fetch.h>
4}
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -08005#include <poll.h>
6#include <boost/throw_exception.hpp>
7#include <boost/date_time/posix_time/posix_time.hpp>
8#include <boost/random.hpp>
9#include <sstream>
10
11typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str;
12typedef boost::error_info<struct tag_errmsg, int> errmsg_info_int;
13
14using namespace std;
15using namespace boost;
16
17namespace Ccnx {
18
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080019CcnxWrapper::CcnxWrapper()
20 : m_handle (0)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080021 , m_running (true)
22 , m_connected (false)
23{
24 connectCcnd();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080025 m_thread = thread (&CcnxWrapper::ccnLoop, this);
26}
27
28void
29CcnxWrapper::connectCcnd()
30{
Zhenkai Zhu3b82d432013-01-03 22:48:40 -080031 //if (m_handle != 0) {
32 //ccn_disconnect (m_handle);
33 //ccn_destroy (&m_handle);
34 //}
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -080035
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080036 m_handle = ccn_create ();
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -080037 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080038 if (ccn_connect(m_handle, NULL) < 0)
39 {
40 BOOST_THROW_EXCEPTION (CcnxOperationException() << errmsg_info_str("connection to ccnd failed"));
41 }
42 m_connected = true;
43
Zhenkai Zhu3b82d432013-01-03 22:48:40 -080044 //if (!m_registeredInterests.empty())
45 //{
46 // for (map<Name, InterestCallback>::const_iterator it = m_registeredInterests.begin(); it != m_registeredInterests.end(); ++it)
47 //{
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080048 // clearInterestFilter(it->first);
Zhenkai Zhu3b82d432013-01-03 22:48:40 -080049 // setInterestFilter(it->first, it->second);
50 //}
51 //}
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080052}
53
54CcnxWrapper::~CcnxWrapper()
55{
56 {
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -080057 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080058 m_running = false;
59 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -080060
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080061 m_thread.join ();
62 ccn_disconnect (m_handle);
Zhenkai Zhue29616f2013-01-14 15:40:57 -080063 //ccn_destroy (&m_handle);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080064}
65
66void
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080067CcnxWrapper::ccnLoop ()
68{
69 static boost::mt19937 randomGenerator (static_cast<unsigned int> (std::time (0)));
70 static boost::variate_generator<boost::mt19937&, boost::uniform_int<> > rangeUniformRandom (randomGenerator, uniform_int<> (0,1000));
71
72 while (m_running)
73 {
74 try
75 {
76 int res = 0;
77 {
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -080078 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080079 res = ccn_run (m_handle, 0);
80 }
81
82 if (!m_running) break;
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -080083
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080084 if (res < 0)
85 BOOST_THROW_EXCEPTION (CcnxOperationException()
86 << errmsg_info_str("ccn_run returned error"));
87
88
89 pollfd pfds[1];
90 {
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -080091 UniqueRecLock lock(m_mutex);
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -080092
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080093 pfds[0].fd = ccn_get_connection_fd (m_handle);
94 pfds[0].events = POLLIN;
95 if (ccn_output_is_pending (m_handle))
96 pfds[0].events |= POLLOUT;
97 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -080098
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -080099 int ret = poll (pfds, 1, 1);
100 if (ret < 0)
101 {
102 BOOST_THROW_EXCEPTION (CcnxOperationException() << errmsg_info_str("ccnd socket failed (probably ccnd got stopped)"));
103 }
104 }
105 catch (CcnxOperationException &e)
106 {
107 // do not try reconnect for now
Zhenkai Zhu6e7d4d22013-01-15 18:18:18 -0800108 cout << *get_error_info<errmsg_info_str> (e) << endl;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800109 throw e;
110 /*
111 m_connected = false;
112 // probably ccnd has been stopped
113 // try reconnect with sleep
114 int interval = 1;
115 int maxInterval = 32;
116 while (m_running)
117 {
118 try
119 {
120 this_thread::sleep (boost::get_system_time () + TIME_SECONDS(interval) + TIME_MILLISECONDS (rangeUniformRandom ()));
121
122 connectCcnd();
123 _LOG_DEBUG("reconnect to ccnd succeeded");
124 break;
125 }
126 catch (CcnxOperationException &e)
127 {
128 this_thread::sleep (boost::get_system_time () + TIME_SECONDS(interval) + TIME_MILLISECONDS (rangeUniformRandom ()));
129
130 // do exponential backup for reconnect interval
131 if (interval < maxInterval)
132 {
133 interval *= 2;
134 }
135 }
136 }
137 */
138 }
139 catch (const std::exception &exc)
140 {
141 // catch anything thrown within try block that derives from std::exception
142 std::cerr << exc.what();
143 }
144 catch (...)
145 {
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800146 cout << "UNKNOWN EXCEPTION !!!" << endl;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800147 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800148 }
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800149}
150
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800151Bytes
Alexander Afanasyevdcfa9632013-01-07 16:38:19 -0800152CcnxWrapper::createContentObject(const Name &name, const void *buf, size_t len, int freshness)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800153{
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800154 CcnxCharbufPtr ptr = name.toCcnxCharbuf();
155 ccn_charbuf *pname = ptr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800156 ccn_charbuf *content = ccn_charbuf_create();
157
Zhenkai Zhud9d03f62013-01-04 16:57:46 -0800158 struct ccn_signing_params sp = CCN_SIGNING_PARAMS_INIT;
159 sp.freshness = freshness;
160
161 if (ccn_sign_content(m_handle, content, pname, &sp, buf, len) != 0)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800162 {
Zhenkai Zhud9d03f62013-01-04 16:57:46 -0800163 BOOST_THROW_EXCEPTION(CcnxOperationException() << errmsg_info_str("sign content failed"));
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800164 }
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800165
166 Bytes bytes;
167 readRaw(bytes, content->buf, content->length);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800168
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800169 ccn_charbuf_destroy (&content);
170
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800171 return bytes;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800172}
173
174int
Zhenkai Zhubad089c2012-12-28 10:28:27 -0800175CcnxWrapper::putToCcnd (const Bytes &contentObject)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800176{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800177 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800178 if (!m_running || !m_connected)
179 return -1;
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800180
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800181
Zhenkai Zhu974c5a62012-12-28 14:15:30 -0800182 if (ccn_put(m_handle, head(contentObject), contentObject.size()) < 0)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800183 {
184 // BOOST_THROW_EXCEPTION(CcnxOperationException() << errmsg_info_str("ccnput failed"));
185 }
186
187 return 0;
188}
189
190int
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800191CcnxWrapper::publishData (const Name &name, const unsigned char *buf, size_t len, int freshness)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800192{
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800193 Bytes co = createContentObject(name, buf, len, freshness);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800194 return putToCcnd(co);
195}
196
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800197int
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800198CcnxWrapper::publishData (const Name &name, const Bytes &content, int freshness)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800199{
Alexander Afanasyevdcfa9632013-01-07 16:38:19 -0800200 return publishData(name, head(content), content.size(), freshness);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800201}
202
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800203
204static ccn_upcall_res
205incomingInterest(ccn_closure *selfp,
206 ccn_upcall_kind kind,
207 ccn_upcall_info *info)
208{
209 CcnxWrapper::InterestCallback *f = static_cast<CcnxWrapper::InterestCallback*> (selfp->data);
210
211 switch (kind)
212 {
213 case CCN_UPCALL_FINAL: // effective in unit tests
214 delete f;
215 delete selfp;
216 return CCN_UPCALL_RESULT_OK;
217
218 case CCN_UPCALL_INTEREST:
219 break;
220
221 default:
222 return CCN_UPCALL_RESULT_OK;
223 }
224
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800225 Name interest(info->interest_ccnb, info->interest_comps);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800226
227 (*f) (interest);
228 return CCN_UPCALL_RESULT_OK;
229}
230
231static ccn_upcall_res
232incomingData(ccn_closure *selfp,
233 ccn_upcall_kind kind,
234 ccn_upcall_info *info)
235{
Zhenkai Zhu974c5a62012-12-28 14:15:30 -0800236 Closure *cp = static_cast<Closure *> (selfp->data);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800237
238 switch (kind)
239 {
240 case CCN_UPCALL_FINAL: // effecitve in unit tests
Zhenkai Zhu19f81de2013-01-04 22:27:47 -0800241 delete cp;
242 cp = NULL;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800243 delete selfp;
244 return CCN_UPCALL_RESULT_OK;
245
246 case CCN_UPCALL_CONTENT:
247 break;
248
249 case CCN_UPCALL_INTEREST_TIMED_OUT: {
250 if (cp != NULL && cp->getRetry() > 0) {
251 cp->decRetry();
252 return CCN_UPCALL_RESULT_REEXPRESS;
253 }
254
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800255 Name interest(info->interest_ccnb, info->interest_comps);
Zhenkai Zhu974c5a62012-12-28 14:15:30 -0800256 Closure::TimeoutCallbackReturnValue rv = cp->runTimeoutCallback(interest);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800257 switch(rv)
258 {
Zhenkai Zhu974c5a62012-12-28 14:15:30 -0800259 case Closure::RESULT_OK : return CCN_UPCALL_RESULT_OK;
260 case Closure::RESULT_REEXPRESS : return CCN_UPCALL_RESULT_REEXPRESS;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800261 default : break;
262 }
263 return CCN_UPCALL_RESULT_OK;
264 }
265
266 default:
267 return CCN_UPCALL_RESULT_OK;
268 }
269
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800270 const unsigned char *pcontent;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800271 size_t len;
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800272 if (ccn_content_get_value(info->content_ccnb, info->pco->offset[CCN_PCO_E], info->pco, &pcontent, &len) < 0)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800273 {
274 // BOOST_THROW_EXCEPTION(CcnxOperationException() << errmsg_info_str("decode ContentObject failed"));
275 }
276
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800277 Name name(info->content_ccnb, info->content_comps);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800278
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800279 Bytes content;
280 // copy content and do processing on the copy
281 // otherwise the pointed memory may have been changed during the processing
282 readRaw(content, pcontent, len);
283
284 cp->runDataCallback(name, content);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800285
286 return CCN_UPCALL_RESULT_OK;
287}
288
Zhenkai Zhu19f81de2013-01-04 22:27:47 -0800289int CcnxWrapper::sendInterest (const Name &interest, const Closure *closure, const Selectors &selectors)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800290{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800291 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800292 if (!m_running || !m_connected)
293 return -1;
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800294
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800295 CcnxCharbufPtr namePtr = interest.toCcnxCharbuf();
296 ccn_charbuf *pname = namePtr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800297 ccn_closure *dataClosure = new ccn_closure;
298
Zhenkai Zhu19f81de2013-01-04 22:27:47 -0800299 Closure *myClosure = closure->dup();
300 dataClosure->data = (void *)myClosure;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800301
302 dataClosure->p = &incomingData;
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800303
304 CcnxCharbufPtr selectorsPtr = selectors.toCcnxCharbuf();
305 ccn_charbuf *templ = NULL;
306 if (selectorsPtr != CcnxCharbuf::Null)
307 {
308 templ = selectorsPtr->getBuf();
309 }
310
311 if (ccn_express_interest (m_handle, pname, dataClosure, templ) < 0)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800312 {
313 }
314
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800315 return 0;
316}
317
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800318int CcnxWrapper::setInterestFilter (const Name &prefix, const InterestCallback &interestCallback)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800319{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800320 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800321 if (!m_running || !m_connected)
322 return -1;
323
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800324 CcnxCharbufPtr ptr = prefix.toCcnxCharbuf();
325 ccn_charbuf *pname = ptr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800326 ccn_closure *interestClosure = new ccn_closure;
327
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800328 interestClosure->data = new InterestCallback (interestCallback); // should be removed when closure is removed
329 interestClosure->p = &incomingInterest;
330 int ret = ccn_set_interest_filter (m_handle, pname, interestClosure);
331 if (ret < 0)
332 {
333 }
334
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800335 m_registeredInterests.insert(pair<Name, InterestCallback>(prefix, interestCallback));
Alexander Afanasyevdcfa9632013-01-07 16:38:19 -0800336
337 return ret;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800338}
339
340void
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800341CcnxWrapper::clearInterestFilter (const Name &prefix)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800342{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800343 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800344 if (!m_running || !m_connected)
345 return;
346
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800347 CcnxCharbufPtr ptr = prefix.toCcnxCharbuf();
348 ccn_charbuf *pname = ptr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800349
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800350 int ret = ccn_set_interest_filter (m_handle, pname, 0);
351 if (ret < 0)
352 {
353 }
354
355 m_registeredInterests.erase(prefix);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800356}
357
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800358Name
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800359CcnxWrapper::getLocalPrefix ()
360{
361 struct ccn * tmp_handle = ccn_create ();
362 int res = ccn_connect (tmp_handle, NULL);
363 if (res < 0)
364 {
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800365 return Name();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800366 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800367
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800368 string retval = "";
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800369
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800370 struct ccn_charbuf *templ = ccn_charbuf_create();
371 ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
372 ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
373 ccn_charbuf_append_closer(templ); /* </Name> */
374 // XXX - use pubid if possible
375 ccn_charbuf_append_tt(templ, CCN_DTAG_MaxSuffixComponents, CCN_DTAG);
376 ccnb_append_number(templ, 1);
377 ccn_charbuf_append_closer(templ); /* </MaxSuffixComponents> */
378 ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%d", 2);
379 ccn_charbuf_append_closer(templ); /* </Interest> */
380
381 struct ccn_charbuf *name = ccn_charbuf_create ();
382 res = ccn_name_from_uri (name, "/local/ndn/prefix");
383 if (res < 0) {
384 }
385 else
386 {
387 struct ccn_fetch *fetch = ccn_fetch_new (tmp_handle);
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800388
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800389 struct ccn_fetch_stream *stream = ccn_fetch_open (fetch, name, "/local/ndn/prefix",
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800390 NULL, 4, CCN_V_HIGHEST, 0);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800391 if (stream == NULL) {
392 }
393 else
394 {
395 ostringstream os;
396
397 int counter = 0;
398 char buf[256];
399 while (true) {
400 res = ccn_fetch_read (stream, buf, sizeof(buf));
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800401
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800402 if (res == 0) {
403 break;
404 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800405
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800406 if (res > 0) {
407 os << string(buf, res);
408 } else if (res == CCN_FETCH_READ_NONE) {
409 if (counter < 2)
410 {
411 ccn_run(tmp_handle, 1000);
412 counter ++;
413 }
414 else
415 {
416 break;
417 }
418 } else if (res == CCN_FETCH_READ_END) {
419 break;
420 } else if (res == CCN_FETCH_READ_TIMEOUT) {
421 break;
422 } else {
423 break;
424 }
425 }
426 retval = os.str ();
427 stream = ccn_fetch_close(stream);
428 }
429 fetch = ccn_fetch_destroy(fetch);
430 }
431
432 ccn_charbuf_destroy (&name);
433
434 ccn_disconnect (tmp_handle);
435 ccn_destroy (&tmp_handle);
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800436
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800437 return Name(retval);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800438}
439
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800440}