Merge branch 'master' of feistymeow.org:feisty_meow
[feisty_meow.git] / octopi / library / cromp / cromp_common.h
1 #ifndef CROMP_COMMON_CLASS
2 #define CROMP_COMMON_CLASS
3
4 /*
5 *  Name   : cromp_common
6 *  Author : Chris Koeritz
7 *******************************************************************************
8 * Copyright (c) 2000-$now By Author.  This program is free software; you can  *
9 * redistribute it and/or modify it under the terms of the GNU General Public  *
10 * License as published by the Free Software Foundation; either version 2 of   *
11 * the License or (at your option) any later version.  This is online at:      *
12 *     http://www.fsf.org/copyleft/gpl.html                                    *
13 * Please send any updates to: fred@gruntose.com                               *
14 \*****************************************************************************/
15
16 #include <crypto/rsa_crypto.h>
17 #include <octopus/octopus.h>
18 #include <octopus/entity_defs.h>
19 #include <octopus/entity_data_bin.h>
20 #include <octopus/infoton.h>
21 #include <sockets/internet_address.h>
22 #include <sockets/machine_uid.h>
23 #include <sockets/spocket.h>
24 #include <sockets/tcpip_stack.h>
25
26 namespace cromp {
27
28 const int DEFAULT_MAX_ENTITY_QUEUE = 14 * basis::MEGABYTE;
29   //!< the default size we allow per each entity.
30   /*!<  note that if there are many entities and they're all getting full, the total allowed
31   will be this number multiplied by the number of entities. */
32
33 //! A few common features used by both CROMP clients and servers.
34
35 class cromp_common : public virtual basis::root_object
36 {
37 public:
38   cromp_common(const basis::astring &host, int max_per_ent);
39     // constructs a normal common object.  open_common() must be invoked before
40     // this object becomes useful.  the "host" should be the actual TCPIP host
41     // that this program is running on.  the "max_per_ent" is the maximum
42     // allowed size (in bytes) of pending items per entity.
43
44   cromp_common(sockets::spocket *preexisting, octopi::octopus *singleton);
45     // uses a "preexisting" spocket object for the communications needed here.
46     // the "singleton" octopus is used instead of our base class for restoring
47     // any data.  note that "singleton" is not dealt with in the destructor;
48     // it is considered owned externally.  however, the "preexisting" spocket
49     // is considered to be owned by this class now.  also note that if a NULL_POINTER
50     // "preexisting" socket is passed, then socket creation occurs by the
51     // normal process.
52
53   virtual ~cromp_common();
54
55   static int default_port();
56     // returns the default port used by cromp and octopus.  this is not
57     // appropriate for most derived apps; they should use their own ports.
58
59   DEFINE_CLASS_NAME("cromp_common");
60
61   basis::outcome open_common(const sockets::internet_address &where);
62     // opens the object to begin communication.  this is the first point at
63     // which the socket is opened.
64
65   basis::outcome close_common();
66     // shuts down our presence on the network.
67
68   sockets::spocket *spock() const;
69     // allows external access to our socket object.  do not abuse this.
70     // also keep in mind that in some stages of construction, this can return
71     // NULL_POINTER.  do not assume it is non-null.
72
73   sockets::internet_address other_side() const;
74     // returns the location that we're connected to, if any.
75
76   virtual basis::outcome add_tentacle(octopi::tentacle *to_add, bool filter = false);
77     // allows customization of the processing that the cromp object performs.
78
79   enum outcomes {
80     OKAY = basis::common::OKAY,
81     DISALLOWED = basis::common::DISALLOWED,
82     BAD_INPUT = basis::common::BAD_INPUT,
83     NOT_FOUND = basis::common::NOT_FOUND,
84     TIMED_OUT = basis::common::TIMED_OUT,
85     GARBAGE = basis::common::GARBAGE,
86     NO_HANDLER = basis::common::NO_HANDLER,
87     PARTIAL = basis::common::PARTIAL,
88     ENCRYPTION_MISMATCH = basis::common::ENCRYPTION_MISMATCH,
89
90     NO_SERVER = sockets::communication_commons::NO_SERVER,
91     NO_CONNECTION = sockets::communication_commons::NO_CONNECTION,
92
93     DEFINE_OUTCOME(TOO_FULL, -40, "The request cannot be processed yet")
94   };
95
96   static const char *outcome_name(const basis::outcome &to_name);
97
98   static basis::astring chew_hostname(const sockets::internet_address &addr,
99           sockets::internet_address *resolved = NULL_POINTER);
100     // resolves the hostname in "addr" and returns the resolved hostname as
101     // a machine_uid compact_form().  the "resolved" form of the address is
102     // also stored if the pointer is non-null.
103
104   basis::astring responses_text_form() const;
105     // returns a textual form of the responses awaiting pickup.
106
107   bool buffer_clog(int clog_point = 1 * basis::MEGABYTE) const;
108     // returns true if the buffer is bigger than a certain "clog_point".
109
110   basis::outcome pack_and_ship(const octopi::infoton &request,
111           const octopi::octopus_request_id &item_id, int max_tries);
112     // requests a transaction from the other side, specified by the "request".
113     // the return value is OKAY if the request was successfully sent or it
114     // will be another outcome that indicates a failure of transmission.
115     // the "item_id" must be set ahead of time to identify the request and
116     // sender.  the "max_tries" limits how many times the sending is
117     // reattempted on failure.
118
119   basis::outcome pack_and_ship(const octopi::infoton_list &requests, int max_tries);
120     // sends a batch of "requests" in one blast.
121
122   basis::outcome retrieve_and_restore(octopi::infoton * &item,
123           const octopi::octopus_request_id &req_id, int timeout);
124     // attempts to pull down data from our spocket and process it back into
125     // an infoton in "item".   only the specific object for the "req_id"
126     // will be provided.  if the "timeout" is non-zero, then data will be
127     // awaited that long.  if "timeout" is zero, the method will return
128     // immediately if the data is not already available.
129
130   basis::outcome retrieve_and_restore_any(octopi::infoton * &item, octopi::octopus_request_id &req_id,
131           int timeout);
132     // returns the first infoton that becomes available.  the "req_id" is set
133     // to the identifier from the transaction.  this is useful more for the
134     // server side than for the client side.
135
136   basis::outcome push_outgoing(int max_tries);
137     // composes calls to grab_anything and send_buffer into an attempt to
138     // get all of the data out that is waiting while not ignoring the incoming
139     // data from the other side.
140
141   void grab_anything(bool wait);
142     // attempts to locate any data waiting for our socket.  any infotons
143     // found get stuffed into the requests bin.  this is never needed for
144     // cromp_clients; the retrieve methods will automatically invoke this
145     // as appropriate.  if "wait" is true, then a data pause will occur
146     // on the socket to await data.
147
148   basis::outcome send_buffer();
149     // pushes out any pending data waiting for the other side.  the returns
150     // can range the gamut, but OKAY and PARTIAL are both successful outcomes.
151     // OKAY means that everything was sent successfully (or there was nothing
152     // to send).  PARTIAL means that not all the data was sent, but some got
153     // out successfully.  any other errors probably indicate a major problem.
154
155   // these adjust the storage sizes allowed internally.
156   int max_bytes_per_entity() const;
157   void max_bytes_per_entity(int max_bytes_per_entity);
158
159   // provides information on the overall number of bytes encountered by all
160   // cromp clients in this program.  these are only intended for testing
161   // purposes and might in fact roll over for a busy client app.
162   static double total_bytes_sent() { return _bytes_sent_total; }
163   static double total_bytes_received() { return _bytes_received_total; }
164
165   static const int HOSTCHOP;
166     // this is the number of characters from the host's name that go into the
167     // octopus identity.  the portion after that many characters is a compacted
168     // form of the machine_uid.
169
170   static bool decode_host(const basis::astring &coded_host, basis::astring &hostname,
171            sockets::machine_uid &machine);
172     // takes the "coded_host" from an entity and returns the "hostname" and
173     // "machine" information that was encoded in it.  those will be gibberish
174     // unless true is returned.
175
176   octopi::octopus *octo() const { return _octopus; }
177     // returns our octopus support object.  this should always exist when this
178     // object is constructed properly.
179
180   static const crypto::rsa_crypto &localhost_only_key();
181     // this key should *only* be used for speeding up encryption on the local
182     // host.  it is generated when the first caller needs it but then is
183     // a constant key during the program's runtime.  this object can be used
184     // for initializing services when it is _known_ that they are connecting
185     // only on the localhost; that's the only place it should be used because
186     // re-using the key on the network provides less security than using
187     // the randomized encryption startup in cromp.
188
189   int pending_sends() const;
190     //!< returns the number of bytes still unsent.
191
192   int accumulated_bytes() const;
193     //!< returns the number of bytes pending processing from the other side.
194
195 protected:
196   octopi::octopus *singleton() const { return _singleton; }
197     // returns the singleton octopus passed to the constructor earlier.
198     // this will return NULL_POINTER if it was not constructed that way.
199
200 private:
201   sockets::spocket *_commlink;  // transceiver for data.
202   octopi::octopus *_octopus;  // main octopus; might be same as singleton.
203   octopi::octopus *_singleton;  // used for dependent cromp server objects.
204   octopi::entity_data_bin *_requests;  // where the incoming requests are stored.
205   basis::mutex *_accum_lock;  // protects the accumulator and other data below.
206   timely::time_stamp *_last_data_seen;  // last time we got anything on socket.
207   basis::byte_array *_accumulator;  // accumulates data for this object.
208   basis::byte_array *_sendings;  // accumulates outgoing sends when socket is full.
209   basis::byte_array *_receive_buffer;  // temporary buffer.
210   basis::byte_array *_still_flat;  // another temporary buffer.
211   timely::time_stamp *_last_cleanup;  // when we last cleaned out our bin.
212
213   // helps for testing; not used for operation.
214   static double _bytes_sent_total;
215   static double _bytes_received_total;
216
217   void snarf_from_socket(bool wait);
218     // retrieves data waiting on the socket and adds to the accumulator.
219     // if "wait" is true, then the presence of data is awaited first.
220
221   void process_accumulator();
222     // chews on the accumulated data to seek any commands that are present.
223
224   void conditional_cleaning();
225     // flushes out any old items if they haven't been cleaned in a bit.
226
227   basis::outcome retrieve_and_restore_root(bool get_anything, octopi::infoton * &item,
228           octopi::octopus_request_id &req_id, int timeout);
229     // used for both types of retrieval; if "get_anything" is true, then
230     // any old item will be returned.  if "get_anything" is false, then only
231     // the item with "req_id" is returned.
232 };
233
234 } //namespace.
235
236 #endif
237