IBR-DTNSuite
0.8
|
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 }