IBR-DTNSuite 0.6

tools/src/dtnoutbox.cpp

Go to the documentation of this file.
00001 /*
00002  * dtnoutbox.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/api/BLOBBundle.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 << "-- dtnoutbox (IBR-DTN) --" << endl;
00032         cout << "Syntax: dtnoutbox [options] <name> <outbox> <destination>"  << endl;
00033         cout << " <name>           the application name" << endl;
00034         cout << " <outbox>         directory with outgoing files" << endl;
00035         cout << " <destination>    the destination EID for all outgoing files" << 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 < 4) { print_help(); exit(0); }
00045 
00046     map<string,string> ret;
00047 
00048     ret["name"] = argv[argc - 3];
00049     ret["outbox"] = argv[argc - 2];
00050     ret["destination"] = argv[argc - 1];
00051 
00052     for (int i = 0; i < (argc - 3); i++)
00053     {
00054         string arg = argv[i];
00055 
00056         // print help if requested
00057         if (arg == "-h" || arg == "--help")
00058         {
00059             print_help();
00060             exit(0);
00061         }
00062 
00063         if ((arg == "-w" || arg == "--workdir") && (argc > i))
00064         {
00065             ret["workdir"] = argv[i + 1];
00066         }
00067     }
00068 
00069     return ret;
00070 }
00071 
00072 // set this variable to false to stop the app
00073 bool _running = true;
00074 
00075 // global connection
00076 ibrcommon::tcpclient *_conn = NULL;
00077 
00078 void term(int signal)
00079 {
00080     if (signal >= 1)
00081     {
00082         _running = false;
00083         if (_conn != NULL) _conn->close();
00084     }
00085 }
00086 
00087 /*
00088  * main application method
00089  */
00090 int main(int argc, char** argv)
00091 {
00092     // catch process signals
00093     signal(SIGINT, term);
00094     signal(SIGTERM, term);
00095 
00096     // read the configuration
00097     map<string,string> conf = readconfiguration(argc, argv);
00098 
00099     // init working directory
00100     if (conf.find("workdir") != conf.end())
00101     {
00102         ibrcommon::File blob_path(conf["workdir"]);
00103 
00104         if (blob_path.exists())
00105         {
00106                 ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), true);
00107         }
00108     }
00109 
00110     // backoff for reconnect
00111     size_t backoff = 2;
00112 
00113     // check outbox for files
00114         File outbox(conf["outbox"]);
00115 
00116     // loop, if no stop if requested
00117     while (_running)
00118     {
00119         try {
00120                 // Create a stream to the server using TCP.
00121                 ibrcommon::tcpclient conn("127.0.0.1", 4550);
00122 
00123                 // enable nodelay option
00124                 conn.enableNoDelay();
00125 
00126                 // set the connection globally
00127                 _conn = &conn;
00128 
00129             // Initiate a client for synchronous receiving
00130             dtn::api::Client client(conf["name"], conn, dtn::api::Client::MODE_SENDONLY);
00131 
00132             // Connect to the server. Actually, this function initiate the
00133             // stream protocol by starting the thread and sending the contact header.
00134             client.connect();
00135 
00136             // reset backoff if connected
00137             backoff = 2;
00138 
00139             // check the connection
00140             while (_running)
00141             {
00142                 list<File> files;
00143                 outbox.getFiles(files);
00144 
00145                 // <= 2 because of "." and ".."
00146                 if (files.size() <= 2)
00147                 {
00148                     // wait some seconds
00149                     sleep(10);
00150 
00151                     continue;
00152                 }
00153 
00154                 stringstream file_list;
00155 
00156                 int prefix_length = outbox.getPath().length() + 1;
00157 
00158                 for (list<File>::iterator iter = files.begin(); iter != files.end(); iter++)
00159                 {
00160                         File &f = (*iter);
00161 
00162                         // skip system files ("." and "..")
00163                         if (f.isSystem()) continue;
00164 
00165                                         // remove the prefix of the outbox path
00166                         string rpath = f.getPath();
00167                         rpath = rpath.substr(prefix_length, rpath.length() - prefix_length);
00168 
00169                         file_list << rpath << " ";
00170                 }
00171 
00172                 // output of all files to send
00173                 cout << "files: " << file_list.str() << endl;
00174 
00175                 // "--remove-files" deletes files after adding
00176                 stringstream cmd; cmd << "tar --remove-files -cO -C " << outbox.getPath() << " " << file_list.str();
00177 
00178                 // make a tar archive
00179                 appstreambuf app(cmd.str(), appstreambuf::MODE_READ);
00180                 istream stream(&app);
00181 
00182                         // create a blob
00183                 ibrcommon::BLOB::Reference blob = ibrcommon::BLOB::create();
00184 
00185                         // stream the content of "tar" to the payload block
00186                         (*blob.iostream()) << stream.rdbuf();
00187 
00188                 // create a new bundle
00189                         dtn::data::EID destination = EID(conf["destination"]);
00190                         dtn::api::BLOBBundle b(destination, blob);
00191 
00192                 // send the bundle
00193                         client << b; client.flush();
00194 
00195                 if (_running)
00196                 {
00197                                         // wait some seconds
00198                                         sleep(10);
00199                 }
00200             }
00201 
00202             // close the client connection
00203             client.close();
00204 
00205             // close the connection
00206             conn.close();
00207 
00208             // set the global connection to NULL
00209             _conn = NULL;
00210         } catch (const ibrcommon::tcpclient::SocketException&) {
00211                 // set the global connection to NULL
00212                 _conn = NULL;
00213 
00214                 if (_running)
00215                 {
00216                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00217                                 sleep(backoff);
00218 
00219                                 // if backoff < 10 minutes
00220                                 if (backoff < 600)
00221                                 {
00222                                         // set a new backoff
00223                                         backoff = backoff * 2;
00224                                 }
00225                 }
00226         } catch (const ibrcommon::IOException&) {
00227                 // set the global connection to NULL
00228                 _conn = NULL;
00229 
00230                 if (_running)
00231                 {
00232                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00233                                 sleep(backoff);
00234 
00235                                 // if backoff < 10 minutes
00236                                 if (backoff < 600)
00237                                 {
00238                                         // set a new backoff
00239                                         backoff = backoff * 2;
00240                                 }
00241                 }
00242         } catch (const std::exception&) {
00243                 // set the global connection to NULL
00244                 _conn = NULL;
00245         }
00246     }
00247 
00248     return (EXIT_SUCCESS);
00249 }