2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file consensus/consensus_api.c
24 * @author Florian Dold
27 #include "gnunet_util_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_client_lib.h"
30 #include "gnunet_consensus_service.h"
31 #include "consensus.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "consensus-api",__VA_ARGS__)
38 * Handle for the service.
40 struct GNUNET_CONSENSUS_Handle
43 * Configuration to use.
45 const struct GNUNET_CONFIGURATION_Handle *cfg;
48 * Client connected to the consensus service, may be NULL if not connected.
50 struct GNUNET_CLIENT_Connection *client;
53 * Callback for new elements. Not called for elements added locally.
55 GNUNET_CONSENSUS_ElementCallback new_element_cb;
58 * Closure for new_element_cb
60 void *new_element_cls;
63 * The (local) session identifier for the consensus session.
65 struct GNUNET_HashCode session_id;
68 * GNUNES_YES iff the join message has been sent to the service.
73 * Called when the conclude operation finishes or fails.
75 GNUNET_CONSENSUS_ConcludeCallback conclude_cb;
78 * Closure for the conclude callback.
83 * Deadline for the conclude operation.
85 struct GNUNET_TIME_Absolute conclude_deadline;
88 * Message queue for the client.
90 struct GNUNET_MQ_Handle *mq;
94 * FIXME: this should not bee necessary when the API
95 * issue has been fixed
99 GNUNET_CONSENSUS_InsertDoneCallback idc;
105 * Called when the server has sent is a new element
107 * @param cls consensus handle
108 * @param mh element message
111 handle_new_element (void *cls,
112 const struct GNUNET_MessageHeader *mh)
114 struct GNUNET_CONSENSUS_Handle *consensus = cls;
115 const struct GNUNET_CONSENSUS_ElementMessage *msg
116 = (const struct GNUNET_CONSENSUS_ElementMessage *) mh;
117 struct GNUNET_SET_Element element;
119 LOG (GNUNET_ERROR_TYPE_DEBUG,
120 "received new element\n");
122 element.element_type = msg->element_type;
123 element.size = ntohs (msg->header.size) - sizeof (struct GNUNET_CONSENSUS_ElementMessage);
124 element.data = &msg[1];
126 consensus->new_element_cb (consensus->new_element_cls, &element);
131 * Called when the server has announced
132 * that the conclusion is over.
134 * @param cls consensus handle
135 * @param msg conclude done message
138 handle_conclude_done (void *cls,
139 const struct GNUNET_MessageHeader *msg)
141 struct GNUNET_CONSENSUS_Handle *consensus = cls;
143 GNUNET_CONSENSUS_ConcludeCallback cc;
145 GNUNET_MQ_destroy (consensus->mq);
146 consensus->mq = NULL;
148 GNUNET_CLIENT_disconnect (consensus->client);
149 consensus->client = NULL;
152 GNUNET_assert (NULL != (cc = consensus->conclude_cb));
153 consensus->conclude_cb = NULL;
154 cc (consensus->conclude_cls);
159 * Generic error handler, called with the appropriate
160 * error code and the same closure specified at the creation of
162 * Not every message queue implementation supports an error handler.
164 * @param cls closure, same closure as for the message handlers
165 * @param error error code
168 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
170 LOG (GNUNET_ERROR_TYPE_WARNING, "consensus service disconnected us\n");
175 * Create a consensus session.
177 * @param cfg configuration to use for connecting to the consensus service
178 * @param num_peers number of peers in the peers array
179 * @param peers array of peers participating in this consensus session
180 * Inclusion of the local peer is optional.
181 * @param session_id session identifier
182 * Allows a group of peers to have more than consensus session.
183 * @param start start time of the consensus, conclude should be called before
185 * @param deadline time when the consensus should have concluded
186 * @param new_element_cb callback, called when a new element is added to the set by
188 * @param new_element_cls closure for new_element
189 * @return handle to use, NULL on error
191 struct GNUNET_CONSENSUS_Handle *
192 GNUNET_CONSENSUS_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
193 unsigned int num_peers,
194 const struct GNUNET_PeerIdentity *peers,
195 const struct GNUNET_HashCode *session_id,
196 struct GNUNET_TIME_Absolute start,
197 struct GNUNET_TIME_Absolute deadline,
198 GNUNET_CONSENSUS_ElementCallback new_element_cb,
199 void *new_element_cls)
201 struct GNUNET_CONSENSUS_Handle *consensus;
202 struct GNUNET_CONSENSUS_JoinMessage *join_msg;
203 struct GNUNET_MQ_Envelope *ev;
204 const static struct GNUNET_MQ_MessageHandler mq_handlers[] = {
206 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_RECEIVED_ELEMENT, 0},
207 {handle_conclude_done,
208 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE_DONE, 0},
209 GNUNET_MQ_HANDLERS_END
212 consensus = GNUNET_new (struct GNUNET_CONSENSUS_Handle);
213 consensus->cfg = cfg;
214 consensus->new_element_cb = new_element_cb;
215 consensus->new_element_cls = new_element_cls;
216 consensus->session_id = *session_id;
217 consensus->client = GNUNET_CLIENT_connect ("consensus", cfg);
218 consensus->mq = GNUNET_MQ_queue_for_connection_client (consensus->client,
219 mq_handlers, mq_error_handler, consensus);
221 GNUNET_assert (consensus->client != NULL);
223 ev = GNUNET_MQ_msg_extra (join_msg,
224 (num_peers * sizeof (struct GNUNET_PeerIdentity)),
225 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_JOIN);
227 join_msg->session_id = consensus->session_id;
228 join_msg->start = GNUNET_TIME_absolute_hton (start);
229 join_msg->deadline = GNUNET_TIME_absolute_hton (deadline);
230 join_msg->num_peers = htonl (num_peers);
233 num_peers * sizeof (struct GNUNET_PeerIdentity));
235 GNUNET_MQ_send (consensus->mq, ev);
241 idc_adapter (void *cls)
243 struct InsertDoneInfo *i = cls;
244 i->idc (i->cls, GNUNET_OK);
249 * Insert an element in the set being reconsiled. Must not be called after
250 * "GNUNET_CONSENSUS_conclude".
252 * @param consensus handle for the consensus session
253 * @param element the element to be inserted
254 * @param idc function called when we are done with this element and it
255 * is thus allowed to call GNUNET_CONSENSUS_insert again
256 * @param idc_cls closure for 'idc'
259 GNUNET_CONSENSUS_insert (struct GNUNET_CONSENSUS_Handle *consensus,
260 const struct GNUNET_SET_Element *element,
261 GNUNET_CONSENSUS_InsertDoneCallback idc,
264 struct GNUNET_CONSENSUS_ElementMessage *element_msg;
265 struct GNUNET_MQ_Envelope *ev;
266 struct InsertDoneInfo *i;
268 LOG (GNUNET_ERROR_TYPE_DEBUG, "inserting, size=%llu\n", element->size);
270 ev = GNUNET_MQ_msg_extra (element_msg, element->size,
271 GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_INSERT);
273 memcpy (&element_msg[1], element->data, element->size);
277 i = GNUNET_new (struct InsertDoneInfo);
280 GNUNET_MQ_notify_sent (ev, idc_adapter, i);
282 GNUNET_MQ_send (consensus->mq, ev);
287 * We are done with inserting new elements into the consensus;
288 * try to conclude the consensus within a given time window.
289 * After conclude has been called, no further elements may be
290 * inserted by the client.
292 * @param consensus consensus session
293 * @param deadline deadline after which the conculde callback
295 * @param conclude called when the conclusion was successful
296 * @param conclude_cls closure for the conclude callback
299 GNUNET_CONSENSUS_conclude (struct GNUNET_CONSENSUS_Handle *consensus,
300 GNUNET_CONSENSUS_ConcludeCallback conclude,
303 struct GNUNET_MQ_Envelope *ev;
305 GNUNET_assert (NULL != conclude);
306 GNUNET_assert (NULL == consensus->conclude_cb);
308 consensus->conclude_cls = conclude_cls;
309 consensus->conclude_cb = conclude;
311 ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE);
312 GNUNET_MQ_send (consensus->mq, ev);
317 * Destroy a consensus handle (free all state associated with
318 * it, no longer call any of the callbacks).
320 * @param consensus handle to destroy
323 GNUNET_CONSENSUS_destroy (struct GNUNET_CONSENSUS_Handle *consensus)
325 if (NULL != consensus->mq)
327 GNUNET_MQ_destroy (consensus->mq);
328 consensus->mq = NULL;
330 if (NULL != consensus->client)
332 GNUNET_CLIENT_disconnect (consensus->client);
333 consensus->client = NULL;
335 GNUNET_free (consensus);