cromp_transaction.cpp

Go to the documentation of this file.
00001 #ifndef CROMP_TRANSACTION_IMPLEMENTATION_FILE
00002 #define CROMP_TRANSACTION_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : cromp_transaction                                                 *
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_transaction.h"
00019 
00020 #include <basis/log_base.h>
00021 #include <basis/mutex.h>
00022 #include <basis/portable.h>
00023 #include <data_struct/static_memory_gremlin.h>
00024 #include <octopus/entity_defs.h>
00025 #include <octopus/infoton.h>
00026 #include <loggers/file_logger.h>
00027 #include <sockets/definitions_sockets.h>
00028 #include <textual/parser_bits.h>
00029 
00030 #include <stdio.h>
00031 
00032 using namespace basis;
00033 
00034 //#define DEBUG_CROMP_TRANSACTION
00035   // uncomment for noisy version.
00036 
00037 const int MAXIMUM_TRANSACTION = 100 * MEGABYTE;
00038   // the largest transaction we allow in cromp.  if more information needs
00039   // to be passed, then do it in chunks.
00040 
00041 #undef LOG
00042 #ifdef DEBUG_CROMP_TRANSACTION
00043   // since the transaction stuff is so low-level, we risk a feedback loop if
00044   // we log stuff when the program wide logger is itself a communication
00045   // object.
00046   #define LOG(s) CLASS_EMERGENCY_LOG(file_logger(portable::env_string("TMP") + "/cromp_transaction.log"), s)
00047 #else
00048   #define LOG(s) 
00049 #endif
00050 
00051 SAFE_STATIC(mutex, __cromp_transaction_lock, )
00052 
00053 cromp_transaction::~cromp_transaction()
00054 {}
00055 
00056 const char *cromp_transaction::outcome_name(const outcome &to_name)
00057 {
00058   switch (to_name.value()) {
00059     case WAY_TOO_SMALL: return "WAY_TOO_SMALL";
00060     case ILLEGAL_LENGTH: return "ILLEGAL_LENGTH";
00061     default: return communication_commons::outcome_name(to_name);
00062   }
00063 }
00064 
00065 byte_array &cromp_name_array()
00066 {
00067   static byte_array _hidden_cromp_array;
00068   static bool _initted = false;
00069   if (!_initted) {
00070     auto_synchronizer l(__cromp_transaction_lock());
00071     // check again in case someone scooped us.
00072     if (!_initted) {
00073       // add the special name field.
00074       attach(_hidden_cromp_array, byte('c'));
00075       attach(_hidden_cromp_array, byte('r'));
00076       attach(_hidden_cromp_array, byte('o'));
00077       attach(_hidden_cromp_array, byte('m'));
00078       attach(_hidden_cromp_array, byte('p'));
00079       attach(_hidden_cromp_array, byte('!'));
00080       // add the space for the length.
00081       for (int i = 0; i < 8; i++)
00082         attach(_hidden_cromp_array, byte('?'));
00083       _initted = true;
00084     }
00085   }
00086   return _hidden_cromp_array;
00087 }
00088 
00089 int cromp_transaction::minimum_flat_size(const octopus_request_id &id)
00090 {
00091   return cromp_name_array().length()  // cromp identifier in header.
00092       + id.packed_size();  // size of the request id.
00093 }
00094 
00095 int cromp_transaction::minimum_flat_size(const string_array &classifier,
00096     const octopus_request_id &id)
00097 {
00098   return minimum_flat_size(id)
00099       + infoton::fast_pack_overhead(classifier);
00100           // size required for infoton::fast_pack.
00101 }
00102 
00103 void cromp_transaction::flatten(byte_array &packed_form,
00104     const infoton &request, const octopus_request_id &id)
00105 {
00106   FUNCDEF("pack");
00107   int posn = packed_form.length();
00108     // save where we started adding.
00109 
00110   packed_form += cromp_name_array();
00111     // add the cromp prefix and space for the length.
00112 
00113   // add the identifier.
00114   id.pack(packed_form);
00115 
00116   // add the real data.
00117   infoton::fast_pack(packed_form, request);
00118 #ifdef DEBUG_CROMP_TRANSACTION
00119   // make a copy of the packed infoton to compare.
00120   byte_array temp_holding;
00121   infoton::fast_pack(temp_holding, request);
00122 #endif
00123 
00124 //hmmm: check if too big!
00125 
00126   // backpatch the length now.
00127   isprintf len_string("%08x", packed_form.length() - posn);
00128 #ifdef DEBUG_CROMP_TRANSACTION
00129   LOG(isprintf("len string is %s", len_string.s()));
00130 #endif
00131   for (int j = 6; j < 14; j++)
00132     packed_form[posn + j] = byte(len_string[j - 6]);
00133 
00134 #ifdef DEBUG_CROMP_TRANSACTION
00135   byte_array copy = packed_form.subarray(posn, packed_form.last());
00136   byte_array tempo;
00137   octopus_request_id urfid;
00138   if (!cromp_transaction::unflatten(copy, tempo, urfid))
00139     continuable_error(static_class_name(), func,
00140         "failed to unpack what we just packed.");
00141   else if (urfid != id)
00142     continuable_error(static_class_name(), func, "wrong id after unpack.");
00143   else if (tempo != temp_holding)
00144     continuable_error(static_class_name(), func, "wrong data after unpack.");
00145 #endif
00146 
00147 }
00148 
00149 bool cromp_transaction::unflatten(byte_array &packed_form,
00150     byte_array &still_flat, octopus_request_id &req_id)
00151 {
00152   FUNCDEF("unflatten");
00153   still_flat.reset();
00154   int len = 0;
00155   // not ready yet.
00156   if (peek_header(packed_form, len) != OKAY) {
00157 #ifdef DEBUG_CROMP_TRANSACTION
00158     LOG("failed to peek the header!");
00159 #endif
00160     return false;
00161   }
00162   packed_form.zap(0, 14 - 1);
00163   if (!req_id.unpack(packed_form)) return false;
00164   int array_len = len - 14 - req_id.packed_size();
00165 
00166 #ifdef DEBUG_CROMP_TRANSACTION
00167   if (array_len > packed_form.length())
00168     continuable_error(static_class_name(), func,
00169         "data needed is insufficient!  peek was wrong.");
00170 #endif
00171 
00172   still_flat = packed_form.subarray(0, array_len - 1);
00173   packed_form.zap(0, array_len - 1);
00174   return true;
00175 }
00176 
00177 #define WHACK_AND_GO { packed_form.zap(0, 0); continue; }
00178 
00179 #define CHECK_LENGTH \
00180   if (packed_form.length() < necessary_length) { \
00181     /* to this point, we are happy with the contents. */ \
00182     return true; \
00183   } \
00184   necessary_length++; /* require the next higher length. */
00185 
00186 bool cromp_transaction::resynchronize(byte_array &packed_form)
00187 {
00188   FUNCDEF("resynchronize");
00189   while (true) {
00190     if (!packed_form.length()) {
00191 //#ifdef DEBUG_CROMP_TRANSACTION
00192       LOG("roasted entire contents...");
00193 //#endif
00194       return false;
00195     }
00196     if (packed_form[0] != 'c') WHACK_AND_GO;
00197     int necessary_length = 2;
00198     CHECK_LENGTH;
00199     if (packed_form[1] != 'r') WHACK_AND_GO;
00200     CHECK_LENGTH;
00201     if (packed_form[2] != 'o') WHACK_AND_GO;
00202     CHECK_LENGTH;
00203     if (packed_form[3] != 'm') WHACK_AND_GO;
00204     CHECK_LENGTH;
00205     if (packed_form[4] != 'p') WHACK_AND_GO;
00206     CHECK_LENGTH;
00207     if (packed_form[5] != '!') WHACK_AND_GO;
00208     for (int k = 6; k < 14; k++) {
00209       CHECK_LENGTH;
00210       if (!parser_bits::is_hexadecimal(packed_form[k]))
00211         WHACK_AND_GO;
00212     }
00213 #ifdef DEBUG_CROMP_TRANSACTION
00214     LOG("found header again...");
00215 #endif
00216     return true;  // looks like we resynched.
00217   }
00218 }
00219 
00220 outcome cromp_transaction::peek_header(const byte_array &packed_form,
00221     int &length)
00222 {
00223   FUNCDEF("peek_header");
00224   length = 0;
00225 #ifdef DEBUG_CROMP_TRANSACTION
00226   LOG("checking for header");
00227 #endif
00228   if (packed_form.length() < 14) return WAY_TOO_SMALL;
00229   if ( (packed_form[0] != 'c') || (packed_form[1] != 'r')
00230       || (packed_form[2] != 'o') || (packed_form[3] != 'm')
00231       || (packed_form[4] != 'p') || (packed_form[5] != '!') )
00232     return GARBAGE;
00233 #ifdef DEBUG_CROMP_TRANSACTION
00234   LOG("obvious header bits look fine");
00235 #endif
00236 
00237   istring len_string;
00238   for (int k = 6; k < 14; k++) {
00239     if (!parser_bits::is_hexadecimal(packed_form[k])) {
00240 #ifdef DEBUG_CROMP_TRANSACTION
00241       LOG("found corruption in hex bytes");
00242 #endif
00243       return GARBAGE;
00244     }
00245     len_string += char(packed_form[k]);
00246   }
00247 #ifdef DEBUG_CROMP_TRANSACTION
00248   LOG("length was unpacked okay");
00249 #endif
00250   u_int temp_len = (u_int)length;
00251   int items = sscanf(len_string.s(), "%08x", &temp_len);
00252   length = temp_len;
00253   if (!items) {
00254 #ifdef DEBUG_CROMP_TRANSACTION
00255     LOG(istring("couldn't parse the len_string of: ") + len_string);
00256 #endif
00257     return GARBAGE;
00258   }
00259 
00260 #ifdef DEBUG_CROMP_TRANSACTION
00261   LOG(isprintf("length string is %s, len calc is %d and bytes "
00262       "given are %d", len_string.s(), length, packed_form.length()));
00263 #endif
00264   if (length > MAXIMUM_TRANSACTION) return ILLEGAL_LENGTH;
00265   if (length > packed_form.length()) return PARTIAL;
00266   return OKAY;
00267 }
00268 
00269 
00270 #endif //CROMP_TRANSACTION_IMPLEMENTATION_FILE
00271 

Generated on Tue Aug 19 04:29:26 2008 for HOOPLE Libraries by  doxygen 1.5.1