45 using namespace basis;
62 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
73 auto_synchronizer l(*_lock)
76 #define CHECK_LOCKOUT \
79 return NO_CONNECTION; \
83 #define CAST_REPLY(type, varname, newvar, retval) \
84 type *newvar = dynamic_cast<type *>(varname); \
86 LOG("failed to cast " #varname " to appropriate type, " #type "."); \
93 class asynch_connection_thread :
public ethread
96 asynch_connection_thread(cromp_client &parent)
98 ~asynch_connection_thread() { stop(); }
99 void perform_activity(
void *
formal(ptr)) {
101 while (!should_stop()) {
102 if (_parent.connected()) {
103 LOG(_parent.instance_name() +
" got connected.");
110 LOG(_parent.instance_name() +
" still unconnected; trying connect now.");
111 _parent.locked_connect();
112 LOG(_parent.instance_name()
113 +
" done calling connect.");
116 _parent._disallowed =
false;
120 cromp_client &_parent;
129 _connection_wait(connection_wait),
137 _channel_secured(false),
143 #ifdef DEBUG_CROMP_CLIENT
164 _channel_secured =
false;
167 WHACK(c_verification);
174 {
return *c_verification; }
181 #ifdef DEBUG_CROMP_CLIENT
182 LOG(
astring(
"enabling encryption for ") + class_name() +
" on "
203 void cromp_client::stop_asynch_thread()
205 #ifdef DEBUG_CROMP_CLIENT
208 if (_asynch_connector) {
209 #ifdef DEBUG_CROMP_CLIENT
212 _asynch_connector->cancel();
214 _asynch_connector->stop();
215 WHACK(_asynch_connector);
223 #ifdef DEBUG_CROMP_CLIENT
226 stop_asynch_thread();
230 *_ent = randomize_entity();
234 _channel_secured =
false;
235 _connection_wait = connection_wait;
237 #ifdef DEBUG_CROMP_CLIENT
254 (byte_array::empty_array(), _hidden_stack().hostname(), 0),
NULL_POINTER);
256 return octopus_entity(host, application_configuration::process_id(),
271 FUNCDEF(
"synchronous_request");
278 ret =
acquire(received, item_id, timeout);
288 {
return _empty_blank_verif(); }
295 _channel_secured =
false;
301 if (ret !=
OKAY)
return ret;
304 if (!ide_reply->_new_name.blank()) {
305 #ifdef DEBUG_CROMP_CLIENT
307 + ide_reply->_new_name.mangled_form());
310 *_ent = ide_reply->_new_name;
313 #ifdef DEBUG_CROMP_CLIENT
314 LOG(
"identity request failed: got blank name.");
320 if (_encrypting && !_channel_secured) {
324 LOG(
"there's no encryption arm!!!!");
335 if (ret !=
OKAY)
return ret;
344 ret = _encrypt_arm->
consume(*enc_reply, item_id, transformed);
346 LOG(
astring(
"failed to process encryption infoton for ")
359 encryption_infoton::BLOWFISH_KEY_SIZE);
361 _channel_secured =
true;
373 #ifdef DEBUG_CROMP_CLIENT
374 LOG(
astring(
"got an unhandled request with reason: ")
375 + common::outcome_name(temp_unh->
_reason));
380 outcome success = sec_reply->_success;
382 if (success == tentacle::OKAY) {
385 #ifdef DEBUG_CROMP_CLIENT
386 LOG(
astring(
"login request succeeded, now logged in."));
389 #ifdef DEBUG_CROMP_CLIENT
402 stop_asynch_thread();
405 return locked_connect();
420 if (_asynch_connector) {
421 LOG(
"logic error: asynchronous connector already exists.");
434 outcome cromp_client::locked_connect()
441 *_ent = randomize_entity();
445 #ifdef DEBUG_CROMP_CLIENT
449 #ifdef DEBUG_CROMP_CLIENT
452 if (ret == spocket::OKAY) {
453 #ifdef DEBUG_CROMP_CLIENT
454 LOG(
"finished connection... now affirming identity.");
458 if (ret == spocket::TIMED_OUT)
return TIMED_OUT;
459 if ( (ret == spocket::NO_ANSWER) || (ret == spocket::ACCESS_DENIED) ) {
464 #ifdef DEBUG_CROMP_CLIENT
465 LOG(
a_sprintf(
"error gotten=%s", spocket::outcome_name(ret)));
478 stop_asynch_thread();
480 return locked_disconnect();
485 if (duration < 0) duration = 0;
486 if (interval < 0) interval = 40;
487 if (interval > duration) interval = duration;
496 time_control::sleep_ms(interval);
500 outcome cromp_client::locked_disconnect()
506 _channel_secured =
false;
508 if (ret != spocket::OKAY) {
515 bool cromp_client::wrap_infoton(
const infoton &request,
518 #ifdef DEBUG_CROMP_CLIENT
521 if (!_channel_secured)
return false;
529 if (!is_ident && !is_encrypt && !is_wrapper) {
532 #ifdef DEBUG_CROMP_CLIENT
536 infoton::fast_pack(packed_request, request);
545 #ifdef DEBUG_CROMP_CLIENT
551 if (!_identified && !is_ident)
return BAD_INPUT;
553 if (_encrypting && _channel_secured) {
562 bool wrapped_okay = wrap_infoton(request, real_request);
571 }
else if (_encrypting) {
572 #ifdef DEBUG_CROMP_CLIENT
573 LOG(
"the channel has not been secured yet.");
604 #ifdef DEBUG_CROMP_CLIENT
625 FUNCDEF(
"decrypt_package_as_needed");
628 LOG(
astring(
"received an encryption_wrapper but we are not "
629 "encrypting, on ") + cmd_id.
text_form());
634 outcome ret = _encrypt_arm->
consume(*response, cmd_id, transformed);
643 bool worked = infoton::fast_unpack(transformed, classif, decro);
645 LOG(
"failed to fast_unpack the transformed data.");
650 if (rest_ret == tentacle::OKAY) {
655 LOG(
"failed to restore transformed infoton.");
a_sprintf is a specialization of astring that provides printf style support.
Provides a dynamically resizable ASCII character string.
A very common template for a dynamic array of bytes.
Outcomes describe the state of completion for an operation.
virtual basis::outcome login()
octopi::octopus_request_id next_id()
basis::outcome connect(const basis::byte_array &verification=blank_verification())
basis::outcome submit(const octopi::infoton &request, octopi::octopus_request_id &item_id, int max_tries=80)
static const basis::byte_array & blank_verification()
const octopi::octopus_entity & entity() const
basis::outcome acquire(octopi::infoton *&response, const octopi::octopus_request_id &cmd_id, int timeout=DEFAULT_MAX_RESPONSE_WAIT)
const basis::byte_array & verification() const
void keep_alive_pause(int duration=0, int interval=40)
basis::outcome synchronous_request(const octopi::infoton &to_send, octopi::infoton *&received, octopi::octopus_request_id &item_id, int timeout=DEFAULT_MAX_RESPONSE_WAIT)
basis::outcome disconnect()
friend class asynch_connection_thread
basis::outcome acquire_any(octopi::infoton *&response, octopi::octopus_request_id &cmd_id, int timeout=DEFAULT_MAX_RESPONSE_WAIT)
basis::astring instance_name() const
basis::outcome asynch_connect()
void reset(const sockets::internet_address &destination, int connection_wait=DEFAULT_MAX_CONNECT_WAIT, int max_per_ent=DEFAULT_MAX_ENTITY_QUEUE)
void decrypt_package_as_needed(basis::outcome &to_return, octopi::infoton *&response, const octopi::octopus_request_id &cmd_id)
A few common features used by both CROMP clients and servers.
static const char * outcome_name(const basis::outcome &to_name)
octopi::octopus * octo() const
basis::outcome open_common(const sockets::internet_address &where)
basis::outcome push_outgoing(int max_tries)
sockets::spocket * spock() const
basis::outcome retrieve_and_restore(octopi::infoton *&item, const octopi::octopus_request_id &req_id, int timeout)
basis::outcome close_common()
basis::outcome pack_and_ship(const octopi::infoton &request, const octopi::octopus_request_id &item_id, int max_tries)
sockets::internet_address other_side() const
basis::outcome retrieve_and_restore_any(octopi::infoton *&item, octopi::octopus_request_id &req_id, int timeout)
static basis::astring chew_hostname(const sockets::internet_address &addr, sockets::internet_address *resolved=NULL_POINTER)
int max_bytes_per_entity() const
virtual basis::outcome add_tentacle(octopi::tentacle *to_add, bool filter=false)
void grab_anything(bool wait)
static const crypto::rsa_crypto & localhost_only_key()
Provides BlowFish encryption on byte_arrays using the OpenSSL package.
bool encrypt(const basis::byte_array &source, basis::byte_array &target) const
encrypts the "source" array into the "target" array.
bool set_key(const basis::byte_array &new_key, int key_size)
sets the encryption key to "new_key".
const basis::byte_array & get_key() const
returns our current key.
bool private_key(basis::byte_array &privkey) const
makes a copy of the private key held here.
a platform-independent way to acquire random numbers in a specific range.
the blank_entity_registry can be used when security is not an issue.
Encapsulates the chit-chat necessary to establish an encrypted connection.
basis::outcome prepare_public_key(const crypto::rsa_crypto &private_key)
prepares the request side for a client.
Processes the encryption_infoton object for setting up an encrypted channel.
key_repository & keys() const
provides access to our list of keys.
const crypto::rsa_crypto & private_key() const
provides access to the key held here.
virtual basis::outcome consume(infoton &to_chow, const octopus_request_id &item_id, basis::byte_array &transformed)
the base class handles the processing of the request in "to_chow".
Wraps an encrypted infoton when the octopus is in an encrypted mode.
basis::byte_array _wrapped
the encrypted data that's held here.
Encapsulates just the action of identifying an octopus user.
An infoton is an individual request parcel with accompanying information.
virtual void text_form(basis::base_string &state_fill) const =0
requires derived infotons to be able to show their state as a string.
void unlock(octenc_key_record *to_unlock)
drops the lock on the key record in "to_unlock".
octenc_key_record * lock(const octopus_entity &ent)
locates the key for "ent", if it's stored.
Provides rudimentary login services.
Tracks the keys that have been assigned for a secure channel.
crypto::blowfish_crypto _key
used for communicating with an entity.
Provides a way of identifying users of an octopus object.
basis::astring text_form() const
returns a readable form of the identifier.
basis::astring mangled_form() const
returns the combined string form of the identifier.
Identifies requests made on an octopus by users.
basis::astring text_form() const
human readable form of the request.
octopus_entity _entity
the entity.
basis::outcome restore(const structures::string_array &classifier, basis::byte_array &packed_form, infoton *&reformed)
regenerates a packed infoton given its classifier.
Encapsulates security activities (login, logout, refresh).
Informs the caller that a request type was unknown to the server octopus.
basis::outcome _reason
the reason why this request was provided.
this simple tentacle just unpacks the encryption_wrapper infoton.
Provides a platform-independent object for adding threads to a program.
this type of address describes a destination out on the internet.
basis::outcome connect(int communication_wait=20 *basis::SECOND_ms)
basis::outcome disconnect()
Helpful functions for interacting with TCP/IP stacks.
A roller that's based on integers. This is the most common type so far.
void set_current(contents new_current)
allows the current id to be manipulated.
contents next_id()
returns a unique (per instance of this type) id.
An array of strings with some additional helpful methods.
Represents a point in time relative to the operating system startup time.
#define CAST_REPLY(type, varname, newvar, retval)
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
#define NULL_POINTER
The value representing a pointer to nothing.
#define MAXINT32
Maximum 32-bit integer value.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
SAFE_STATIC(byte_array, _empty_blank_verif,)
const int INTERCONNECTION_SNOOZE
const int MAX_CONN_ATTEMPTS
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
Provides access to the operating system's socket methods.
A dynamic container class that holds any kind of object via pointers.