1 #ifndef CROMP_CLIENT_CLASS
2 #define CROMP_CLIENT_CLASS
4 /*****************************************************************************\
6 * Name : cromp_client *
7 * Author : Chris Koeritz *
11 * Supplies primitive operations for requesting services of a CROMP-based *
12 * server application. Tentacles in cromp clients are only used for *
13 * restoring original objects, but they are required for that. Keep in mind *
14 * that for communication to be possible, a cromp server and its cromp client *
15 * must possess tentacles that grok the same infotons. They do not need to *
16 * be the same objects and probably shouldn't be. It makes sense to *
17 * implement an unpacking / cloning tentacle and then derive the full-service *
18 * request processing tentacle from it. *
20 *******************************************************************************
21 * Copyright (c) 2000-$now By Author. This program is free software; you can *
22 * redistribute it and/or modify it under the terms of the GNU General Public *
23 * License as published by the Free Software Foundation; either version 2 of *
24 * the License or (at your option) any later version. This is online at: *
25 * http://www.fsf.org/copyleft/gpl.html *
26 * Please send any updates to: fred@gruntose.com *
27 \*****************************************************************************/
29 #include "cromp_common.h"
31 #include <crypto/blowfish_crypto.h>
32 #include <sockets/internet_address.h>
33 #include <structures/roller.h>
34 #include <tentacles/encryption_tentacle.h>
35 #include <tentacles/encryption_wrapper.h>
36 #include <tentacles/entity_registry.h>
37 #include <timely/time_stamp.h>
42 class asynch_connection_thread;
44 class cromp_client : public cromp_common
48 DEFAULT_MAX_CONNECT_WAIT = 28 * basis::SECOND_ms,
49 // the server had better connect within this time limit or it will
50 // be considered missing in action.
51 DEFAULT_MAX_RESPONSE_WAIT = 4 * basis::MINUTE_ms
52 // a server should be able to answer in this interval or something is
53 // really wrong with the system.
56 cromp_client(const sockets::internet_address &destination,
57 int connection_wait = DEFAULT_MAX_CONNECT_WAIT,
58 int max_per_ent = DEFAULT_MAX_ENTITY_QUEUE);
59 // will connect to a cromp_server on the host specified by "destination".
61 virtual ~cromp_client();
63 DEFINE_CLASS_NAME("cromp_client");
65 basis::astring instance_name() const {
66 return basis::astring(class_name()) + ": " + entity().text_form();
69 const octopi::octopus_entity &entity() const;
70 // returns our identity within the octopus server.
72 void enable_encryption();
73 // this turns on the encryption. this should be done before the first
74 // connect or login invocations. once it's enabled, it stays enabled.
76 void reset(const sockets::internet_address &destination,
77 int connection_wait = DEFAULT_MAX_CONNECT_WAIT,
78 int max_per_ent = DEFAULT_MAX_ENTITY_QUEUE);
79 // disconnects from any previous server and reconstructs this client.
80 // the client will be left in an unconnected and unauthenticated state.
81 // any pre-existing tentacles will still be hooked up to the object.
82 // use connect() to re-establish the connection to the server.
84 basis::outcome connect(const basis::byte_array &verification = blank_verification());
85 // attempts to connect to the server. OKAY is returned if this succeeds.
87 static const basis::byte_array &blank_verification(); // empty verification.
89 basis::outcome asynch_connect();
90 // this is a non-blocking connect. it behaves like connect(), but should
91 // never take more than a few milliseconds to return. if the client is
92 // already connected, then nothing is done. otherwise no operations will
93 // be permitted until the reconnection has succeeded. a call to regular
94 // connect() cancels the asynchronous connect.
96 bool connected() const;
97 // returns true if we think we are connected to the server.
99 basis::outcome disconnect();
100 // disconnects from the cromp server and releases all connection resources.
102 virtual basis::outcome login();
103 // attempts to log in to the server. we must already have connected
104 // when this is called. the "verification" is a protocol specific
105 // package of info that can be used to validate the login.
109 basis::outcome submit(const octopi::infoton &request, octopi::octopus_request_id &item_id,
111 // requests a transaction from the cromp_server described by "request".
112 // the return value is OKAY if the request was successfully sent or it
113 // will be another outcome that indicates a failure of transmission.
114 // the "max_tries" is the number of times to try getting the send out;
115 // if asynchronous sends are allowed to accumulate, then 1 works here.
117 basis::outcome acquire(octopi::infoton * &response, const octopi::octopus_request_id &cmd_id,
118 int timeout = DEFAULT_MAX_RESPONSE_WAIT);
119 // attempts to receive a "response" to a previously submitted request
120 // with the "cmd_id". if "timeout" is non-zero, then the response will
121 // be awaited for "timeout" milliseconds. otherwise the function returns
122 // immediately. note that "response" will only be generated properly given
123 // a tentacle that knows the infoton type received. this requires the
124 // cromp_client to have tentacles registered for all of the types to be
125 // exchanged. this can be used for asynchronous retrieval if the timeout
126 // is zero and one knows a previously requested "cmd_id".
130 // grittier functions...
132 basis::outcome synchronous_request(const octopi::infoton &to_send, octopi::infoton * &received,
133 octopi::octopus_request_id &item_id,
134 int timeout = DEFAULT_MAX_RESPONSE_WAIT);
135 // submits the infoton "to_send" and waits for the reply. if there is
136 // a reply in the allotted time, then "received" is set to that. the
137 // "item_id" is set to the request id assigned to the request.
139 basis::outcome acquire_any(octopi::infoton * &response, octopi::octopus_request_id &cmd_id,
140 int timeout = DEFAULT_MAX_RESPONSE_WAIT);
141 // a request to retrieve any waiting data for the client. similar to
142 // acquire above, but does not require one to know the command id.
144 octopi::octopus_request_id next_id();
145 // generates the next identifier. this can be used as a unique identifier
146 // for derived objects since the id is issued from our server. it is
147 // not unique across different types of cromp servers though, nor across
148 // cromp servers running on different hosts.
150 void decrypt_package_as_needed(basis::outcome &to_return, octopi::infoton * &response,
151 const octopi::octopus_request_id &cmd_id);
152 // this ensures that if the "response" is encrypted, it will be decrypted
153 // and replaced with the real object intended. this method is invoked
154 // automatically by acquire(), but if the cromp_common retrieve methods are
155 // used directly, this should be done to the response before using it.
157 void keep_alive_pause(int duration = 0, int interval = 40);
158 // pauses this thread but keeps calling into the cromp support to ensure
159 // items get delivered or received when possible. the call will snooze
160 // for at least "duration" milliseconds with individual sleeps being
161 // allowed the "interval" milliseconds.
163 const basis::byte_array &verification() const;
164 // returns the verification token held currently, if it's been set.
167 bool _encrypting; // true if this connection should be encrypted.
168 int _connection_wait; // the length of time we'll allow a connection.
169 basis::mutex *_lock; // protects our data members below.
170 octopi::octopus_entity *_ent; // our identity within the octopus server.
171 structures::int_roller *_req_id; // the numbering of our nth request is depicted here.
172 bool _identified; // true if our initial identifier verification succeeded.
173 bool _authorized; // true if our login was successful.
174 bool _disallowed; // nothing is allowed right now except asynch connecting.
175 friend class asynch_connection_thread; // solely so it can use r_p_c method.
176 asynch_connection_thread *_asynch_connector; // b-ground connection thread.
177 bool _channel_secured; // true if an encrypted connection has been made.
178 crypto::blowfish_crypto *_crypto; // tracks our key, once we have one.
179 octopi::encryption_tentacle *_encrypt_arm; // processes encryption for us.
180 octopi::blank_entity_registry *_guardian; // simple security support.
181 basis::byte_array *c_verification; // verification token we were given.
183 void stop_asynch_thread(); // stops the background connector.
185 basis::outcome locked_connect();
186 // called by the other types of connection processes to get the work done.
188 octopi::octopus_entity randomize_entity() const;
189 // provides a junk entity for our temporary identifier that we'll use
190 // until the server gives us a new one.
192 basis::outcome locked_disconnect();
193 // assumes that the client is locked. this is the real disconnect.
195 bool wrap_infoton(const octopi::infoton &request, octopi::encryption_wrapper &wrapped);
196 // wraps an infoton for sending over an encrypted connection.