37 using namespace basis;
38 using namespace cromp;
47 #define LOG(a) CLASS_EMERGENCY_LOG(program_wide_logger::get(), a)
69 virtual int execute();
73 int push_client_download();
84 bool _leave_when_no_clients;
93 transporter::transporter()
98 _leave_when_no_clients(false),
111 if (args.get_value(
"port", port_text,
false))
114 if (args.find(
"exit", posn)) {
115 LOG(
"seeing the 'exit without clients' flag set.");
116 _leave_when_no_clients =
true;
120 if (args.find(
"encrypt", indy,
false)
121 || (args.find(
'e', indy,
false)) ) {
122 LOG(
"enabling encryption!");
129 if (args.find(
"client", indy,
false)) {
130 LOG(
"client side chosen");
140 if (args.get_value(
"host", host_temp,
false)) {
142 hostname = host_temp;
143 }
else LOG(
astring(
"using host: ") + hostname);
144 strcpy(addr.
hostname, hostname.s());
148 if (!args.get_value(
"key", key,
false)) {
150 LOG(
"No keyword specified on command line.");
154 if (!args.get_value(
"root", root,
false)) {
156 LOG(
"No transfer root was specified on the command line.");
160 LOG(
"starting transfer server");
161 _server_side =
new cromp_server(cromp_server::any_address(port));
164 | file_transfer_tentacle::COMPARE_SIZE_AND_TIME
165 | file_transfer_tentacle::COMPARE_CONTENT_SAMPLE));
167 LOG(key +
" => " + root);
169 _server_side->add_tentacle(new_tent);
170 _server_side->enable_servers(_encryption);
172 LOG(
"starting transfer client");
174 if (_encryption) _client_side->enable_encryption();
176 outcome ret = _client_side->connect();
177 if (ret != cromp_client::OKAY)
179 "the server: ") + cromp_client::outcome_name(ret));
183 | file_transfer_tentacle::COMPARE_SIZE_AND_TIME
184 | file_transfer_tentacle::COMPARE_CONTENT_SAMPLE));
186 if (!args.get_value(
"source", _source,
false)) {
188 LOG(
"No source path was specified on the command line.");
191 if (!args.get_value(
"target", _target,
false)) {
193 LOG(
"No target path was specified on the command line.");
199 (_client_side->entity(), _source, _target, includes);
200 if (regis != cromp_client::OKAY)
203 _client_side->add_tentacle(new_tent);
206 _started_okay =
true;
210 transporter::~transporter()
220 log(astring::empty_string());
222 This program can transfer directory trees across the network. It will only\n\
223 copy the files missing on the client's side given what the server offers.\n\
224 The program can function as either the server side or the client side.\n\
225 The available flags are:\n\
227 %s --client --host srvname --port P --source key_path --target cli_dest\n\
229 The client side needs to know the server host (srvname) and the port where\n\
230 the server is listening for connections (P). The client will compare its\n\
231 local path (cli_dest) with the server's keyed path (key_path) and copy the\n\
232 files that are missing on the client's side. The key path will begin with\n\
233 whatever keyword the server is offering, plus optional additional path\n\
234 components to retrieve less than the whole tree being served.\n\
237 %s --server --host srvname --port P --key keyname --root srv_path\n\
239 The server side needs to know what address and port to listen on (srvname\n\
240 and P). It will open a server there that provides a directory hierarchy\n\
241 starting at the root specified (srv_path). The directory tree will be known\n\
242 to clients as the key word (keyname), thus freeing the clients from needing\n\
243 to know absolute paths on the server.\n\
245 ", name.
s(), name.
s()));
250 int transporter::push_client_download()
252 FUNCDEF(
"push_client_download");
256 initiate.
_command = file_transfer_infoton::BUILD_TARGET_TREE;
265 outcome build_ret = _client_side->submit(initiate, cmd_id);
266 if (build_ret != tentacle::OKAY)
268 " target tree: ") + cromp_client::outcome_name(build_ret));
271 initiate.
_command = file_transfer_infoton::TREE_COMPARISON;
273 target_area.calculate(
false);
276 outcome start_ret = _client_side->submit(initiate, cmd_id);
277 if (start_ret != tentacle::OKAY)
279 " the transfer: ") + cromp_client::outcome_name(start_ret));
283 outcome first_receipt = _client_side->acquire(start_reply_tmp, cmd_id);
284 if (first_receipt != cromp_client::OKAY)
286 + cromp_client::outcome_name(start_ret));
296 if (!diffs.
unpack(pack_copy))
301 outcome eval_ret = _client_side->octo()->evaluate(start_reply, cmd_id,
true);
302 if (eval_ret != cromp_client::OKAY)
304 "start response: ") + cromp_client::outcome_name(eval_ret));
313 ongoing.
_command = file_transfer_infoton::PLACE_FILE_CHUNKS;
318 outcome place_ret = _client_side->submit(ongoing, cmd_id);
319 if (place_ret != cromp_client::OKAY)
321 "chunk: ") + cromp_client::outcome_name(place_ret));
325 outcome place_receipt = _client_side->acquire(place_reply_tmp, cmd_id);
326 if (place_receipt != cromp_client::OKAY)
328 "place response: ") + cromp_client::outcome_name(place_receipt));
334 log(
astring(
"The server does not support file transfers."), ALWAYS_PRINT);
335 WHACK(place_reply_tmp);
344 outcome eval_ret2 = _client_side->octo()->evaluate(place_reply, cmd_id,
true);
345 if (eval_ret2 != tentacle::OKAY)
347 "place response: ") + cromp_client::outcome_name(eval_ret2));
350 LOG(
"hit termination condition: no data packed in for file chunks.");
357 int transporter::execute()
361 if (!_started_okay)
return 32;
368 if (_server_side && !_server_side->clients() && _leave_when_no_clients
374 if (_client_side)
return push_client_download();
378 LOG(
a_sprintf(
"There are %d clients.", _server_side->clients()));
383 time_control::sleep_ms(100);
int print_instructions(bool good, const astring &program_name)
The application_shell is a base object for console programs.
a_sprintf is a specialization of astring that provides printf style support.
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
int length() const
Returns the current reported length of the allocated C array.
Provides a dynamically resizable ASCII character string.
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
int convert(int default_value) const
Converts the string into a corresponding integer.
A very common template for a dynamic array of bytes.
Outcomes describe the state of completion for an operation.
An object that traverses directory trees and provides a view of all files.
basis::astring text_form(int max_lines=MAXINT32) const
max_lines is the maximum number of lines to print into the string.
virtual bool unpack(basis::byte_array &packed_form)
Restores the packable from the "packed_form".
Provides operations commonly needed on file names.
const basis::astring & raw() const
returns the astring that we're holding onto for the path.
filename basename() const
returns the base of the filename; no directory.
Base objects used by the file transfer tentacle to schedule transfers.
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.
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.
Identifies requests made on an octopus by users.
Informs the caller that a request type was unknown to the server octopus.
this type of address describes a destination out on the internet.
char hostname[MAXIMUM_HOSTNAME_LENGTH]
An array of strings with some additional helpful methods.
A simple object that wraps a templated set of strings.
Represents a point in time relative to the operating system startup time.
#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.
#define DEFINE_CLASS_NAME(objname)
Defines the name of a class by providing a couple standard methods.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
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.
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
const int MEGABYTE
Number of bytes in a megabyte.
const int SECOND_ms
Number of milliseconds in a second.
const int MINUTE_ms
Number of milliseconds in a minute.
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.
const int REPORTING_INTERVAL
const int REFRESH_INTERVAL