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