feisty meow concerns codebase 2.140
cromp_client.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : cromp_client *
4* Author : Chris Koeritz *
5* *
6*******************************************************************************
7* Copyright (c) 2000-$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 "cromp_client.h"
16#include "cromp_common.h"
17#include "cromp_transaction.h"
18
19#include <basis/astring.h>
20#include <basis/functions.h>
21#include <basis/mutex.h>
23#include <crypto/rsa_crypto.h>
25#include <mathematics/chaos.h>
26#include <octopus/entity_defs.h>
29#include <processes/ethread.h>
31#include <sockets/machine_uid.h>
32#include <sockets/spocket.h>
33#include <sockets/tcpip_stack.h>
35#include <structures/roller.h>
42#include <timely/time_control.h>
43#include <timely/time_stamp.h>
44
45using namespace basis;
46using namespace configuration;
47using namespace crypto;
48using namespace loggers;
49using namespace mathematics;
50using namespace octopi;
51using namespace processes;
52using namespace sockets;
53using namespace structures;
54using namespace timely;
55
56namespace cromp {
57
58//#define DEBUG_CROMP_CLIENT
59 // uncomment for noisier version.
60
61#undef LOG
62#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
63
64const int MAX_CONN_ATTEMPTS = 3;
65 // the number of times we'll retry connecting for certain errors.
66
67const int INTERCONNECTION_SNOOZE = 200;
68 // we will pause this long if the initial connection attempt failed, and
69 // in between each attempt thereafter except the last.
70
71// grab control of the class, preventing multiple threads from trampling data.
72#define AUTO_LOCK \
73 auto_synchronizer l(*_lock)
74
75// make sure the client is in an operational state.
76#define CHECK_LOCKOUT \
77 if (_disallowed) { \
78 /* we can't do anything now due to the state of the connection. */ \
79 return NO_CONNECTION; \
80 }
81
82// tries to get a particular type of object back from an infoton response.
83#define CAST_REPLY(type, varname, newvar, retval) \
84 type *newvar = dynamic_cast<type *>(varname); \
85 if (!newvar) { \
86 LOG("failed to cast " #varname " to appropriate type, " #type "."); \
87 WHACK(varname); \
88 return retval; \
89 }
90
92
93class asynch_connection_thread : public ethread
94{
95public:
96 asynch_connection_thread(cromp_client &parent)
97 : ethread(), _parent(parent) {}
98 ~asynch_connection_thread() { stop(); }
99 void perform_activity(void *formal(ptr)) {
100 FUNCDEF("perform_activity");
101 while (!should_stop()) {
102 if (_parent.connected()) {
103 LOG(_parent.instance_name() + " got connected.");
104 break; // done?
105 }
106 // invoke the real connection maker. we should be synchronized wrt
107 // multiple threads since the "_disallowed" flag is set before this
108 // thread is ever started. no one that locks the cromp_client will
109 // get a chance to interfere.
110 LOG(_parent.instance_name() + " still unconnected; trying connect now.");
111 _parent.locked_connect();
112 LOG(_parent.instance_name()
113 + " done calling connect.");
114 }
115 // single shot thread is exiting now.
116 _parent._disallowed = false;
117 }
118
119private:
120 cromp_client &_parent;
121};
122
124
125cromp_client::cromp_client(const internet_address &addr, int connection_wait,
126 int max_per_ent)
127: cromp_common(cromp_common::chew_hostname(addr), max_per_ent),
128 _encrypting(false),
129 _connection_wait(connection_wait),
130 _lock(new mutex),
131 _ent(new octopus_entity(randomize_entity())),
132 _req_id(new int_roller(1, MAXINT32 - 20)),
133 _identified(false),
134 _authorized(false),
135 _disallowed(false),
136 _asynch_connector(NULL_POINTER),
137 _channel_secured(false),
138 _crypto(new blowfish_crypto(encryption_infoton::BLOWFISH_KEY_SIZE)),
139 _encrypt_arm(NULL_POINTER),
140 _guardian(new blank_entity_registry),
141 c_verification(new byte_array)
142{
143#ifdef DEBUG_CROMP_CLIENT
144 FUNCDEF("constructor");
145 LOG(astring("initial entity=") + _ent->mangled_form());
146#endif
147 open_common(addr);
148
149 // add simple security handling.
150 add_tentacle(new login_tentacle(*_guardian));
151 // add a non-filtering tentacle for checking security. we mainly need
152 // this to be able to unpack answers from the server.
153}
154
156{
157 FUNCDEF("destructor");
158 disconnect();
159 close_common();
160 _identified = false;
161 _authorized = false;
162 WHACK(_ent);
163 WHACK(_req_id);
164 _channel_secured = false;
165 WHACK(_crypto);
166 WHACK(_guardian);
167 WHACK(c_verification);
168 WHACK(_lock);
169}
170
171bool cromp_client::connected() const { return spock()->connected(); }
172
174{ return *c_verification; }
175
177{
178 FUNCDEF("enable_encryption");
179 AUTO_LOCK;
180
181#ifdef DEBUG_CROMP_CLIENT
182 LOG(astring("enabling encryption for ") + class_name() + " on "
183 + other_side().text_form());
184#endif
185 _encrypting = true;
186
187 // plug in the encryption support.
188 if (other_side().is_localhost()) {
189 // if the address is localhost, then we will use the standard key.
190 byte_array temp_priv_key;
191 localhost_only_key().private_key(temp_priv_key);
192 _encrypt_arm = new encryption_tentacle(temp_priv_key);
193//hmmm: there is a risk that if they reset to a new address we'd still be
194// using the slightly less secure local key. could be ameliorated by
195// zapping the encryption tentacle for a reset and readding it if it
196// existed?
197 } else
199 add_tentacle(_encrypt_arm, true);
201}
202
203void cromp_client::stop_asynch_thread()
204{
205#ifdef DEBUG_CROMP_CLIENT
206 FUNCDEF("stop_asynch_thread");
207#endif
208 if (_asynch_connector) {
209#ifdef DEBUG_CROMP_CLIENT
210 LOG(instance_name() + " stopping thread.");
211#endif
212 _asynch_connector->cancel(); // send it a nudge before we grab control.
213 AUTO_LOCK; // lock the class to prevent interference.
214 _asynch_connector->stop();
215 WHACK(_asynch_connector);
216 }
217 _disallowed = false; // no longer running the background thread.
218}
219
220void cromp_client::reset(const internet_address &addr, int connection_wait,
221 int max_per_ent)
222{
223#ifdef DEBUG_CROMP_CLIENT
224 FUNCDEF("reset");
225#endif
226 stop_asynch_thread();
227 AUTO_LOCK;
228 close_common(); // shut down the low-level stuff.
229 max_bytes_per_entity(max_per_ent);
230 *_ent = randomize_entity();
231 _req_id->set_current(1);
232 _identified = false;
233 _authorized = false;
234 _channel_secured = false;
235 _connection_wait = connection_wait;
236 _disallowed = false;
237#ifdef DEBUG_CROMP_CLIENT
238 LOG(astring("resetting entity=") + _ent->mangled_form());
239#endif
240 open_common(addr);
241}
242
244{
245 AUTO_LOCK;
246 return *_ent;
247}
248
249SAFE_STATIC(tcpip_stack, _hidden_stack, )
250
251octopus_entity cromp_client::randomize_entity() const
252{
254 (byte_array::empty_array(), _hidden_stack().hostname(), 0), NULL_POINTER);
257 randomizer.inclusive(0, MAXINT32 / 3),
258 randomizer.inclusive(0, MAXINT32 / 3));
259}
260
262{
263 AUTO_LOCK;
264 return octopus_request_id(*_ent, _req_id->next_id());
265}
266
268 infoton * & received, octopus_request_id &item_id,
269 int timeout)
270{
271 FUNCDEF("synchronous_request");
272 received = NULL_POINTER;
273 outcome ret = submit(to_send, item_id);
274 if (ret != OKAY) {
275 LOG(astring("failed to submit request: ") + outcome_name(ret) + " on " + to_send.text_form());
276 return ret;
277 }
278 ret = acquire(received, item_id, timeout);
279 if (ret != OKAY) {
280 LOG(astring("failed to acquire response: ") + outcome_name(ret) + " for " + to_send.text_form());
281 return ret;
282 }
283 return OKAY;
284}
285
286SAFE_STATIC(byte_array, _empty_blank_verif, );
288{ return _empty_blank_verif(); }
289
291{
292 FUNCDEF("login");
294 if (!_identified) {
295 _channel_secured = false;
296 // we need to secure an identity with the server.
297 identity_infoton identity;
299 infoton *response;
300 outcome ret = synchronous_request(identity, response, item_id);
301 if (ret != OKAY) return ret;
302
303 CAST_REPLY(identity_infoton, response, ide_reply, NO_SERVER);
304 if (!ide_reply->_new_name.blank()) {
305#ifdef DEBUG_CROMP_CLIENT
306 LOG(astring("setting new entity to: ")
307 + ide_reply->_new_name.mangled_form());
308#endif
309 AUTO_LOCK;
310 *_ent = ide_reply->_new_name;
311 _identified = true;
312 } else {
313#ifdef DEBUG_CROMP_CLIENT
314 LOG("identity request failed: got blank name.");
315#endif
316 }
317 WHACK(ide_reply);
318 }
319
320 if (_encrypting && !_channel_secured) {
321 // now the encryption needs to be cranked up.
322
323 if (!_encrypt_arm)
324 LOG("there's no encryption arm!!!!");
325
326 encryption_infoton encro;
327 {
328 AUTO_LOCK;
329 encro.prepare_public_key(_encrypt_arm->private_key());
330 }
331
332 infoton *response;
333 octopus_request_id item_id;
334 outcome ret = synchronous_request(encro, response, item_id);
335 if (ret != OKAY) return ret;
336
338 // this is a reasonable answer (mismatch), because a non-encrypting
339 // server should tell us a general failure response, since it shouldn't
340 // understand the request.
341
342 // handle the encryption infoton by feeding our tentacle the new key.
343 byte_array transformed;
344 ret = _encrypt_arm->consume(*enc_reply, item_id, transformed);
345 if (ret != OKAY) {
346 LOG(astring("failed to process encryption infoton for ")
347 + item_id.text_form());
348 WHACK(enc_reply); // nothing to give out.
349 return ret;
350 }
351 WHACK(enc_reply);
352
353 octenc_key_record *reco = _encrypt_arm->keys().lock(item_id._entity);
354 if (!reco) {
355 LOG(astring("failed to locate key for ") + item_id._entity.text_form());
356 return NOT_FOUND;
357 }
358 _crypto->set_key(reco->_key.get_key(),
360 _encrypt_arm->keys().unlock(reco);
361 _channel_secured = true;
362 }
363
364 if (!_authorized) {
365 // we need to go through whatever authentication is used by the server.
367 security_infoton securinfo(login_type, OKAY, *c_verification);
368 octopus_request_id item_id;
369 infoton *response;
370 outcome ret = synchronous_request(securinfo, response, item_id);
371 unhandled_request *temp_unh = dynamic_cast<unhandled_request *>(response);
372 if (temp_unh) {
373#ifdef DEBUG_CROMP_CLIENT
374 LOG(astring("got an unhandled request with reason: ")
375 + common::outcome_name(temp_unh->_reason));
376#endif
377 return temp_unh->_reason; // return the original reason.
378 }
379 CAST_REPLY(security_infoton, response, sec_reply, NO_SERVER);
380 outcome success = sec_reply->_success;
381 WHACK(sec_reply);
382 if (success == tentacle::OKAY) {
383 AUTO_LOCK;
384 _authorized = true;
385#ifdef DEBUG_CROMP_CLIENT
386 LOG(astring("login request succeeded, now logged in."));
387#endif
388 } else {
389#ifdef DEBUG_CROMP_CLIENT
390 LOG(astring("login request failed."));
391#endif
392 return success;
393 }
394 }
395
396 return OKAY;
397}
398
400{
401 FUNCDEF("connect");
402 stop_asynch_thread();
403 AUTO_LOCK; // protect from multiple connect attempts.
404 *c_verification = verification;
405 return locked_connect();
406}
407
409{
410 FUNCDEF("asynch_connect");
411 if (connected()) return OKAY; // why bother?
412 if (_asynch_connector) return NO_CONNECTION; // in progress.
413//#ifdef DEBUG_CROMP_CLIENT
414 LOG(instance_name() + " entry.");
415//#endif
416 {
417 AUTO_LOCK;
418 // protect this block only; we want to unlock before thread gets started.
419 if (connected()) return OKAY; // done already somehow.
420 if (_asynch_connector) {
421 LOG("logic error: asynchronous connector already exists.");
422 return NO_CONNECTION;
423 }
424 _disallowed = true;
425 _asynch_connector = new asynch_connection_thread(*this);
426 }
427 _asynch_connector->start(NULL_POINTER);
428//#ifdef DEBUG_CROMP_CLIENT
429 LOG(instance_name() + " exit.");
430//#endif
431 return NO_CONNECTION;
432}
433
434outcome cromp_client::locked_connect()
435{
436 FUNCDEF("locked_connect");
437 if (!spock()) return BAD_INPUT;
438 if (connected()) return OKAY; // already connected.
439
440 locked_disconnect(); // clean out any previous connection.
441 *_ent = randomize_entity(); // reset the login id.
442
443 int attempts = 0;
444 while (attempts++ < MAX_CONN_ATTEMPTS) {
445#ifdef DEBUG_CROMP_CLIENT
446 LOG(instance_name() + " calling spocket connect.");
447#endif
448 outcome ret = spock()->connect(_connection_wait);
449#ifdef DEBUG_CROMP_CLIENT
450 LOG(instance_name() + " done calling spocket connect.");
451#endif
452 if (ret == spocket::OKAY) {
453#ifdef DEBUG_CROMP_CLIENT
454 LOG("finished connection... now affirming identity.");
455#endif
456 return login();
457 }
458 if (ret == spocket::TIMED_OUT) return TIMED_OUT;
459 if ( (ret == spocket::NO_ANSWER) || (ret == spocket::ACCESS_DENIED) ) {
460 // clean up. this is a real case of something hosed.
461 locked_disconnect();
462 return NO_SERVER;
463 }
464#ifdef DEBUG_CROMP_CLIENT
465 LOG(a_sprintf("error gotten=%s", spocket::outcome_name(ret)));
466#endif
467
468 if (attempts < MAX_CONN_ATTEMPTS - 1)
470 }
471 LOG(instance_name() + " failed to connect.");
472 locked_disconnect(); // clean up.
473 return NO_CONNECTION;
474}
475
477{
478 stop_asynch_thread();
479 AUTO_LOCK;
480 return locked_disconnect();
481}
482
483void cromp_client::keep_alive_pause(int duration, int interval)
484{
485 if (duration < 0) duration = 0;
486 if (interval < 0) interval = 40;
487 if (interval > duration) interval = duration;
488
489 // keep looping on the cromp stimulation methods until the time has elapsed.
490 time_stamp leave_at(duration);
491 while (time_stamp() < leave_at) {
492 push_outgoing(1);
493 grab_anything(false);
494 // we'll only sleep if they didn't give us a zero duration.
495 if (duration)
496 time_control::sleep_ms(interval); // snooze a hopefully short time.
497 }
498}
499
500outcome cromp_client::locked_disconnect()
501{
502 if (!spock()) return BAD_INPUT;
503 outcome ret = spock()->disconnect();
504 _identified = false;
505 _authorized = false;
506 _channel_secured = false;
507 *_ent = octopus_entity(); // reset the login id.
508 if (ret != spocket::OKAY) {
509//hmmm: any other outcomes to return?
510 return OKAY;
511 }
512 return OKAY;
513}
514
515bool cromp_client::wrap_infoton(const infoton &request,
516 encryption_wrapper &wrapped)
517{
518#ifdef DEBUG_CROMP_CLIENT
519 FUNCDEF("wrap_infoton");
520#endif
521 if (!_channel_secured) return false;
522 // identity is not wrapped with encryption; we need to establish and identity
523 // to talk on a distinct channel with the server. even if that identity were
524 // compromised, the interloper should still not be able to listen in on the
525 // establishment of an encryption channel.
526 bool is_ident = !!dynamic_cast<const identity_infoton *>(&request);
527 bool is_encrypt = !!dynamic_cast<const encryption_infoton *>(&request);
528 bool is_wrapper = !!dynamic_cast<const encryption_wrapper *>(&request);
529 if (!is_ident && !is_encrypt && !is_wrapper) {
530 // check that we have already got a channel to speak over. otherwise, we
531 // can't do any encrypting of messages yet.
532#ifdef DEBUG_CROMP_CLIENT
533 LOG(astring("encrypting ") + request.text_form());
534#endif
535 byte_array packed_request;
536 infoton::fast_pack(packed_request, request);
537 _crypto->encrypt(packed_request, wrapped._wrapped);
538 return true;
539 } else return false; // we didn't need or want to wrap it.
540}
541
543 octopus_request_id &item_id, int max_tries)
544{
545#ifdef DEBUG_CROMP_CLIENT
546 FUNCDEF("submit");
547#endif
549 item_id = next_id();
550 bool is_ident = !!dynamic_cast<const identity_infoton *>(&request);
551 if (!_identified && !is_ident) return BAD_INPUT;
552
553 if (_encrypting && _channel_secured) {
554 // if we're encrypting things, then we need to encrypt this too. this
555 // assumes that authentication is wrapped by encryption, which is the sane
556 // thing to do. identity is not wrapped that way though; we need to
557 // establish and identity to talk on a distinct channel with the server.
558 // even if that identity were compromised, the interloper would still not
559 // be able to listen in on the establishment of an encryption channel.
560
561 encryption_wrapper real_request;
562 bool wrapped_okay = wrap_infoton(request, real_request);
563 if (wrapped_okay) {
564 outcome to_return = cromp_common::pack_and_ship(real_request, item_id,
565 max_tries);
566 return to_return;
567 }
568 // if it didn't wrap okay, we fall through to a normal send, because it's
569 // probably an encryption or identity infoton, which needs to go through
570 // without being wrapped.
571 } else if (_encrypting) {
572#ifdef DEBUG_CROMP_CLIENT
573 LOG("the channel has not been secured yet.");
574#endif
575 }
576
577 outcome to_return = cromp_common::pack_and_ship(request, item_id, max_tries);
578 return to_return;
579}
580
582 const octopus_request_id &cmd_id, int timeout)
583{
584 FUNCDEF("acquire");
586 outcome to_return = cromp_common::retrieve_and_restore(response, cmd_id,
587 timeout);
588
589 unhandled_request *intermed = dynamic_cast<unhandled_request *>(response);
590 if (intermed) {
591 // override the return value with the real outcome of a failed operation.
592 to_return = intermed->_reason;
593LOG(astring("using unhandled request's intermediate result: ") + outcome_name(to_return));
594 }
595
596 decrypt_package_as_needed(to_return, response, cmd_id);
597
598 return to_return;
599}
600
602 octopus_request_id &cmd_id, int timeout)
603{
604#ifdef DEBUG_CROMP_CLIENT
605 FUNCDEF("acquire_any");
606#endif
608 outcome to_return = cromp_common::retrieve_and_restore_any(response, cmd_id,
609 timeout);
610
611 unhandled_request *intermed = dynamic_cast<unhandled_request *>(response);
612 if (intermed) {
613 // override the return value with the real outcome of a failed operation.
614 to_return = intermed->_reason;
615 }
616
617 decrypt_package_as_needed(to_return, response, cmd_id);
618
619 return to_return;
620}
621
623 infoton * &response, const octopus_request_id &cmd_id)
624{
625 FUNCDEF("decrypt_package_as_needed");
626 if (dynamic_cast<encryption_wrapper *>(response)) {
627 if (!_encrypt_arm) {
628 LOG(astring("received an encryption_wrapper but we are not "
629 "encrypting, on ") + cmd_id.text_form());
630 to_return = ENCRYPTION_MISMATCH;
631 return;
632 }
633 byte_array transformed;
634 outcome ret = _encrypt_arm->consume(*response, cmd_id, transformed);
635 if ( (ret != OKAY) && (ret != PARTIAL) ) {
636 LOG(astring("failed to decrypt wrapper for ") + cmd_id.text_form());
637 to_return = ret;
638 return;
639 }
640
641 string_array classif;
642 byte_array decro; // decrypted packed infoton.
643 bool worked = infoton::fast_unpack(transformed, classif, decro);
644 if (!worked) {
645 LOG("failed to fast_unpack the transformed data.");
646 to_return = ENCRYPTION_MISMATCH; // what else would we call that?
647 } else {
648 infoton *new_req = NULL_POINTER;
649 outcome rest_ret = octo()->restore(classif, decro, new_req);
650 if (rest_ret == tentacle::OKAY) {
651 // we got a good transformed version.
652 WHACK(response);
653 response = new_req; // substitution complete.
654 } else {
655 LOG("failed to restore transformed infoton.");
656 to_return = ENCRYPTION_MISMATCH; // what else would we call that?
657 }
658 }
659 }
660}
661
662} //namespace.
663
664
#define LOG(s)
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
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
static const byte_array & empty_array()
Definition byte_array.h:57
static const char * outcome_name(const outcome &to_name)
Returns a string representation of the outcome "to_name".
Outcomes describe the state of completion for an operation.
Definition outcome.h:31
static basis::un_int process_id()
returns the process id for this task, if that's relevant on the OS.
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)
cromp_client(const sockets::internet_address &destination, int connection_wait=DEFAULT_MAX_CONNECT_WAIT, int max_per_ent=DEFAULT_MAX_ENTITY_QUEUE)
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)
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)
octopi::octopus * octo() const
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.
Definition chaos.h:51
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.
static const int RSA_KEY_SIZE
this key size should be used for all RSA private keys.
static const int BLOWFISH_KEY_SIZE
this will be used for blowfish keys that this object generates.
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.
Definition infoton.h:32
virtual void text_form(basis::base_string &state_fill) const =0
requires derived infotons to be able to show their state as a string.
static void fast_pack(basis::byte_array &packed_form, const infoton &to_pack)
flattens an infoton "to_pack" into the byte array "packed_form".
Definition infoton.cpp:162
static bool fast_unpack(basis::byte_array &packed_form, structures::string_array &classifier, basis::byte_array &info)
undoes a previous fast_pack to restore the previous information.
Definition infoton.cpp:227
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.
Definition entity_defs.h:35
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.
static octopus_request_id randomized_id()
provides a pre-randomized request id.
basis::outcome restore(const structures::string_array &classifier, basis::byte_array &packed_form, infoton *&reformed)
regenerates a packed infoton given its classifier.
Definition octopus.cpp:318
Encapsulates security activities (login, logout, refresh).
@ LI_LOGIN
the requester wants to log in as a new entity.
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.
Definition ethread.h:36
void stop()
tells the thread to shutdown and waits for the shutdown to occur.
Definition ethread.cpp:194
ethread()
creates a single-shot thread object.
Definition ethread.cpp:86
bool should_stop() const
reports whether the thread should stop right now.
Definition ethread.h:136
this type of address describes a destination out on the internet.
basis::outcome connect(int communication_wait=20 *basis::SECOND_ms)
Definition spocket.cpp:274
static const char * outcome_name(const basis::outcome &to_name)
Definition spocket.cpp:180
basis::outcome disconnect()
Definition spocket.cpp:188
Helpful functions for interacting with TCP/IP stacks.
Definition tcpip_stack.h:38
A roller that's based on integers. This is the most common type so far.
Definition roller.h:79
void set_current(contents new_current)
allows the current id to be manipulated.
Definition roller.h:94
contents next_id()
returns a unique (per instance of this type) id.
Definition roller.h:105
An array of strings with some additional helpful methods.
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 CHECK_LOCKOUT
#define AUTO_LOCK
#define CAST_REPLY(type, varname, newvar, retval)
#define formal(parameter)
This macro just eats what it's passed; it marks unused formal parameters.
Definition definitions.h:48
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define MAXINT32
Maximum 32-bit integer value.
Definition definitions.h:75
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
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 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.
Definition averager.h:21
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>
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
#define randomizer()