IBR-DTNSuite  0.8
tools/src/dtntunnel.cpp
Go to the documentation of this file.
00001 //============================================================================
00002 // Name        : IPtunnel.cpp
00003 // Author      : IBR, TU Braunschweig
00004 // Version     :
00005 // Copyright   :
00006 // Description : Hello World in C++, Ansi-style
00007 //============================================================================
00008 
00009 #include "config.h"
00010 
00011 #include <iostream>
00012 #include <stdlib.h>
00013 
00014 // Base for send and receive bundle to/from the IBR-DTN daemon.
00015 #include "ibrdtn/api/Client.h"
00016 
00017 // Container for bundles.
00018 #include "ibrdtn/api/Bundle.h"
00019 #include "ibrdtn/api/BLOBBundle.h"
00020 
00021 // Container for bundles carrying strings.
00022 #include "ibrdtn/api/StringBundle.h"
00023 
00024 //  TCP client implemeted as a stream.
00025 #include "ibrcommon/net/tcpclient.h"
00026 
00027 // Some classes to be thread-safe.
00028 #include "ibrcommon/thread/Mutex.h"
00029 #include "ibrcommon/thread/MutexLock.h"
00030 
00031 // Basic functionalities for streaming.
00032 #include <iostream>
00033 
00034 // A queue for bundles.
00035 #include <queue>
00036 
00037 #include <csignal>
00038 
00039 #include <unistd.h>
00040 #include <fcntl.h>
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <string.h>
00044 #include <errno.h>
00045 
00046 #include <sys/ioctl.h>
00047 #include <sys/socket.h>
00048 #include <linux/if.h>
00049 
00050 using namespace std;
00051 
00052 /*
00053  * Allocate TUN device, returns opened fd.
00054  * Stores dev name in the first arg(must be large enough).
00055  */
00056 static int tun_open_common0(char *dev, int istun)
00057 {
00058     char tunname[14];
00059     int i, fd, err;
00060 
00061     if( *dev ) {
00062        sprintf(tunname, "/dev/%s", dev);
00063        return open(tunname, O_RDWR);
00064     }
00065 
00066     sprintf(tunname, "/dev/%s", istun ? "tun" : "tap");
00067     err = 0;
00068     for(i=0; i < 255; i++){
00069        sprintf(tunname + 8, "%d", i);
00070        /* Open device */
00071        if( (fd=open(tunname, O_RDWR)) > 0 ) {
00072           strcpy(dev, tunname + 5);
00073           return fd;
00074        }
00075        else if (errno != ENOENT)
00076           err = errno;
00077        else if (i)      /* don't try all 256 devices */
00078           break;
00079     }
00080     if (err)
00081         errno = err;
00082     return -1;
00083 }
00084 
00085 #ifdef HAVE_LINUX_IF_TUN_H /* New driver support */
00086 #include <linux/if_tun.h>
00087 
00088 #ifndef OTUNSETNOCSUM
00089 /* pre 2.4.6 compatibility */
00090 #define OTUNSETNOCSUM  (('T'<< 8) | 200)
00091 #define OTUNSETDEBUG   (('T'<< 8) | 201)
00092 #define OTUNSETIFF     (('T'<< 8) | 202)
00093 #define OTUNSETPERSIST (('T'<< 8) | 203)
00094 #define OTUNSETOWNER   (('T'<< 8) | 204)
00095 #endif
00096 
00097 static int tun_open_common(char *dev, int istun)
00098 {
00099     struct ifreq ifr;
00100     int fd;
00101 
00102     if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
00103        return tun_open_common0(dev, istun);
00104 
00105     memset(&ifr, 0, sizeof(ifr));
00106     ifr.ifr_flags = (istun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
00107     if (*dev)
00108        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
00109 
00110     if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
00111        if (errno == EBADFD) {
00112           /* Try old ioctl */
00113           if (ioctl(fd, OTUNSETIFF, (void *) &ifr) < 0)
00114              goto failed;
00115        } else
00116           goto failed;
00117     }
00118 
00119     strcpy(dev, ifr.ifr_name);
00120     return fd;
00121 
00122 failed:
00123     close(fd);
00124     return -1;
00125 }
00126 
00127 #else
00128 
00129 # define tun_open_common(dev, type) tun_open_common0(dev, type)
00130 
00131 #endif /* New driver support */
00132 
00133 int tun_open(char *dev) { return tun_open_common(dev, 1); }
00134 int tap_open(char *dev) { return tun_open_common(dev, 0); }
00135 
00136 class TUN2BundleGateway : public dtn::api::Client
00137 {
00138         public:
00139                 TUN2BundleGateway(int fd, string app, string address = "127.0.0.1", int port = 4550)
00140                 : dtn::api::Client(app, _tcpclient), _fd(fd), _tcpclient(address, port)
00141                 {
00142                         // enable nodelay option
00143                         _tcpclient.enableNoDelay();
00144                 };
00145 
00149                 virtual ~TUN2BundleGateway()
00150                 {
00151                         // Close the tcp connection.
00152                         _tcpclient.close();
00153                 };
00154 
00155         private:
00156                 // file descriptor for the tun device
00157                 int _fd;
00158 
00164                 void received(dtn::api::Bundle &b)
00165                 {
00166                         ibrcommon::BLOB::Reference ref = b.getData();
00167                         ibrcommon::BLOB::iostream stream = ref.iostream();
00168                         char data[65536];
00169                         stream->read(data, sizeof(data));
00170                         size_t ret = stream->gcount();
00171                         if (::write(_fd, data, ret) < 0)
00172                         {
00173                                 std::cerr << "error while writing" << std::endl;
00174                         }
00175                 }
00176 
00177                 ibrcommon::tcpclient _tcpclient;
00178 };
00179 
00180 bool m_running = true;
00181 int tunnel_fd = -1;
00182 
00183 void term(int signal)
00184 {
00185         if (signal >= 1)
00186         {
00187                 m_running = false;
00188                 ::close(tunnel_fd);
00189                 tunnel_fd = -1;
00190         }
00191 }
00192 
00193 int main(int argc, char *argv[])
00194 {
00195         // catch process signals
00196         signal(SIGINT, term);
00197         signal(SIGTERM, term);
00198 
00199         cout << "IBR-DTN IP <-> Bundle Tunnel" << endl;
00200 
00201         if (argc < 5)
00202         {
00203                 cout << "Syntax: " << argv[0] << " <dev> <ip> <ptp> <dst>" << endl;
00204                 cout << "  <dev>   Virtual network device to create" << endl;
00205                 cout << "  <ip>    Own IP address to set" << endl;
00206                 cout << "  <ptp>   IP address of the Point-To-Point partner" << endl;
00207                 cout << "  <dst>   EID of the destination" << endl;
00208                 return -1;
00209         }
00210 
00211         int tunnel_fd = tun_open(argv[1]);
00212 
00213         if (tunnel_fd == -1)
00214         {
00215                 cerr << "Error: failed to open tun device" << endl;
00216                 return -1;
00217         }
00218 
00219         // create a connection to the dtn daemon
00220         TUN2BundleGateway gateway(tunnel_fd, "tun");
00221 
00222         // set the interface addresses
00223         stringstream ifconfig;
00224         ifconfig << "ifconfig " << argv[1] << " -pointopoint " << argv[2] << " dstaddr " << argv[3];
00225         if ( system(ifconfig.str().c_str()) > 0 )
00226         {
00227                 std::cerr << "can not the interface address" << std::endl;
00228         }
00229 
00230         gateway.connect();
00231 
00232         cout << "ready" << endl;
00233 
00234         while (m_running)
00235         {
00236                 char data[65536];
00237                 int ret = ::read(tunnel_fd, data, sizeof(data));
00238 
00239                 cout << "received " << ret << " bytes" << endl;
00240 
00241                 // create a blob
00242                 ibrcommon::BLOB::Reference blob = ibrcommon::BLOB::create();
00243 
00244                 // add the data
00245                 blob.iostream()->write(data, ret);
00246 
00247                 // create a new bundle
00248                 dtn::api::BLOBBundle b(dtn::data::EID(argv[4]), blob);
00249 
00250                 // transmit the packet
00251                 gateway << b;
00252                 gateway.flush();
00253         }
00254 
00255         gateway.close();
00256 
00257         ::close(tunnel_fd);
00258         tunnel_fd = -1;
00259 
00260         return 0;
00261 }