IBR-DTNSuite  0.10
HTTPConvergenceLayer.cpp
Go to the documentation of this file.
1 
27 #include "Configuration.h"
29 #include "core/BundleCore.h"
30 #include <memory>
31 
32 namespace dtn
33 {
34  namespace net
35  {
37  const int TIMEOUT = 1000;
39  const int CONN_TIMEOUT = 5000;
40 
42  const int HTTP_OK = 200;
44  const int HTTP_NO_DATA = 410;
45 
47  const int CURL_CONN_OK = 0;
49  const int CURL_PARTIAL_FILE = 18;
50 
59  static size_t HTTPConvergenceLayer_callback_read(void *ptr, size_t size, size_t nmemb, void *s)
60  {
61  size_t retcode = 0;
62  std::istream *stream = static_cast<std::istream*>(s);
63 
64  if (stream->eof()) return 0;
65 
66  char *buffer = static_cast<char*>(ptr);
67 
68  stream->read(buffer, (size * nmemb));
69  retcode = stream->gcount();
70 
71  return retcode;
72  }
73 
82  static size_t HTTPConvergenceLayer_callback_write(void *ptr, size_t size, size_t nmemb, void *s)
83  {
84  std::ostream *stream = static_cast<std::ostream*>(s);
85  char *buffer = static_cast<char*>(ptr);
86 
87  if (!stream->good()) return 0;
88 
89  stream->write(buffer, (size * nmemb));
90  stream->flush();
91 
92  return (size * nmemb);
93  }
94 
103  : _server(server), _push_iob(NULL), _running(true)
104  {
105  curl_global_init(CURL_GLOBAL_ALL);
106  }
107 
108 
114  {
115  curl_global_cleanup();
116  }
117 
126  : _stream(&buf)
127  {
128  }
129 
135  {
136  join();
137  }
138 
146  void DownloadThread::run() throw ()
147  {
148  try {
149  while(_stream.good())
150  {
151  try {
152  dtn::data::Bundle bundle;
154 
155  // raise default bundle received event
157  } catch (const ibrcommon::Exception &ex) {
158  IBRCOMMON_LOGGER_DEBUG_TAG("HTTPConvergenceLayer", 10) << "http error: " << ex.what() << IBRCOMMON_LOGGER_ENDL;
159  }
160 
161  yield();
162  }
163  } catch (const ibrcommon::ThreadException &e) {
164  std::cerr << "error: " << e.what() << std::endl;
165  }
166  }
167 
169  {
170  }
171 
186  {
188  std::string url_send;
189 
190  long http_code = 0;
191  //double upload_size = 0;
192 
193  try {
194  // read the bundle out of the storage
195  const dtn::data::Bundle bundle = storage.get(job.getBundle());
196 
198  {
200  dtn::data::DefaultSerializer(*io) << bundle;
201  }
202 
204  size_t length = io.size();
205  CURLcode res;
206  CURL *curl_up;
207 
208  url_send = _server + "?eid=" + dtn::core::BundleCore::local.getString();
209  //+ "&dst-eid=dtn://experthe-laptop/filetransfer";
210  //+ "&priority=2";
211  //+ "&ttl=3600";
212 
213  //if (job._bundle.source.getString() == (dtn::core::BundleCore::local.getString() + "/echo-client"))
214  //{
215  // url_send = _server + "?eid=" + dtn::core::BundleCore::local.getString() + "&dst-eid=echo-client";
216  //}
217 
218  curl_up = curl_easy_init();
219  if(curl_up)
220  {
221  /* we want to use our own read function */
222  curl_easy_setopt(curl_up, CURLOPT_READFUNCTION, HTTPConvergenceLayer_callback_read);
223 
224  /* enable uploading */
225  curl_easy_setopt(curl_up, CURLOPT_UPLOAD, 1L);
226 
227  /* HTTP PUT please */
228  curl_easy_setopt(curl_up, CURLOPT_PUT, 1L);
229 
230  /* disable connection timeout */
231  curl_easy_setopt(curl_up, CURLOPT_CONNECTTIMEOUT, 0);
232 
233  /* specify target URL, and note that this URL should include a file
234  name, not only a directory */
235  curl_easy_setopt(curl_up, CURLOPT_URL, url_send.c_str());
236 
237  /* now specify which file to upload */
238  curl_easy_setopt(curl_up, CURLOPT_READDATA, &(*io));
239 
240  /* provide the size of the upload, we specicially typecast the value
241  to curl_off_t since we must be sure to use the correct data size */
242  curl_easy_setopt(curl_up, CURLOPT_INFILESIZE_LARGE,
243  (curl_off_t)length);
244 
245  /* Now run off and do what you've been told! */
246  res = curl_easy_perform(curl_up);
247 
248  if(res == CURL_CONN_OK)
249  {
250  /* get HTTP Header StatusCode */
251  curl_easy_getinfo (curl_up, CURLINFO_RESPONSE_CODE, &http_code);
252  //curl_easy_getinfo (curl, CURLINFO_SIZE_UPLOAD, &upload_size);
253 
254  /* DEBUG OUTPUT INFORMATION */
255  //std::cout << "CURL CODE : " << res << std::endl;
256  //std::cout << "HTTP CODE : " << http_code << std::endl;
257  //std::cout << "UPLOAD_SIZE: " << upload_size << " Bytes" << std::endl;
258  /* DEBUG OUTPUT INFORMATION */
259 
260  if(http_code == HTTP_OK)
261  {
262  dtn::net::BundleTransfer local_job = job;
263  local_job.complete();
264  }
265  }
266 
267  curl_easy_cleanup(curl_up);
268  }
269  } catch (const dtn::storage::NoBundleFoundException&) {
270  // send transfer aborted event
271  dtn::net::BundleTransfer local_job = job;
273  }
274 
275  }
276 
281  {
283  }
284 
290  {
291  // routine checked for throw() on 15.02.2013
292  }
293 
306  {
307 
308  std::string url = _server + "?eid=" + dtn::core::BundleCore::local.getString();
309 
310  CURL *curl_down;
311 
312  while (_running)
313  {
314  curl_down = curl_easy_init();
315 
316  while(curl_down)
317  {
318  curl_easy_setopt(curl_down, CURLOPT_URL, url.c_str());
319 
320  /* disable connection timeout */
321  curl_easy_setopt(curl_down, CURLOPT_CONNECTTIMEOUT, 0);
322 
323  /* no progress meter please */
324  curl_easy_setopt(curl_down, CURLOPT_NOPROGRESS, 1L);
325 
326  /* cURL DEBUG options */
327  //curl_easy_setopt(curl_down, CURLOPT_DEBUGFUNCTION, my_trace);
328  //curl_easy_setopt(curl_down, CURLOPT_DEBUGDATA, &config);
329 
330  //curl_easy_setopt(curl_down, CURLOPT_DEBUGFUNCTION, my_trace);
331  //curl_easy_setopt(curl_down, CURLOPT_VERBOSE, 1);
332 
333  // create a receiver thread
334  {
335  ibrcommon::MutexLock l(_push_iob_mutex);
336  _push_iob = new ibrcommon::iobuffer();
337  }
338 
339  std::auto_ptr<ibrcommon::iobuffer> auto_kill(_push_iob);
340  std::ostream os(_push_iob);
341  DownloadThread receiver(*_push_iob);
342 
343  /* send all data to this function */
344  curl_easy_setopt(curl_down, CURLOPT_WRITEFUNCTION, HTTPConvergenceLayer_callback_write);
345 
346  /* now specify where to write data */
347  curl_easy_setopt(curl_down, CURLOPT_WRITEDATA, &os);
348 
349  /* do curl */
350  receiver.start();
351  curl_easy_perform(curl_down);
352 
353  {
354  ibrcommon::MutexLock l(_push_iob_mutex);
355  /* finalize iobuffer */
356  _push_iob->finalize();
357  receiver.join();
358  _push_iob = NULL;
359  }
360 
361  /* get HTTP Header StatusCode */
362  //curl_easy_getinfo (curl_down, CURLINFO_RESPONSE_CODE, &http_code);
363  //curl_easy_getinfo (curl, CURLINFO_SIZE_DOWNLOAD, &download_size);
364  //curl_easy_getinfo (curl, CURLINFO_NUM_CONNECTS, &connects);
365 
366  /* Wait some time an retry to connect */
367  sleep(CONN_TIMEOUT); // Wenn Verbindung nicht hergestellt werden konnte warte 5 sec.
368  IBRCOMMON_LOGGER_DEBUG_TAG("HTTPConvergenceLayer", 10) << "http error: " << "Couldn't connect to server ... wait " << CONN_TIMEOUT/1000 << "s until retry" << IBRCOMMON_LOGGER_ENDL;
369  }
370 
371  /* always cleanup */
372  curl_easy_cleanup(curl_down);
373  }
374  yield();
375  }
376 
383  {
384  }
385 
391  {
392  _running = false;
393 
394  ibrcommon::MutexLock l(_push_iob_mutex);
395  if (_push_iob != NULL)
396  {
397  _push_iob->finalize();
398  _push_iob = NULL;
399  }
400  }
401 
406  const std::string HTTPConvergenceLayer::getName() const
407  {
408  return "HTTPConvergenceLayer";
409  }
410  }
411 }