blob: b014a079ef84d3beda69b12f7603ebb49ffb6c1e [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: {
Zhenkai Zhu8339e912013-01-18 18:10:17 -0800250 if (cp != NULL)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800251 {
Zhenkai Zhu8339e912013-01-18 18:10:17 -0800252 Name interest(info->interest_ccnb, info->interest_comps);
253 Closure::TimeoutCallbackReturnValue rv = cp->runTimeoutCallback(interest);
254 switch(rv)
255 {
256 case Closure::RESULT_OK : return CCN_UPCALL_RESULT_OK;
257 case Closure::RESULT_REEXPRESS : return CCN_UPCALL_RESULT_REEXPRESS;
258 default : break;
259 }
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800260 }
261 return CCN_UPCALL_RESULT_OK;
262 }
263
264 default:
265 return CCN_UPCALL_RESULT_OK;
266 }
267
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800268 const unsigned char *pcontent;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800269 size_t len;
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800270 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 -0800271 {
272 // BOOST_THROW_EXCEPTION(CcnxOperationException() << errmsg_info_str("decode ContentObject failed"));
273 }
274
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800275 Name name(info->content_ccnb, info->content_comps);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800276
Zhenkai Zhu43eb2732012-12-28 00:48:26 -0800277 Bytes content;
278 // copy content and do processing on the copy
279 // otherwise the pointed memory may have been changed during the processing
280 readRaw(content, pcontent, len);
281
282 cp->runDataCallback(name, content);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800283
284 return CCN_UPCALL_RESULT_OK;
285}
286
Zhenkai Zhu19f81de2013-01-04 22:27:47 -0800287int CcnxWrapper::sendInterest (const Name &interest, const Closure *closure, const Selectors &selectors)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800288{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800289 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800290 if (!m_running || !m_connected)
291 return -1;
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800292
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800293 CcnxCharbufPtr namePtr = interest.toCcnxCharbuf();
294 ccn_charbuf *pname = namePtr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800295 ccn_closure *dataClosure = new ccn_closure;
296
Zhenkai Zhu19f81de2013-01-04 22:27:47 -0800297 Closure *myClosure = closure->dup();
298 dataClosure->data = (void *)myClosure;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800299
300 dataClosure->p = &incomingData;
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800301
302 CcnxCharbufPtr selectorsPtr = selectors.toCcnxCharbuf();
303 ccn_charbuf *templ = NULL;
304 if (selectorsPtr != CcnxCharbuf::Null)
305 {
306 templ = selectorsPtr->getBuf();
307 }
308
309 if (ccn_express_interest (m_handle, pname, dataClosure, templ) < 0)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800310 {
311 }
312
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800313 return 0;
314}
315
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800316int CcnxWrapper::setInterestFilter (const Name &prefix, const InterestCallback &interestCallback)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800317{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800318 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800319 if (!m_running || !m_connected)
320 return -1;
321
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800322 CcnxCharbufPtr ptr = prefix.toCcnxCharbuf();
323 ccn_charbuf *pname = ptr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800324 ccn_closure *interestClosure = new ccn_closure;
325
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800326 interestClosure->data = new InterestCallback (interestCallback); // should be removed when closure is removed
327 interestClosure->p = &incomingInterest;
328 int ret = ccn_set_interest_filter (m_handle, pname, interestClosure);
329 if (ret < 0)
330 {
331 }
332
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800333 m_registeredInterests.insert(pair<Name, InterestCallback>(prefix, interestCallback));
Alexander Afanasyevdcfa9632013-01-07 16:38:19 -0800334
335 return ret;
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800336}
337
338void
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800339CcnxWrapper::clearInterestFilter (const Name &prefix)
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800340{
Alexander Afanasyev20bc8e22013-01-17 10:56:04 -0800341 UniqueRecLock lock(m_mutex);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800342 if (!m_running || !m_connected)
343 return;
344
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800345 CcnxCharbufPtr ptr = prefix.toCcnxCharbuf();
346 ccn_charbuf *pname = ptr->getBuf();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800347
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800348 int ret = ccn_set_interest_filter (m_handle, pname, 0);
349 if (ret < 0)
350 {
351 }
352
353 m_registeredInterests.erase(prefix);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800354}
355
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800356Name
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800357CcnxWrapper::getLocalPrefix ()
358{
359 struct ccn * tmp_handle = ccn_create ();
360 int res = ccn_connect (tmp_handle, NULL);
361 if (res < 0)
362 {
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800363 return Name();
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800364 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800365
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800366 string retval = "";
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800367
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800368 struct ccn_charbuf *templ = ccn_charbuf_create();
369 ccn_charbuf_append_tt(templ, CCN_DTAG_Interest, CCN_DTAG);
370 ccn_charbuf_append_tt(templ, CCN_DTAG_Name, CCN_DTAG);
371 ccn_charbuf_append_closer(templ); /* </Name> */
372 // XXX - use pubid if possible
373 ccn_charbuf_append_tt(templ, CCN_DTAG_MaxSuffixComponents, CCN_DTAG);
374 ccnb_append_number(templ, 1);
375 ccn_charbuf_append_closer(templ); /* </MaxSuffixComponents> */
376 ccnb_tagged_putf(templ, CCN_DTAG_Scope, "%d", 2);
377 ccn_charbuf_append_closer(templ); /* </Interest> */
378
379 struct ccn_charbuf *name = ccn_charbuf_create ();
380 res = ccn_name_from_uri (name, "/local/ndn/prefix");
381 if (res < 0) {
382 }
383 else
384 {
385 struct ccn_fetch *fetch = ccn_fetch_new (tmp_handle);
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800386
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800387 struct ccn_fetch_stream *stream = ccn_fetch_open (fetch, name, "/local/ndn/prefix",
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800388 NULL, 4, CCN_V_HIGHEST, 0);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800389 if (stream == NULL) {
390 }
391 else
392 {
393 ostringstream os;
394
395 int counter = 0;
396 char buf[256];
397 while (true) {
398 res = ccn_fetch_read (stream, buf, sizeof(buf));
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800399
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800400 if (res == 0) {
401 break;
402 }
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800403
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800404 if (res > 0) {
405 os << string(buf, res);
406 } else if (res == CCN_FETCH_READ_NONE) {
407 if (counter < 2)
408 {
409 ccn_run(tmp_handle, 1000);
410 counter ++;
411 }
412 else
413 {
414 break;
415 }
416 } else if (res == CCN_FETCH_READ_END) {
417 break;
418 } else if (res == CCN_FETCH_READ_TIMEOUT) {
419 break;
420 } else {
421 break;
422 }
423 }
424 retval = os.str ();
425 stream = ccn_fetch_close(stream);
426 }
427 fetch = ccn_fetch_destroy(fetch);
428 }
429
430 ccn_charbuf_destroy (&name);
431
432 ccn_disconnect (tmp_handle);
433 ccn_destroy (&tmp_handle);
Zhenkai Zhu0d8f5d52012-12-30 12:54:07 -0800434
Zhenkai Zhucb2d0dd2013-01-03 14:10:48 -0800435 return Name(retval);
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800436}
437
Zhenkai Zhu1ddeb6f2012-12-27 14:04:18 -0800438}