1 /*****************************************************************************\
3 * Name : cromp_transaction *
4 * Author : Chris Koeritz *
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 \*****************************************************************************/
15 #include "cromp_transaction.h"
17 #include <basis/mutex.h>
18 #include <loggers/file_logger.h>
19 #include <octopus/entity_defs.h>
20 #include <octopus/infoton.h>
21 #include <sockets/tcpip_stack.h>
22 #include <structures/static_memory_gremlin.h>
23 #include <textual/parser_bits.h>
27 using namespace basis;
28 using namespace loggers;
29 using namespace octopi;
30 using namespace sockets;
31 using namespace structures;
32 using namespace textual;
36 //#define DEBUG_CROMP_TRANSACTION
37 // uncomment for noisy version.
39 const int MAXIMUM_TRANSACTION = 100 * MEGABYTE;
40 // the largest transaction we allow in cromp. if more information needs
41 // to be passed, then do it in chunks.
44 #ifdef DEBUG_CROMP_TRANSACTION
45 // since the transaction stuff is so low-level, we risk a feedback loop if
46 // we log stuff when the program wide logger is itself a communication
48 #define LOG(s) CLASS_EMERGENCY_LOG(file_logger(portable::env_string("TMP") + "/cromp_transaction.log"), s)
53 SAFE_STATIC(mutex, __cromp_transaction_lock, )
55 cromp_transaction::~cromp_transaction()
58 const char *cromp_transaction::outcome_name(const outcome &to_name)
60 switch (to_name.value()) {
61 case WAY_TOO_SMALL: return "WAY_TOO_SMALL";
62 case ILLEGAL_LENGTH: return "ILLEGAL_LENGTH";
63 default: return communication_commons::outcome_name(to_name);
67 byte_array &cromp_name_array()
69 static byte_array _hidden_cromp_array;
70 static bool _initted = false;
72 auto_synchronizer l(__cromp_transaction_lock());
73 // check again in case someone scooped us.
75 // add the special name field.
76 attach(_hidden_cromp_array, abyte('c'));
77 attach(_hidden_cromp_array, abyte('r'));
78 attach(_hidden_cromp_array, abyte('o'));
79 attach(_hidden_cromp_array, abyte('m'));
80 attach(_hidden_cromp_array, abyte('p'));
81 attach(_hidden_cromp_array, abyte('!'));
82 // add the space for the length.
83 for (int i = 0; i < 8; i++)
84 attach(_hidden_cromp_array, abyte('?'));
88 return _hidden_cromp_array;
91 int cromp_transaction::minimum_flat_size(const octopus_request_id &id)
93 return cromp_name_array().length() // cromp identifier in header.
94 + id.packed_size(); // size of the request id.
97 int cromp_transaction::minimum_flat_size(const string_array &classifier,
98 const octopus_request_id &id)
100 return minimum_flat_size(id)
101 + infoton::fast_pack_overhead(classifier);
102 // size required for infoton::fast_pack.
105 void cromp_transaction::flatten(byte_array &packed_form,
106 const infoton &request, const octopus_request_id &id)
108 #ifdef DEBUG_CROMP_TRANSACTION
111 int posn = packed_form.length();
112 // save where we started adding.
114 packed_form += cromp_name_array();
115 // add the cromp prefix and space for the length.
117 // add the identifier.
118 id.pack(packed_form);
120 // add the real data.
121 infoton::fast_pack(packed_form, request);
122 #ifdef DEBUG_CROMP_TRANSACTION
123 // make a copy of the packed infoton to compare.
124 byte_array temp_holding;
125 infoton::fast_pack(temp_holding, request);
128 //hmmm: check if too big!
130 // backpatch the length now.
131 a_sprintf len_string("%08x", packed_form.length() - posn);
132 #ifdef DEBUG_CROMP_TRANSACTION
133 LOG(a_sprintf("len string is %s", len_string.s()));
135 for (int j = 6; j < 14; j++)
136 packed_form[posn + j] = abyte(len_string[j - 6]);
138 #ifdef DEBUG_CROMP_TRANSACTION
139 byte_array copy = packed_form.subarray(posn, packed_form.last());
141 octopus_request_id urfid;
142 if (!cromp_transaction::unflatten(copy, tempo, urfid))
143 continuable_error(static_class_name(), func,
144 "failed to unpack what we just packed.");
145 else if (urfid != id)
146 continuable_error(static_class_name(), func, "wrong id after unpack.");
147 else if (tempo != temp_holding)
148 continuable_error(static_class_name(), func, "wrong data after unpack.");
153 bool cromp_transaction::unflatten(byte_array &packed_form,
154 byte_array &still_flat, octopus_request_id &req_id)
156 #ifdef DEBUG_CROMP_TRANSACTION
157 FUNCDEF("unflatten");
162 if (peek_header(packed_form, len) != OKAY) {
163 #ifdef DEBUG_CROMP_TRANSACTION
164 LOG("failed to peek the header!");
168 packed_form.zap(0, 14 - 1);
169 if (!req_id.unpack(packed_form)) return false;
170 int array_len = len - 14 - req_id.packed_size();
172 #ifdef DEBUG_CROMP_TRANSACTION
173 if (array_len > packed_form.length())
174 continuable_error(static_class_name(), func,
175 "data needed is insufficient! peek was wrong.");
178 still_flat = packed_form.subarray(0, array_len - 1);
179 packed_form.zap(0, array_len - 1);
183 #define WHACK_AND_GO { packed_form.zap(0, 0); continue; }
185 #define CHECK_LENGTH \
186 if (packed_form.length() < necessary_length) { \
187 /* to this point, we are happy with the contents. */ \
190 necessary_length++; /* require the next higher length. */
192 bool cromp_transaction::resynchronize(byte_array &packed_form)
194 #ifdef DEBUG_CROMP_TRANSACTION
195 FUNCDEF("resynchronize");
198 if (!packed_form.length()) {
199 //#ifdef DEBUG_CROMP_TRANSACTION
200 LOG("roasted entire contents...");
204 if (packed_form[0] != 'c') WHACK_AND_GO;
205 int necessary_length = 2;
207 if (packed_form[1] != 'r') WHACK_AND_GO;
209 if (packed_form[2] != 'o') WHACK_AND_GO;
211 if (packed_form[3] != 'm') WHACK_AND_GO;
213 if (packed_form[4] != 'p') WHACK_AND_GO;
215 if (packed_form[5] != '!') WHACK_AND_GO;
216 for (int k = 6; k < 14; k++) {
218 if (!parser_bits::is_hexadecimal(packed_form[k]))
221 #ifdef DEBUG_CROMP_TRANSACTION
222 LOG("found header again...");
224 return true; // looks like we resynched.
228 outcome cromp_transaction::peek_header(const byte_array &packed_form,
231 #ifdef DEBUG_CROMP_TRANSACTION
232 FUNCDEF("peek_header");
235 #ifdef DEBUG_CROMP_TRANSACTION
236 LOG("checking for header");
238 if (packed_form.length() < 14) return WAY_TOO_SMALL;
239 if ( (packed_form[0] != 'c') || (packed_form[1] != 'r')
240 || (packed_form[2] != 'o') || (packed_form[3] != 'm')
241 || (packed_form[4] != 'p') || (packed_form[5] != '!') )
243 #ifdef DEBUG_CROMP_TRANSACTION
244 LOG("obvious header bits look fine");
248 for (int k = 6; k < 14; k++) {
249 if (!parser_bits::is_hexadecimal(packed_form[k])) {
250 #ifdef DEBUG_CROMP_TRANSACTION
251 LOG("found corruption in hex bytes");
255 len_string += char(packed_form[k]);
257 #ifdef DEBUG_CROMP_TRANSACTION
258 LOG("length was unpacked okay");
260 basis::un_int temp_len = (basis::un_int)length;
261 int items = sscanf(len_string.s(), "%08x", &temp_len);
264 #ifdef DEBUG_CROMP_TRANSACTION
265 LOG(astring("couldn't parse the len_string of: ") + len_string);
270 #ifdef DEBUG_CROMP_TRANSACTION
271 LOG(a_sprintf("length string is %s, len calc is %d and bytes "
272 "given are %d", len_string.s(), length, packed_form.length()));
274 if (length > MAXIMUM_TRANSACTION) return ILLEGAL_LENGTH;
275 if (length > packed_form.length()) return PARTIAL;