IBR-DTNSuite 0.6

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