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 2, 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 * @author Florian Dold
24 * @brief general purpose request queue
30 * Signature of functions implementing the
31 * sending part of a message queue
33 * @param q the message queue
34 * @param m the message
36 typedef void (*SendImpl) (struct GNUNET_MQ_MessageQueue *q, struct GNUNET_MQ_Message *m);
39 typedef void (*DestroyImpl) (struct GNUNET_MQ_MessageQueue *q);
43 * Collection of the state necessary to read and write gnunet messages
44 * to a stream socket. Should be used as closure for stream_data_processor.
46 struct MessageStreamState
48 struct GNUNET_SERVER_MessageStreamTokenizer *mst;
49 struct MessageQueue *mq;
50 struct GNUNET_STREAM_Socket *socket;
51 struct GNUNET_STREAM_ReadHandle *rh;
52 struct GNUNET_STREAM_WriteHandle *wh;
56 struct ServerClientSocketState
58 struct GNUNET_SERVER_Client *client;
59 struct GNUNET_SERVER_TransmitHandle* th;
63 struct ClientConnectionState
65 struct GNUNET_CLIENT_Connection *connection;
66 struct GNUNET_CLIENT_TransmitHandle *th;
70 struct GNUNET_MQ_MessageQueue
73 * Handlers array, or NULL if the queue should not receive messages
75 const struct GNUNET_MQ_Handler *handlers;
78 * Closure for the handler callbacks
83 * Actual implementation of message sending,
84 * called when a message is added
89 * Implementation-dependent queue destruction function
91 DestroyImpl destroy_impl;
94 * Implementation-specific state
99 * Linked list of messages pending to be sent
101 struct GNUNET_MQ_Message *msg_head;
104 * Linked list of messages pending to be sent
106 struct GNUNET_MQ_Message *msg_tail;
109 * Message that is currently scheduled to be
110 * sent. Not the head of the message queue, as the implementation
111 * needs to know if sending has been already scheduled or not.
113 struct GNUNET_MQ_Message *current_msg;
116 * Map of associations, lazily allocated
118 struct GNUNET_CONTAINER_MultiHashMap32 *assoc_map;
121 * Next id that should be used for the assoc_map,
122 * initialized lazily to a random value together with
129 struct GNUNET_MQ_Message
132 * Messages are stored in a linked list
134 struct GNUNET_MQ_Message *next;
137 * Messages are stored in a linked list
139 struct GNUNET_MQ_Message *prev;
142 * Actual allocated message header,
143 * usually points to the end of the containing GNUNET_MQ_Message
145 struct GNUNET_MessageHeader *mh;
148 * Queue the message is queued in, NULL if message is not queued.
150 struct GNUNET_MQ_MessageQueue *parent_queue;
153 * Called after the message was sent irrevokably
155 GNUNET_MQ_NotifyCallback sent_cb;
158 * Closure for send_cb
165 * Call the right callback for a message received
169 dispatch_message (struct GNUNET_MQ_MessageQueue *mq, const struct GNUNET_MessageHeader *mh)
171 const struct GNUNET_MQ_Handler *handler;
173 handler = mq->handlers;
176 for (; NULL != handler->cb; handler++)
177 if (handler->type == ntohs (mh->type))
178 handler->cb (mq->handlers_cls, mh);
183 GNUNET_MQ_discard (struct GNUNET_MQ_Message *mqm)
185 GNUNET_assert (NULL == mqm->parent_queue);
191 * Send a message with the give message queue.
192 * May only be called once per message.
194 * @param mq message queue
195 * @param mqm the message to send.
198 GNUNET_MQ_send (struct GNUNET_MQ_MessageQueue *mq, struct GNUNET_MQ_Message *mqm)
200 mq->send_impl (mq, mqm);
204 struct GNUNET_MQ_Message *
205 GNUNET_MQ_msg_ (struct GNUNET_MessageHeader **mhp, uint16_t size, uint16_t type)
207 struct GNUNET_MQ_Message *mqm;
208 mqm = GNUNET_malloc (sizeof *mqm + size);
209 mqm->mh = (struct GNUNET_MessageHeader *) &mqm[1];
210 mqm->mh->size = htons (size);
211 mqm->mh->type = htons (type);
219 GNUNET_MQ_nest_ (struct GNUNET_MQ_Message **mqmp,
220 const struct GNUNET_MessageHeader *m)
227 GNUNET_assert (NULL != mqmp);
228 old_size = ntohs ((*mqmp)->mh->size);
229 /* message too large to concatenate? */
230 if (ntohs ((*mqmp)->mh->size) + ntohs (m->size) < ntohs (m->size))
231 return GNUNET_SYSERR;
232 new_size = old_size + ntohs (m->size);
233 *mqmp = GNUNET_realloc (mqmp, sizeof (struct GNUNET_MQ_Message) + new_size);
234 memcpy ((*mqmp)->mh + old_size, m, new_size - old_size);
235 (*mqmp)->mh->size = htons (new_size);
241 * Functions of this signature are called whenever writing operations
242 * on a stream are executed
244 * @param cls the closure from GNUNET_STREAM_write
245 * @param status the status of the stream at the time this function is called;
246 * GNUNET_STREAM_OK if writing to stream was completed successfully;
247 * GNUNET_STREAM_TIMEOUT if the given data is not sent successfully
248 * (this doesn't mean that the data is never sent, the receiver may
249 * have read the data but its ACKs may have been lost);
250 * GNUNET_STREAM_SHUTDOWN if the stream is shutdown for writing in the
251 * mean time; GNUNET_STREAM_SYSERR if the stream is broken and cannot
253 * @param size the number of bytes written
256 stream_write_queued (void *cls, enum GNUNET_STREAM_Status status, size_t size)
258 struct GNUNET_MQ_MessageQueue *mq = cls;
259 struct MessageStreamState *mss = (struct MessageStreamState *) mq->impl_state;
260 struct GNUNET_MQ_Message *mqm;
262 GNUNET_assert (GNUNET_STREAM_OK == status);
264 /* call cb for message we finished sending */
265 mqm = mq->current_msg;
268 if (NULL != mqm->sent_cb)
269 mqm->sent_cb (mqm->sent_cls);
276 mq->current_msg = mqm;
279 GNUNET_CONTAINER_DLL_remove (mq->msg_head, mq->msg_tail, mqm);
280 mss->wh = GNUNET_STREAM_write (mss->socket, mqm->mh, ntohs (mqm->mh->size),
281 GNUNET_TIME_UNIT_FOREVER_REL,
282 stream_write_queued, mq);
283 GNUNET_assert (NULL != mss->wh);
288 stream_socket_send_impl (struct GNUNET_MQ_MessageQueue *mq,
289 struct GNUNET_MQ_Message *mqm)
291 struct MessageStreamState *mss = (struct MessageStreamState *) mq->impl_state;
292 if (NULL != mq->current_msg)
294 GNUNET_CONTAINER_DLL_insert_tail (mq->msg_head, mq->msg_tail, mqm);
297 mq->current_msg = mqm;
298 mss->wh = GNUNET_STREAM_write (mss->socket, mqm->mh, ntohs (mqm->mh->size),
299 GNUNET_TIME_UNIT_FOREVER_REL,
300 stream_write_queued, mq);
305 * Functions with this signature are called whenever a
306 * complete message is received by the tokenizer.
308 * Do not call GNUNET_SERVER_mst_destroy in callback
311 * @param client identification of the client
312 * @param message the actual message
314 * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
317 stream_mst_callback (void *cls, void *client,
318 const struct GNUNET_MessageHeader *message)
320 struct GNUNET_MQ_MessageQueue *mq = cls;
322 GNUNET_assert (NULL != message);
323 dispatch_message (mq, message);
329 * Functions of this signature are called whenever data is available from the
332 * @param cls the closure from GNUNET_STREAM_read
333 * @param status the status of the stream at the time this function is called
334 * @param data traffic from the other side
335 * @param size the number of bytes available in data read; will be 0 on timeout
336 * @return number of bytes of processed from 'data' (any data remaining should be
337 * given to the next time the read processor is called).
340 stream_data_processor (void *cls,
341 enum GNUNET_STREAM_Status status,
345 struct GNUNET_MQ_MessageQueue *mq = cls;
346 struct MessageStreamState *mss;
349 mss = (struct MessageStreamState *) mq->impl_state;
350 GNUNET_assert (GNUNET_STREAM_OK == status);
351 ret = GNUNET_SERVER_mst_receive (mss->mst, NULL, data, size, GNUNET_NO, GNUNET_NO);
352 GNUNET_assert (GNUNET_OK == ret);
353 /* we always read all data */
354 mss->rh = GNUNET_STREAM_read (mss->socket, GNUNET_TIME_UNIT_FOREVER_REL,
355 stream_data_processor, mq);
360 struct GNUNET_MQ_MessageQueue *
361 GNUNET_MQ_queue_for_stream_socket (struct GNUNET_STREAM_Socket *socket,
362 const struct GNUNET_MQ_Handler *handlers,
365 struct GNUNET_MQ_MessageQueue *mq;
366 struct MessageStreamState *mss;
368 mq = GNUNET_new (struct GNUNET_MQ_MessageQueue);
369 mss = GNUNET_new (struct MessageStreamState);
370 mss->socket = socket;
371 mq->impl_state = mss;
372 mq->send_impl = stream_socket_send_impl;
373 mq->handlers = handlers;
374 mq->handlers_cls = cls;
375 if (NULL != handlers)
377 mss->mst = GNUNET_SERVER_mst_create (stream_mst_callback, mq);
378 mss->rh = GNUNET_STREAM_read (socket, GNUNET_TIME_UNIT_FOREVER_REL,
379 stream_data_processor, mq);
385 /*** Transmit a queued message to the session's client.
387 * @param cls consensus session
388 * @param size number of bytes available in buf
389 * @param buf where the callee should write the message
390 * @return number of bytes written to buf
393 transmit_queued (void *cls, size_t size,
396 struct GNUNET_MQ_MessageQueue *mq = cls;
397 struct GNUNET_MQ_Message *mqm = mq->current_msg;
398 struct ServerClientSocketState *state = mq->impl_state;
401 mq->current_msg = NULL;
402 GNUNET_assert (NULL != mqm);
403 GNUNET_assert (NULL != buf);
404 msg_size = ntohs (mqm->mh->size);
405 GNUNET_assert (size >= msg_size);
406 memcpy (buf, mqm->mh, msg_size);
409 if (NULL != mq->msg_head)
411 mq->current_msg = mq->msg_head;
412 GNUNET_CONTAINER_DLL_remove (mq->msg_head, mq->msg_tail, mq->current_msg);
414 GNUNET_SERVER_notify_transmit_ready (state->client, msg_size,
415 GNUNET_TIME_UNIT_FOREVER_REL,
416 &transmit_queued, mq);
423 server_client_send_impl (struct GNUNET_MQ_MessageQueue *mq, struct GNUNET_MQ_Message *mqm)
425 struct ServerClientSocketState *state = mq->impl_state;
428 GNUNET_assert (NULL != state);
430 if (NULL != state->th)
432 GNUNET_CONTAINER_DLL_insert_tail (mq->msg_head, mq->msg_tail, mqm);
435 GNUNET_assert (NULL == mq->current_msg);
436 msize = ntohs (mq->msg_head->mh->size);
437 mq->current_msg = mqm;
439 GNUNET_SERVER_notify_transmit_ready (state->client, msize,
440 GNUNET_TIME_UNIT_FOREVER_REL,
441 &transmit_queued, mq);
445 struct GNUNET_MQ_MessageQueue *
446 GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client)
448 struct GNUNET_MQ_MessageQueue *mq;
449 struct ServerClientSocketState *scss;
451 mq = GNUNET_new (struct GNUNET_MQ_MessageQueue);
452 scss = GNUNET_new (struct ServerClientSocketState);
453 mq->impl_state = scss;
454 mq->send_impl = server_client_send_impl;
460 * Transmit a queued message to the session's client.
462 * @param cls consensus session
463 * @param size number of bytes available in buf
464 * @param buf where the callee should write the message
465 * @return number of bytes written to buf
468 connection_client_transmit_queued (void *cls, size_t size,
471 struct GNUNET_MQ_MessageQueue *mq = cls;
472 struct GNUNET_MQ_Message *mqm = mq->current_msg;
473 struct ClientConnectionState *state = mq->impl_state;
476 mq->current_msg = NULL;
477 GNUNET_assert (NULL != mqm);
478 GNUNET_assert (NULL != buf);
479 msg_size = ntohs (mqm->mh->size);
480 GNUNET_assert (size >= msg_size);
481 memcpy (buf, mqm->mh, msg_size);
484 if (NULL != mq->msg_head)
486 mq->current_msg = mq->msg_head;
487 GNUNET_CONTAINER_DLL_remove (mq->msg_head, mq->msg_tail, mq->current_msg);
489 GNUNET_CLIENT_notify_transmit_ready (state->connection, htons (mq->current_msg->mh->size),
490 GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO,
491 &connection_client_transmit_queued, mq);
498 connection_client_send_impl (struct GNUNET_MQ_MessageQueue *mq,
499 struct GNUNET_MQ_Message *mqm)
501 struct ClientConnectionState *state = mq->impl_state;
504 GNUNET_assert (NULL != state);
506 if (NULL != state->th)
508 GNUNET_CONTAINER_DLL_insert_tail (mq->msg_head, mq->msg_tail, mqm);
511 GNUNET_assert (NULL == mq->current_msg);
512 mq->current_msg = mqm;
513 msize = ntohs (mqm->mh->size);
515 GNUNET_CLIENT_notify_transmit_ready (state->connection, msize,
516 GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO,
517 &connection_client_transmit_queued, mq);
522 * Type of a function to call when we receive a message
526 * @param msg message received, NULL on timeout or fatal error
529 handle_client_message (void *cls,
530 const struct GNUNET_MessageHeader *msg)
532 struct GNUNET_MQ_MessageQueue *mq = cls;
534 GNUNET_assert (NULL != msg);
535 dispatch_message (mq, msg);
539 struct GNUNET_MQ_MessageQueue *
540 GNUNET_MQ_queue_for_connection_client (struct GNUNET_CLIENT_Connection *connection,
541 const struct GNUNET_MQ_Handler *handlers,
544 struct GNUNET_MQ_MessageQueue *mq;
545 struct ClientConnectionState *state;
547 GNUNET_assert (NULL != connection);
549 mq = GNUNET_new (struct GNUNET_MQ_MessageQueue);
550 mq->handlers = handlers;
551 mq->handlers_cls = cls;
552 state = GNUNET_new (struct ClientConnectionState);
553 state->connection = connection;
554 mq->impl_state = state;
555 mq->send_impl = connection_client_send_impl;
557 if (NULL != handlers)
559 GNUNET_CLIENT_receive (connection, handle_client_message, mq,
560 GNUNET_TIME_UNIT_FOREVER_REL);
569 GNUNET_MQ_replace_handlers (struct GNUNET_MQ_MessageQueue *mq,
570 const struct GNUNET_MQ_Handler *new_handlers,
573 mq->handlers = new_handlers;
574 mq->handlers_cls = cls;
580 * Associate the assoc_data in mq with a unique request id.
582 * @param mq message queue, id will be unique for the queue
583 * @param mqm message to associate
584 * @param data to associate
587 GNUNET_MQ_assoc_add (struct GNUNET_MQ_MessageQueue *mq,
588 struct GNUNET_MQ_Message *mqm,
593 if (NULL == mq->assoc_map)
594 mq->assoc_map = GNUNET_CONTAINER_multihashmap32_create (8);
596 GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map, id, assoc_data,
597 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
604 GNUNET_MQ_assoc_get (struct GNUNET_MQ_MessageQueue *mq, uint32_t request_id)
606 if (NULL == mq->assoc_map)
608 return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id);
613 GNUNET_MQ_assoc_remove (struct GNUNET_MQ_MessageQueue *mq, uint32_t request_id)
617 if (NULL == mq->assoc_map)
619 val = GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id);
620 GNUNET_CONTAINER_multihashmap32_remove (mq->assoc_map, request_id, val);
626 GNUNET_MQ_notify_sent (struct GNUNET_MQ_Message *mqm,
627 GNUNET_MQ_NotifyCallback cb,
636 GNUNET_MQ_destroy (struct GNUNET_MQ_MessageQueue *mq)
638 /* FIXME: destroy all pending messages in the queue */