IBR-DTNSuite  0.8
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 #include <unistd.h>
00027 
00028 using namespace ibrcommon;
00029 
00030 void print_help()
00031 {
00032         cout << "-- dtninbox (IBR-DTN) --" << endl;
00033         cout << "Syntax: dtninbox [options] <name> <inbox>"  << endl;
00034         cout << " <name>           the application name" << endl;
00035         cout << " <inbox>          directory where incoming files should be placed" << endl;
00036         cout << "* optional parameters *" << endl;
00037         cout << " -h|--help        display this text" << endl;
00038         cout << " -w|--workdir     temporary work directory" << endl;
00039 }
00040 
00041 map<string,string> readconfiguration(int argc, char** argv)
00042 {
00043     // print help if not enough parameters are set
00044     if (argc < 3) { print_help(); exit(0); }
00045 
00046     map<string,string> ret;
00047 
00048     ret["name"] = argv[argc - 2];
00049     ret["inbox"] = argv[argc - 1];
00050 
00051     for (int i = 0; i < (argc - 2); i++)
00052     {
00053         string arg = argv[i];
00054 
00055         // print help if requested
00056         if (arg == "-h" || arg == "--help")
00057         {
00058             print_help();
00059             exit(0);
00060         }
00061 
00062         if ((arg == "-w" || arg == "--workdir") && (argc > i))
00063         {
00064             ret["workdir"] = argv[i + 1];
00065         }
00066     }
00067 
00068     return ret;
00069 }
00070 
00071 // set this variable to false to stop the app
00072 bool _running = true;
00073 
00074 // global connection
00075 ibrcommon::tcpclient *_conn = NULL;
00076 
00077 void term(int signal)
00078 {
00079     if (signal >= 1)
00080     {
00081         _running = false;
00082         if (_conn != NULL) _conn->close();
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::File blob_path(conf["workdir"]);
00102 
00103         if (blob_path.exists())
00104         {
00105                 ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), true);
00106         }
00107     }
00108 
00109     // backoff for reconnect
00110     size_t backoff = 2;
00111 
00112     // check outbox for files
00113         File outbox(conf["outbox"]);
00114 
00115     // loop, if no stop if requested
00116     while (_running)
00117     {
00118         try {
00119                 // Create a stream to the server using TCP.
00120                 ibrcommon::tcpclient conn("127.0.0.1", 4550);
00121 
00122                 // enable nodelay option
00123                 conn.enableNoDelay();
00124 
00125                 // set the connection globally
00126                 _conn = &conn;
00127 
00128             // Initiate a client for synchronous receiving
00129             dtn::api::Client client(conf["name"], conn);
00130 
00131             // Connect to the server. Actually, this function initiate the
00132             // stream protocol by starting the thread and sending the contact header.
00133             client.connect();
00134 
00135             // reset backoff if connected
00136             backoff = 2;
00137 
00138             // check the connection
00139             while (_running)
00140             {
00141                 // receive the bundle
00142                 dtn::api::Bundle b = client.getBundle();
00143 
00144                 // get the reference to the blob
00145                 ibrcommon::BLOB::Reference ref = b.getData();
00146 
00147                 // create the extract command
00148                 stringstream cmdstream; cmdstream << "tar -x -C " << conf["inbox"];
00149 
00150                 // create a tar handler
00151                 appstreambuf extractor(cmdstream.str(), appstreambuf::MODE_WRITE);
00152                 ostream stream(&extractor);
00153 
00154                 // write the payload to the extractor
00155                 stream << ref.iostream()->rdbuf();
00156 
00157                 // flush the stream
00158                 stream.flush();
00159             }
00160 
00161             // close the client connection
00162             client.close();
00163 
00164             // close the connection
00165             conn.close();
00166 
00167             // set the global connection to NULL
00168             _conn = NULL;
00169         } catch (const ibrcommon::tcpclient::SocketException&) {
00170                 // set the global connection to NULL
00171                 _conn = NULL;
00172 
00173                 if (_running)
00174                 {
00175                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00176                                 sleep(backoff);
00177 
00178                                 // if backoff < 10 minutes
00179                                 if (backoff < 600)
00180                                 {
00181                                         // set a new backoff
00182                                         backoff = backoff * 2;
00183                                 }
00184                 }
00185         } catch (const ibrcommon::IOException&) {
00186                 // set the global connection to NULL
00187                 _conn = NULL;
00188 
00189                 if (_running)
00190                 {
00191                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00192                                 sleep(backoff);
00193 
00194                                 // if backoff < 10 minutes
00195                                 if (backoff < 600)
00196                                 {
00197                                         // set a new backoff
00198                                         backoff = backoff * 2;
00199                                 }
00200                 }
00201         } catch (const std::exception&) {
00202                 // set the global connection to NULL
00203                 _conn = NULL;
00204         }
00205     }
00206 
00207     return (EXIT_SUCCESS);
00208 }