2 This file is part of GNUnet.
3 (C) 2011 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 ats/gnunet-service-ats_addresses.c
23 * @brief ats service address management
24 * @author Matthias Wachs
25 * @author Christian Grothoff
28 #include "gnunet_ats_service.h"
29 #include "gnunet-service-ats.h"
30 #include "gnunet-service-ats_addresses.h"
31 #include "gnunet-service-ats_performance.h"
32 #include "gnunet-service-ats_scheduling.h"
33 #include "gnunet-service-ats_reservations.h"
35 #include "gnunet-service-ats_addresses_mlp.h"
38 #define ATS_BLOCKING_DELTA GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100)
43 * Assign each peer an equal amount of bandwidth (bw)
45 * bw_per_peer = bw_total / #active addresses
50 * Use MLP solver to assign bandwidth
55 static struct GNUNET_CONTAINER_MultiHashMap *addresses;
58 static struct GAS_MLP_Handle *mlp;
61 static unsigned long long wan_quota_in;
63 static unsigned long long wan_quota_out;
65 static unsigned int active_addr_count;
73 send_bw_notification (struct ATS_Address *aa)
75 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n",
76 GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__),
77 ntohl (aa->assigned_bw_out.value__));
78 GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr,
79 aa->addr_len, aa->session_id,
80 aa->ats, aa->ats_count,
83 GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in);
84 GAS_performance_notify_all_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len,
85 aa->ats, aa->ats_count, aa->assigned_bw_out,
90 * Update a bandwidth assignment for a peer. This trivial method currently
91 * simply assigns the same share to all active connections.
95 * @param value the 'struct ATS_Address'
96 * @return GNUNET_OK (continue to iterate)
99 update_bw_simple_it (void *cls, const struct GNUNET_HashCode * key, void *value)
101 struct ATS_Address *aa = value;
103 if (GNUNET_YES != aa->active)
105 GNUNET_assert (active_addr_count > 0);
109 aa->assigned_bw_in.value__ = htonl (wan_quota_in / active_addr_count);
110 aa->assigned_bw_out.value__ = htonl (wan_quota_out / active_addr_count);
112 send_bw_notification (aa);
119 * Some (significant) input changed, recalculate bandwidth assignment
123 recalculate_assigned_bw ()
125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
126 "Recalculating bandwidth for all active connections\n");
127 GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed",
129 GNUNET_STATISTICS_set (GSA_stats, "# active addresses", active_addr_count,
132 GNUNET_CONTAINER_multihashmap_iterate (addresses, &update_bw_simple_it, NULL);
136 * Free the given address
137 * @param addr address to destroy
140 free_address (struct ATS_Address *addr)
142 GNUNET_free_non_null (addr->ats);
143 GNUNET_free (addr->plugin);
148 * Create a ATS_address with the given information
150 * @param plugin_name plugin
151 * @param plugin_addr address
152 * @param plugin_addr_len address length
153 * @param session_id session
154 * @return the ATS_Address
156 static struct ATS_Address *
157 create_address (const struct GNUNET_PeerIdentity *peer,
158 const char *plugin_name,
159 const void *plugin_addr, size_t plugin_addr_len,
162 struct ATS_Address *aa = NULL;
164 aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
166 aa->addr_len = plugin_addr_len;
168 memcpy (&aa[1], plugin_addr, plugin_addr_len);
169 aa->plugin = GNUNET_strdup (plugin_name);
170 aa->session_id = session_id;
176 * Destroy the given address.
178 * @param addr address to destroy
179 * @return GNUNET_YES if bandwidth allocations should be recalcualted
182 destroy_address (struct ATS_Address *addr)
187 GNUNET_assert (GNUNET_YES ==
188 GNUNET_CONTAINER_multihashmap_remove (addresses,
189 &addr->peer.hashPubKey,
194 GAS_mlp_address_delete (mlp, addresses, addr);
197 if (GNUNET_YES == addr->active)
200 addr->active = GNUNET_NO;
208 struct CompareAddressContext
210 const struct ATS_Address *search;
212 /* exact_address != NULL if address and session is equal */
213 struct ATS_Address *exact_address;
214 /* exact_address != NULL if address and session is 0 */
215 struct ATS_Address *base_address;
220 compare_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
222 struct CompareAddressContext *cac = cls;
223 struct ATS_Address *aa = value;
225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing peer %4s: address length %u session %u <-> address length %u session %u\n",
227 aa->addr_len, aa->session_id,
228 cac->search->addr_len, cac->search->session_id);
230 /* Find an matching exact address:
233 * aa->addr_len == cac->search->addr_len
234 * aa->plugin == cac->search->plugin
235 * aa->addr == cac->search->addr
236 * aa->session == cac->search->session
238 * return as exact address
240 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
242 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
243 cac->exact_address = aa;
246 /* Find an matching base address:
250 * aa->session_id == 0
253 * aa->addr_len == cac->search->addr_len
254 * aa->plugin == cac->search->plugin
255 * aa->addr == cac->search->addr
257 * return as base address
259 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
261 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
262 cac->base_address = aa;
265 /* Find an matching exact address based on session:
269 * cac->search->addr_len == 0
272 * aa->plugin == cac->search->plugin
273 * aa->session_id == cac->search->session_id
275 * return as exact address
277 if (0 == cac->search->addr_len)
279 if ((0 == strcmp (aa->plugin, cac->search->plugin)) && (aa->session_id == cac->search->session_id))
280 cac->exact_address = aa;
283 if (cac->exact_address == NULL)
284 return GNUNET_YES; /* Continue iteration to find exact address */
286 return GNUNET_NO; /* Stop iteration since we have an exact address */
291 * Find an existing equivalent address record.
292 * Compares by peer identity and network address OR by session ID
293 * (one of the two must match).
295 * @param peer peer to lookup addresses for
296 * @param addr existing address record
297 * @return existing address record, NULL for none
300 find_address (const struct GNUNET_PeerIdentity *peer,
301 const struct ATS_Address *addr)
303 struct CompareAddressContext cac;
305 cac.exact_address = NULL;
306 cac.base_address = NULL;
308 GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
309 &compare_address_it, &cac);
312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
313 "Found exact address: %s base address: %s\n",
314 (cac.exact_address != NULL) ? "YES" : "NO",
315 (cac.base_address != NULL) ? "YES" : "NO");
317 if (cac.exact_address == NULL)
318 return cac.base_address;
319 return cac.exact_address;
323 static struct ATS_Address *
324 lookup_address (const struct GNUNET_PeerIdentity *peer,
325 const char *plugin_name, const void *plugin_addr,
326 size_t plugin_addr_len, uint32_t session_id,
327 const struct GNUNET_ATS_Information *atsi,
330 struct ATS_Address *aa;
331 struct ATS_Address *old;
333 aa = create_address (peer,
335 plugin_addr, plugin_addr_len,
338 aa->mlp_information = NULL;
339 aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
340 aa->ats_count = atsi_count;
341 memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
343 /* Get existing address or address with session == 0 */
344 old = find_address (peer, aa);
350 else if (old->session_id != session_id)
360 compare_address_session_it (void *cls, const struct GNUNET_HashCode * key, void *value)
362 struct CompareAddressContext *cac = cls;
363 struct ATS_Address *aa = value;
365 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
367 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
369 cac->exact_address = aa;
378 * Find an existing equivalent address record.
379 * Compares by peer identity and network address AND by session ID
380 * (one of the two must match).
382 * @param peer peer to lookup addresses for
383 * @param addr existing address record
384 * @return existing address record, NULL for none
386 static struct ATS_Address *
387 find_exact_address (const struct GNUNET_PeerIdentity *peer,
388 const struct ATS_Address *addr)
390 struct CompareAddressContext cac;
392 cac.exact_address = NULL;
394 GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
395 &compare_address_session_it, &cac);
396 return cac.exact_address;
402 GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
403 const char *plugin_name, const void *plugin_addr,
404 size_t plugin_addr_len, uint32_t session_id,
405 const struct GNUNET_ATS_Information *atsi,
408 struct ATS_Address *aa;
409 struct ATS_Address *old;
411 if (GNUNET_NO == running)
414 GNUNET_assert (NULL != addresses);
416 aa = create_address (peer,
418 plugin_addr, plugin_addr_len,
421 aa->mlp_information = NULL;
422 aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
423 aa->ats_count = atsi_count;
424 memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
426 /* Get existing address or address with session == 0 */
427 old = find_address (peer, aa);
430 /* We have a new address */
431 GNUNET_assert (GNUNET_OK ==
432 GNUNET_CONTAINER_multihashmap_put (addresses,
433 &peer->hashPubKey, aa,
434 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' session id %u, %p\n",
436 GNUNET_i2s (peer), session_id, aa);
440 if (old->session_id == 0)
442 /* We have a base address with out an session, update this address */
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "Updated existing address for peer `%s' %p with new session %u\n",
445 GNUNET_i2s (peer), old, session_id);
446 GNUNET_free_non_null (old->ats);
447 old->session_id = session_id;
451 old->ats_count = aa->ats_count;
452 GNUNET_free (aa->plugin);
457 /* This address and session is already existing */
458 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
459 "Added already existing address for peer `%s' `%s' %p with new session %u\n",
460 GNUNET_i2s (peer), plugin_name, session_id);
466 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
467 const char *plugin_name, const void *plugin_addr,
468 size_t plugin_addr_len, uint32_t session_id,
469 const struct GNUNET_ATS_Information *atsi,
472 struct ATS_Address *old;
475 if (GNUNET_NO == running)
478 GNUNET_assert (NULL != addresses);
480 /* Get existing address */
481 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
482 session_id, atsi, atsi_count);
485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n",
486 GNUNET_i2s (peer), plugin_name, session_id);
491 for (i = 0; i < atsi_count; i++)
492 switch (ntohl (atsi[i].type))
494 case GNUNET_ATS_UTILIZATION_UP:
495 old->atsp_utilization_out.value__ = atsi[i].value;
497 case GNUNET_ATS_UTILIZATION_DOWN:
498 old->atsp_utilization_in.value__ = atsi[i].value;
500 case GNUNET_ATS_QUALITY_NET_DELAY:
501 old->atsp_latency.rel_value = ntohl (atsi[i].value);
503 case GNUNET_ATS_QUALITY_NET_DISTANCE:
504 old->atsp_distance = ntohl (atsi[i].value);
506 case GNUNET_ATS_COST_WAN:
507 old->atsp_cost_wan = ntohl (atsi[i].value);
509 case GNUNET_ATS_COST_LAN:
510 old->atsp_cost_lan = ntohl (atsi[i].value);
512 case GNUNET_ATS_COST_WLAN:
513 old->atsp_cost_wlan = ntohl (atsi[i].value);
515 case GNUNET_ATS_NETWORK_TYPE:
516 old->atsp_network_type = ntohl (atsi[i].value);
520 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
521 "Received unsupported ATS type %u\n", ntohl (atsi[i].type));
527 GAS_mlp_address_update (mlp, addresses, old);
535 * If session != 0, just the session is deleted, the address itself still exists
536 * If session == 0, remove full address
537 * If session == 0 and addrlen == 0, destroy inbound address
541 * @param value the 'struct ATS_Address'
542 * @return GNUNET_OK (continue to iterate)
545 destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *value)
547 const struct ATS_Address *info = cls;
548 struct ATS_Address *aa = value;
551 memcmp (&aa->peer, &info->peer,
552 sizeof (struct GNUNET_PeerIdentity)));
553 /* session == 0, remove full address */
554 if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) &&
555 (aa->addr_len == info->addr_len) &&
556 (0 == memcmp (info->addr, aa->addr, aa->addr_len)))
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Deleting address for peer `%s': `%s' %u\n",
561 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
563 if (GNUNET_YES == destroy_address (aa))
564 recalculate_assigned_bw ();
567 /* session != 0, just remove session */
568 if (aa->session_id != info->session_id)
569 return GNUNET_OK; /* irrelevant */
570 if (aa->session_id != 0)
571 GNUNET_break (0 == strcmp (info->plugin, aa->plugin));
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "Deleting session for peer `%s': `%s' %u\n",
575 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
578 if (GNUNET_YES == aa->active)
580 aa->active = GNUNET_NO;
582 recalculate_assigned_bw ();
585 /* session == 0 and addrlen == 0 : destroy address */
586 if (aa->addr_len == 0)
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589 "Deleting session and address for peer `%s': `%s' %u\n",
590 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
591 (void) destroy_address (aa);
595 /* session was set to 0, update address */
598 GAS_mlp_address_update (mlp, addresses, aa);
607 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
608 const char *plugin_name, const void *plugin_addr,
609 size_t plugin_addr_len, uint32_t session_id)
611 struct ATS_Address *aa;
612 struct ATS_Address *old;
614 if (GNUNET_NO == running)
617 /* Get existing address */
618 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
619 session_id, NULL, 0);
622 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
623 GNUNET_i2s (peer), plugin_name, session_id);
628 GNUNET_break (0 < strlen (plugin_name));
629 aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
631 GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
632 &destroy_by_session_id, aa);
639 * Find a "good" address to use for a peer. If we already have an existing
640 * address, we stick to it. Otherwise, we pick by lowest distance and then
643 * @param cls the 'struct ATS_Address**' where we store the result
645 * @param value another 'struct ATS_Address*' to consider using
646 * @return GNUNET_OK (continue to iterate)
649 find_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
651 struct ATS_Address **ap = cls;
652 struct ATS_Address *aa = (struct ATS_Address *) value;
653 struct ATS_Address *ab = *ap;
654 struct GNUNET_TIME_Absolute now;
656 now = GNUNET_TIME_absolute_get();
658 if (aa->blocked_until.abs_value == GNUNET_TIME_absolute_max (now, aa->blocked_until).abs_value)
660 /* This address is blocked for suggestion */
661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
662 "Address %p blocked for suggestion for %llu ms \n",
664 GNUNET_TIME_absolute_get_difference(now, aa->blocked_until).rel_value);
668 aa->block_interval = GNUNET_TIME_relative_add (aa->block_interval, ATS_BLOCKING_DELTA);
669 aa->blocked_until = GNUNET_TIME_absolute_add (now, aa->block_interval);
671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
672 "Address %p ready for suggestion, block interval now %llu \n", aa, aa->block_interval);
674 /* FIXME this is a hack */
679 if ((0 == strcmp (ab->plugin, "tcp")) &&
680 (0 == strcmp (aa->plugin, "tcp")))
682 if ((0 != ab->addr_len) &&
685 /* saved address was an outbound address, but we have an inbound address */
689 if (0 == ab->addr_len)
691 /* saved address was an inbound address, so do not overwrite */
696 /* FIXME end of hack */
703 if ((ntohl (ab->assigned_bw_in.value__) == 0) &&
704 (ntohl (aa->assigned_bw_in.value__) > 0))
706 /* stick to existing connection */
710 if (ab->atsp_distance > aa->atsp_distance)
712 /* user shorter distance */
716 if (ab->atsp_latency.rel_value > aa->atsp_latency.rel_value)
718 /* user lower latency */
728 GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
729 const char *plugin_name, const void *plugin_addr,
730 size_t plugin_addr_len, uint32_t session_id, int in_use)
733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
734 "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE",
735 GNUNET_i2s (peer), in_use);
738 struct ATS_Address *old;
740 if (GNUNET_NO == running)
741 return GNUNET_SYSERR;
743 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id, NULL, 0);
746 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
747 "Trying to set unknown address `%s', %s %u %s \n",
749 plugin_name, session_id,
750 (GNUNET_NO == in_use) ? "NO" : "YES");
752 return GNUNET_SYSERR;
754 if (old->used == in_use)
757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
758 "Address in use called multiple times for peer `%s': %s -> %s \n",
760 (GNUNET_NO == old->used) ? "NO" : "YES",
761 (GNUNET_NO == in_use) ? "NO" : "YES");
762 return GNUNET_SYSERR;
767 GAS_mlp_address_update (mlp, addresses, old);
774 request_address_mlp (const struct GNUNET_PeerIdentity *peer)
776 struct ATS_Address *aa;
780 /* Get preferred address from MLP */
781 struct ATS_PreferedAddress * paddr = NULL;
782 paddr = GAS_mlp_get_preferred_address (mlp, addresses, peer);
784 aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(paddr->bandwidth_out);
785 /* FIXME use bw in value */
786 paddr->bandwidth_in = paddr->bandwidth_out;
787 aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (paddr->bandwidth_in);
793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
794 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
797 if (aa->active == GNUNET_NO)
799 aa->active = GNUNET_YES;
802 send_bw_notification (aa);
806 /* just to be sure... */
807 GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
808 aa->addr_len, aa->session_id,
809 aa->ats, aa->ats_count,
818 request_address_simple (const struct GNUNET_PeerIdentity *peer)
820 struct ATS_Address *aa;
823 /* Get address with: stick to current address, lower distance, lower latency */
824 GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey,
825 &find_address_it, &aa);
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
829 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
834 "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
836 if (aa->active == GNUNET_NO)
838 aa->active = GNUNET_YES;
840 if (ats_mode == SIMPLE)
842 recalculate_assigned_bw ();
847 /* just to be sure... */
848 GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
849 aa->addr_len, aa->session_id,
850 aa->ats, aa->ats_count,
858 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
860 if (GNUNET_NO == running)
863 if (ats_mode == SIMPLE)
865 request_address_simple (peer);
869 request_address_mlp(peer);
875 reset_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
877 struct ATS_Address *aa = value;
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Resetting interval for peer `%s' address %p from %llu to 0\n", GNUNET_i2s (&aa->peer), aa, aa->block_interval);
882 aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
883 aa->block_interval = GNUNET_TIME_UNIT_ZERO;
889 GAS_addresses_handle_backoff_reset (const struct GNUNET_PeerIdentity *peer)
891 GNUNET_break (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (addresses,
899 // FIXME: this function should likely end up in the LP-subsystem and
900 // not with 'addresses' in the future...
902 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
903 enum GNUNET_ATS_PreferenceKind kind,
906 if (GNUNET_NO == running)
910 GAS_mlp_address_change_preference (mlp, peer, kind, score);
917 * Initialize address subsystem.
919 * @param cfg configuration to use
920 * @param stats the statistics handle to use
923 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
924 const struct GNUNET_STATISTICS_Handle *stats)
928 char *quota_wan_in_str;
929 char *quota_wan_out_str;
933 addresses = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
934 GNUNET_assert (NULL != addresses);
936 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", "WAN_QUOTA_IN", "a_wan_in_str))
938 if (0 == strcmp(quota_wan_in_str, "unlimited") ||
939 (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_wan_in_str, &wan_quota_in)))
940 wan_quota_in = (UINT32_MAX) /10;
942 GNUNET_free (quota_wan_in_str);
943 quota_wan_in_str = NULL;
947 wan_quota_in = (UINT32_MAX) /10;
950 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", "WAN_QUOTA_OUT", "a_wan_out_str))
952 if (0 == strcmp(quota_wan_out_str, "unlimited") ||
953 (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_wan_out_str, &wan_quota_out)))
954 wan_quota_out = (UINT32_MAX) /10;
956 GNUNET_free (quota_wan_out_str);
957 quota_wan_out_str = NULL;
961 wan_quota_out = (UINT32_MAX) /10;
964 mode = GNUNET_CONFIGURATION_get_value_yesno (cfg, "ats", "MLP");
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MLP mode %u", mode);
972 /* Init the MLP solver with default values */
973 mlp = GAS_mlp_init (cfg, stats, MLP_MAX_EXEC_DURATION, MLP_MAX_ITERATIONS);
976 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode\n");
977 GNUNET_STATISTICS_update (GSA_stats, "MLP mode enabled", 0, GNUNET_NO);
982 GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 1, GNUNET_NO);
986 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP mode was configured, but libglpk is not installed, switching to simple mode");
987 GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO);
993 GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO);
996 /* No configuration value */
998 GNUNET_STATISTICS_update (GSA_stats, "MLP enabled", 0, GNUNET_NO);
1004 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started with %s mode\n", (SIMPLE == ats_mode) ? "SIMPLE" : "MLP");
1005 running = GNUNET_YES;
1010 * Free memory of address.
1013 * @param key peer identity (unused)
1014 * @param value the 'struct ATS_Address' to free
1015 * @return GNUNET_OK (continue to iterate)
1018 free_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1020 struct ATS_Address *aa = value;
1022 destroy_address (aa);
1028 GAS_addresses_destroy_all ()
1030 if (GNUNET_NO == running)
1033 if (addresses != NULL)
1034 GNUNET_CONTAINER_multihashmap_iterate (addresses, &free_address_it, NULL);
1035 GNUNET_assert (active_addr_count == 0);
1040 * Shutdown address subsystem.
1043 GAS_addresses_done ()
1045 GAS_addresses_destroy_all ();
1046 running = GNUNET_NO;
1047 GNUNET_CONTAINER_multihashmap_destroy (addresses);
1050 if (ats_mode == MLP)
1057 struct PeerIteratorContext
1059 GNUNET_ATS_Peer_Iterator it;
1061 struct GNUNET_CONTAINER_MultiHashMap *peers_returned;
1066 const struct GNUNET_HashCode * key,
1069 struct PeerIteratorContext *ip_ctx = cls;
1070 struct GNUNET_PeerIdentity tmp;
1072 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(ip_ctx->peers_returned, key))
1074 GNUNET_CONTAINER_multihashmap_put(ip_ctx->peers_returned, key, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1075 tmp.hashPubKey = (*key);
1076 ip_ctx->it (ip_ctx->it_cls, &tmp);
1083 * Return all peers currently known to ATS
1085 * @param p_it the iterator to call for every peer
1086 * @param p_it_cls the closure for the iterator
1089 GAS_addresses_iterate_peers (GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
1091 struct PeerIteratorContext ip_ctx;
1096 GNUNET_assert (NULL != addresses);
1098 size = GNUNET_CONTAINER_multihashmap_size(addresses);
1102 ip_ctx.it_cls = p_it_cls;
1103 ip_ctx.peers_returned = GNUNET_CONTAINER_multihashmap_create (size, GNUNET_NO);
1104 GNUNET_CONTAINER_multihashmap_iterate (addresses, &peer_it, &ip_ctx);
1105 GNUNET_CONTAINER_multihashmap_destroy (ip_ctx.peers_returned);
1107 p_it (p_it_cls, NULL);
1110 struct PeerInfoIteratorContext
1112 GNUNET_ATS_PeerInfo_Iterator it;
1118 peerinfo_it (void *cls,
1119 const struct GNUNET_HashCode * key,
1122 struct PeerInfoIteratorContext *pi_ctx = cls;
1123 struct ATS_Address *addr = (struct ATS_Address *) value;
1125 if ((NULL != pi_ctx->it) && (GNUNET_YES == addr->used))
1126 pi_ctx->it (pi_ctx->it_cls,
1129 addr->addr, addr->addr_len,
1130 addr->ats, addr->ats_count,
1131 addr->assigned_bw_out,
1132 addr->assigned_bw_in);
1138 * Return all peers currently known to ATS
1140 * @param peer the respective peer
1141 * @param pi_it the iterator to call for every peer
1142 * @param pi_it_cls the closure for the iterator
1145 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_PeerInfo_Iterator pi_it, void *pi_it_cls)
1147 struct PeerInfoIteratorContext pi_ctx;
1148 struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
1149 GNUNET_assert (NULL != peer);
1150 GNUNET_assert (NULL != addresses);
1152 zero_bw = GNUNET_BANDWIDTH_value_init (0);
1154 pi_ctx.it_cls = pi_it_cls;
1156 GNUNET_CONTAINER_multihashmap_get_multiple (addresses, &peer->hashPubKey, &peerinfo_it, &pi_ctx);
1159 pi_it (pi_it_cls, NULL, NULL, NULL, 0, NULL, 0, zero_bw, zero_bw);
1164 /* end of gnunet-service-ats_addresses.c */