cromp_client.cpp

Go to the documentation of this file.
00001 #ifndef CROMP_CLIENT_IMPLEMENTATION_FILE
00002 #define CROMP_CLIENT_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : cromp_client                                                      *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 2000-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #include "cromp_client.h"
00019 #include "cromp_common.h"
00020 #include "cromp_transaction.h"
00021 
00022 #include <basis/chaos.h>
00023 #include <basis/function.h>
00024 #include <basis/istring.h>
00025 #include <basis/log_base.h>
00026 #include <basis/mutex.h>
00027 #include <basis/portable.h>
00028 #include <data_struct/static_memory_gremlin.h>
00029 #include <mechanisms/ithread.h>
00030 #include <mechanisms/roller.cpp>
00031 #include <mechanisms/time_stamp.h>
00032 #include <octopus/entity_defs.h>
00033 #include <octopus/identity_infoton.h>
00034 #include <octopus/unhandled_request.h>
00035 #include <sockets/address.h>
00036 #include <sockets/machine_uid.h>
00037 #include <sockets/spocket.h>
00038 #include <sockets/tcpip_stack.h>
00039 #include <tentacles/encryption_tentacle.h>
00040 #include <tentacles/encryption_wrapper.h>
00041 #include <tentacles/entity_registry.h>
00042 #include <tentacles/key_repository.h>
00043 #include <tentacles/login_tentacle.h>
00044 #include <tentacles/security_infoton.h>
00045 
00046 #ifndef OMIT_CRYPTO_SUPPORT
00047   #include <crypto/rsa_crypto.h>
00048 #endif
00049 
00050 //#define DEBUG_CROMP_CLIENT
00051   // uncomment for noisier version.
00052 
00053 #undef LOG
00054 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00055 #undef FILT_LOG
00056 #define FILT_LOG(filter, s) CLASS_FILTER_LOG(program_wide_logger(), s, filter)
00057 
00058 const int MAX_CONN_ATTEMPTS = 3;
00059   // the number of times we'll retry connecting for certain errors.
00060 
00061 const int INTERCONNECTION_SNOOZE = 200;
00062   // we will pause this long if the initial connection attempt failed, and
00063   // in between each attempt thereafter except the last.
00064 
00065 // grab control of the class, preventing multiple threads from trampling data.
00066 #define AUTO_LOCK \
00067   auto_synchronizer l(*_lock)
00068 
00069 // make sure the client is in an operational state.
00070 #define CHECK_LOCKOUT \
00071   if (_disallowed) { \
00072     /* we can't do anything now due to the state of the connection. */ \
00073     return NO_CONNECTION; \
00074   }
00075 
00076 // tries to get a particular type of object back from an infoton response.
00077 #define CAST_REPLY(type, varname, newvar, retval) \
00078   type *newvar = dynamic_cast<type *>(varname); \
00079   if (!newvar) { \
00080     LOG("failed to cast " #varname " to appropriate type, " #type "."); \
00081     WHACK(varname); \
00082     return retval; \
00083   }
00084 
00086 
00087 class asynch_connection_thread : public ithread
00088 {
00089 public:
00090   asynch_connection_thread(cromp_client &parent)
00091       : ithread(), _parent(parent) {}
00092   ~asynch_connection_thread() { stop(); }
00093   void perform_activity(void *formal(ptr)) {
00094     FUNCDEF("perform_activity");
00095     while (!should_stop()) {
00096       if (_parent.connected()) {
00097         FILT_LOG(common::NETWORK_LOGGING, _parent.instance_name()
00098             + " got connected.");
00099         break;  // done?
00100       }
00101       // invoke the real connection maker.  we should be synchronized wrt
00102       // multiple threads since the "_disallowed" flag is set before this
00103       // thread is ever started.  no one that locks the cromp_client will
00104       // get a chance to interfere.
00105       FILT_LOG(common::NETWORK_LOGGING, _parent.instance_name() + " still "
00106           "unconnected; trying connect now.");
00107       _parent.locked_connect();
00108       FILT_LOG(common::NETWORK_LOGGING, _parent.instance_name()
00109           + " done calling connect.");
00110     }
00111     // single shot thread is exiting now.
00112     _parent._disallowed = false;
00113   }
00114 
00115 private:
00116   cromp_client &_parent;
00117 };
00118 
00120 
00121 cromp_client::cromp_client(const internet_address &addr, int connection_wait,
00122     int max_per_ent)
00123 : cromp_common(cromp_common::chew_hostname(addr), max_per_ent),
00124   _encrypting(false),
00125   _connection_wait(connection_wait),
00126   _lock(new mutex),
00127   _ent(new octopus_entity(randomize_entity())),
00128   _req_id(new int_roller(1, MAXINT - 20)),
00129   _identified(false),
00130   _authorized(false),
00131   _disallowed(false),
00132   _asynch_connector(NIL),
00133 #ifndef OMIT_CRYPTO_SUPPORT
00134   _channel_secured(false),
00135   _crypto(new blowfish_crypto(encryption_infoton::BLOWFISH_KEY_SIZE)),
00136   _encrypt_arm(NIL),
00137 #endif
00138   _guardian(new blank_entity_registry)
00139 {
00140   FUNCDEF("constructor");
00141 #ifdef DEBUG_CROMP_CLIENT
00142   LOG(istring("initial entity=") + _ent->mangled_form());
00143 #endif
00144   open_common(addr);
00145 
00146   // add simple security handling.
00147   add_tentacle(new login_tentacle(*_guardian));
00148     // add a non-filtering tentacle for checking security.  we mainly need
00149     // this to be able to unpack answers from the server.
00150 }
00151 
00152 cromp_client::~cromp_client()
00153 {
00154   FUNCDEF("destructor");
00155   disconnect();
00156   close_common();
00157   _identified = false;
00158   _authorized = false;
00159   WHACK(_ent);
00160   WHACK(_req_id);
00161 #ifndef OMIT_CRYPTO_SUPPORT
00162   _channel_secured = false;
00163   WHACK(_crypto);
00164 #endif
00165   WHACK(_guardian);
00166   WHACK(_lock);
00167 }
00168 
00169 bool cromp_client::connected() const { return spock()->connected(); }
00170 
00171 void cromp_client::enable_encryption()
00172 {
00173   FUNCDEF("enable_encryption");
00174 #ifndef OMIT_CRYPTO_SUPPORT
00175   AUTO_LOCK;
00176 
00177 #ifdef DEBUG_CROMP_CLIENT
00178   LOG(istring("enabling encryption for ") + class_name() + " on "
00179       + other_side().text_form());
00180 #endif
00181   _encrypting = true;
00182 
00183   // plug in the encryption support.
00184   if (other_side().is_localhost()) {
00185     // if the address is localhost, then we will use the standard key.
00186     byte_array temp_priv_key;
00187     localhost_only_key().private_key(temp_priv_key);
00188     _encrypt_arm = new encryption_tentacle(temp_priv_key);
00189 //hmmm: there is a risk that if they reset to a new address we'd still be
00190 //      using the slightly less secure local key.  could be ameliorated by
00191 //      zapping the encryption tentacle for a reset and readding it if it
00192 //      existed?
00193   } else
00194     _encrypt_arm = new encryption_tentacle(encryption_infoton::RSA_KEY_SIZE);
00195   add_tentacle(_encrypt_arm, true);
00196   add_tentacle(new unwrapping_tentacle, false);
00197 #endif
00198 }
00199 
00200 void cromp_client::stop_asynch_thread()
00201 {
00202   FUNCDEF("stop_asynch_thread");
00203   if (_asynch_connector) {
00204 #ifdef DEBUG_CROMP_CLIENT
00205     LOG(instance_name() + " stopping thread.");
00206 #endif
00207     _asynch_connector->cancel();  // send it a nudge before we grab control.
00208     AUTO_LOCK;  // lock the class to prevent interference.
00209     _asynch_connector->stop();
00210     WHACK(_asynch_connector);
00211   }
00212   _disallowed = false;  // no longer running the background thread.
00213 }
00214 
00215 void cromp_client::reset(const internet_address &addr, int connection_wait,
00216     int max_per_ent)
00217 {
00218   FUNCDEF("reset");
00219   stop_asynch_thread();
00220   AUTO_LOCK;
00221   close_common();  // shut down the low-level stuff.
00222   max_bytes_per_entity(max_per_ent);
00223   *_ent = randomize_entity();
00224   _req_id->set_current(1);
00225   _identified = false;
00226   _authorized = false;
00227 #ifndef OMIT_CRYPTO_SUPPORT
00228   _channel_secured = false;
00229 #endif
00230   _connection_wait = connection_wait;
00231   _disallowed = false;
00232 #ifdef DEBUG_CROMP_CLIENT
00233   LOG(istring("resetting entity=") + _ent->mangled_form());
00234 #endif
00235   open_common(addr);
00236 }
00237 
00238 const octopus_entity &cromp_client::entity() const
00239 {
00240   AUTO_LOCK;
00241   return *_ent;
00242 }
00243 
00244 SAFE_STATIC(tcpip_stack, _hidden_stack, )
00245 
00246 octopus_entity cromp_client::randomize_entity() const
00247 {
00248   istring host = cromp_common::chew_hostname(internet_address
00249       (byte_array::empty_array(), _hidden_stack().hostname(), 0), NIL);
00250   chaos randomizer;
00251   return octopus_entity(host, portable::process_id(),
00252       randomizer.inclusive(0, MAXINT / 3),
00253       randomizer.inclusive(0, MAXINT / 3));
00254 }
00255 
00256 octopus_request_id cromp_client::next_id()
00257 {
00258   AUTO_LOCK;
00259   return octopus_request_id(*_ent, _req_id->next_id());
00260 }
00261 
00262 outcome cromp_client::synchronous_request(const infoton &to_send,
00263     infoton * & received, octopus_request_id &item_id,
00264     int timeout)
00265 {
00266   FUNCDEF("synchronous_request");
00267   received = NIL;
00268   outcome ret = submit(to_send, item_id);
00269   if (ret != OKAY) {
00270     FILT_LOG(common::NETWORK_LOGGING, istring("failed to submit request: ")
00271         + outcome_name(ret) + " on " + to_send.text_form());
00272     return ret;
00273   }
00274   ret = acquire(received, item_id, timeout);
00275   if (ret != OKAY) {
00276     FILT_LOG(common::NETWORK_LOGGING, istring("failed to acquire response: ")
00277         + outcome_name(ret) + " for " + to_send.text_form());
00278     return ret;
00279   }
00280   return OKAY;
00281 }
00282 
00283 outcome cromp_client::login()
00284 {
00285   FUNCDEF("login");
00286   CHECK_LOCKOUT;
00287   if (!_identified) {
00288 #ifndef OMIT_CRYPTO_SUPPORT
00289     _channel_secured = false;
00290 #endif
00291     // we need to secure an identity with the server.
00292     identity_infoton identity;
00293     octopus_request_id item_id = octopus_request_id::randomized_id();
00294     infoton *response;
00295     outcome ret = synchronous_request(identity, response, item_id);
00296     if (ret != OKAY) return ret;
00297 
00298     CAST_REPLY(identity_infoton, response, ide_reply, NO_SERVER);
00299     if (!ide_reply->_new_name.blank()) {
00300 #ifdef DEBUG_CROMP_CLIENT
00301       LOG(istring("setting new entity to: ")
00302           + ide_reply->_new_name.mangled_form());
00303 #endif
00304       AUTO_LOCK;
00305       *_ent = ide_reply->_new_name;
00306       _identified = true;
00307     } else {
00308 #ifdef DEBUG_CROMP_CLIENT
00309       LOG("identity request failed: got blank name.");
00310 #endif
00311     }
00312     WHACK(ide_reply);
00313   }
00314 
00315 #ifndef OMIT_CRYPTO_SUPPORT
00316   if (_encrypting && !_channel_secured) {
00317     // now the encryption needs to be cranked up.
00318 
00319     if (!_encrypt_arm)
00320       LOG("there's no encryption arm!!!!");
00321 
00322     encryption_infoton encro;
00323     {
00324       AUTO_LOCK;
00325       encro.prepare_public_key(_encrypt_arm->private_key());
00326     }
00327 
00328     infoton *response;
00329     octopus_request_id item_id;
00330     outcome ret = synchronous_request(encro, response, item_id);
00331     if (ret != OKAY) return ret;
00332 
00333     CAST_REPLY(encryption_infoton, response, enc_reply, ENCRYPTION_MISMATCH);
00334       // this is a reasonable answer (mismatch), because a non-encrypting
00335       // server should tell us a general failure response, since it shouldn't
00336       // understand the request.
00337 
00338     // handle the encryption infoton by feeding our tentacle the new key.
00339     byte_array transformed;
00340     ret = _encrypt_arm->consume(*enc_reply, item_id, transformed);
00341     if (ret != OKAY) {
00342       LOG(istring("failed to process encryption infoton for ")
00343           + item_id.text_form());
00344       WHACK(enc_reply);  // nothing to give out.
00345       return ret;
00346     }
00347     WHACK(enc_reply);
00348 
00349     octenc_key_record *reco = _encrypt_arm->keys().lock(item_id._entity);
00350     if (!reco) {
00351       LOG(istring("failed to locate key for ") + item_id._entity.text_form());
00352       return NOT_FOUND;
00353     }
00354     _crypto->set_key(reco->_key.get_key(),
00355         encryption_infoton::BLOWFISH_KEY_SIZE);
00356     _encrypt_arm->keys().unlock(reco);
00357     _channel_secured = true;
00358   }
00359 #endif
00360 
00361   if (!_authorized) {
00362     // we need to go through whatever authentication is used by the server.
00363     security_infoton::login_modes login_type = security_infoton::LI_LOGIN;
00364     security_infoton securinfo(login_type, OKAY, byte_array());
00365     octopus_request_id item_id;
00366     infoton *response;
00367     outcome ret = synchronous_request(securinfo, response, item_id);
00368     unhandled_request *temp_unh = dynamic_cast<unhandled_request *>(response);
00369     if (temp_unh) {
00370 #ifdef DEBUG_CROMP_CLIENT
00371       LOG(istring("got an unhandled request with reason: ")
00372           + common::outcome_name(temp_unh->_reason));
00373 #endif
00374       return temp_unh->_reason;  // return the original reason.
00375     }
00376     CAST_REPLY(security_infoton, response, sec_reply, NO_SERVER);
00377     outcome success = sec_reply->_success;
00378     if (success == tentacle::OKAY) {
00379       AUTO_LOCK;
00380       _authorized = true;
00381     } else {
00382 #ifdef DEBUG_CROMP_CLIENT
00383       LOG(istring("login request failed."));
00384 #endif
00385     }
00386     WHACK(sec_reply);
00387   }
00388 
00389   return OKAY;
00390 }
00391 
00392 outcome cromp_client::connect()
00393 {
00394   FUNCDEF("connect");
00395   stop_asynch_thread();
00396   AUTO_LOCK;  // protect from multiple connect attempts.
00397   return locked_connect();
00398 }
00399 
00400 outcome cromp_client::asynch_connect()
00401 {
00402   FUNCDEF("asynch_connect");
00403   if (connected()) return OKAY;  // why bother?
00404   if (_asynch_connector) return NO_CONNECTION;  // in progress.
00405 //#ifdef DEBUG_CROMP_CLIENT
00406   LOG(instance_name() + " entry.");
00407 //#endif
00408   {
00409     AUTO_LOCK;
00410       // protect this block only; we want to unlock before thread gets started.
00411     if (connected()) return OKAY;  // done already somehow.
00412     if (_asynch_connector) {
00413       LOG("logic error: asynchronous connector already exists.");
00414       return NO_CONNECTION;
00415     }
00416     _disallowed = true;
00417     _asynch_connector = new asynch_connection_thread(*this);
00418   }
00419   _asynch_connector->start(NIL);
00420 //#ifdef DEBUG_CROMP_CLIENT
00421   LOG(instance_name() + " exit.");
00422 //#endif
00423   return NO_CONNECTION;
00424 }
00425 
00426 outcome cromp_client::locked_connect()
00427 {
00428   FUNCDEF("locked_connect");
00429   if (!spock()) return BAD_INPUT;
00430   if (connected()) return OKAY;  // already connected.
00431 
00432   locked_disconnect();  // clean out any previous connection.
00433   *_ent = randomize_entity();  // reset the login id.
00434 
00435   int attempts = 0;
00436   while (attempts++ < MAX_CONN_ATTEMPTS) {
00437 #ifdef DEBUG_CROMP_CLIENT
00438     LOG(instance_name() + " calling spocket connect.");
00439 #endif
00440     outcome ret = spock()->connect(_connection_wait);
00441 #ifdef DEBUG_CROMP_CLIENT
00442     LOG(instance_name() + " done calling spocket connect.");
00443 #endif
00444     if (ret == spocket::OKAY) {
00445 #ifdef DEBUG_CROMP_CLIENT
00446       LOG("finished connection...  now affirming identity.");
00447 #endif
00448       return login();
00449     }
00450     if (ret == spocket::TIMED_OUT) return TIMED_OUT;
00451     if ( (ret == spocket::NO_ANSWER) || (ret == spocket::ACCESS_DENIED) ) {
00452       // clean up.  this is a real case of something hosed.
00453       locked_disconnect();
00454       return NO_SERVER;
00455     }
00456 #ifdef DEBUG_CROMP_CLIENT
00457     LOG(isprintf("error gotten=%s", spocket::outcome_name(ret)));
00458 #endif
00459 
00460     if (attempts < MAX_CONN_ATTEMPTS - 1)
00461       portable::sleep_ms(INTERCONNECTION_SNOOZE);
00462   }
00463   FILT_LOG(common::NETWORK_LOGGING, instance_name() + " failed to connect.");
00464   locked_disconnect();  // clean up.
00465   return NO_CONNECTION;
00466 }
00467 
00468 outcome cromp_client::disconnect()
00469 {
00470   stop_asynch_thread();
00471   AUTO_LOCK;
00472   return locked_disconnect();
00473 }
00474 
00475 void cromp_client::keep_alive_pause(int duration, int interval)
00476 {
00477   if (duration < 0) duration = 0;
00478   if (interval < 0) interval = 40;
00479   if (interval > duration) interval = duration;
00480   
00481   // keep looping on the cromp stimulation methods until the time has elapsed.
00482   time_stamp leave_at(duration);
00483   while (time_stamp() < leave_at) {
00484     push_outgoing(1);
00485     grab_anything(false);
00486     // we'll only sleep if they didn't give us a zero duration.
00487     if (duration)
00488       portable::sleep_ms(interval);  // snooze a hopefully short time.
00489   }
00490 }
00491 
00492 outcome cromp_client::locked_disconnect()
00493 {
00494   if (!spock()) return BAD_INPUT;
00495   outcome ret = spock()->disconnect();
00496   _identified = false;
00497   _authorized = false;
00498 #ifndef OMIT_CRYPTO_SUPPORT
00499   _channel_secured = false;
00500 #endif
00501   *_ent = octopus_entity();  // reset the login id.
00502   if (ret != spocket::OKAY) {
00503 //hmmm: any other outcomes to return?
00504     return OKAY;
00505   }
00506   return OKAY;
00507 }
00508 
00509 #ifndef OMIT_CRYPTO_SUPPORT
00510 bool cromp_client::wrap_infoton(const infoton &request,
00511     encryption_wrapper &wrapped)
00512 {
00513   FUNCDEF("wrap_infoton");
00514   if (!_channel_secured) return false;
00515   // identity is not wrapped with encryption; we need to establish and identity
00516   // to talk on a distinct channel with the server.  even if that identity were
00517   // compromised, the interloper should still not be able to listen in on the
00518   // establishment of an encryption channel.
00519   bool is_ident = !!dynamic_cast<const identity_infoton *>(&request);
00520   bool is_encrypt = !!dynamic_cast<const encryption_infoton *>(&request);
00521   bool is_wrapper = !!dynamic_cast<const encryption_wrapper *>(&request);
00522   if (!is_ident && !is_encrypt && !is_wrapper) {
00523     // check that we have already got a channel to speak over.  otherwise, we
00524     // can't do any encrypting of messages yet.
00525     if (!_channel_secured) {
00526 #ifdef DEBUG_CROMP_CLIENT
00527       LOG("the channel has not been secured yet.");
00528 #endif
00529       return false;
00530     }
00531 #ifdef DEBUG_CROMP_CLIENT
00532     LOG(istring("encrypting ") + request.text_form());
00533 #endif
00534     byte_array packed_request;
00535     infoton::fast_pack(packed_request, request);
00536     _crypto->encrypt(packed_request, wrapped._wrapped);
00537     return true;
00538   } else return false;  // we didn't need or want to wrap it.
00539 }
00540 #endif
00541 
00542 outcome cromp_client::submit(const infoton &request,
00543     octopus_request_id &item_id, int max_tries)
00544 {
00545   FUNCDEF("submit");
00546   CHECK_LOCKOUT;
00547   item_id = next_id();
00548   bool is_ident = !!dynamic_cast<const identity_infoton *>(&request);
00549   if (!_identified && !is_ident) return BAD_INPUT;
00550 
00551 #ifndef OMIT_CRYPTO_SUPPORT
00552   if (_encrypting && _channel_secured) {
00553     // if we're encrypting things, then we need to encrypt this too.  this
00554     // assumes that authentication is wrapped by encryption, which is the sane
00555     // thing to do.  identity is not wrapped that way though; we need to
00556     // establish and identity to talk on a distinct channel with the server.
00557     // even if that identity were compromised, the interloper would still not
00558     // be able to listen in on the establishment of an encryption channel.
00559 
00560     encryption_wrapper real_request;
00561     bool wrapped_okay = wrap_infoton(request, real_request);
00562     if (wrapped_okay) {
00563       outcome to_return = cromp_common::pack_and_ship(real_request, item_id,
00564           max_tries);
00565       return to_return;
00566     }
00567     // if it didn't wrap okay, we fall through to a normal send, because it's
00568     // probably an encryption or identity infoton, which needs to go through
00569     // without being wrapped.
00570   } else {
00571 #ifdef DEBUG_CROMP_CLIENT
00572     LOG("the channel has not been secured yet.");
00573 #endif
00574   }
00575 #endif
00576 
00577   outcome to_return = cromp_common::pack_and_ship(request, item_id, max_tries);
00578   return to_return;
00579 }
00580 
00581 outcome cromp_client::acquire(infoton * &response,
00582     const octopus_request_id &cmd_id, int timeout)
00583 {
00584   FUNCDEF("acquire");
00585   CHECK_LOCKOUT;
00586   outcome to_return = cromp_common::retrieve_and_restore(response, cmd_id,
00587       timeout);
00588 
00589   unhandled_request *intermed = dynamic_cast<unhandled_request *>(response);
00590   if (intermed) {
00591     // override the return value with the real outcome of a failed operation.
00592     to_return = intermed->_reason;
00593   }
00594 
00595   decrypt_package_as_needed(to_return, response, cmd_id);
00596 
00597   return to_return;
00598 }
00599 
00600 void cromp_client::decrypt_package_as_needed(outcome &to_return,
00601     infoton * &response, const octopus_request_id &cmd_id)
00602 {
00603   FUNCDEF("decrypt_package_as_needed");
00604 #ifndef OMIT_CRYPTO_SUPPORT
00605   if (dynamic_cast<encryption_wrapper *>(response)) {
00606     if (!_encrypt_arm) {
00607       LOG(istring("received an encryption_wrapper but we are not "
00608           "encrypting, on ") + cmd_id.text_form());
00609       to_return = ENCRYPTION_MISMATCH;
00610       return;
00611     }
00612     byte_array transformed;
00613     outcome ret = _encrypt_arm->consume(*response, cmd_id, transformed);
00614     if ( (ret != OKAY) && (ret != PARTIAL) ) {
00615       LOG(istring("failed to decrypt wrapper for ") + cmd_id.text_form());
00616       to_return = ret;
00617       return;
00618     }
00619 
00620     string_array classif;
00621     byte_array decro;  // decrypted packed infoton.
00622     bool worked = infoton::fast_unpack(transformed, classif, decro);
00623     if (!worked) {
00624       LOG("failed to fast_unpack the transformed data.");
00625       to_return = ENCRYPTION_MISMATCH;  // what else would we call that?
00626     } else {
00627       infoton *new_req = NIL;
00628       outcome rest_ret = octo()->restore(classif, decro, new_req);
00629       if (rest_ret == tentacle::OKAY) {
00630         // we got a good transformed version.
00631         WHACK(response);
00632         response = new_req;  // substitution complete.
00633       } else {
00634         LOG("failed to restore transformed infoton.");
00635         to_return = ENCRYPTION_MISMATCH;  // what else would we call that?
00636       }
00637     }
00638   }
00639 #else
00640   // encryption is not needed.
00641   if (cmd_id._request_num || response) {}
00642   to_return = OKAY;
00643 #endif
00644 }
00645 
00646 
00647 #endif //CROMP_CLIENT_IMPLEMENTATION_FILE
00648 

Generated on Fri Aug 29 04:28:27 2008 for HOOPLE Libraries by  doxygen 1.5.1