feisty meow concerns codebase 2.140
find_missing.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : find_missing *
4* Author : Chris Koeritz *
5* *
6*******************************************************************************
7* Copyright (c) 2002-$now By Author. This program is free software; you can *
8* redistribute it and/or modify it under the terms of the GNU General Public *
9* License as published by the Free Software Foundation; either version 2 of *
10* the License or (at your option) any later version. This is online at: *
11* http://www.fsf.org/copyleft/gpl.html *
12* Please send any updates to: fred@gruntose.com *
13\*****************************************************************************/
14
15#include <basis/byte_array.h>
16#include <basis/astring.h>
17
19//#include <application/command_line.h>
20#include <basis/astring.h>
21#include <cromp/cromp_client.h>
22#include <cromp/cromp_server.h>
27//#include <loggers/program_wide_logger.h>
28#include <octopus/entity_defs.h>
29#include <octopus/tentacle.h>
31#include <sockets/machine_uid.h>
32#include <sockets/tcpip_stack.h>
35#include <timely/time_control.h>
36#include <timely/time_stamp.h>
37
38using namespace application;
39using namespace basis;
40using namespace cromp;
41using namespace filesystem;
42using namespace loggers;
43using namespace octopi;
44using namespace sockets;
45using namespace structures;
46using namespace textual;
47using namespace timely;
48
49#undef BASE_LOG
50#define BASE_LOG(a) EMERGENCY_LOG(program_wide_logger::get(), astring(a))
51#undef LOG
52#define LOG(a) CLASS_EMERGENCY_LOG(program_wide_logger::get(), astring(a))
53
54const int REPORTING_INTERVAL = 28 * SECOND_ms; // how often to squawk.
55
56const int REFRESH_INTERVAL = 20 * MINUTE_ms; // how often we check tree.
57
58const int COMPARATOR_PORT = 10809;
59 // simple port grabbed randomly for the default.
60
61const int MAX_CHUNK = 16 * KILOBYTE;
62 // chunk size doesn't matter here; not transferring.
63
65
66class find_missing : public application_shell
67{
68public:
69 find_missing();
70 ~find_missing();
71
72 virtual int execute();
73
74 DEFINE_CLASS_NAME("find_missing");
75
76 int retrieve_info_from_server();
77 // for a client side comparison, this finds out which files are
78 // different and reports them.
79
81 // shows the instructions for this program.
82
83private:
84 bool _saw_clients; // true if we ever got a connection.
85 cromp_server *_server_side;
86 // provides connection and transmission services for servers.
87 cromp_client *_client_side; // client side connection.
88 bool _leave_when_no_clients; // true if we should just do one run.
89 bool _encryption; // true if we're encrypting.
90 astring _source; // the source path which a client will ask the server for.
91 astring _target; // the target path where files are stored for the client.
92 bool _started_okay; // got through the command line checking.
93};
94
96
97find_missing::find_missing()
99 _saw_clients(false),
100 _server_side(NULL_POINTER),
101 _client_side(NULL_POINTER),
102 _leave_when_no_clients(false),
103 _encryption(false),
104 _started_okay(false)
105{
106 FUNCDEF("constructor");
108 LOG("");
109 LOG("");
110
112 // check for a port on the command line.
113 astring port_text;
114 int port = COMPARATOR_PORT;
115 if (args.get_value("port", port_text, false))
116 port = port_text.convert(COMPARATOR_PORT);
117 int posn = 0;
118 if (args.find("exit", posn)) {
119 LOG("seeing the 'exit without clients' flag set.");
120 _leave_when_no_clients = true;
121 }
122
123 int indy = 0;
124 if (args.find("encrypt", indy, false)
125 || (args.find('e', indy, false)) ) {
126LOG("enabling encryption!");
127 // they're saying that we should encrypt the communication.
128 _encryption = true;
129 }
130
131 bool server = true;
132 indy = 0;
133 if (args.find("client", indy, false)) {
134LOG("client role chosen.");
135 server = false;
136 } else {
137LOG("server role chosen.");
138 }
139
140 internet_address addr;
141 addr.port = port;
142
143 // check for a hostname on the command line.
144 astring hostname("local");
145 astring host_temp;
146 if (args.get_value("host", host_temp, false)) {
147 LOG(astring("using host: ") + host_temp);
148 hostname = host_temp;
149 } else LOG(astring("using host: ") + hostname);
150 strcpy(addr.hostname, hostname.s());
151
152 if (server) {
153 astring key;
154 if (!args.get_value("key", key, false)) {
156 LOG("No keyword specified on command line.");
157 return;
158 }
159 astring root;
160 if (!args.get_value("root", root, false)) {
162 LOG("No transfer root was specified on the command line.");
163 return;
164 }
165
166 LOG("starting comparison server");
167 _server_side = new cromp_server(cromp_server::any_address(port));
172 new_tent->add_correspondence(key, root, REFRESH_INTERVAL);
173 _server_side->add_tentacle(new_tent);
174 _server_side->enable_servers(_encryption);
175 } else {
176 LOG("starting comparison client");
177 _client_side = new cromp_client(addr);
178 if (_encryption) _client_side->enable_encryption();
179
180 outcome ret = _client_side->connect();
181 if (ret != cromp_client::OKAY)
182 non_continuable_error(class_name(), func, astring("failed to connect to "
183 "the server: ") + cromp_client::outcome_name(ret));
184
189 if (!args.get_value("source", _source, false)) {
191 LOG("No source path was specified on the command line.");
192 return;
193 }
194 if (!args.get_value("target", _target, false)) {
196 LOG("No target path was specified on the command line.");
197 return;
198 }
199
200 string_array includes;
201 outcome regis = new_tent->register_file_transfer
202 (_client_side->entity(), _source, _target, includes);
203 if (regis != cromp_client::OKAY)
204 non_continuable_error(class_name(), func, "failed to register transfer");
205
206 _client_side->add_tentacle(new_tent);
207 }
208
209 _started_okay = true;
210
211}
212
213find_missing::~find_missing()
214{
215 WHACK(_client_side);
216 WHACK(_server_side);
217}
218
219int find_missing::print_instructions()
220{
222 BASE_LOG(a_sprintf("%s usage:", name.s()));
223 BASE_LOG("");
225This program can compare directory trees and report the files that are\n\
226missing on the client's side compared to what the server is offering.\n\
227The program can function as either the server side or the client side.\n\
228The available flags are:\n\
229\n\
230%s --client --host srvname --port P --source key_path --target cli_dest\n\
231\n\
232The client side needs to know the server host (srvname) and the port where\n\
233the server is listening for connections (P). The client will compare its\n\
234local path (cli_dest) with the server's keyed path (key_path). The key\n\
235path will begin with whatever keyword the server is offering, plus optional\n\
236additional path components to retrieve less than the whole tree being\n\
237served.\n\
238\n\
239\n\
240%s --server --host srvname --port P --key keyname --root srv_path\n\
241\n\
242The server side needs to know what address and port to listen on (srvname\n\
243and P). It will open a server there that provides a directory hierarchy\n\
244starting at the root specified (srv_path). The directory tree will be known\n\
245to clients as the key word (keyname), thus freeing the clients from needing\n\
246to know absolute paths on the server.\n\
247\n\
248", name.s(), name.s()));
249
250 return 23;
251}
252
253int find_missing::retrieve_info_from_server()
254{
255 FUNCDEF("retrieve_info_from_server");
256 // prepare a client request
257 file_transfer_infoton initiate;
258 initiate._request = true;
260 initiate._src_root = _source;
261 initiate._dest_root = _target;
262 directory_tree target_area(_target);
263 target_area.calculate(false);
264 string_set includes;
265 initiate.package_tree_info(target_area, includes);
266 octopus_request_id cmd_id;
267 outcome start_ret = _client_side->submit(initiate, cmd_id);
268 if (start_ret != tentacle::OKAY)
269 non_continuable_error(class_name(), func, astring("failed to initiate "
270 " the transfer: ") + cromp_client::outcome_name(start_ret));
271
272 infoton *start_reply_tmp = NULL_POINTER;
273//hmmm: set timeout appropriate to the speed of the connection!
274 outcome first_receipt = _client_side->acquire(start_reply_tmp, cmd_id);
275 if (first_receipt != cromp_client::OKAY)
276 non_continuable_error(class_name(), func, astring("failed to receive response: ")
277 + cromp_client::outcome_name(start_ret));
278 file_transfer_infoton *start_reply = dynamic_cast<file_transfer_infoton *>
279 (start_reply_tmp);
280 if (!start_reply)
281 non_continuable_error(class_name(), func, "failed to cast starting infoton to "
282 "proper type");
283
284 filename_list diffs;
285 byte_array pack_copy = start_reply->_packed_data;
286 if (!diffs.unpack(pack_copy))
287 non_continuable_error(class_name(), func, "could not unpack filename list!");
288 BASE_LOG("Differences found between local target and server's tree:");
290 for (int i = 0; i < diffs.elements(); i++) {
291 BASE_LOG(a_sprintf("%d: %s", i + 1, diffs[i]->raw().s()));
292 }
293
294 return 0;
295}
296
297int find_missing::execute()
298{
299 FUNCDEF("execute");
300
301 if (!_started_okay) return 32;
302
303 time_stamp next_report(REPORTING_INTERVAL);
304
305 while (true) {
306 // make sure we didn't see our exit condition.
307
308 if (_server_side && !_server_side->clients() && _leave_when_no_clients
309 && _saw_clients) {
310 LOG("exiting now");
311 break;
312 }
313
314 if (_client_side) return retrieve_info_from_server();
315
316 if (time_stamp() > next_report) {
317 if (_server_side)
318 LOG(a_sprintf("There are %d clients.", _server_side->clients()));
319//report about client side also.
320 next_report.reset(REPORTING_INTERVAL);
321 }
322
324 }
325 return 0;
326}
327
329
330HOOPLE_MAIN(find_missing, )
331
int print_instructions(bool good, const astring &program_name)
Definition checker.cpp:45
The application_shell is a base object for console programs.
virtual int execute()=0
< retrieves the command line from the /proc hierarchy on linux.
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
int convert(int default_value) const
Converts the string into a corresponding integer.
Definition astring.cpp:760
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
Outcomes describe the state of completion for an operation.
Definition outcome.h:31
static sockets::internet_address any_address(int port)
An object that traverses directory trees and provides a view of all files.
virtual bool unpack(basis::byte_array &packed_form)
Restores the packable from the "packed_form".
Provides operations commonly needed on file names.
Definition filename.h:64
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
Definition filename.cpp:97
filename basename() const
returns the base of the filename; no directory.
Definition filename.cpp:385
Base objects used by the file transfer tentacle to schedule transfers.
@ TREE_COMPARISON
the destination root will be compared with the source root.
basis::abyte _command
one of the commands above.
basis::astring _src_root
the top-level directory of the source.
bool _request
if it's not a request, then it's a response.
basis::astring _dest_root
the top-level directory of the destination.
void package_tree_info(const filesystem::directory_tree &tree, const structures::string_array &includes)
prepares the packed data from the "tree" and "includes" list.
basis::byte_array _packed_data
the packed headers and file chunks.
Manages the transferrence of directory trees from one place to another.
basis::outcome add_correspondence(const basis::astring &source_mapping, const basis::astring &source_root, int refresh_interval)
adds a file transfer correspondence.
@ COMPARE_SIZE_AND_TIME
uses size and time to see differences.
@ ONLY_REPORT_DIFFS
no actual file transfer, just reports.
@ COMPARE_CONTENT_SAMPLE
samples parts of file for comparison.
basis::outcome register_file_transfer(const octopus_entity &ent, const basis::astring &src_root, const basis::astring &dest_root, const structures::string_array &include)
records a transfer that is going to commence.
An infoton is an individual request parcel with accompanying information.
Definition infoton.h:32
Identifies requests made on an octopus by users.
this type of address describes a destination out on the internet.
char hostname[MAXIMUM_HOSTNAME_LENGTH]
int elements() const
the maximum number of elements currently allowed in this amorph.
Definition amorph.h:66
An array of strings with some additional helpful methods.
A simple object that wraps a templated set of strings.
Definition set.h:168
static void sleep_ms(basis::un_int msec)
a system independent name for a forced snooze measured in milliseconds.
Represents a point in time relative to the operating system startup time.
Definition time_stamp.h:38
#define SETUP_COMBO_LOGGER
a macro that retasks the program-wide logger as a combo_logger.
#define non_continuable_error(c, f, i)
an extra piece of information used, if available, in bounds_halt below.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
Definition enhance_cpp.h:42
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
const int COMPARATOR_PORT
const int MAX_CHUNK
#define BASE_LOG(a)
#define LOG(a)
const int REPORTING_INTERVAL
const int REFRESH_INTERVAL
Provides macros that implement the 'main' program of an application.
#define HOOPLE_MAIN(obj_name, obj_args)
options that should work for most unix and linux apps.
Definition hoople_main.h:61
Implements an application lock to ensure only one is running at once.
char ** _global_argv
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
const int SECOND_ms
Number of milliseconds in a second.
const int MINUTE_ms
Number of milliseconds in a minute.
const int KILOBYTE
Number of bytes in a kilobyte.
A platform independent way to obtain the timestamp of a file.
A logger that sends to the console screen using the standard output device.
Provides access to the operating system's socket methods.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
#include <time.h>