25 #include <ibrcommon/net/socket.h>
26 #include <ibrcommon/thread/Mutex.h>
27 #include <ibrcommon/thread/MutexLock.h>
28 #include <ibrcommon/thread/SignalHandler.h>
30 #include <ibrcommon/data/BLOB.h>
31 #include <ibrcommon/data/File.h>
32 #include <ibrcommon/appstreambuf.h>
33 #include <ibrcommon/Logger.h>
46 #include <sys/types.h>
52 typedef std::set<io::ObservedFile>
fileset;
62 const std::string
TAG =
"dtnoutbox";
67 : interval(5000), rounds(3), path(
"/"), regex_str(
"^\\."),
68 bundle_group(
false), invert(
false), quiet(
false), verbose(
false), fat(
false), enabled(
true)
81 std::string regex_str;
95 {
"destination", required_argument, 0,
'd'},
96 {
"help", no_argument, 0,
'h'},
97 {
"group", no_argument, 0,
'g'},
98 {
"workdir", required_argument, 0,
'w'},
99 {
"interval", required_argument, 0,
'i'},
100 {
"rounds", required_argument, 0,
'r'},
101 {
"path", required_argument, 0,
'p'},
102 {
"regex", required_argument, 0,
'R'},
103 {
"quiet", no_argument, 0,
'q'},
104 {
"verbose", no_argument, 0,
'v'},
112 const unsigned char logopts = 0;
115 const unsigned char logerr = ibrcommon::Logger::LOGGER_ERR | ibrcommon::Logger::LOGGER_CRIT;
118 const unsigned char logstd = ibrcommon::Logger::LOGGER_ALL ^ (ibrcommon::Logger::LOGGER_DEBUG |
logerr);
121 const unsigned char logsys = ibrcommon::Logger::LOGGER_ALL ^ (ibrcommon::Logger::LOGGER_DEBUG | ibrcommon::Logger::LOGGER_NOTICE);
123 const unsigned char logall = ibrcommon::Logger::LOGGER_ALL;
128 ibrcommon::Logger::addStream(std::cout, logsys, logopts);
131 ibrcommon::Logger::addStream(std::cout, logall, logopts);
136 ibrcommon::Logger::addStream(std::cerr, logerr, logopts);
141 std::cout <<
"-- dtnoutbox (IBR-DTN) --" << std::endl;
142 std::cout <<
"Syntax: dtnoutbox [options] <name> <outbox> <destination>" << std::endl;
143 std::cout <<
" <name> The application name" << std::endl;
145 std::cout <<
" <outbox> Location of outgoing files, directory or vfat-image" << std::endl;
147 std::cout <<
" <outbox> Directory of outgoing files" << std::endl;
149 std::cout <<
" <destination> The destination EID for all outgoing files" << std::endl << std::endl;
150 std::cout <<
"* optional parameters *" << std::endl;
151 std::cout <<
" -h|--help Display this text" << std::endl;
152 std::cout <<
" -g|--group Receiver is a destination group" << std::endl;
153 std::cout <<
" -w|--workdir <dir>" << std::endl;
154 std::cout <<
" Temporary work directory" << std::endl;
155 std::cout <<
" -i|--interval <milliseconds>" << std::endl;
156 std::cout <<
" Interval in milliseconds, in which <outbox> is scanned" << std::endl;
157 std::cout <<
" for new/changed files. default: 5000" << std::endl;
158 std::cout <<
" -r|--rounds <n> Number of rounds of intervals, after which a unchanged" << std::endl;
159 std::cout <<
" file is considered as written. default: 3" << std::endl;
161 std::cout <<
" -p|--path <path> Path of outbox within vfat-image. default: /" << std::endl;
163 std::cout <<
" -R|--regex <regex>" << std::endl;
164 std::cout <<
" All files in <outbox> matching this regular expression" << std::endl;
165 std::cout <<
" will be ignored. default: ^\\." << std::endl;
166 std::cout <<
" -I|--invert Invert the regular expression defined with -R"<< std::endl;
167 std::cout <<
" -q|--quiet Only print error messages" << std::endl;
168 std::cout <<
" -v|--verbose print more verbose info messages, only works without -q" << std::endl;
179 int option_index = 0;
180 int c = getopt_long (argc, argv,
"hw:i:r:p:R:qvIg",
194 printf (
" with arg %s", optarg);
203 conf.bundle_group =
true;
206 conf.workdir = std::string(optarg);
209 conf.interval = atoi(optarg);
212 conf.rounds = atoi(optarg);
215 conf.path = std::string(optarg);
218 conf.regex_str = std::string(optarg);
238 if ((argc - optind) < 3)
244 conf.name = std::string(argv[optind]);
245 conf.destination = std::string(argv[optind+2]);
246 conf.outbox = std::string(argv[optind+1]);
249 if (conf.regex_str.length() > 0 && regcomp(&conf.regex,conf.regex_str.c_str(),0))
251 IBRCOMMON_LOGGER_TAG(
TAG,error) <<
"ERROR: invalid regex: " << optarg << IBRCOMMON_LOGGER_ENDL;
257 if (conf.outbox.at(conf.outbox.length()-1) ==
'/')
258 conf.outbox = conf.outbox.substr(0,conf.outbox.length() -1);
263 IBRCOMMON_LOGGER_TAG(
TAG,notice) <<
"got signal " << signal << IBRCOMMON_LOGGER_ENDL;
293 int main(
int argc,
char** argv )
297 sighandler.handle(SIGINT);
298 sighandler.handle(SIGTERM);
300 sighandler.handle(SIGUSR1);
312 sighandler.initialize();
315 if (conf.workdir.length() > 0)
319 if (blob_path.exists())
321 ibrcommon::BLOB::changeProvider(
new ibrcommon::FileBLOBProvider(blob_path),
true);
326 unsigned int backoff = 2;
328 ibrcommon::File outbox_file(conf.outbox);
331 fileset new_files, prev_files, deleted_files, files_to_send;
342 if (outbox_file.exists() && !outbox_file.isDirectory())
347 const io::FATFile fat_root(*imagereader, conf.path);
350 IBRCOMMON_LOGGER_TAG(
TAG,error) <<
"ERROR: image-file provided, but this tool has been compiled without libtffs support!" << IBRCOMMON_LOGGER_ENDL;
356 if (!outbox_file.exists()) {
357 ibrcommon::File::createDirectory(outbox_file);
362 IBRCOMMON_LOGGER_TAG(
TAG,info) <<
"-- dtnoutbox --" << IBRCOMMON_LOGGER_ENDL;
370 ibrcommon::vaddress addr(
"localhost", 4550);
371 ibrcommon::socketstream conn(
new ibrcommon::tcpsocket(addr));
392 std::set_difference(prev_files.begin(), prev_files.end(), current_files.begin(), current_files.end(), std::inserter(deleted_files, deleted_files.begin()));
395 for (fileset::const_iterator iter = deleted_files.begin(); iter != deleted_files.end(); ++iter)
400 for (hashlist::iterator hash_it = sent_hashes.begin(); hash_it != sent_hashes.end(); ) {
401 if ((*hash_it).getPath() == deletedFile.
getFile().getPath()) {
402 sent_hashes.erase(hash_it++);
409 observed_files.remove(deletedFile);
412 IBRCOMMON_LOGGER_TAG(
TAG,info) <<
"file removed: " << deletedFile.
getFile().getBasename() << IBRCOMMON_LOGGER_ENDL;
417 std::set_difference(current_files.begin(), current_files.end(), prev_files.begin(), prev_files.end(), std::inserter(new_files, new_files.begin()));
420 for (fileset::const_iterator iter = new_files.begin(); iter != new_files.end(); ++iter)
424 int reg_ret = regexec(&conf.regex, of.
getFile().getBasename().c_str(), 0, NULL, 0);
425 if (!reg_ret && !conf.invert)
427 if (reg_ret && conf.invert)
431 if (reg_ret && reg_ret != REG_NOMATCH)
434 regerror(reg_ret,&conf.regex,msgbuf,
sizeof(msgbuf));
435 IBRCOMMON_LOGGER_TAG(
TAG,info) <<
"ERROR: regex match failed : " << std::string(msgbuf) << IBRCOMMON_LOGGER_ENDL;
439 observed_files.push_back(of);
442 IBRCOMMON_LOGGER_TAG(
TAG, info) <<
"file found: " << of.
getFile().getBasename() << IBRCOMMON_LOGGER_ENDL;
447 prev_files.insert(current_files.begin(), current_files.end());
449 IBRCOMMON_LOGGER_TAG(
TAG, notice)
450 <<
"file statistics: "
451 << observed_files.size() <<
" observed, "
452 << deleted_files.size() <<
" deleted, "
453 << new_files.size() <<
" new"
454 << IBRCOMMON_LOGGER_ENDL;
457 files_to_send.clear();
460 IBRCOMMON_LOGGER_TAG(
TAG, notice) <<
"updating observed files:" << IBRCOMMON_LOGGER_ENDL;
461 for (filelist::iterator iter = observed_files.begin(); iter != observed_files.end(); ++iter)
470 if (sent_hashes.find(of.
getHash()) == sent_hashes.end())
472 sent_hashes.insert(of.
getHash());
473 files_to_send.insert(*iter);
477 IBRCOMMON_LOGGER_TAG(
TAG, notice)
479 << of.
getFile().getBasename() <<
": "
481 << IBRCOMMON_LOGGER_ENDL;
484 if (!files_to_send.empty())
486 std::stringstream ss;
487 for (fileset::const_iterator it = files_to_send.begin(); it != files_to_send.end(); ++it) {
488 ss << (*it).getFile().getBasename() <<
" ";
490 IBRCOMMON_LOGGER_TAG(
"dtnoutbox",info) <<
"files sent: " << ss.str() << IBRCOMMON_LOGGER_ENDL;
494 ibrcommon::BLOB::Reference blob = ibrcommon::BLOB::create();
498 ibrcommon::BLOB::iostream stream = blob.iostream();
515 if (conf.bundle_group)
521 }
catch (
const ibrcommon::IOException &e) {
522 IBRCOMMON_LOGGER_TAG(
TAG,error) <<
"send failed: " << e.what() << IBRCOMMON_LOGGER_ENDL;
528 IBRCOMMON_LOGGER_TAG(
TAG, notice) << conf.interval <<
" ms wait" << IBRCOMMON_LOGGER_ENDL;
536 regfree(&conf.regex);
545 catch (
const ibrcommon::socket_exception&)
549 IBRCOMMON_LOGGER_TAG(
TAG,error) <<
"Connection to bundle daemon failed. Retry in " << backoff <<
" seconds." << IBRCOMMON_LOGGER_ENDL;
550 ibrcommon::Thread::sleep(backoff * 1000);
556 backoff = backoff * 2;
560 catch (
const ibrcommon::IOException&)
564 IBRCOMMON_LOGGER_TAG(
TAG,error) <<
"Connection to bundle daemon failed. Retry in " << backoff <<
" seconds." << IBRCOMMON_LOGGER_ENDL;
565 ibrcommon::Thread::sleep(backoff * 1000);
571 backoff = backoff * 2;
575 catch (
const std::exception&) { };
579 observed_files.clear();
583 if (imagereader != NULL)
delete imagereader;
586 return (EXIT_SUCCESS);
const unsigned char logsys
void findFiles(std::set< ObservedFile > &files) const
const unsigned char logerr
struct option long_options[]
size_t getStableCounter() const
std::set< io::FileHash > hashlist
void init_logger(config_t &conf)
std::set< io::ObservedFile > fileset
int main(int argc, char **argv)
ibrcommon::Conditional _wait_cond
void sighandler_func(int signal)
static void write(std::ostream &output, const io::ObservedFile &root, const std::set< ObservedFile > &files_to_send)
void read_configuration(int argc, char **argv, config_t &conf)
std::list< io::ObservedFile > filelist
ibrcommon::File blob_path("/tmp")
const unsigned char logstd
unidirectional communication is requested, no reception of bundles
const io::FileHash & getHash() const
void set(FLAGS flag, bool value)
const ibrcommon::File & getFile() const