29 #include <libdaemon/daemon.h>
36 #include <ibrcommon/net/socket.h>
39 #include "ibrcommon/thread/Mutex.h"
40 #include "ibrcommon/thread/MutexLock.h"
41 #include <ibrcommon/thread/SignalHandler.h>
42 #include <ibrcommon/Logger.h>
57 #include <sys/ioctl.h>
58 #include <sys/socket.h>
60 #include <linux/if_tun.h>
66 char clonedev[] =
"/dev/net/tun";
76 if( (fd = open(clonedev, O_RDWR)) < 0 ) {
81 memset(&ifr, 0,
sizeof(ifr));
83 ifr.ifr_flags = flags;
89 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
93 if( (err = ioctl(fd, TUNSETIFF, (
void *) &ifr)) < 0 ) {
102 strcpy(dev, ifr.ifr_name);
122 float throughput_sum_up = 0;
123 float throughput_sum_down = 0;
125 for (
int i = 0; i < 5; ++i) {
130 std::cout <<
" up: " << setiosflags(ios::right) << setw(12) << setiosflags(ios::fixed) << setprecision(2) << (throughput_sum_up/1024) <<
" kB/s ";
131 std::cout <<
" down: " << setiosflags(ios::right) << setw(12) << setiosflags(ios::fixed) << setprecision(2) << (throughput_sum_down/1024) <<
" kB/s\r" << std::flush;
134 if (throughput_pos > 4) throughput_pos = 0;
143 TUN2BundleGateway(
const std::string &app, ibrcommon::socketstream &stream,
const std::string &ptp_dev)
144 : dtn::api::
Client(app, stream), _stream(stream), _fd(-1)
146 char tun_name[IFNAMSIZ];
148 strcpy(tun_name, ptp_dev.c_str());
151 tun_device = tun_name;
154 throw ibrcommon::Exception(
"Error: failed to open tun device");
163 virtual ~TUN2BundleGateway()
180 void process(
const dtn::data::EID &endpoint,
unsigned int lifetime = 60) {
181 if (_fd == -1)
throw ibrcommon::Exception(
"Tunnel closed.");
184 ssize_t ret = ::read(_fd, data,
sizeof(data));
187 throw ibrcommon::Exception(
"Error: failed to read from tun device");
193 ibrcommon::BLOB::Reference blob = ibrcommon::BLOB::create();
196 blob.iostream()->write(data, ret);
210 const std::string& getDeviceName()
const
216 ibrcommon::socketstream &_stream;
221 std::string tun_device;
231 ibrcommon::BLOB::iostream stream = ref.iostream();
233 stream->read(data,
sizeof(data));
234 size_t ret = stream->gcount();
236 if (::write(_fd, data, ret) < 0)
238 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Error while writing" << IBRCOMMON_LOGGER_ENDL;
253 if (_gateway != NULL)
254 _gateway->shutdown();
260 std::cout <<
"-- dtntunnel (IBR-DTN) --" << std::endl;
261 std::cout <<
"Syntax: " << argv0 <<
" [options] <endpoint>" << std::endl;
262 std::cout <<
" <endpoint> Destination of outgoing bundles" << std::endl << std::endl;
263 std::cout <<
"* optional parameters *" << std::endl;
264 std::cout <<
" -h Display help message" << std::endl;
265 std::cout <<
" -d <dev> Virtual network device to create (default: tun0)" << std::endl;
266 std::cout <<
" -s <name> Application suffix of the local endpoint (default: tunnel)" << std::endl;
267 std::cout <<
" -l <seconds> Lifetime of each packet (default: 60)" << std::endl;
268 std::cout <<
" -t Show throughput" << std::endl;
269 #ifdef HAVE_LIBDAEMON
270 std::cout <<
" -D Daemonize the process" << std::endl;
271 std::cout <<
" -k Stop the running daemon" << std::endl;
272 std::cout <<
" -p <file> Store the pid in this pidfile" << std::endl;
276 #ifdef HAVE_LIBDAEMON
277 static char* __daemon_pidfile__ = NULL;
279 static const char* __daemon_pid_file_proc__(
void) {
280 return __daemon_pidfile__;
284 int main(
int argc,
char *argv[])
289 std::string ptp_dev(
"tun0");
290 std::string app_name(
"tunnel");
291 std::string endpoint(
"dtn:none");
292 unsigned int lifetime = 60;
293 bool daemonize =
false;
294 bool stop_daemon =
false;
296 bool throughput =
false;
299 ibrcommon::SignalHandler sighandler(
term);
300 sighandler.handle(SIGINT);
301 sighandler.handle(SIGTERM);
302 sighandler.handle(SIGQUIT);
304 #ifdef HAVE_LIBDAEMON
305 while ((c = getopt (argc, argv,
"td:s:l:hDkp:")) != -1)
307 while ((c = getopt (argc, argv,
"td:s:l:h")) != -1)
311 #ifdef HAVE_LIBDAEMON
338 lifetime = atoi(optarg);
347 for (index = optind; index < argc; ++index)
352 endpoint = std::string(argv[index]);
360 if (!stop_daemon && (optindex < 1)) {
print_help(argv[0]); exit(0); }
363 sighandler.initialize();
367 const unsigned char logopts = 0;
370 const unsigned char logerr = ibrcommon::Logger::LOGGER_ERR | ibrcommon::Logger::LOGGER_CRIT;
373 const unsigned char logstd = ibrcommon::Logger::LOGGER_ALL ^ (ibrcommon::Logger::LOGGER_DEBUG |
logerr);
376 const unsigned char logsys = ibrcommon::Logger::LOGGER_ALL ^ (ibrcommon::Logger::LOGGER_DEBUG | ibrcommon::Logger::LOGGER_NOTICE);
378 #ifdef HAVE_LIBDAEMON
381 ibrcommon::Logger::enableSyslog(argv[0], LOG_PID, LOG_DAEMON, logsys);
386 ibrcommon::Logger::addStream(std::cout, logstd, logopts);
389 ibrcommon::Logger::addStream(std::cerr, logerr, logopts);
392 #ifdef HAVE_LIBDAEMON
395 #ifdef HAVE_DAEMON_RESET_SIGS
397 if (daemon_reset_sigs(-1) < 0) {
398 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Failed to reset all signal handlers: " << strerror(errno) << IBRCOMMON_LOGGER_ENDL;
403 if (daemon_unblock_sigs(-1) < 0) {
404 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Failed to unblock all signals: " << strerror(errno) << IBRCOMMON_LOGGER_ENDL;
411 daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);
414 if (pidfile.length() > 0) {
415 __daemon_pidfile__ =
new char[pidfile.length() + 1];
416 ::strcpy(__daemon_pidfile__, pidfile.c_str());
417 daemon_pid_file_proc = __daemon_pid_file_proc__;
428 if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0)
429 IBRCOMMON_LOGGER_TAG(
"Core", warning) <<
"Failed to kill daemon: " << strerror(errno) << IBRCOMMON_LOGGER_ENDL;
431 return ret < 0 ? 1 : 0;
435 if ((pid = daemon_pid_file_is_running()) >= 0) {
436 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Daemon already running on PID file " << pid << IBRCOMMON_LOGGER_ENDL;
441 if (daemon_retval_init() < 0) {
442 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Failed to create pipe." << IBRCOMMON_LOGGER_ENDL;
447 if ((pid = daemon_fork()) < 0) {
450 daemon_retval_done();
457 if ((ret = daemon_retval_wait(20)) < 0) {
458 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Could not recieve return value from daemon process: " << strerror(errno) << IBRCOMMON_LOGGER_ENDL;
466 if (daemon_close_all(-1) < 0) {
467 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Failed to close all file descriptors: " << strerror(errno) << IBRCOMMON_LOGGER_ENDL;
470 daemon_retval_send(1);
473 daemon_retval_send(255);
474 daemon_signal_done();
475 daemon_pid_file_remove();
481 if (daemon_pid_file_create() < 0) {
482 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Could not create PID file ( " << strerror(errno) <<
")." << IBRCOMMON_LOGGER_ENDL;
483 daemon_retval_send(2);
486 daemon_retval_send(255);
487 daemon_signal_done();
488 daemon_pid_file_remove();
494 daemon_retval_send(0);
499 IBRCOMMON_LOGGER_TAG(
"Core", info) <<
"IBR-DTN IP <-> Bundle Tunnel" << IBRCOMMON_LOGGER_ENDL;
502 ibrcommon::vaddress addr(
"localhost", 4550);
503 ibrcommon::socketstream conn(
new ibrcommon::tcpsocket(addr));
507 TUN2BundleGateway gateway(app_name, conn, ptp_dev);
510 IBRCOMMON_LOGGER_TAG(
"Core", info) <<
"Local: " << app_name << IBRCOMMON_LOGGER_ENDL;
511 IBRCOMMON_LOGGER_TAG(
"Core", info) <<
"Peer: " << endpoint << IBRCOMMON_LOGGER_ENDL;
512 IBRCOMMON_LOGGER_TAG(
"Core", info) <<
"Device: " << gateway.getDeviceName() << IBRCOMMON_LOGGER_ENDL;
513 IBRCOMMON_LOGGER_TAG(
"Core", notice) << IBRCOMMON_LOGGER_ENDL;
514 IBRCOMMON_LOGGER_TAG(
"Core", notice) <<
"Now you need to set-up the ip tunnel. You can use commands like this:" << IBRCOMMON_LOGGER_ENDL;
515 IBRCOMMON_LOGGER_TAG(
"Core", notice) <<
"# sudo ip link set " << gateway.getDeviceName() <<
" up mtu 65535" << IBRCOMMON_LOGGER_ENDL;
516 IBRCOMMON_LOGGER_TAG(
"Core", notice) <<
"# sudo ip addr add 10.0.0.1/24 dev " << gateway.getDeviceName() << IBRCOMMON_LOGGER_ENDL;
517 IBRCOMMON_LOGGER_TAG(
"Core", notice) << IBRCOMMON_LOGGER_ENDL;
522 if (!daemonize && throughput) {
526 sev.sigev_notify = SIGEV_SIGNAL;
527 sev.sigev_signo = SIGRTMIN;
528 sev.sigev_value.sival_ptr = &timerid;
531 timer_create(CLOCK_MONOTONIC, &sev, &timerid);
534 struct itimerspec its;
535 size_t freq_nanosecs = 200000000;
536 its.it_value.tv_sec = freq_nanosecs / 1000000000;;
537 its.it_value.tv_nsec = freq_nanosecs % 1000000000;
538 its.it_interval.tv_sec = its.it_value.tv_sec;
539 its.it_interval.tv_nsec = its.it_value.tv_nsec;
541 if (timer_settime(timerid, 0, &its, NULL) == -1) {
542 IBRCOMMON_LOGGER_TAG(
"Core", error) <<
"Timer set failed." << IBRCOMMON_LOGGER_ENDL;
551 gateway.process(eid, lifetime);
555 }
catch (
const ibrcommon::Exception &ex) {
557 IBRCOMMON_LOGGER_TAG(
"Core", error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
562 #ifdef HAVE_LIBDAEMON
565 IBRCOMMON_LOGGER_TAG(
"Core", info) <<
"Stopped" << app_name << IBRCOMMON_LOGGER_ENDL;
566 daemon_retval_send(255);
567 daemon_signal_done();
568 daemon_pid_file_remove();
572 std::cout << std::endl;
const unsigned char logsys
void add_throughput_data(ssize_t amount, int updown)
const unsigned char logerr
Client(const std::string &app, ibrcommon::socketstream &stream, const COMMUNICATION_MODE mode=MODE_BIDIRECTIONAL)
int tun_alloc(char *dev, short int flags)
int main(int argc, char *argv[])
virtual void received(const dtn::streams::StreamContactHeader &)
size_t throughput_data_down[5]
void shutdown(ConnectionShutdownCases csc=CONNECTION_SHUTDOWN_SIMPLE_SHUTDOWN)
const unsigned char logstd
size_t throughput_data_up[5]
iterator find(block_t blocktype)
TUN2BundleGateway * _gateway
void print_help(const char *argv0)
void timer_display_throughput(int)