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     }
00083 }
00084 
00085 /*
00086  * main application method
00087  */
00088 int main(int argc, char** argv)
00089 {
00090     // catch process signals
00091     signal(SIGINT, term);
00092     signal(SIGTERM, term);
00093 
00094     // read the configuration
00095     map<string,string> conf = readconfiguration(argc, argv);
00096 
00097     // init working directory
00098     if (conf.find("workdir") != conf.end())
00099     {
00100         ibrcommon::File blob_path(conf["workdir"]);
00101 
00102         if (blob_path.exists())
00103         {
00104                 ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), true);
00105         }
00106     }
00107 
00108     // backoff for reconnect
00109     size_t backoff = 2;
00110 
00111     // check outbox for files
00112         File outbox(conf["outbox"]);
00113 
00114     // loop, if no stop if requested
00115     while (_running)
00116     {
00117         try {
00118                 // Create a stream to the server using TCP.
00119                 ibrcommon::tcpclient conn("127.0.0.1", 4550);
00120 
00121                 // enable nodelay option
00122                 conn.enableNoDelay();
00123 
00124                 // set the connection globally
00125                 _conn = &conn;
00126 
00127             // Initiate a client for synchronous receiving
00128             dtn::api::Client client(conf["name"], conn);
00129 
00130             // Connect to the server. Actually, this function initiate the
00131             // stream protocol by starting the thread and sending the contact header.
00132             client.connect();
00133 
00134             // reset backoff if connected
00135             backoff = 2;
00136 
00137             // check the connection
00138             while (_running)
00139             {
00140                 // receive the bundle
00141                 dtn::api::Bundle b = client.getBundle();
00142 
00143                 // get the reference to the blob
00144                 ibrcommon::BLOB::Reference ref = b.getData();
00145 
00146                 // create the extract command
00147                 stringstream cmdstream; cmdstream << "tar -x -C " << conf["inbox"];
00148 
00149                 // create a tar handler
00150                 appstreambuf extractor(cmdstream.str(), appstreambuf::MODE_WRITE);
00151                 ostream stream(&extractor);
00152 
00153                 // write the payload to the extractor
00154                 stream << ref.iostream()->rdbuf();
00155 
00156                 // flush the stream
00157                 stream.flush();
00158             }
00159 
00160             // close the client connection
00161             client.close();
00162 
00163             // close the connection
00164             conn.close();
00165 
00166             // set the global connection to NULL
00167             _conn = NULL;
00168         } catch (const ibrcommon::tcpclient::SocketException&) {
00169                 // set the global connection to NULL
00170                 _conn = NULL;
00171 
00172                 if (_running)
00173                 {
00174                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00175                                 sleep(backoff);
00176 
00177                                 // if backoff < 10 minutes
00178                                 if (backoff < 600)
00179                                 {
00180                                         // set a new backoff
00181                                         backoff = backoff * 2;
00182                                 }
00183                 }
00184         } catch (const ibrcommon::IOException&) {
00185                 // set the global connection to NULL
00186                 _conn = NULL;
00187 
00188                 if (_running)
00189                 {
00190                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00191                                 sleep(backoff);
00192 
00193                                 // if backoff < 10 minutes
00194                                 if (backoff < 600)
00195                                 {
00196                                         // set a new backoff
00197                                         backoff = backoff * 2;
00198                                 }
00199                 }
00200         } catch (const std::exception&) {
00201                 // set the global connection to NULL
00202                 _conn = NULL;
00203         }
00204     }
00205 
00206     return (EXIT_SUCCESS);
00207 }