|
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 } 00085 } 00086 00087 /* 00088 * main application method 00089 */ 00090 int main(int argc, char** argv) 00091 { 00092 // catch process signals 00093 signal(SIGINT, term); 00094 signal(SIGTERM, term); 00095 00096 // read the configuration 00097 map<string,string> conf = readconfiguration(argc, argv); 00098 00099 // init working directory 00100 if (conf.find("workdir") != conf.end()) 00101 { 00102 ibrcommon::File blob_path(conf["workdir"]); 00103 00104 if (blob_path.exists()) 00105 { 00106 ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), true); 00107 } 00108 } 00109 00110 // backoff for reconnect 00111 size_t backoff = 2; 00112 00113 // check outbox for files 00114 File outbox(conf["outbox"]); 00115 00116 // loop, if no stop if requested 00117 while (_running) 00118 { 00119 try { 00120 // Create a stream to the server using TCP. 00121 ibrcommon::tcpclient conn("127.0.0.1", 4550); 00122 00123 // enable nodelay option 00124 conn.enableNoDelay(); 00125 00126 // set the connection globally 00127 _conn = &conn; 00128 00129 // Initiate a client for synchronous receiving 00130 dtn::api::Client client(conf["name"], conn, dtn::api::Client::MODE_SENDONLY); 00131 00132 // Connect to the server. Actually, this function initiate the 00133 // stream protocol by starting the thread and sending the contact header. 00134 client.connect(); 00135 00136 // reset backoff if connected 00137 backoff = 2; 00138 00139 // check the connection 00140 while (_running) 00141 { 00142 list<File> files; 00143 outbox.getFiles(files); 00144 00145 // <= 2 because of "." and ".." 00146 if (files.size() <= 2) 00147 { 00148 // wait some seconds 00149 sleep(10); 00150 00151 continue; 00152 } 00153 00154 stringstream file_list; 00155 00156 int prefix_length = outbox.getPath().length() + 1; 00157 00158 for (list<File>::iterator iter = files.begin(); iter != files.end(); iter++) 00159 { 00160 File &f = (*iter); 00161 00162 // skip system files ("." and "..") 00163 if (f.isSystem()) continue; 00164 00165 // remove the prefix of the outbox path 00166 string rpath = f.getPath(); 00167 rpath = rpath.substr(prefix_length, rpath.length() - prefix_length); 00168 00169 file_list << rpath << " "; 00170 } 00171 00172 // output of all files to send 00173 cout << "files: " << file_list.str() << endl; 00174 00175 // "--remove-files" deletes files after adding 00176 stringstream cmd; cmd << "tar --remove-files -cO -C " << outbox.getPath() << " " << file_list.str(); 00177 00178 // make a tar archive 00179 appstreambuf app(cmd.str(), appstreambuf::MODE_READ); 00180 istream stream(&app); 00181 00182 // create a blob 00183 ibrcommon::BLOB::Reference blob = ibrcommon::BLOB::create(); 00184 00185 // stream the content of "tar" to the payload block 00186 (*blob.iostream()) << stream.rdbuf(); 00187 00188 // create a new bundle 00189 dtn::data::EID destination = EID(conf["destination"]); 00190 dtn::api::BLOBBundle b(destination, blob); 00191 00192 // send the bundle 00193 client << b; client.flush(); 00194 00195 if (_running) 00196 { 00197 // wait some seconds 00198 sleep(10); 00199 } 00200 } 00201 00202 // close the client connection 00203 client.close(); 00204 00205 // close the connection 00206 conn.close(); 00207 00208 // set the global connection to NULL 00209 _conn = NULL; 00210 } catch (const ibrcommon::tcpclient::SocketException&) { 00211 // set the global connection to NULL 00212 _conn = NULL; 00213 00214 if (_running) 00215 { 00216 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl; 00217 sleep(backoff); 00218 00219 // if backoff < 10 minutes 00220 if (backoff < 600) 00221 { 00222 // set a new backoff 00223 backoff = backoff * 2; 00224 } 00225 } 00226 } catch (const ibrcommon::IOException&) { 00227 // set the global connection to NULL 00228 _conn = NULL; 00229 00230 if (_running) 00231 { 00232 cout << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << endl; 00233 sleep(backoff); 00234 00235 // if backoff < 10 minutes 00236 if (backoff < 600) 00237 { 00238 // set a new backoff 00239 backoff = backoff * 2; 00240 } 00241 } 00242 } catch (const std::exception&) { 00243 // set the global connection to NULL 00244 _conn = NULL; 00245 } 00246 } 00247 00248 return (EXIT_SUCCESS); 00249 }