IBR-DTNSuite 0.6

tools/src/dtninbox.cpp

Go to the documentation of this file.
00001 /*
00002  * dtninbox.cpp
00003  *
00004  *  Created on: 20.11.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "config.h"
00009 #include "ibrdtn/api/Client.h"
00010 #include "ibrdtn/api/FileBundle.h"
00011 #include "ibrcommon/net/tcpclient.h"
00012 #include "ibrcommon/thread/Mutex.h"
00013 #include "ibrcommon/thread/MutexLock.h"
00014 #include "ibrdtn/data/PayloadBlock.h"
00015 #include "ibrdtn/data/Bundle.h"
00016 #include "ibrcommon/data/BLOB.h"
00017 #include "ibrcommon/data/File.h"
00018 #include "ibrcommon/appstreambuf.h"
00019 
00020 #include <stdlib.h>
00021 #include <iostream>
00022 #include <map>
00023 #include <vector>
00024 #include <csignal>
00025 #include <sys/types.h>
00026 
00027 using namespace ibrcommon;
00028 
00029 void print_help()
00030 {
00031         cout << "-- dtninbox (IBR-DTN) --" << endl;
00032         cout << "Syntax: dtninbox [options] <name> <inbox>"  << endl;
00033         cout << " <name>           the application name" << endl;
00034         cout << " <inbox>          directory where incoming files should be placed" << endl;
00035         cout << "* optional parameters *" << endl;
00036         cout << " -h|--help        display this text" << endl;
00037         cout << " -w|--workdir     temporary work directory" << endl;
00038 }
00039 
00040 map<string,string> readconfiguration(int argc, char** argv)
00041 {
00042     // print help if not enough parameters are set
00043     if (argc < 3) { print_help(); exit(0); }
00044 
00045     map<string,string> ret;
00046 
00047     ret["name"] = argv[argc - 2];
00048     ret["inbox"] = argv[argc - 1];
00049 
00050     for (int i = 0; i < (argc - 2); i++)
00051     {
00052         string arg = argv[i];
00053 
00054         // print help if requested
00055         if (arg == "-h" || arg == "--help")
00056         {
00057             print_help();
00058             exit(0);
00059         }
00060 
00061         if ((arg == "-w" || arg == "--workdir") && (argc > i))
00062         {
00063             ret["workdir"] = argv[i + 1];
00064         }
00065     }
00066 
00067     return ret;
00068 }
00069 
00070 // set this variable to false to stop the app
00071 bool _running = true;
00072 
00073 // global connection
00074 ibrcommon::tcpclient *_conn = NULL;
00075 
00076 void term(int signal)
00077 {
00078     if (signal >= 1)
00079     {
00080         _running = false;
00081         if (_conn != NULL) _conn->close();
00082         exit(0);
00083     }
00084 }
00085 
00086 /*
00087  * main application method
00088  */
00089 int main(int argc, char** argv)
00090 {
00091     // catch process signals
00092     signal(SIGINT, term);
00093     signal(SIGTERM, term);
00094 
00095     // read the configuration
00096     map<string,string> conf = readconfiguration(argc, argv);
00097 
00098     // init working directory
00099     if (conf.find("workdir") != conf.end())
00100     {
00101         ibrcommon::BLOB::tmppath = File(conf["workdir"]);
00102     }
00103 
00104     // backoff for reconnect
00105     size_t backoff = 2;
00106 
00107     // check outbox for files
00108         File outbox(conf["outbox"]);
00109 
00110     // loop, if no stop if requested
00111     while (_running)
00112     {
00113         try {
00114                 // Create a stream to the server using TCP.
00115                 ibrcommon::tcpclient conn("127.0.0.1", 4550);
00116 
00117                 // enable nodelay option
00118                 conn.enableNoDelay();
00119 
00120                 // set the connection globally
00121                 _conn = &conn;
00122 
00123             // Initiate a client for synchronous receiving
00124             dtn::api::Client client(conf["name"], conn);
00125 
00126             // Connect to the server. Actually, this function initiate the
00127             // stream protocol by starting the thread and sending the contact header.
00128             client.connect();
00129 
00130             // reset backoff if connected
00131             backoff = 2;
00132 
00133             // check the connection
00134             while (_running)
00135             {
00136                 // receive the bundle
00137                 dtn::api::Bundle b = client.getBundle();
00138 
00139                 // get the reference to the blob
00140                 ibrcommon::BLOB::Reference ref = b.getData();
00141 
00142                 // create the extract command
00143                 stringstream cmdstream; cmdstream << "tar -x -C " << conf["inbox"];
00144 
00145                 // create a tar handler
00146                 appstreambuf extractor(cmdstream.str(), appstreambuf::MODE_WRITE);
00147                 ostream stream(&extractor);
00148 
00149                 // write the payload to the extractor
00150                 stream << ref.iostream()->rdbuf();
00151 
00152                 // flush the stream
00153                 stream.flush();
00154             }
00155 
00156             // close the client connection
00157             client.close();
00158 
00159             // close the connection
00160             conn.close();
00161 
00162             // set the global connection to NULL
00163             _conn = NULL;
00164         } catch (const ibrcommon::tcpclient::SocketException&) {
00165                 // set the global connection to NULL
00166                 _conn = NULL;
00167 
00168                 if (_running)
00169                 {
00170                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00171                                 sleep(backoff);
00172 
00173                                 // if backoff < 10 minutes
00174                                 if (backoff < 600)
00175                                 {
00176                                         // set a new backoff
00177                                         backoff = backoff * 2;
00178                                 }
00179                 }
00180         } catch (const ibrcommon::IOException&) {
00181                 // set the global connection to NULL
00182                 _conn = NULL;
00183 
00184                 if (_running)
00185                 {
00186                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00187                                 sleep(backoff);
00188 
00189                                 // if backoff < 10 minutes
00190                                 if (backoff < 600)
00191                                 {
00192                                         // set a new backoff
00193                                         backoff = backoff * 2;
00194                                 }
00195                 }
00196         } catch (const std::exception&) {
00197                 // set the global connection to NULL
00198                 _conn = NULL;
00199         }
00200     }
00201 
00202     return (EXIT_SUCCESS);
00203 }