feisty meow concerns codebase  2.140
cromp_transaction.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : cromp_transaction *
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_transaction.h"
16 
17 #include <basis/environment.h>
18 #include <basis/mutex.h>
20 #include <loggers/file_logger.h>
22 #include <octopus/entity_defs.h>
23 #include <octopus/infoton.h>
24 #include <sockets/tcpip_stack.h>
26 #include <textual/parser_bits.h>
27 
28 #include <stdio.h>
29 
30 using namespace basis;
31 using namespace loggers;
32 using namespace octopi;
33 using namespace sockets;
34 using namespace structures;
35 using namespace textual;
36 
37 namespace cromp {
38 
39 #define DEBUG_CROMP_TRANSACTION
40  // uncomment for noisy version.
41 
42 const int MAXIMUM_TRANSACTION = 100 * MEGABYTE;
43  // the largest transaction we allow in cromp. if more information needs
44  // to be passed, then do it in chunks.
45 
46 #undef LOG
47 #ifdef DEBUG_CROMP_TRANSACTION
48  // since the transaction stuff is so low-level, we risk a feedback loop if
49  // we log stuff when the program wide logger is itself a communication
50  // object.
51  #define LOG(s) CLASS_EMERGENCY_LOG(file_logger(environment::TMP() + "/cromp_transaction.log"), s)
52 #else
53  #define LOG(s)
54 #endif
55 
56 SAFE_STATIC(mutex, __cromp_transaction_lock, )
57 
59 {}
60 
61 const char *cromp_transaction::outcome_name(const outcome &to_name)
62 {
63  switch (to_name.value()) {
64  case WAY_TOO_SMALL: return "WAY_TOO_SMALL";
65  case ILLEGAL_LENGTH: return "ILLEGAL_LENGTH";
66  default: return communication_commons::outcome_name(to_name);
67  }
68 }
69 
71 {
72  static byte_array _hidden_cromp_array;
73  static bool _initted = false;
74  if (!_initted) {
75  auto_synchronizer l(__cromp_transaction_lock());
76  // check again in case someone scooped us.
77  if (!_initted) {
78  // add the special name field.
79  attach(_hidden_cromp_array, abyte('c'));
80  attach(_hidden_cromp_array, abyte('r'));
81  attach(_hidden_cromp_array, abyte('o'));
82  attach(_hidden_cromp_array, abyte('m'));
83  attach(_hidden_cromp_array, abyte('p'));
84  attach(_hidden_cromp_array, abyte('!'));
85  // add the space for the length.
86  for (int i = 0; i < 8; i++)
87  attach(_hidden_cromp_array, abyte('?'));
88  _initted = true;
89  }
90  }
91  return _hidden_cromp_array;
92 }
93 
94 int cromp_transaction::minimum_flat_size(const octopus_request_id &id)
95 {
96  return cromp_name_array().length() // cromp identifier in header.
97  + id.packed_size(); // size of the request id.
98 }
99 
100 int cromp_transaction::minimum_flat_size(const string_array &classifier,
101  const octopus_request_id &id)
102 {
103  return minimum_flat_size(id)
104  + infoton::fast_pack_overhead(classifier);
105  // size required for infoton::fast_pack.
106 }
107 
108 void cromp_transaction::flatten(byte_array &packed_form,
109  const infoton &request, const octopus_request_id &id)
110 {
111 #ifdef DEBUG_CROMP_TRANSACTION
112  FUNCDEF("pack");
113 #endif
114  int posn = packed_form.length();
115  // save where we started adding.
116 
117  packed_form += cromp_name_array();
118  // add the cromp prefix and space for the length.
119 
120  // add the identifier.
121  id.pack(packed_form);
122 
123  // add the real data.
124  infoton::fast_pack(packed_form, request);
125 #ifdef DEBUG_CROMP_TRANSACTION
126  // make a copy of the packed infoton to compare.
127  byte_array temp_holding;
128  infoton::fast_pack(temp_holding, request);
129 #endif
130 
131 //hmmm: check if too big!
132 
133  // backpatch the length now.
134  a_sprintf len_string("%08x", packed_form.length() - posn);
135 #ifdef DEBUG_CROMP_TRANSACTION
136  LOG(a_sprintf("len string is %s", len_string.s()));
137 #endif
138  for (int j = 6; j < 14; j++)
139  packed_form[posn + j] = abyte(len_string[j - 6]);
140 
141 #ifdef DEBUG_CROMP_TRANSACTION
142  byte_array copy = packed_form.subarray(posn, packed_form.last());
143  byte_array tempo;
144  octopus_request_id urfid;
145  if (!cromp_transaction::unflatten(copy, tempo, urfid))
147  "failed to unpack what we just packed.");
148  else if (urfid != id)
149  continuable_error(static_class_name(), func, "wrong id after unpack.");
150  else if (tempo != temp_holding)
151  continuable_error(static_class_name(), func, "wrong data after unpack.");
152 #endif
153 
154 }
155 
156 bool cromp_transaction::unflatten(byte_array &packed_form,
157  byte_array &still_flat, octopus_request_id &req_id)
158 {
159 #ifdef DEBUG_CROMP_TRANSACTION
160  FUNCDEF("unflatten");
161 #endif
162  still_flat.reset();
163  int len = 0;
164  // not ready yet.
165  if (peek_header(packed_form, len) != OKAY) {
166 #ifdef DEBUG_CROMP_TRANSACTION
167  LOG("failed to peek the header!");
168 #endif
169  return false;
170  }
171  packed_form.zap(0, 14 - 1);
172  if (!req_id.unpack(packed_form)) return false;
173  int array_len = len - 14 - req_id.packed_size();
174 
175 #ifdef DEBUG_CROMP_TRANSACTION
176  if (array_len > packed_form.length())
178  "data needed is insufficient! peek was wrong.");
179 #endif
180 
181  still_flat = packed_form.subarray(0, array_len - 1);
182  packed_form.zap(0, array_len - 1);
183  return true;
184 }
185 
186 #define WHACK_AND_GO { packed_form.zap(0, 0); continue; }
187 
188 #define CHECK_LENGTH \
189  if (packed_form.length() < necessary_length) { \
190  /* to this point, we are happy with the contents. */ \
191  return true; \
192  } \
193  necessary_length++; /* require the next higher length. */
194 
195 bool cromp_transaction::resynchronize(byte_array &packed_form)
196 {
197 #ifdef DEBUG_CROMP_TRANSACTION
198  FUNCDEF("resynchronize");
199 #endif
200  while (true) {
201  if (!packed_form.length()) {
202 //#ifdef DEBUG_CROMP_TRANSACTION
203  LOG("roasted entire contents...");
204 //#endif
205  return false;
206  }
207  if (packed_form[0] != 'c') WHACK_AND_GO;
208  int necessary_length = 2;
209  CHECK_LENGTH;
210  if (packed_form[1] != 'r') WHACK_AND_GO;
211  CHECK_LENGTH;
212  if (packed_form[2] != 'o') WHACK_AND_GO;
213  CHECK_LENGTH;
214  if (packed_form[3] != 'm') WHACK_AND_GO;
215  CHECK_LENGTH;
216  if (packed_form[4] != 'p') WHACK_AND_GO;
217  CHECK_LENGTH;
218  if (packed_form[5] != '!') WHACK_AND_GO;
219  for (int k = 6; k < 14; k++) {
220  CHECK_LENGTH;
221  if (!parser_bits::is_hexadecimal(packed_form[k]))
222  WHACK_AND_GO;
223  }
224 #ifdef DEBUG_CROMP_TRANSACTION
225  LOG("found header again...");
226 #endif
227  return true; // looks like we resynched.
228  }
229 }
230 
231 outcome cromp_transaction::peek_header(const byte_array &packed_form,
232  int &length)
233 {
234 #ifdef DEBUG_CROMP_TRANSACTION
235  FUNCDEF("peek_header");
236 #endif
237  length = 0;
238 #ifdef DEBUG_CROMP_TRANSACTION
239  LOG("checking for header");
240 #endif
241  if (packed_form.length() < 14) return WAY_TOO_SMALL;
242  if ( (packed_form[0] != 'c') || (packed_form[1] != 'r')
243  || (packed_form[2] != 'o') || (packed_form[3] != 'm')
244  || (packed_form[4] != 'p') || (packed_form[5] != '!') )
245  return GARBAGE;
246 #ifdef DEBUG_CROMP_TRANSACTION
247  LOG("obvious header bits look fine");
248 #endif
249 
250  astring len_string;
251  for (int k = 6; k < 14; k++) {
252  if (!parser_bits::is_hexadecimal(packed_form[k])) {
253 #ifdef DEBUG_CROMP_TRANSACTION
254  LOG("found corruption in hex bytes");
255 #endif
256  return GARBAGE;
257  }
258  len_string += char(packed_form[k]);
259  }
260 #ifdef DEBUG_CROMP_TRANSACTION
261  LOG("length was unpacked okay");
262 #endif
263  basis::un_int temp_len = (basis::un_int)length;
264  int items = sscanf(len_string.s(), "%08x", &temp_len);
265  length = temp_len;
266  if (!items) {
267 #ifdef DEBUG_CROMP_TRANSACTION
268  LOG(astring("couldn't parse the len_string of: ") + len_string);
269 #endif
270  return GARBAGE;
271  }
272 
273 #ifdef DEBUG_CROMP_TRANSACTION
274  LOG(a_sprintf("length string is %s, len calc is %d and bytes "
275  "given are %d", len_string.s(), length, packed_form.length()));
276 #endif
277  if (length > MAXIMUM_TRANSACTION) return ILLEGAL_LENGTH;
278  if (length > packed_form.length()) return PARTIAL;
279  return OKAY;
280 }
281 
282 } //namespace.
283 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition: array.h:349
array subarray(int start, int end) const
Returns the array segment between the indices "start" and "end".
Definition: array.h:443
int length() const
Returns the current reported length of the allocated C array.
Definition: array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition: array.h:769
int last() const
Returns the last valid element in the array.
Definition: array.h:118
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition: mutex.h:113
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
int value() const
Definition: outcome.h:51
An infoton is an individual request parcel with accompanying information.
Definition: infoton.h:32
Identifies requests made on an octopus by users.
Definition: entity_defs.h:114
int packed_size() const
reports how large the packed id will be.
virtual bool unpack(basis::byte_array &packed_form)
Restores the packable from the "packed_form".
An array of strings with some additional helpful methods.
Definition: string_array.h:32
#define continuable_error(c, f, i)
#define LOG(s)
#define WHACK_AND_GO
#define CHECK_LENGTH
char * copy(register char *str)
Definition: makedep.cpp:554
#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
const int MEGABYTE
Number of bytes in a megabyte.
Definition: definitions.h:135
unsigned char abyte
A fairly important unit which is seldom defined...
Definition: definitions.h:51
void attach(byte_array &packed_form, const char *to_attach)
Packs a character string "to_attach" into "packed_form".
Definition: astring.cpp:1015
unsigned int un_int
Abbreviated name for unsigned integers.
Definition: definitions.h:62
const int MAXIMUM_TRANSACTION
byte_array & cromp_name_array()
A logger that sends to the console screen using the standard output device.
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
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
#define static_class_name()