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"
34 #include "gnunet-service-ats_addresses_mlp.h"
35 #include "gnunet-service-ats_addresses_simplistic.h"
39 * Available ressource assignment modes
46 * Assign each peer an equal amount of bandwidth (bw)
48 * bw_per_peer = bw_total / #active addresses
55 * Solve ressource assignment as an optimization problem
56 * Uses an mixed integer programming solver
62 * Handle for ATS address component
64 struct GAS_Addresses_Suggestion_Requests
66 struct GAS_Addresses_Suggestion_Requests *next;
67 struct GAS_Addresses_Suggestion_Requests *prev;
69 struct GNUNET_PeerIdentity id;
73 * Handle for ATS address component
75 struct GAS_Addresses_Handle
78 * A multihashmap to store all addresses
80 struct GNUNET_CONTAINER_MultiHashMap *addresses;
83 * Configure WAN quota in
85 unsigned long long wan_quota_in;
88 * Configure WAN quota out
90 unsigned long long wan_quota_out;
93 * Is ATS addresses running
98 * Configured ATS solver
108 * Address suggestion requests DLL head
110 struct GAS_Addresses_Suggestion_Requests *r_head;
113 * Address suggestion requests DLL tail
115 struct GAS_Addresses_Suggestion_Requests *r_tail;
117 /* Solver functions */
122 GAS_solver_init s_init;
125 * Update address in solver
127 GAS_solver_address_update s_update;
130 * Get address from solver
132 GAS_solver_get_preferred_address s_get;
135 * Delete address in solver
137 GAS_solver_address_delete s_del;
140 * Change preference for quality in solver
142 GAS_solver_address_change_preference s_pref;
147 GAS_solver_done s_done;
154 struct GAS_Addresses_Handle *handle;
158 assemble_ats_information (const struct ATS_Address *aa, struct GNUNET_ATS_Information **dest)
160 unsigned int ats_count = GNUNET_ATS_PropertyCount - 1;
161 struct GNUNET_ATS_Information *ats = GNUNET_malloc (ats_count * sizeof (struct GNUNET_ATS_Information));
164 ats[0].type = ntohl(GNUNET_ATS_UTILIZATION_UP);
165 ats[0].value = aa->atsp_utilization_out.value__;
166 ats[1].type = ntohl(GNUNET_ATS_UTILIZATION_DOWN);
167 ats[1].value = aa->atsp_utilization_in.value__;
168 ats[2].type = ntohl(GNUNET_ATS_NETWORK_TYPE);
169 ats[2].value = ntohl(aa->atsp_network_type);
170 ats[3].type = ntohl(GNUNET_ATS_QUALITY_NET_DELAY);
171 ats[3].value = ntohl(aa->atsp_latency.rel_value);
172 ats[4].type = ntohl(GNUNET_ATS_QUALITY_NET_DISTANCE);
173 ats[4].value = ntohl(aa->atsp_distance);
174 ats[5].type = ntohl(GNUNET_ATS_COST_WAN);
175 ats[5].value = ntohl (aa->atsp_cost_wan);
176 ats[6].type = ntohl(GNUNET_ATS_COST_LAN);
177 ats[6].value = ntohl (aa->atsp_cost_lan);
178 ats[7].type = ntohl(GNUNET_ATS_COST_WLAN);
179 ats[7].value = ntohl (aa->atsp_cost_wlan);
184 * Free the given address
185 * @param addr address to destroy
188 free_address (struct ATS_Address *addr)
190 GNUNET_free_non_null (addr->ats);
191 GNUNET_free (addr->plugin);
196 * Create a ATS_address with the given information
198 * @param plugin_name plugin
199 * @param plugin_addr address
200 * @param plugin_addr_len address length
201 * @param session_id session
202 * @return the ATS_Address
204 static struct ATS_Address *
205 create_address (const struct GNUNET_PeerIdentity *peer,
206 const char *plugin_name,
207 const void *plugin_addr, size_t plugin_addr_len,
210 struct ATS_Address *aa = NULL;
212 aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
214 aa->addr_len = plugin_addr_len;
216 memcpy (&aa[1], plugin_addr, plugin_addr_len);
217 aa->plugin = GNUNET_strdup (plugin_name);
218 aa->session_id = session_id;
224 * Destroy the given address.
226 * @param addr address to destroy
227 * @return GNUNET_YES if bandwidth allocations should be recalcualted
230 destroy_address (struct ATS_Address *addr)
235 GNUNET_assert (GNUNET_YES ==
236 GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
237 &addr->peer.hashPubKey,
240 handle->s_del (handle->solver, handle->addresses, addr);
246 struct CompareAddressContext
248 const struct ATS_Address *search;
250 /* exact_address != NULL if address and session is equal */
251 struct ATS_Address *exact_address;
252 /* exact_address != NULL if address and session is 0 */
253 struct ATS_Address *base_address;
258 compare_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
260 struct CompareAddressContext *cac = cls;
261 struct ATS_Address *aa = value;
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing peer %4s: address length %u session %u <-> address length %u session %u\n",
265 aa->addr_len, aa->session_id,
266 cac->search->addr_len, cac->search->session_id);
268 /* Find an matching exact address:
271 * aa->addr_len == cac->search->addr_len
272 * aa->plugin == cac->search->plugin
273 * aa->addr == cac->search->addr
274 * aa->session == cac->search->session
276 * return as exact address
278 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
280 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
281 cac->exact_address = aa;
284 /* Find an matching base address:
288 * aa->session_id == 0
291 * aa->addr_len == cac->search->addr_len
292 * aa->plugin == cac->search->plugin
293 * aa->addr == cac->search->addr
295 * return as base address
297 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
299 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
300 cac->base_address = aa;
303 /* Find an matching exact address based on session:
307 * cac->search->addr_len == 0
310 * aa->plugin == cac->search->plugin
311 * aa->session_id == cac->search->session_id
313 * return as exact address
315 if (0 == cac->search->addr_len)
317 if ((0 == strcmp (aa->plugin, cac->search->plugin)) && (aa->session_id == cac->search->session_id))
318 cac->exact_address = aa;
321 if (cac->exact_address == NULL)
322 return GNUNET_YES; /* Continue iteration to find exact address */
324 return GNUNET_NO; /* Stop iteration since we have an exact address */
329 * Find an existing equivalent address record.
330 * Compares by peer identity and network address OR by session ID
331 * (one of the two must match).
333 * @param peer peer to lookup addresses for
334 * @param addr existing address record
335 * @return existing address record, NULL for none
338 find_address (const struct GNUNET_PeerIdentity *peer,
339 const struct ATS_Address *addr)
341 struct CompareAddressContext cac;
343 cac.exact_address = NULL;
344 cac.base_address = NULL;
346 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
347 &compare_address_it, &cac);
350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
351 "Found exact address: %s base address: %s\n",
352 (cac.exact_address != NULL) ? "YES" : "NO",
353 (cac.base_address != NULL) ? "YES" : "NO");
355 if (cac.exact_address == NULL)
356 return cac.base_address;
357 return cac.exact_address;
361 static struct ATS_Address *
362 lookup_address (const struct GNUNET_PeerIdentity *peer,
363 const char *plugin_name, const void *plugin_addr,
364 size_t plugin_addr_len, uint32_t session_id,
365 const struct GNUNET_ATS_Information *atsi,
368 struct ATS_Address *aa;
369 struct ATS_Address *old;
371 aa = create_address (peer,
373 plugin_addr, plugin_addr_len,
376 aa->mlp_information = NULL;
377 aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
378 aa->ats_count = atsi_count;
379 memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
381 /* Get existing address or address with session == 0 */
382 old = find_address (peer, aa);
388 else if (old->session_id != session_id)
398 compare_address_session_it (void *cls, const struct GNUNET_HashCode * key, void *value)
400 struct CompareAddressContext *cac = cls;
401 struct ATS_Address *aa = value;
403 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
405 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
407 cac->exact_address = aa;
416 * Find an existing equivalent address record.
417 * Compares by peer identity and network address AND by session ID
418 * (one of the two must match).
420 * @param peer peer to lookup addresses for
421 * @param addr existing address record
422 * @return existing address record, NULL for none
424 static struct ATS_Address *
425 find_exact_address (const struct GNUNET_PeerIdentity *peer,
426 const struct ATS_Address *addr)
428 struct CompareAddressContext cac;
430 cac.exact_address = NULL;
432 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
433 &compare_address_session_it, &cac);
434 return cac.exact_address;
439 GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
440 const char *plugin_name, const void *plugin_addr,
441 size_t plugin_addr_len, uint32_t session_id,
442 const struct GNUNET_ATS_Information *atsi,
445 struct ATS_Address *aa;
446 struct ATS_Address *old;
448 if (GNUNET_NO == handle->running)
451 GNUNET_assert (NULL != handle->addresses);
453 aa = create_address (peer,
455 plugin_addr, plugin_addr_len,
457 aa->mlp_information = NULL;
458 aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
459 aa->ats_count = atsi_count;
460 memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
462 /* Get existing address or address with session == 0 */
463 old = find_address (peer, aa);
466 /* We have a new address */
467 GNUNET_assert (GNUNET_OK ==
468 GNUNET_CONTAINER_multihashmap_put (handle->addresses,
469 &peer->hashPubKey, aa,
470 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' session id %u, %p\n",
472 GNUNET_i2s (peer), session_id, aa);
473 /* Tell solver about update */
474 handle->s_update (handle->solver, handle->addresses, aa);
478 if (old->session_id != 0)
480 /* This address and session is already existing */
481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
482 "Added already existing address for peer `%s' `%s' %p with new session %u\n",
483 GNUNET_i2s (peer), plugin_name, session_id);
488 /* We have an address without an session, update this address */
489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490 "Updated existing address for peer `%s' %p with new session %u\n",
491 GNUNET_i2s (peer), old, session_id);
492 GNUNET_free_non_null (old->ats);
493 old->session_id = session_id;
497 old->ats_count = aa->ats_count;
498 GNUNET_free (aa->plugin);
500 handle->s_update (handle->solver, handle->addresses, old);
505 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
506 const char *plugin_name, const void *plugin_addr,
507 size_t plugin_addr_len, uint32_t session_id,
508 const struct GNUNET_ATS_Information *atsi,
511 struct ATS_Address *old;
514 if (GNUNET_NO == handle->running)
517 GNUNET_assert (NULL != handle->addresses);
519 /* Get existing address */
520 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
521 session_id, atsi, atsi_count);
524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n",
525 GNUNET_i2s (peer), plugin_name, session_id);
530 for (i = 0; i < atsi_count; i++)
531 switch (ntohl (atsi[i].type))
533 case GNUNET_ATS_UTILIZATION_UP:
534 old->atsp_utilization_out.value__ = atsi[i].value;
536 case GNUNET_ATS_UTILIZATION_DOWN:
537 old->atsp_utilization_in.value__ = atsi[i].value;
539 case GNUNET_ATS_QUALITY_NET_DELAY:
540 old->atsp_latency.rel_value = ntohl (atsi[i].value);
542 case GNUNET_ATS_QUALITY_NET_DISTANCE:
543 old->atsp_distance = ntohl (atsi[i].value);
545 case GNUNET_ATS_COST_WAN:
546 old->atsp_cost_wan = ntohl (atsi[i].value);
548 case GNUNET_ATS_COST_LAN:
549 old->atsp_cost_lan = ntohl (atsi[i].value);
551 case GNUNET_ATS_COST_WLAN:
552 old->atsp_cost_wlan = ntohl (atsi[i].value);
554 case GNUNET_ATS_NETWORK_TYPE:
555 old->atsp_network_type = ntohl (atsi[i].value);
559 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
560 "Received unsupported ATS type %u\n", ntohl (atsi[i].type));
564 /* Tell solver about update */
565 handle->s_update (handle->solver, handle->addresses, old);
572 * If session != 0, just the session is deleted, the address itself still exists
573 * If session == 0, remove full address
574 * If session == 0 and addrlen == 0, destroy inbound address
578 * @param value the 'struct ATS_Address'
579 * @return GNUNET_OK (continue to iterate)
582 destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *value)
584 const struct ATS_Address *info = cls;
585 struct ATS_Address *aa = value;
588 memcmp (&aa->peer, &info->peer,
589 sizeof (struct GNUNET_PeerIdentity)));
590 /* session == 0, remove full address */
591 if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) &&
592 (aa->addr_len == info->addr_len) &&
593 (0 == memcmp (info->addr, aa->addr, aa->addr_len)))
596 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
597 "Deleting address for peer `%s': `%s' %u\n",
598 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
600 destroy_address (aa);
601 // FIXME if (GNUNET_YES == destroy_address (aa))recalculate_assigned_bw ();
604 /* session != 0, just remove session */
605 if (aa->session_id != info->session_id)
606 return GNUNET_OK; /* irrelevant */
607 if (aa->session_id != 0)
608 GNUNET_break (0 == strcmp (info->plugin, aa->plugin));
610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611 "Deleting session for peer `%s': `%s' %u\n",
612 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
615 if (GNUNET_YES == aa->active)
617 aa->active = GNUNET_NO;
618 //FIXME recalculate_assigned_bw ();
621 /* session == 0 and addrlen == 0 : destroy address */
622 if (aa->addr_len == 0)
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "Deleting session and address for peer `%s': `%s' %u\n",
626 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
627 (void) destroy_address (aa);
631 /* session was set to 0, update address */
633 if (handle->ats_mode == MODE_MLP)
634 GAS_mlp_address_update (handle->solver, handle->addresses, aa);
643 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
644 const char *plugin_name, const void *plugin_addr,
645 size_t plugin_addr_len, uint32_t session_id)
647 struct ATS_Address *aa;
648 struct ATS_Address *old;
650 if (GNUNET_NO == handle->running)
653 /* Get existing address */
654 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
655 session_id, NULL, 0);
658 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
659 GNUNET_i2s (peer), plugin_name, session_id);
663 GNUNET_break (0 < strlen (plugin_name));
664 aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
665 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
666 &destroy_by_session_id, aa);
672 GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
673 const char *plugin_name, const void *plugin_addr,
674 size_t plugin_addr_len, uint32_t session_id, int in_use)
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE",
679 GNUNET_i2s (peer), in_use);
682 struct ATS_Address *old;
684 if (GNUNET_NO == handle->running)
685 return GNUNET_SYSERR;
687 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id, NULL, 0);
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 "Trying to set unknown address `%s', %s %u %s \n",
693 plugin_name, session_id,
694 (GNUNET_NO == in_use) ? "NO" : "YES");
696 return GNUNET_SYSERR;
698 if (old->used == in_use)
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
702 "Address in use called multiple times for peer `%s': %s -> %s \n",
704 (GNUNET_NO == old->used) ? "NO" : "YES",
705 (GNUNET_NO == in_use) ? "NO" : "YES");
706 return GNUNET_SYSERR;
710 /* Tell solver about update */
711 handle->s_update (handle->solver, handle->addresses, old);
718 * Cancel address suggestions for a peer
720 * @param peer the respective peer
723 GAS_addresses_request_address_cancel (const struct GNUNET_PeerIdentity *peer)
725 struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
728 if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
736 "No address requests pending for peer `%s', cannot remove!\n", GNUNET_i2s (peer));
739 GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
745 * Add an address suggestions for a peer
747 * @param peer the respective peer
750 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
752 struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
753 const struct ATS_Address *aa;
754 struct GNUNET_ATS_Information *ats;
755 unsigned int ats_count;
757 if (GNUNET_NO == handle->running)
761 if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
762 break; /* already suggesting */
767 cur = GNUNET_malloc (sizeof (struct GAS_Addresses_Suggestion_Requests));
769 GNUNET_CONTAINER_DLL_insert (handle->r_head, handle->r_tail, cur);
772 /* Get prefered address from solver */
773 aa = handle->s_get (handle->solver, handle->addresses, peer);
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
776 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
779 "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
781 ats_count = assemble_ats_information (aa, &ats);
782 GAS_scheduling_transmit_address_suggestion (peer,
784 aa->addr, aa->addr_len,
795 reset_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
797 struct ATS_Address *aa = value;
799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
800 "Resetting interval for peer `%s' address %p from %llu to 0\n",
801 GNUNET_i2s (&aa->peer), aa, aa->block_interval);
803 aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
804 aa->block_interval = GNUNET_TIME_UNIT_ZERO;
810 GAS_addresses_handle_backoff_reset (const struct GNUNET_PeerIdentity *peer)
812 GNUNET_break (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses,
820 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
821 enum GNUNET_ATS_PreferenceKind kind,
824 if (GNUNET_NO == handle->running)
827 /* Tell solver about update */
828 handle->s_pref (handle->solver, peer, kind, score);
832 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
834 int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
835 char * entry_in = NULL;
836 char * entry_out = NULL;
837 char * quota_out_str;
841 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
846 case GNUNET_ATS_NET_UNSPECIFIED:
847 entry_out = "UNSPECIFIED_QUOTA_OUT";
848 entry_in = "UNSPECIFIED_QUOTA_IN";
850 case GNUNET_ATS_NET_LOOPBACK:
851 entry_out = "LOOPBACK_QUOTA_OUT";
852 entry_in = "LOOPBACK_QUOTA_IN";
854 case GNUNET_ATS_NET_LAN:
855 entry_out = "LAN_QUOTA_OUT";
856 entry_in = "LAN_QUOTA_IN";
858 case GNUNET_ATS_NET_WAN:
859 entry_out = "WAN_QUOTA_OUT";
860 entry_in = "WAN_QUOTA_IN";
862 case GNUNET_ATS_NET_WLAN:
863 entry_out = "WLAN_QUOTA_OUT";
864 entry_in = "WLAN_QUOTA_IN";
870 if ((entry_in == NULL) || (entry_out == NULL))
874 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, "a_out_str))
876 if (0 == strcmp(quota_out_str, BIG_M_STRING) ||
877 (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &out_dest[c])))
878 out_dest[c] = UINT32_MAX;
880 GNUNET_free (quota_out_str);
881 quota_out_str = NULL;
883 else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
884 out_dest[c] = UINT32_MAX;
886 out_dest[c] = UINT32_MAX;
889 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, "a_in_str))
891 if (0 == strcmp(quota_in_str, BIG_M_STRING) ||
892 (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
893 in_dest[c] = UINT32_MAX;
895 GNUNET_free (quota_in_str);
898 else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
900 in_dest[c] = UINT32_MAX;
904 in_dest[c] = UINT32_MAX;
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded quota: %s %u, %s %u\n", entry_in, in_dest[c], entry_out, out_dest[c]);
909 return GNUNET_ATS_NetworkTypeCount;
915 * Initialize address subsystem.
917 * @param cfg configuration to use
918 * @param stats the statistics handle to use
920 struct GAS_Addresses_Handle *
921 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
922 const struct GNUNET_STATISTICS_Handle *stats)
924 struct GAS_Addresses_Handle *ah;
925 int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
926 unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
927 unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
932 ah = GNUNET_malloc (sizeof (struct GAS_Addresses_Handle));
934 handle->running = GNUNET_NO;
936 /* Initialize the addresses database */
937 ah->addresses = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
938 GNUNET_assert (NULL != ah->addresses);
940 /* Figure out configured solution method */
941 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
943 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No ressource assignment method configured, using simplistic approch\n");
944 ah->ats_mode = MODE_SIMPLISTIC;
948 for (c = 0; c < strlen (mode_str); c++)
949 mode_str[c] = toupper (mode_str[c]);
950 if (0 == strcmp (mode_str, "SIMPLISTIC"))
952 ah->ats_mode = MODE_SIMPLISTIC;
954 else if (0 == strcmp (mode_str, "MLP"))
956 ah->ats_mode = MODE_MLP;
958 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Assignment method `%s' configured, but GLPK is not availabe, please install \n", mode_str);
959 ah->ats_mode = MODE_SIMPLISTIC;
964 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid ressource assignment method `%s' configured, using simplistic approch\n", mode_str);
965 ah->ats_mode = MODE_SIMPLISTIC;
967 GNUNET_free (mode_str);
969 /* Start configured solution method */
970 switch (ah->ats_mode)
973 /* Init the MLP solver with default values */
975 ah->ats_mode = MODE_MLP;
976 ah->s_init = &GAS_mlp_init;
977 ah->s_update = &GAS_mlp_address_update;
978 ah->s_get = &GAS_mlp_get_preferred_address;
979 ah->s_pref = &GAS_mlp_address_change_preference;
980 ah->s_del = &GAS_mlp_address_delete;
981 ah->s_done = &GAS_mlp_done;
987 case MODE_SIMPLISTIC:
988 /* Init the simplistic solver with default values */
989 ah->ats_mode = MODE_SIMPLISTIC;
990 ah->s_init = &GAS_simplistic_init;
991 ah->s_update = &GAS_simplistic_address_update;
992 ah->s_get = &GAS_simplistic_get_preferred_address;
993 ah->s_pref = &GAS_simplistic_address_change_preference;
994 ah->s_del = &GAS_simplistic_address_delete;
995 ah->s_done = &GAS_simplistic_done;
996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "SIMPLISTIC");
1003 GNUNET_assert (NULL != ah->s_init);
1004 GNUNET_assert (NULL != ah->s_update);
1005 GNUNET_assert (NULL != ah->s_get);
1006 GNUNET_assert (NULL != ah->s_pref);
1007 GNUNET_assert (NULL != ah->s_del);
1008 GNUNET_assert (NULL != ah->s_done);
1010 quota_count = load_quotas(cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
1012 ah->solver = ah->s_init (cfg, stats, quotas, quotas_in, quotas_out, quota_count);
1013 if (NULL == ah->solver)
1015 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to initialize solver!\n");
1020 /* up and running */
1021 ah->running = GNUNET_YES;
1027 * Free memory of address.
1030 * @param key peer identity (unused)
1031 * @param value the 'struct ATS_Address' to free
1032 * @return GNUNET_OK (continue to iterate)
1035 free_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1037 struct ATS_Address *aa = value;
1039 destroy_address (aa);
1045 GAS_addresses_destroy_all ()
1047 if (GNUNET_NO == handle->running)
1050 if (handle->addresses != NULL)
1051 GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &free_address_it, NULL);
1056 * Shutdown address subsystem.
1059 GAS_addresses_done (struct GAS_Addresses_Handle *handle)
1061 struct GAS_Addresses_Suggestion_Requests *cur;
1063 GNUNET_assert (NULL != handle);
1064 GAS_addresses_destroy_all ();
1065 handle->running = GNUNET_NO;
1066 GNUNET_CONTAINER_multihashmap_destroy (handle->addresses);
1067 handle->addresses = NULL;
1068 while (NULL != (cur = handle->r_head))
1070 GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
1074 GNUNET_free (handle);
1075 /* Stop configured solution method */
1079 struct PeerIteratorContext
1081 GNUNET_ATS_Peer_Iterator it;
1083 struct GNUNET_CONTAINER_MultiHashMap *peers_returned;
1088 const struct GNUNET_HashCode * key,
1091 struct PeerIteratorContext *ip_ctx = cls;
1092 struct GNUNET_PeerIdentity tmp;
1094 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(ip_ctx->peers_returned, key))
1096 GNUNET_CONTAINER_multihashmap_put(ip_ctx->peers_returned, key, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1097 tmp.hashPubKey = (*key);
1098 ip_ctx->it (ip_ctx->it_cls, &tmp);
1105 * Return all peers currently known to ATS
1107 * @param p_it the iterator to call for every peer, callbach with id == NULL
1109 * @param p_it_cls the closure for the iterator
1112 GAS_addresses_iterate_peers (GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
1114 struct PeerIteratorContext ip_ctx;
1119 GNUNET_assert (NULL != handle->addresses);
1121 size = GNUNET_CONTAINER_multihashmap_size(handle->addresses);
1125 ip_ctx.it_cls = p_it_cls;
1126 ip_ctx.peers_returned = GNUNET_CONTAINER_multihashmap_create (size, GNUNET_NO);
1127 GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &peer_it, &ip_ctx);
1128 GNUNET_CONTAINER_multihashmap_destroy (ip_ctx.peers_returned);
1130 p_it (p_it_cls, NULL);
1133 struct PeerInfoIteratorContext
1135 GNUNET_ATS_PeerInfo_Iterator it;
1141 peerinfo_it (void *cls,
1142 const struct GNUNET_HashCode * key,
1145 struct PeerInfoIteratorContext *pi_ctx = cls;
1146 struct ATS_Address *addr = (struct ATS_Address *) value;
1147 struct GNUNET_ATS_Information *ats;
1150 if (NULL != pi_ctx->it)
1152 ats_count = assemble_ats_information (addr, &ats);
1154 pi_ctx->it (pi_ctx->it_cls,
1157 addr->addr, addr->addr_len,
1160 addr->assigned_bw_out,
1161 addr->assigned_bw_in);
1169 * Return all peers currently known to ATS
1171 * @param peer the respective peer
1172 * @param pi_it the iterator to call for every peer
1173 * @param pi_it_cls the closure for the iterator
1176 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_PeerInfo_Iterator pi_it, void *pi_it_cls)
1178 struct PeerInfoIteratorContext pi_ctx;
1179 struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
1180 GNUNET_assert (NULL != peer);
1181 GNUNET_assert (NULL != handle->addresses);
1183 return; /* does not make sense without callback */
1185 zero_bw = GNUNET_BANDWIDTH_value_init (0);
1187 pi_ctx.it_cls = pi_it_cls;
1189 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey, &peerinfo_it, &pi_ctx);
1192 pi_it (pi_it_cls, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0, zero_bw, zero_bw);
1197 /* end of gnunet-service-ats_addresses.c */