2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file testbed/gnunet-service-testbed_connectionpool.c
23 * @brief connection pooling for connections to peers' services
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
27 #include "gnunet-service-testbed.h"
28 #include "gnunet-service-testbed_connectionpool.h"
29 #include "testbed_api_operations.h"
32 * Redefine LOG with a changed log component string
37 #define LOG(kind,...) \
38 GNUNET_log_from (kind, "testbed-connectionpool", __VA_ARGS__)
42 * Time to expire a cache entry
44 #define CACHE_EXPIRY \
45 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
49 * The request handle for obtaining a pooled connection
51 struct GST_ConnectionPool_GetHandle;
57 struct PooledConnection
60 * Next ptr for placing this object in the DLL of least recently used pooled
63 struct PooledConnection *next;
66 * Prev ptr for placing this object in the DLL of the least recently used
69 struct PooledConnection *prev;
72 * The transport handle to the peer corresponding to this entry; can be NULL
74 struct GNUNET_TRANSPORT_Handle *handle_transport;
77 * The core handle to the peer corresponding to this entry; can be NULL
79 struct GNUNET_CORE_Handle *handle_core;
82 * The operation handle for transport handle
84 struct GNUNET_TESTBED_Operation *op_transport;
87 * The operation handle for core handle
89 struct GNUNET_TESTBED_Operation *op_core;
92 * The peer identity of this peer. Will be set upon opening a connection to
93 * the peers CORE service. Will be NULL until then and after the CORE
94 * connection is closed
96 struct GNUNET_PeerIdentity *peer_identity;
99 * The configuration of the peer. Should be not NULL as long as the core_handle
100 * or transport_handle are valid
102 struct GNUNET_CONFIGURATION_Handle *cfg;
105 * DLL head for the queue to serve notifications when a peer is connected
107 struct GST_ConnectionPool_GetHandle *head_notify;
110 * DLL tail for the queue to serve notifications when a peer is connected
112 struct GST_ConnectionPool_GetHandle *tail_notify;
115 * DLL head for the queue of #GST_ConnectionPool_GetHandle requests that are
116 * waiting for this connection to be opened
118 struct GST_ConnectionPool_GetHandle *head_waiting;
121 * DLL tail for the queue of #GST_ConnectionPool_GetHandle requests that are
122 * waiting for this connection to be opened
124 struct GST_ConnectionPool_GetHandle *tail_waiting;
127 * The task to expire this connection from the connection pool
129 struct GNUNET_SCHEDULER_Task * expire_task;
132 * The task to notify a waiting #GST_ConnectionPool_GetHandle object
134 struct GNUNET_SCHEDULER_Task * notify_task;
137 * Number of active requests using this pooled connection
142 * Is this entry in LRU
147 * Is this entry present in the connection pool
152 * The index of this peer
159 * The request handle for obtaining a pooled connection
161 struct GST_ConnectionPool_GetHandle
164 * The next ptr for inclusion in the notification DLLs. At first the object
165 * is placed in the waiting DLL of the corresponding #PooledConnection
166 * object. After the handle is opened it is moved to the notification DLL if
167 * @p connect_notify_cb and @p target are not NULL
169 struct GST_ConnectionPool_GetHandle *next;
172 * The prev ptr for inclusion in the notification DLLs
174 struct GST_ConnectionPool_GetHandle *prev;
177 * The pooled connection object this handle corresponds to
179 struct PooledConnection *entry;
182 * The cache callback to call when a handle is available
184 GST_connection_pool_connection_ready_cb cb;
187 * The closure for the above callback
192 * The peer identity of the target peer. When this target peer is connected,
193 * call the notify callback
195 const struct GNUNET_PeerIdentity *target;
198 * The callback to be called for serving notification that the target peer is
201 GST_connection_pool_peer_connect_notify connect_notify_cb;
204 * The closure for the notify callback
206 void *connect_notify_cb_cls;
209 * The service we want to connect to
211 enum GST_ConnectionPool_Service service;
214 * Did we call the pool_connection_ready_cb already?
216 int connection_ready_called;
219 * Are we waiting for any peer connect notifications?
226 * A hashmap for quickly finding connections in the connection pool
228 static struct GNUNET_CONTAINER_MultiHashMap32 *map;
231 * DLL head for maitaining the least recently used #PooledConnection objects.
232 * The head is the least recently used object.
234 static struct PooledConnection *head_lru;
237 * DLL tail for maitaining the least recently used #PooledConnection objects
239 static struct PooledConnection *tail_lru;
242 * DLL head for maintaining #PooledConnection objects that are not added into
243 * the connection pool as it was full at the time the object's creation
246 static struct PooledConnection *head_not_pooled;
249 * DLL tail for maintaining #PooledConnection objects that are not added into
250 * the connection pool as it was full at the time the object's creation
252 static struct PooledConnection *tail_not_pooled;
255 * The maximum number of entries that can be present in the connection pool
257 static unsigned int max_size;
261 * Cancel the expiration task of the give #PooledConnection object
263 * @param entry the #PooledConnection object
266 expire_task_cancel (struct PooledConnection *entry);
270 * Destroy a #PooledConnection object
272 * @param entry the #PooledConnection object
275 destroy_pooled_connection (struct PooledConnection *entry)
277 GNUNET_assert ((NULL == entry->head_notify) && (NULL == entry->tail_notify));
278 GNUNET_assert ((NULL == entry->head_waiting) && (NULL ==
279 entry->tail_waiting));
280 GNUNET_assert (0 == entry->demand);
281 expire_task_cancel (entry);
283 GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
285 GNUNET_assert (GNUNET_OK ==
286 GNUNET_CONTAINER_multihashmap32_remove (map,
289 if (NULL != entry->notify_task)
291 GNUNET_SCHEDULER_cancel (entry->notify_task);
292 entry->notify_task = NULL;
294 LOG_DEBUG ("Cleaning up handles of a pooled connection\n");
295 if (NULL != entry->handle_transport)
296 GNUNET_assert (NULL != entry->op_transport);
297 if (NULL != entry->op_transport)
299 GNUNET_TESTBED_operation_done (entry->op_transport);
300 entry->op_transport = NULL;
302 if (NULL != entry->op_core)
304 GNUNET_TESTBED_operation_done (entry->op_core);
305 entry->op_core = NULL;
307 GNUNET_assert (NULL == entry->handle_core);
308 GNUNET_assert (NULL == entry->handle_transport);
309 GNUNET_CONFIGURATION_destroy (entry->cfg);
315 * Expire a #PooledConnection object
317 * @param cls the #PooledConnection object
318 * @param tc scheduler task context
321 expire (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
323 struct PooledConnection *entry = cls;
325 entry->expire_task = NULL;
326 destroy_pooled_connection (entry);
331 * Cancel the expiration task of the give #PooledConnection object
333 * @param entry the #PooledConnection object
336 expire_task_cancel (struct PooledConnection *entry)
338 if (NULL != entry->expire_task)
340 GNUNET_SCHEDULER_cancel (entry->expire_task);
341 entry->expire_task = NULL;
347 * Function to add a #PooledConnection object into LRU and begin the expiry task
349 * @param entry the #PooledConnection object
352 add_to_lru (struct PooledConnection *entry)
354 GNUNET_assert (0 == entry->demand);
355 GNUNET_assert (!entry->in_lru);
356 GNUNET_CONTAINER_DLL_insert_tail (head_lru, tail_lru, entry);
357 entry->in_lru = GNUNET_YES;
358 GNUNET_assert (NULL == entry->expire_task);
359 entry->expire_task = GNUNET_SCHEDULER_add_delayed (CACHE_EXPIRY,
365 * Function to find a #GST_ConnectionPool_GetHandle which is waiting for one of
366 * the handles in given entry which are now available.
368 * @param entry the pooled connection whose active list has to be searched
369 * @param head the starting list element in the GSTCacheGetHandle where the
370 * search has to be begin
371 * @return a suitable GSTCacheGetHandle whose handle ready notify callback
372 * hasn't been called yet. NULL if no such suitable GSTCacheGetHandle
375 static struct GST_ConnectionPool_GetHandle *
376 search_waiting (const struct PooledConnection *entry,
377 struct GST_ConnectionPool_GetHandle *head)
379 struct GST_ConnectionPool_GetHandle *gh;
381 for (gh = head; NULL != gh; gh = gh->next)
385 case GST_CONNECTIONPOOL_SERVICE_CORE:
386 if (NULL == entry->handle_core)
388 if (NULL == entry->peer_identity)
389 continue; /* CORE connection isn't ready yet */
391 case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
392 if (NULL == entry->handle_transport)
403 * A handle in the #PooledConnection object pointed by @a cls is ready and there
404 * is a #GST_ConnectionPool_GetHandle object waiting in the waiting list. This
405 * function retrieves that object and calls the handle ready callback. It
406 * further schedules itself if there are similar waiting objects which can be notified.
408 * @param cls the #PooledConnection object
409 * @param tc the task context from scheduler
412 connection_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
414 struct PooledConnection *entry = cls;
415 struct GST_ConnectionPool_GetHandle *gh;
416 struct GST_ConnectionPool_GetHandle *gh_next;
418 GNUNET_assert (NULL != entry->notify_task);
419 entry->notify_task = NULL;
420 gh = search_waiting (entry, entry->head_waiting);
421 GNUNET_assert (NULL != gh);
423 if (NULL != gh->next)
424 gh_next = search_waiting (entry, gh->next);
425 GNUNET_CONTAINER_DLL_remove (entry->head_waiting, entry->tail_waiting, gh);
426 gh->connection_ready_called = 1;
428 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
429 if ( (NULL != gh->target) && (NULL != gh->connect_notify_cb) )
431 GNUNET_CONTAINER_DLL_insert_tail (entry->head_notify, entry->tail_notify,
433 gh->notify_waiting = 1;
435 LOG_DEBUG ("Connection ready for handle type %u\n", gh->service);
436 gh->cb (gh->cb_cls, entry->handle_core, entry->handle_transport,
437 entry->peer_identity);
442 * Function called from peer connect notify callbacks from CORE and TRANSPORT
443 * connections. This function calls the pending peer connect notify callbacks
444 * which are queued in an entry.
446 * @param cls the #PooledConnection object
447 * @param peer the peer that connected
448 * @param service the service where this notification has originated
451 peer_connect_notify_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
452 const enum GST_ConnectionPool_Service service)
454 struct PooledConnection *entry = cls;
455 struct GST_ConnectionPool_GetHandle *gh;
456 struct GST_ConnectionPool_GetHandle *gh_next;
457 GST_connection_pool_peer_connect_notify cb;
460 for (gh = entry->head_notify; NULL != gh;)
462 GNUNET_assert (NULL != gh->target);
463 GNUNET_assert (NULL != gh->connect_notify_cb);
464 GNUNET_assert (gh->connection_ready_called);
465 if (service != gh->service)
470 if (0 != memcmp (gh->target, peer, sizeof (struct GNUNET_PeerIdentity)))
475 cb = gh->connect_notify_cb;
476 cb_cls = gh->connect_notify_cb_cls;
478 GNUNET_CONTAINER_DLL_remove (entry->head_notify, entry->tail_notify, gh);
479 gh->notify_waiting = 0;
480 LOG_DEBUG ("Peer connected to peer %u at service %u\n", entry->index, gh->service);
488 * Function called to notify transport users that another
489 * peer connected to us.
491 * @param cls the #PooledConnection object
492 * @param peer the peer that connected
495 transport_peer_connect_notify_cb (void *cls,
496 const struct GNUNET_PeerIdentity *peer)
498 struct PooledConnection *entry = cls;
500 peer_connect_notify_cb (entry, peer, GST_CONNECTIONPOOL_SERVICE_TRANSPORT);
505 * Function called when resources for opening a connection to TRANSPORT are
508 * @param cls the #PooledConnection object
511 opstart_get_handle_transport (void *cls)
513 struct PooledConnection *entry = cls;
515 GNUNET_assert (NULL != entry);
516 LOG_DEBUG ("Opening a transport connection to peer %u\n", entry->index);
517 entry->handle_transport =
518 GNUNET_TRANSPORT_connect (entry->cfg, NULL, entry, NULL,
519 &transport_peer_connect_notify_cb, NULL);
520 if (NULL == entry->handle_transport)
525 if (0 == entry->demand)
527 if (NULL != entry->notify_task)
529 if (NULL != search_waiting (entry, entry->head_waiting))
531 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
538 * Function called when the operation responsible for opening a TRANSPORT
539 * connection is marked as done.
541 * @param cls the cache entry
544 oprelease_get_handle_transport (void *cls)
546 struct PooledConnection *entry = cls;
548 if (NULL == entry->handle_transport)
550 GNUNET_TRANSPORT_disconnect (entry->handle_transport);
551 entry->handle_transport = NULL;
556 * Method called whenever a given peer connects at CORE level
558 * @param cls the #PooledConnection object
559 * @param peer peer identity this notification is about
562 core_peer_connect_cb (void *cls, const struct GNUNET_PeerIdentity *peer)
564 struct PooledConnection *entry = cls;
566 peer_connect_notify_cb (entry, peer, GST_CONNECTIONPOOL_SERVICE_CORE);
571 * Function called after GNUNET_CORE_connect has succeeded (or failed
572 * for good). Note that the private key of the peer is intentionally
573 * not exposed here; if you need it, your process should try to read
574 * the private key file directly (which should work if you are
575 * authorized...). Implementations of this function must not call
576 * GNUNET_CORE_disconnect (other than by scheduling a new task to
579 * @param cls the #PooledConnection object
580 * @param my_identity ID of this peer, NULL if we failed
583 core_startup_cb (void *cls,
584 const struct GNUNET_PeerIdentity *my_identity)
586 struct PooledConnection *entry = cls;
588 if (NULL == my_identity)
593 GNUNET_assert (NULL == entry->peer_identity);
594 entry->peer_identity = GNUNET_new (struct GNUNET_PeerIdentity);
595 memcpy (entry->peer_identity,
597 sizeof (struct GNUNET_PeerIdentity));
598 if (0 == entry->demand)
600 if (NULL != entry->notify_task)
602 if (NULL != search_waiting (entry, entry->head_waiting))
604 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
611 * Function called when resources for opening a connection to CORE are
614 * @param cls the #PooledConnection object
617 opstart_get_handle_core (void *cls)
619 struct PooledConnection *entry = cls;
620 const struct GNUNET_CORE_MessageHandler no_handlers[] = {
624 GNUNET_assert (NULL != entry);
625 LOG_DEBUG ("Opening a CORE connection to peer %u\n", entry->index);
627 GNUNET_CORE_connect (entry->cfg, entry, /* closure */
628 &core_startup_cb, /* core startup notify */
629 &core_peer_connect_cb, /* peer connect notify */
630 NULL, /* peer disconnect notify */
631 NULL, /* inbound notify */
632 GNUNET_NO, /* inbound header only? */
633 NULL, /* outbound notify */
634 GNUNET_NO, /* outbound header only? */
640 * Function called when the operation responsible for opening a TRANSPORT
641 * connection is marked as done.
643 * @param cls the #PooledConnection object
646 oprelease_get_handle_core (void *cls)
648 struct PooledConnection *entry = cls;
650 if (NULL == entry->handle_core)
652 GNUNET_CORE_disconnect (entry->handle_core);
653 entry->handle_core = NULL;
654 GNUNET_free_non_null (entry->peer_identity);
655 entry->peer_identity = NULL;
660 * This function will be called for every #PooledConnection object in @p map
663 * @param key current key code
664 * @param value the #PooledConnection object
665 * @return #GNUNET_YES if we should continue to
670 cleanup_iterator (void *cls,
674 struct PooledConnection *entry = value;
676 GNUNET_assert (NULL != entry);
677 destroy_pooled_connection (entry);
683 * Initialise the connection pool.
685 * @param size the size of the connection pool. Each entry in the connection
686 * pool can handle a connection to each of the services enumerated in
687 * #GST_ConnectionPool_Service
690 GST_connection_pool_init (unsigned int size)
695 GNUNET_assert (NULL == map);
696 map = GNUNET_CONTAINER_multihashmap32_create (((size * 3) / 4) + 1);
701 * Cleanup the connection pool
704 GST_connection_pool_destroy ()
706 struct PooledConnection *entry;
710 GNUNET_assert (GNUNET_SYSERR !=
711 GNUNET_CONTAINER_multihashmap32_iterate (map,
714 GNUNET_CONTAINER_multihashmap32_destroy (map);
717 while (NULL != (entry = head_lru))
719 GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
720 destroy_pooled_connection (entry);
722 GNUNET_assert (NULL == head_not_pooled);
727 * Get a connection handle to @a service. If the connection is opened before
728 * and the connection handle is present in the connection pool, it is returned
729 * through @a cb. @a peer_id is used for the lookup in the connection pool. If
730 * the connection handle is not present in the connection pool, a new connection
731 * handle is opened for the @a service using @a cfg. Additionally, @a target,
732 * @a connect_notify_cb can be specified to get notified when @a target is
733 * connected at @a service.
735 * @note @a connect_notify_cb will not be called if @a target is
736 * already connected @a service level. Use
737 * GNUNET_TRANSPORT_check_peer_connected() or a similar function from the
738 * respective @a service's API to check if the target peer is already connected or
739 * not. @a connect_notify_cb will be called only once or never (in case @a target
740 * cannot be connected or is already connected).
742 * @param peer_id the index of the peer
743 * @param cfg the configuration with which the transport handle has to be
744 * created if it was not present in the cache
745 * @param service the service of interest
746 * @param cb the callback to notify when the transport handle is available
747 * @param cb_cls the closure for @a cb
748 * @param target the peer identify of the peer whose connection to our TRANSPORT
749 * subsystem will be notified through the @a connect_notify_cb. Can be NULL
750 * @param connect_notify_cb the callback to call when the @a target peer is
751 * connected. This callback will only be called once or never again (in
752 * case the target peer cannot be connected). Can be NULL
753 * @param connect_notify_cb_cls the closure for @a connect_notify_cb
754 * @return the handle which can be used cancel or mark that the handle is no
757 struct GST_ConnectionPool_GetHandle *
758 GST_connection_pool_get_handle (unsigned int peer_id,
759 const struct GNUNET_CONFIGURATION_Handle *cfg,
760 enum GST_ConnectionPool_Service service,
761 GST_connection_pool_connection_ready_cb cb,
763 const struct GNUNET_PeerIdentity *target,
764 GST_connection_pool_peer_connect_notify connect_notify_cb,
765 void *connect_notify_cb_cls)
767 struct GST_ConnectionPool_GetHandle *gh;
768 struct PooledConnection *entry;
769 struct GNUNET_TESTBED_Operation *op;
773 peer_id32 = (uint32_t) peer_id;
777 entry = GNUNET_CONTAINER_multihashmap32_get (map, peer_id32);
782 GNUNET_assert (0 == entry->demand);
783 expire_task_cancel (entry);
784 GNUNET_CONTAINER_DLL_remove (head_lru, tail_lru, entry);
785 entry->in_lru = GNUNET_NO;
789 case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
790 handle = entry->handle_transport;
792 LOG_DEBUG ("Found TRANSPORT handle for peer %u\n",
795 case GST_CONNECTIONPOOL_SERVICE_CORE:
796 handle = entry->handle_core;
798 LOG_DEBUG ("Found CORE handle for peer %u\n",
805 entry = GNUNET_new (struct PooledConnection);
806 entry->index = peer_id32;
808 && (GNUNET_CONTAINER_multihashmap32_size (map) < max_size))
810 GNUNET_assert (GNUNET_OK ==
811 GNUNET_CONTAINER_multihashmap32_put (map,
814 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
815 entry->in_pool = GNUNET_YES;
819 GNUNET_CONTAINER_DLL_insert_tail (head_not_pooled, tail_not_pooled, entry);
821 entry->cfg = GNUNET_CONFIGURATION_dup (cfg);
824 gh = GNUNET_new (struct GST_ConnectionPool_GetHandle);
829 gh->connect_notify_cb = connect_notify_cb;
830 gh->connect_notify_cb_cls = connect_notify_cb_cls;
831 gh->service = service;
832 GNUNET_CONTAINER_DLL_insert (entry->head_waiting, entry->tail_waiting, gh);
835 if (NULL == entry->notify_task)
837 if (NULL != search_waiting (entry, entry->head_waiting))
838 entry->notify_task = GNUNET_SCHEDULER_add_now (&connection_ready, entry);
845 case GST_CONNECTIONPOOL_SERVICE_TRANSPORT:
846 if (NULL != entry->op_transport)
847 return gh; /* Operation pending */
848 op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_transport,
849 &oprelease_get_handle_transport);
850 entry->op_transport = op;
852 case GST_CONNECTIONPOOL_SERVICE_CORE:
853 if (NULL != entry->op_core)
854 return gh; /* Operation pending */
855 op = GNUNET_TESTBED_operation_create_ (entry, &opstart_get_handle_core,
856 &oprelease_get_handle_core);
860 GNUNET_TESTBED_operation_queue_insert_ (GST_opq_openfds, op);
861 GNUNET_TESTBED_operation_begin_wait_ (op);
867 * Relinquish a #GST_ConnectionPool_GetHandle object. If the connection
868 * associated with the object is currently being used by other
869 * #GST_ConnectionPool_GetHandle objects, it is left in the connection pool. If
870 * no other objects are using the connection and the connection pool is not full
871 * then it is placed in a LRU queue. If the connection pool is full, then
872 * connections from the LRU queue are evicted and closed to create place for this
873 * connection. If the connection pool if full and the LRU queue is empty, then
874 * the connection is closed.
876 * @param gh the handle
879 GST_connection_pool_get_handle_done (struct GST_ConnectionPool_GetHandle *gh)
881 struct PooledConnection *entry;
884 LOG_DEBUG ("Cleaning up get handle %p for service %u, peer %u\n",
886 gh->service, entry->index);
887 if (!gh->connection_ready_called)
889 GNUNET_CONTAINER_DLL_remove (entry->head_waiting, entry->tail_waiting, gh);
890 if ( (NULL == search_waiting (entry, entry->head_waiting))
891 && (NULL != entry->notify_task) )
893 GNUNET_SCHEDULER_cancel (entry->notify_task);
894 entry->notify_task = NULL;
897 if (gh->notify_waiting)
899 GNUNET_CONTAINER_DLL_remove (entry->head_notify, entry->tail_notify, gh);
900 gh->notify_waiting = 0;
904 GNUNET_assert (!entry->in_lru);
906 GNUNET_CONTAINER_DLL_remove (head_not_pooled, tail_not_pooled, entry);
909 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap32_contains (map,
912 if (GNUNET_CONTAINER_multihashmap32_size (map) == max_size)
914 if (NULL == head_lru)
916 destroy_pooled_connection (head_lru);
918 GNUNET_assert (GNUNET_OK ==
919 GNUNET_CONTAINER_multihashmap32_put (map,
922 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
923 entry->in_pool = GNUNET_YES;
927 GNUNET_assert (0 < entry->demand);
929 if (0 != entry->demand)
936 destroy_pooled_connection (entry);