|
IBR-DTNSuite 0.6
|
00001 /* 00002 * dtnoutbox.cpp 00003 * 00004 * Created on: 20.11.2009 00005 * Author: morgenro 00006 */ 00007 00008 #include "config.h" 00009 #include "ibrdtn/api/Client.h" 00010 #include "ibrdtn/api/FileBundle.h" 00011 #include "ibrcommon/net/tcpclient.h" 00012 #include "ibrcommon/thread/Mutex.h" 00013 #include "ibrcommon/thread/MutexLock.h" 00014 #include "ibrdtn/data/PayloadBlock.h" 00015 #include "ibrdtn/api/BLOBBundle.h" 00016 #include "ibrcommon/data/BLOB.h" 00017 #include "ibrcommon/data/File.h" 00018 #include "ibrcommon/appstreambuf.h" 00019 00020 #include <stdlib.h> 00021 #include <iostream> 00022 #include <map> 00023 #include <vector> 00024 #include <csignal> 00025 #include <sys/types.h> 00026 00027 using namespace ibrcommon; 00028 00029 void print_help() 00030 { 00031 cout << "-- dtnoutbox (IBR-DTN) --" << endl; 00032 cout << "Syntax: dtnoutbox [options] <name> <outbox> <destination>" << endl; 00033 cout << " <name> the application name" << endl; 00034 cout << " <outbox> directory with outgoing files" << endl; 00035 cout << " <destination> the destination EID for all outgoing files" << endl; 00036 cout << "* optional parameters *" << endl; 00037 cout << " -h|--help display this text" << endl; 00038 cout << " -w|--workdir temporary work directory" << endl; 00039 } 00040 00041 map<string,string> readconfiguration(int argc, char** argv) 00042 { 00043 // print help if not enough parameters are set 00044 if (argc < 4) { print_help(); exit(0); } 00045 00046 map<string,string> ret; 00047 00048 ret["name"] = argv[argc - 3]; 00049 ret["outbox"] = argv[argc - 2]; 00050 ret["destination"] = argv[argc - 1]; 00051 00052 for (int i = 0; i < (argc - 3); i++) 00053 { 00054 string arg = argv[i]; 00055 00056 // print help if requested 00057 if (arg == "-h" || arg == "--help") 00058 { 00059 print_help(); 00060 exit(0); 00061 } 00062 00063 if ((arg == "-w" || arg == "--workdir") && (argc > i)) 00064 { 00065 ret["workdir"] = argv[i + 1]; 00066 } 00067 } 00068 00069 return ret; 00070 } 00071 00072 // set this variable to false to stop the app 00073 bool _running = true; 00074 00075 // global connection 00076 ibrcommon::tcpclient *_conn = NULL; 00077 00078 void term(int signal) 00079 { 00080 if (signal >= 1) 00081 { 00082 _running = false; 00083 if (_conn != NULL) _conn->close(); 00084 exit(0); 00085 } 00086 } 00087 00088 /* 00089 * main application method 00090 */ 00091 int main(int argc, char** argv) 00092 { 00093 // catch process signals 00094 signal(SIGINT, term); 00095 signal(SIGTERM, term); 00096 00097 // read the configuration 00098 map<string,string> conf = readconfiguration(argc, argv); 00099 00100 // init working directory 00101 if (conf.find("workdir") != conf.end()) 00102 { 00103 ibrcommon::BLOB::tmppath = File(conf["workdir"]); 00104 } 00105 00106 // backoff for reconnect 00107 size_t backoff = 2; 00108 00109 // check outbox for files 00110 File outbox(conf["outbox"]); 00111 00112 // loop, if no stop if requested 00113 while (_running) 00114 { 00115 try { 00116 // Create a stream to the server using TCP. 00117 ibrcommon::tcpclient conn("127.0.0.1", 4550); 00118 00119 // enable nodelay option 00120 conn.enableNoDelay(); 00121 00122 // set the connection globally 00123 _conn = &conn; 00124 00125 // Initiate a client for synchronous receiving 00126 dtn::api::Client client(conf["name"], conn, dtn::api::Client::MODE_SENDONLY); 00127 00128 // Connect to the server. Actually, this function initiate the 00129 // stream protocol by starting the thread and sending the contact header. 00130 client.connect(); 00131 00132 // reset backoff if connected 00133 backoff = 2; 00134 00135 // check the connection 00136 while (_running) 00137 { 00138 list<File> files; 00139 outbox.getFiles(files); 00140 00141 // <= 2 because of "." and ".." 00142 if (files.size() <= 2) 00143 { 00144 // wait some seconds 00145 sleep(10); 00146 00147 continue; 00148 } 00149 00150 stringstream file_list; 00151 00152 int prefix_length = outbox.getPath().length() + 1; 00153 00154 for (list<File>::iterator iter = files.begin(); iter != files.end(); iter++) 00155 { 00156 File &f = (*iter); 00157 00158 // skip system files ("." and "..") 00159 if (f.isSystem()) continue; 00160 00161 // remove the prefix of the outbox path 00162 string rpath = f.getPath(); 00163 rpath = rpath.substr(prefix_length, rpath.length() - prefix_length); 00164 00165 file_list << rpath << " "; 00166 } 00167 00168 // output of all files to send 00169 cout << "files: " << file_list.str() << endl; 00170 00171 // "--remove-files" deletes files after adding 00172 stringstream cmd; cmd << "tar --remove-files -cO -C " << outbox.getPath() << " " << file_list.str(); 00173 00174 // make a tar archive 00175 appstreambuf app(cmd.str(), appstreambuf::MODE_READ); 00176 istream stream(&app); 00177 00178 // create a blob 00179 ibrcommon::BLOB::Reference blob = ibrcommon::TmpFileBLOB::create(); 00180 00181 // stream the content of "tar" to the payload block 00182 (*blob.iostream()) << stream.rdbuf(); 00183 00184 // create a new bundle 00185 dtn::data::EID destination = EID(conf["destination"]); 00186 dtn::api::BLOBBundle b(destination, blob); 00187 00188 // send the bundle 00189 client << b; client.flush(); 00190 00191 if (_running) 00192 { 00193 // wait some seconds 00194 sleep(10); 00195 } 00196 } 00197 00198 // close the client connection 00199 client.close(); 00200 00201 // close the connection 00202 conn.close(); 00203 00204 // set the global connection to NULL 00205 _conn = NULL; 00206 } catch (const ibrcommon::tcpclient::SocketException&) { 00207 // set the global connection to NULL 00208 _conn = NULL; 00209 00210 if (_running) 00211 { 00212 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl; 00213 sleep(backoff); 00214 00215 // if backoff < 10 minutes 00216 if (backoff < 600) 00217 { 00218 // set a new backoff 00219 backoff = backoff * 2; 00220 } 00221 } 00222 } catch (const ibrcommon::IOException&) { 00223 // set the global connection to NULL 00224 _conn = NULL; 00225 00226 if (_running) 00227 { 00228 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl; 00229 sleep(backoff); 00230 00231 // if backoff < 10 minutes 00232 if (backoff < 600) 00233 { 00234 // set a new backoff 00235 backoff = backoff * 2; 00236 } 00237 } 00238 } catch (const std::exception&) { 00239 // set the global connection to NULL 00240 _conn = NULL; 00241 } 00242 } 00243 00244 return (EXIT_SUCCESS); 00245 }