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