IBR-DTNSuite  0.12
dtntrigger.cpp
Go to the documentation of this file.
1 /*
2  * dtntrigger.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "config.h"
23 #include <ibrdtn/data/Bundle.h>
24 #include <ibrdtn/api/Client.h>
25 #include <ibrcommon/net/socket.h>
26 #include <ibrcommon/data/File.h>
28 
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 
34 // set this variable to false to stop the app
35 bool _running = true;
36 
37 // global connection
39 
40 std::string _appname = "trigger";
41 std::string _script = "";
42 std::string _shell = "/bin/sh";
43 
45 
47 
48 bool signed_only = false;
49 
50 void print_help()
51 {
52  cout << "-- dtntrigger (IBR-DTN) --" << endl;
53  cout << "Syntax: dtntrigger [options] <name> <shell> [trigger-script]" << endl;
54  cout << "<name> The application name" << endl;
55  cout << "<shell> Shell to execute the trigger script" << endl;
56  cout << "[trigger-script] The trigger script to execute on incoming bundle (optional)" << endl << endl;
57  cout << "* optional parameters *" << endl;
58  cout << " -h Display this text" << endl;
59  cout << " -g <group> Join a group" << endl;
60  cout << " -w Temporary work directory" << endl;
61  cout << " -s Process signed bundles only" << endl;
62 }
63 
64 int init(int argc, char** argv)
65 {
66  int index;
67  int c;
68 
69  opterr = 0;
70 
71  while ((c = getopt (argc, argv, "hw:g:s")) != -1)
72  switch (c)
73  {
74  case 'w':
75  blob_path = ibrcommon::File(optarg);
76  break;
77 
78  case 'g':
79  group = std::string(optarg);
80  break;
81 
82  case '?':
83  if (optopt == 'w')
84  fprintf (stderr, "Option -%c requires an argument.\n", optopt);
85  else if (isprint (optopt))
86  fprintf (stderr, "Unknown option `-%c'.\n", optopt);
87  else
88  fprintf (stderr,
89  "Unknown option character `\\x%x'.\n",
90  optopt);
91  return 1;
92 
93  case 's':
94  signed_only = true;
95  break;
96 
97  default:
98  print_help();
99  return 1;
100  }
101 
102  int optindex = 0;
103  for (index = optind; index < argc; ++index)
104  {
105  switch (optindex)
106  {
107  case 0:
108  _appname = std::string(argv[index]);
109  break;
110 
111  case 1:
112  _shell = std::string(argv[index]);
113  break;
114 
115  case 2:
116  _script = std::string(argv[index]);
117  break;
118  }
119 
120  optindex++;
121  }
122 
123  // print help if not enough parameters are set
124  if (optindex < 2) { print_help(); exit(0); }
125 
126  // enable file based BLOBs if a correct path is set
127  if (blob_path.exists())
128  {
130  }
131 
132  return 0;
133 }
134 
135 void term(int signal)
136 {
137  if (signal >= 1)
138  {
139  _running = false;
140  if (_conn != NULL) _conn->close();
141  }
142 }
143 
144 /*
145  * main application method
146  */
147 int main(int argc, char** argv)
148 {
149  // catch process signals
150  ibrcommon::SignalHandler sighandler(term);
151  sighandler.handle(SIGINT);
152  sighandler.handle(SIGTERM);
153 
154  // read the configuration
155  if (init(argc, argv) > 0)
156  {
157  return (EXIT_FAILURE);
158  }
159 
160  //initialize sighandler after possible exit call
161  sighandler.initialize();
162 
163  // backoff for reconnect
164  unsigned int backoff = 2;
165 
166  // loop, if no stop if requested
167  while (_running)
168  {
169  try {
170  // Create a stream to the server using TCP.
171  ibrcommon::vaddress addr("localhost", 4550);
173 
174  // set the connection globally
175  _conn = &conn;
176 
177  // Initiate a client for synchronous receiving
178  dtn::api::Client client(_appname, group, conn);
179 
180  // Connect to the server. Actually, this function initiate the
181  // stream protocol by starting the thread and sending the contact header.
182  client.connect();
183 
184  // reset backoff if connected
185  backoff = 2;
186 
187  // check the connection
188  while (_running)
189  {
190  // receive the bundle
191  dtn::data::Bundle b = client.getBundle();
192 
193  // skip non-signed bundles if we should accept signed bundles only
195 
196  // get the reference to the blob
198 
199  // get a temporary file name
200  ibrcommon::TemporaryFile file(blob_path, "bundle");
201 
202  // write data to temporary file
203  try {
204  std::fstream out(file.getPath().c_str(), ios::out|ios::binary|ios::trunc);
205  out.exceptions(std::ios::badbit | std::ios::eofbit);
206  out << ref.iostream()->rdbuf();
207  out.close();
208 
209  // call the script
210  std::string cmd = _shell + " " + _script + " " + b.source.getString() + " " + file.getPath();
211  ::system(cmd.c_str());
212 
213  // remove temporary file
214  file.remove();
215  } catch (const ios_base::failure&) {
216 
217  }
218  }
219 
220  // close the client connection
221  client.close();
222 
223  // close the connection
224  conn.close();
225 
226  // set the global connection to NULL
227  _conn = NULL;
228  } catch (const ibrcommon::socket_exception&) {
229  // set the global connection to NULL
230  _conn = NULL;
231 
232  if (_running)
233  {
234  cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
235  ibrcommon::Thread::sleep(backoff * 1000);
236 
237  // if backoff < 10 minutes
238  if (backoff < 600)
239  {
240  // set a new backoff
241  backoff = backoff * 2;
242  }
243  }
244  } catch (const ibrcommon::IOException &ex) {
245  // set the global connection to NULL
246  _conn = NULL;
247 
248  if (_running)
249  {
250  cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
251  ibrcommon::Thread::sleep(backoff * 1000);
252 
253  // if backoff < 10 minutes
254  if (backoff < 600)
255  {
256  // set a new backoff
257  backoff = backoff * 2;
258  }
259  }
260  } catch (const std::exception&) {
261  // set the global connection to NULL
262  _conn = NULL;
263  }
264  }
265 
266  return (EXIT_SUCCESS);
267 }