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 
45 using namespace basis;
46 using namespace configuration;
47 using namespace crypto;
48 using namespace loggers;
49 using namespace mathematics;
50 using namespace octopi;
51 using namespace processes;
52 using namespace sockets;
53 using namespace structures;
54 using namespace timely;
55 
56 namespace 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 
64 const int MAX_CONN_ATTEMPTS = 3;
65  // the number of times we'll retry connecting for certain errors.
66 
67 const 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 
93 class asynch_connection_thread : public ethread
94 {
95 public:
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 
119 private:
120  cromp_client &_parent;
121 };
122 
124 
125 cromp_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 
171 bool 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
198  _encrypt_arm = new encryption_tentacle(encryption_infoton::RSA_KEY_SIZE);
199  add_tentacle(_encrypt_arm, true);
200  add_tentacle(new unwrapping_tentacle, false);
201 }
202 
203 void 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 
220 void 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 
249 SAFE_STATIC(tcpip_stack, _hidden_stack, )
250 
251 octopus_entity cromp_client::randomize_entity() const
252 {
254  (byte_array::empty_array(), _hidden_stack().hostname(), 0), NULL_POINTER);
256  return octopus_entity(host, application_configuration::process_id(),
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 
286 SAFE_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;
298  octopus_request_id item_id = octopus_request_id::randomized_id();
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 
337  CAST_REPLY(encryption_infoton, response, enc_reply, ENCRYPTION_MISMATCH);
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(),
359  encryption_infoton::BLOWFISH_KEY_SIZE);
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.
366  security_infoton::login_modes login_type = security_infoton::LI_LOGIN;
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 
434 outcome 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)
469  time_control::sleep_ms(INTERCONNECTION_SNOOZE);
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 
483 void 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 
500 outcome 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 
515 bool 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;
593 LOG(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 
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
Outcomes describe the state of completion for an operation.
Definition: outcome.h:31
virtual basis::outcome login()
bool connected() const
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
Definition: cromp_client.h:175
basis::outcome acquire_any(octopi::infoton *&response, octopi::octopus_request_id &cmd_id, int timeout=DEFAULT_MAX_RESPONSE_WAIT)
basis::astring instance_name() const
Definition: cromp_client.h:65
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.
Definition: cromp_common.h:36
static const char * outcome_name(const basis::outcome &to_name)
octopi::octopus * octo() const
Definition: cromp_common.h:176
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.
Definition: rsa_crypto.cpp:269
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.
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.
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.
Definition: entity_defs.h:114
basis::astring text_form() const
human readable form of the request.
octopus_entity _entity
the entity.
Definition: entity_defs.h:116
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).
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
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
basis::outcome disconnect()
Definition: spocket.cpp:188
bool connected()
Definition: spocket.cpp:209
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.
Definition: string_array.h:32
Represents a point in time relative to the operating system startup time.
Definition: time_stamp.h:38
#define CHECK_LOCKOUT
#define LOG(s)
#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:57
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
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.
Definition: averager.h:21
Provides access to the operating system's socket methods.
Definition: base_address.h:26
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
#include <time.h>
Definition: earth_time.cpp:37
#define randomizer()