IBR-DTNSuite  0.8
tools/src/dtntrigger.cpp
Go to the documentation of this file.
00001 /*
00002  * dtntrigger.cpp
00003  *
00004  *  Created on: 02.07.2010
00005  *      Author: morgenro
00006  */
00007 
00008 #include "config.h"
00009 #include <ibrdtn/api/Client.h>
00010 #include <ibrcommon/net/tcpclient.h>
00011 #include <ibrcommon/data/File.h>
00012 
00013 #include <csignal>
00014 #include <ctype.h>
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <unistd.h>
00018 
00019 
00020 // set this variable to false to stop the app
00021 bool _running = true;
00022 
00023 // global connection
00024 ibrcommon::tcpclient *_conn = NULL;
00025 
00026 std::string _appname = "trigger";
00027 std::string _script = "";
00028 std::string _shell = "/bin/sh";
00029 
00030 ibrcommon::File blob_path("/tmp");
00031 
00032 dtn::data::EID group;
00033 
00034 void print_help()
00035 {
00036         cout << "-- dtntrigger (IBR-DTN) --" << endl;
00037         cout << "Syntax: dtntrigger [options] <name> <shell> [trigger-script]"  << endl;
00038         cout << "<name>            the application name" << endl;
00039         cout << "<shell>           shell to execute the trigger script" << endl;
00040         cout << "[trigger-script]  optional: the trigger script to execute on incoming bundle" << endl;
00041         cout << "* optional parameters *" << endl;
00042         cout << " -h|--help        display this text" << endl;
00043         cout << " -g <group>       join a group" << endl;
00044         cout << " -w|--workdir     temporary work directory" << endl;
00045 }
00046 
00047 int init(int argc, char** argv)
00048 {
00049         int index;
00050         int c;
00051 
00052         opterr = 0;
00053 
00054         while ((c = getopt (argc, argv, "hw:g:")) != -1)
00055         switch (c)
00056         {
00057                 case 'w':
00058                         blob_path = ibrcommon::File(optarg);
00059                         break;
00060 
00061                 case 'g':
00062                         group = std::string(optarg);
00063                         break;
00064 
00065                 case '?':
00066                         if (optopt == 'w')
00067                         fprintf (stderr, "Option -%c requires an argument.\n", optopt);
00068                         else if (isprint (optopt))
00069                         fprintf (stderr, "Unknown option `-%c'.\n", optopt);
00070                         else
00071                         fprintf (stderr,
00072                                          "Unknown option character `\\x%x'.\n",
00073                                          optopt);
00074                         return 1;
00075 
00076                 default:
00077                         print_help();
00078                         abort();
00079                         break;
00080         }
00081 
00082         int optindex = 0;
00083         for (index = optind; index < argc; index++)
00084         {
00085                 switch (optindex)
00086                 {
00087                 case 0:
00088                         _appname = std::string(argv[index]);
00089                         break;
00090 
00091                 case 1:
00092                         _shell = std::string(argv[index]);
00093                         break;
00094 
00095                 case 2:
00096                         _script = std::string(argv[index]);
00097                         break;
00098                 }
00099 
00100                 optindex++;
00101         }
00102 
00103         // print help if not enough parameters are set
00104         if (optindex < 2) { print_help(); exit(0); }
00105 
00106         // enable file based BLOBs if a correct path is set
00107         if (blob_path.exists())
00108         {
00109                 ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path));
00110         }
00111 
00112         return 0;
00113 }
00114 
00115 void term(int signal)
00116 {
00117         if (signal >= 1)
00118         {
00119                 _running = false;
00120                 if (_conn != NULL) _conn->close();
00121         }
00122 }
00123 
00124 /*
00125  * main application method
00126  */
00127 int main(int argc, char** argv)
00128 {
00129         // catch process signals
00130         signal(SIGINT, term);
00131         signal(SIGTERM, term);
00132 
00133         // read the configuration
00134         if (init(argc, argv) > 0)
00135         {
00136                 return (EXIT_FAILURE);
00137         }
00138 
00139         // backoff for reconnect
00140         size_t backoff = 2;
00141 
00142         // loop, if no stop if requested
00143         while (_running)
00144         {
00145                 try {
00146                         // Create a stream to the server using TCP.
00147                         ibrcommon::tcpclient conn("127.0.0.1", 4550);
00148 
00149                         // enable nodelay option
00150                         conn.enableNoDelay();
00151 
00152                         // set the connection globally
00153                         _conn = &conn;
00154 
00155                         // Initiate a client for synchronous receiving
00156                         dtn::api::Client client(_appname, group, conn);
00157 
00158                         // Connect to the server. Actually, this function initiate the
00159                         // stream protocol by starting the thread and sending the contact header.
00160                         client.connect();
00161 
00162                         // reset backoff if connected
00163                         backoff = 2;
00164 
00165                         // check the connection
00166                         while (_running)
00167                         {
00168                                 // receive the bundle
00169                                 dtn::api::Bundle b = client.getBundle();
00170 
00171                                 // get the reference to the blob
00172                                 ibrcommon::BLOB::Reference ref = b.getData();
00173 
00174                                 // get a temporary file name
00175                                 ibrcommon::TemporaryFile file(blob_path, "bundle");
00176 
00177                                 // write data to temporary file
00178                                 try {
00179                                         std::fstream out(file.getPath().c_str(), ios::out|ios::binary|ios::trunc);
00180                                         out.exceptions(std::ios::badbit | std::ios::eofbit);
00181                                         out << ref.iostream()->rdbuf();
00182                                         out.close();
00183 
00184                                         // call the script
00185                                         std::string cmd = _shell + " " + _script + " " + b.getSource().getString() + " " + file.getPath();
00186                                         ::system(cmd.c_str());
00187 
00188                                         // remove temporary file
00189                                         file.remove();
00190                                 } catch (const ios_base::failure&) {
00191 
00192                                 }
00193                         }
00194 
00195                         // close the client connection
00196                         client.close();
00197 
00198                         // close the connection
00199                         conn.close();
00200 
00201                         // set the global connection to NULL
00202                         _conn = NULL;
00203                 } catch (const ibrcommon::tcpclient::SocketException&) {
00204                         // set the global connection to NULL
00205                         _conn = NULL;
00206 
00207                         if (_running)
00208                         {
00209                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00210                                 sleep(backoff);
00211 
00212                                 // if backoff < 10 minutes
00213                                 if (backoff < 600)
00214                                 {
00215                                         // set a new backoff
00216                                         backoff = backoff * 2;
00217                                 }
00218                         }
00219                 } catch (const ibrcommon::IOException &ex) {
00220                         // set the global connection to NULL
00221                         _conn = NULL;
00222 
00223                         if (_running)
00224                         {
00225                                 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
00226                                 sleep(backoff);
00227 
00228                                 // if backoff < 10 minutes
00229                                 if (backoff < 600)
00230                                 {
00231                                         // set a new backoff
00232                                         backoff = backoff * 2;
00233                                 }
00234                         }
00235                 } catch (const std::exception&) {
00236                         // set the global connection to NULL
00237                         _conn = NULL;
00238                 }
00239         }
00240 
00241         return (EXIT_SUCCESS);
00242 }