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