IBR-DTNSuite  0.10
dtnoutbox.cpp
Go to the documentation of this file.
1 /*
2  * dtnoutbox.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/api/Client.h"
24 #include "ibrcommon/net/socket.h"
25 #include "ibrcommon/thread/Mutex.h"
28 #include "ibrcommon/data/BLOB.h"
29 #include "ibrcommon/data/File.h"
30 #include "ibrcommon/appstreambuf.h"
31 
32 #include <stdlib.h>
33 #include <iostream>
34 #include <map>
35 #include <vector>
36 #include <csignal>
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 using namespace ibrcommon;
41 
42 void print_help()
43 {
44  cout << "-- dtnoutbox (IBR-DTN) --" << endl;
45  cout << "Syntax: dtnoutbox [options] <name> <outbox> <destination>" << endl;
46  cout << " <name> the application name" << endl;
47  cout << " <outbox> directory with outgoing files" << endl;
48  cout << " <destination> the destination EID for all outgoing files" << endl;
49  cout << "* optional parameters *" << endl;
50  cout << " -h|--help display this text" << endl;
51  cout << " -w|--workdir temporary work directory" << endl;
52 }
53 
54 map<string,string> readconfiguration(int argc, char** argv)
55 {
56  // print help if not enough parameters are set
57  if (argc < 4) { print_help(); exit(0); }
58 
59  map<string,string> ret;
60 
61  ret["name"] = argv[argc - 3];
62  ret["outbox"] = argv[argc - 2];
63  ret["destination"] = argv[argc - 1];
64 
65  for (int i = 0; i < (argc - 3); ++i)
66  {
67  string arg = argv[i];
68 
69  // print help if requested
70  if (arg == "-h" || arg == "--help")
71  {
72  print_help();
73  exit(0);
74  }
75 
76  if ((arg == "-w" || arg == "--workdir") && (argc > i))
77  {
78  ret["workdir"] = argv[i + 1];
79  }
80  }
81 
82  return ret;
83 }
84 
85 // set this variable to false to stop the app
86 bool _running = true;
87 
88 // global connection
90 
91 void term(int signal)
92 {
93  if (signal >= 1)
94  {
95  _running = false;
96  if (_conn != NULL) _conn->close();
97  }
98 }
99 
100 /*
101  * main application method
102  */
103 int main(int argc, char** argv)
104 {
105  // catch process signals
106  signal(SIGINT, term);
107  signal(SIGTERM, term);
108 
109  // read the configuration
110  map<string,string> conf = readconfiguration(argc, argv);
111 
112  // init working directory
113  if (conf.find("workdir") != conf.end())
114  {
115  ibrcommon::File blob_path(conf["workdir"]);
116 
117  if (blob_path.exists())
118  {
120  }
121  }
122 
123  // backoff for reconnect
124  unsigned int backoff = 2;
125 
126  // check outbox for files
127  File outbox(conf["outbox"]);
128 
129  // loop, if no stop if requested
130  while (_running)
131  {
132  try {
133  // Create a stream to the server using TCP.
134  ibrcommon::vaddress addr("localhost", 4550);
136 
137  // set the connection globally
138  _conn = &conn;
139 
140  // Initiate a client for synchronous receiving
141  dtn::api::Client client(conf["name"], conn, dtn::api::Client::MODE_SENDONLY);
142 
143  // Connect to the server. Actually, this function initiate the
144  // stream protocol by starting the thread and sending the contact header.
145  client.connect();
146 
147  // reset backoff if connected
148  backoff = 2;
149 
150  // check the connection
151  while (_running)
152  {
153  list<File> files;
154  outbox.getFiles(files);
155 
156  // <= 2 because of "." and ".."
157  if (files.size() <= 2)
158  {
159  // wait some seconds
160  sleep(10);
161 
162  continue;
163  }
164 
165  stringstream file_list;
166 
167  for (list<File>::iterator iter = files.begin(); iter != files.end(); ++iter)
168  {
169  File &f = (*iter);
170 
171  // skip system files ("." and "..")
172  if (f.isSystem()) continue;
173 
174  // add the file to the filelist
175  file_list << f.getBasename() << " ";
176  }
177 
178  // output of all files to send
179  cout << "files: " << file_list.str() << endl;
180 
181  // "--remove-files" deletes files after adding
182  stringstream cmd; cmd << "tar --remove-files -cO -C " << outbox.getPath() << " " << file_list.str();
183 
184  // make a tar archive
185  appstreambuf app(cmd.str(), appstreambuf::MODE_READ);
186  istream stream(&app);
187 
188  // create a blob
190 
191  // stream the content of "tar" to the payload block
192  (*blob.iostream()) << stream.rdbuf();
193 
194  // create a new bundle
195  dtn::data::EID destination = EID(conf["destination"]);
196 
197  // create a new bundle
199 
200  // set destination
201  b.destination = destination;
202 
203  // add payload block using the blob
204  b.push_back(blob);
205 
206  // send the bundle
207  client << b; client.flush();
208 
209  if (_running)
210  {
211  // wait some seconds
212  sleep(10);
213  }
214  }
215 
216  // close the client connection
217  client.close();
218 
219  // close the connection
220  conn.close();
221 
222  // set the global connection to NULL
223  _conn = NULL;
224  } catch (const ibrcommon::socket_exception&) {
225  // set the global connection to NULL
226  _conn = NULL;
227 
228  if (_running)
229  {
230  cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
231  sleep(backoff);
232 
233  // if backoff < 10 minutes
234  if (backoff < 600)
235  {
236  // set a new backoff
237  backoff = backoff * 2;
238  }
239  }
240  } catch (const ibrcommon::IOException&) {
241  // set the global connection to NULL
242  _conn = NULL;
243 
244  if (_running)
245  {
246  cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl;
247  sleep(backoff);
248 
249  // if backoff < 10 minutes
250  if (backoff < 600)
251  {
252  // set a new backoff
253  backoff = backoff * 2;
254  }
255  }
256  } catch (const std::exception&) {
257  // set the global connection to NULL
258  _conn = NULL;
259  }
260  }
261 
262  return (EXIT_SUCCESS);
263 }