IBR-DTNSuite  0.10
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>
27 
28 #include <csignal>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 
34 
35 // set this variable to false to stop the app
36 bool _running = true;
37 
38 // global connection
40 
41 std::string _appname = "trigger";
42 std::string _script = "";
43 std::string _shell = "/bin/sh";
44 
46 
48 
49 bool signed_only = false;
50 
51 void print_help()
52 {
53  cout << "-- dtntrigger (IBR-DTN) --" << endl;
54  cout << "Syntax: dtntrigger [options] <name> <shell> [trigger-script]" << endl;
55  cout << "<name> the application name" << endl;
56  cout << "<shell> shell to execute the trigger script" << endl;
57  cout << "[trigger-script] optional: the trigger script to execute on incoming bundle" << endl;
58  cout << "* optional parameters *" << endl;
59  cout << " -h display this text" << endl;
60  cout << " -g <group> join a group" << endl;
61  cout << " -w temporary work directory" << endl;
62  cout << " -s process signed bundles only" << endl;
63 }
64 
65 int init(int argc, char** argv)
66 {
67  int index;
68  int c;
69 
70  opterr = 0;
71 
72  while ((c = getopt (argc, argv, "hw:g:s")) != -1)
73  switch (c)
74  {
75  case 'w':
76  blob_path = ibrcommon::File(optarg);
77  break;
78 
79  case 'g':
80  group = std::string(optarg);
81  break;
82 
83  case '?':
84  if (optopt == 'w')
85  fprintf (stderr, "Option -%c requires an argument.\n", optopt);
86  else if (isprint (optopt))
87  fprintf (stderr, "Unknown option `-%c'.\n", optopt);
88  else
89  fprintf (stderr,
90  "Unknown option character `\\x%x'.\n",
91  optopt);
92  return 1;
93 
94  case 's':
95  signed_only = true;
96  break;
97 
98  default:
99  print_help();
100  return 1;
101  }
102 
103  int optindex = 0;
104  for (index = optind; index < argc; ++index)
105  {
106  switch (optindex)
107  {
108  case 0:
109  _appname = std::string(argv[index]);
110  break;
111 
112  case 1:
113  _shell = std::string(argv[index]);
114  break;
115 
116  case 2:
117  _script = std::string(argv[index]);
118  break;
119  }
120 
121  optindex++;
122  }
123 
124  // print help if not enough parameters are set
125  if (optindex < 2) { print_help(); exit(0); }
126 
127  // enable file based BLOBs if a correct path is set
128  if (blob_path.exists())
129  {
131  }
132 
133  return 0;
134 }
135 
136 void term(int signal)
137 {
138  if (signal >= 1)
139  {
140  _running = false;
141  if (_conn != NULL) _conn->close();
142  }
143 }
144 
145 /*
146  * main application method
147  */
148 int main(int argc, char** argv)
149 {
150  // catch process signals
151  signal(SIGINT, term);
152  signal(SIGTERM, term);
153 
154  // read the configuration
155  if (init(argc, argv) > 0)
156  {
157  return (EXIT_FAILURE);
158  }
159 
160  // backoff for reconnect
161  unsigned int backoff = 2;
162 
163  // loop, if no stop if requested
164  while (_running)
165  {
166  try {
167  // Create a stream to the server using TCP.
168  ibrcommon::vaddress addr("localhost", 4550);
170 
171  // set the connection globally
172  _conn = &conn;
173 
174  // Initiate a client for synchronous receiving
175  dtn::api::Client client(_appname, group, conn);
176 
177  // Connect to the server. Actually, this function initiate the
178  // stream protocol by starting the thread and sending the contact header.
179  client.connect();
180 
181  // reset backoff if connected
182  backoff = 2;
183 
184  // check the connection
185  while (_running)
186  {
187  // receive the bundle
188  dtn::data::Bundle b = client.getBundle();
189 
190  // skip non-signed bundles if we should accept signed bundles only
192 
193  // get the reference to the blob
195 
196  // get a temporary file name
197  ibrcommon::TemporaryFile file(blob_path, "bundle");
198 
199  // write data to temporary file
200  try {
201  std::fstream out(file.getPath().c_str(), ios::out|ios::binary|ios::trunc);
202  out.exceptions(std::ios::badbit | std::ios::eofbit);
203  out << ref.iostream()->rdbuf();
204  out.close();
205 
206  // call the script
207  std::string cmd = _shell + " " + _script + " " + b.source.getString() + " " + file.getPath();
208  ::system(cmd.c_str());
209 
210  // remove temporary file
211  file.remove();
212  } catch (const ios_base::failure&) {
213 
214  }
215  }
216 
217  // close the client connection
218  client.close();
219 
220  // close the connection
221  conn.close();
222 
223  // set the global connection to NULL
224  _conn = NULL;
225  } catch (const ibrcommon::socket_exception&) {
226  // set the global connection to NULL
227  _conn = NULL;
228 
229  if (_running)
230  {
231  cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
232  sleep(backoff);
233 
234  // if backoff < 10 minutes
235  if (backoff < 600)
236  {
237  // set a new backoff
238  backoff = backoff * 2;
239  }
240  }
241  } catch (const ibrcommon::IOException &ex) {
242  // set the global connection to NULL
243  _conn = NULL;
244 
245  if (_running)
246  {
247  cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
248  sleep(backoff);
249 
250  // if backoff < 10 minutes
251  if (backoff < 600)
252  {
253  // set a new backoff
254  backoff = backoff * 2;
255  }
256  }
257  } catch (const std::exception&) {
258  // set the global connection to NULL
259  _conn = NULL;
260  }
261  }
262 
263  return (EXIT_SUCCESS);
264 }