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"
37 #include "gnunet-service-ats_addresses_simplistic.h"
40 #define BIG_M_VALUE (UINT32_MAX) /10
41 #define BIG_M_STRING "unlimited"
44 * Available ressource assignment modes
51 * Assign each peer an equal amount of bandwidth (bw)
53 * bw_per_peer = bw_total / #active addresses
60 * Solve ressource assignment as an optimization problem
61 * Uses an mixed integer programming solver
67 * Handle for ATS address component
69 struct GAS_Addresses_Suggestion_Requests
71 struct GAS_Addresses_Suggestion_Requests *next;
72 struct GAS_Addresses_Suggestion_Requests *prev;
74 struct GNUNET_PeerIdentity id;
78 * Handle for ATS address component
80 struct GAS_Addresses_Handle
83 * A multihashmap to store all addresses
85 struct GNUNET_CONTAINER_MultiHashMap *addresses;
88 * Configure WAN quota in
90 unsigned long long wan_quota_in;
93 * Configure WAN quota out
95 unsigned long long wan_quota_out;
98 * Number of active addresses
100 unsigned int active_addr_count;
103 * Is ATS addresses running
108 * Configured ATS solver
118 * Address suggestion requests DLL head
120 struct GAS_Addresses_Suggestion_Requests *r_head;
123 * Address suggestion requests DLL tail
125 struct GAS_Addresses_Suggestion_Requests *r_tail;
127 /* Solver functions */
132 GAS_solver_init s_init;
135 * Update address in solver
137 GAS_solver_address_update s_update;
140 * Get address from solver
142 GAS_solver_get_preferred_address s_get;
145 * Delete address in solver
147 GAS_solver_address_delete s_del;
150 * Change preference for quality in solver
152 GAS_solver_address_change_preference s_pref;
157 GAS_solver_done s_done;
164 struct GAS_Addresses_Handle *handle;
168 assemble_ats_information (struct ATS_Address *aa, struct GNUNET_ATS_Information **dest)
170 unsigned int ats_count = GNUNET_ATS_PropertyCount - 1;
171 struct GNUNET_ATS_Information *ats = GNUNET_malloc (ats_count * sizeof (struct GNUNET_ATS_Information));
174 ats[0].type = ntohl(GNUNET_ATS_UTILIZATION_UP);
175 ats[0].value = aa->atsp_utilization_out.value__;
176 ats[1].type = ntohl(GNUNET_ATS_UTILIZATION_DOWN);
177 ats[1].value = aa->atsp_utilization_in.value__;
178 ats[2].type = ntohl(GNUNET_ATS_NETWORK_TYPE);
179 ats[2].value = ntohl(aa->atsp_network_type);
180 ats[3].type = ntohl(GNUNET_ATS_QUALITY_NET_DELAY);
181 ats[3].value = ntohl(aa->atsp_latency.rel_value);
182 ats[4].type = ntohl(GNUNET_ATS_QUALITY_NET_DISTANCE);
183 ats[4].value = ntohl(aa->atsp_distance);
184 ats[5].type = ntohl(GNUNET_ATS_COST_WAN);
185 ats[5].value = ntohl (aa->atsp_cost_wan);
186 ats[6].type = ntohl(GNUNET_ATS_COST_LAN);
187 ats[6].value = ntohl (aa->atsp_cost_lan);
188 ats[7].type = ntohl(GNUNET_ATS_COST_WLAN);
189 ats[7].value = ntohl (aa->atsp_cost_wlan);
194 send_bw_notification (struct ATS_Address *aa)
196 struct GNUNET_ATS_Information *ats;
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New bandwidth for peer %s is %u/%u\n",
200 GNUNET_i2s (&aa->peer), ntohl (aa->assigned_bw_in.value__),
201 ntohl (aa->assigned_bw_out.value__));
202 ats_count = assemble_ats_information (aa, &ats);
204 GAS_scheduling_transmit_address_suggestion (&aa->peer, aa->plugin, aa->addr,
205 aa->addr_len, aa->session_id,
209 GAS_reservations_set_bandwidth (&aa->peer, aa->assigned_bw_in);
210 GAS_performance_notify_all_clients (&aa->peer, aa->plugin, aa->addr, aa->addr_len,
212 ats, ats_count, aa->assigned_bw_out,
218 * Update a bandwidth assignment for a peer. This trivial method currently
219 * simply assigns the same share to all active connections.
223 * @param value the 'struct ATS_Address'
224 * @return GNUNET_OK (continue to iterate)
227 update_bw_simple_it (void *cls, const struct GNUNET_HashCode * key, void *value)
229 struct ATS_Address *aa = value;
231 if (GNUNET_YES != aa->active)
233 GNUNET_assert (handle->active_addr_count > 0);
237 aa->assigned_bw_in.value__ = htonl (handle->wan_quota_in / handle->active_addr_count);
238 aa->assigned_bw_out.value__ = htonl (handle->wan_quota_out / handle->active_addr_count);
240 send_bw_notification (aa);
247 * Some (significant) input changed, recalculate bandwidth assignment
251 recalculate_assigned_bw ()
253 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254 "Recalculating bandwidth for all active connections\n");
255 GNUNET_STATISTICS_update (GSA_stats, "# bandwidth recalculations performed",
257 GNUNET_STATISTICS_set (GSA_stats, "# active addresses", handle->active_addr_count,
260 GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &update_bw_simple_it, NULL);
264 * Free the given address
265 * @param addr address to destroy
268 free_address (struct ATS_Address *addr)
270 GNUNET_free_non_null (addr->ats);
271 GNUNET_free (addr->plugin);
276 * Create a ATS_address with the given information
278 * @param plugin_name plugin
279 * @param plugin_addr address
280 * @param plugin_addr_len address length
281 * @param session_id session
282 * @return the ATS_Address
284 static struct ATS_Address *
285 create_address (const struct GNUNET_PeerIdentity *peer,
286 const char *plugin_name,
287 const void *plugin_addr, size_t plugin_addr_len,
290 struct ATS_Address *aa = NULL;
292 aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
294 aa->addr_len = plugin_addr_len;
296 memcpy (&aa[1], plugin_addr, plugin_addr_len);
297 aa->plugin = GNUNET_strdup (plugin_name);
298 aa->session_id = session_id;
304 * Destroy the given address.
306 * @param addr address to destroy
307 * @return GNUNET_YES if bandwidth allocations should be recalcualted
310 destroy_address (struct ATS_Address *addr)
315 GNUNET_assert (GNUNET_YES ==
316 GNUNET_CONTAINER_multihashmap_remove (handle->addresses,
317 &addr->peer.hashPubKey,
321 if (handle->ats_mode == MODE_MLP)
322 GAS_mlp_address_delete (handle->solver, handle->addresses, addr);
325 if (GNUNET_YES == addr->active)
327 handle->active_addr_count--;
328 addr->active = GNUNET_NO;
336 struct CompareAddressContext
338 const struct ATS_Address *search;
340 /* exact_address != NULL if address and session is equal */
341 struct ATS_Address *exact_address;
342 /* exact_address != NULL if address and session is 0 */
343 struct ATS_Address *base_address;
348 compare_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
350 struct CompareAddressContext *cac = cls;
351 struct ATS_Address *aa = value;
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing peer %4s: address length %u session %u <-> address length %u session %u\n",
355 aa->addr_len, aa->session_id,
356 cac->search->addr_len, cac->search->session_id);
358 /* Find an matching exact address:
361 * aa->addr_len == cac->search->addr_len
362 * aa->plugin == cac->search->plugin
363 * aa->addr == cac->search->addr
364 * aa->session == cac->search->session
366 * return as exact address
368 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
370 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
371 cac->exact_address = aa;
374 /* Find an matching base address:
378 * aa->session_id == 0
381 * aa->addr_len == cac->search->addr_len
382 * aa->plugin == cac->search->plugin
383 * aa->addr == cac->search->addr
385 * return as base address
387 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
389 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == 0))
390 cac->base_address = aa;
393 /* Find an matching exact address based on session:
397 * cac->search->addr_len == 0
400 * aa->plugin == cac->search->plugin
401 * aa->session_id == cac->search->session_id
403 * return as exact address
405 if (0 == cac->search->addr_len)
407 if ((0 == strcmp (aa->plugin, cac->search->plugin)) && (aa->session_id == cac->search->session_id))
408 cac->exact_address = aa;
411 if (cac->exact_address == NULL)
412 return GNUNET_YES; /* Continue iteration to find exact address */
414 return GNUNET_NO; /* Stop iteration since we have an exact address */
419 * Find an existing equivalent address record.
420 * Compares by peer identity and network address OR by session ID
421 * (one of the two must match).
423 * @param peer peer to lookup addresses for
424 * @param addr existing address record
425 * @return existing address record, NULL for none
428 find_address (const struct GNUNET_PeerIdentity *peer,
429 const struct ATS_Address *addr)
431 struct CompareAddressContext cac;
433 cac.exact_address = NULL;
434 cac.base_address = NULL;
436 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
437 &compare_address_it, &cac);
440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
441 "Found exact address: %s base address: %s\n",
442 (cac.exact_address != NULL) ? "YES" : "NO",
443 (cac.base_address != NULL) ? "YES" : "NO");
445 if (cac.exact_address == NULL)
446 return cac.base_address;
447 return cac.exact_address;
451 static struct ATS_Address *
452 lookup_address (const struct GNUNET_PeerIdentity *peer,
453 const char *plugin_name, const void *plugin_addr,
454 size_t plugin_addr_len, uint32_t session_id,
455 const struct GNUNET_ATS_Information *atsi,
458 struct ATS_Address *aa;
459 struct ATS_Address *old;
461 aa = create_address (peer,
463 plugin_addr, plugin_addr_len,
466 aa->mlp_information = NULL;
467 aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
468 aa->ats_count = atsi_count;
469 memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
471 /* Get existing address or address with session == 0 */
472 old = find_address (peer, aa);
478 else if (old->session_id != session_id)
488 compare_address_session_it (void *cls, const struct GNUNET_HashCode * key, void *value)
490 struct CompareAddressContext *cac = cls;
491 struct ATS_Address *aa = value;
493 if ((aa->addr_len == cac->search->addr_len) && (0 == strcmp (aa->plugin, cac->search->plugin)))
495 if ((0 == memcmp (aa->addr, cac->search->addr, aa->addr_len)) && (aa->session_id == cac->search->session_id))
497 cac->exact_address = aa;
506 * Find an existing equivalent address record.
507 * Compares by peer identity and network address AND by session ID
508 * (one of the two must match).
510 * @param peer peer to lookup addresses for
511 * @param addr existing address record
512 * @return existing address record, NULL for none
514 static struct ATS_Address *
515 find_exact_address (const struct GNUNET_PeerIdentity *peer,
516 const struct ATS_Address *addr)
518 struct CompareAddressContext cac;
520 cac.exact_address = NULL;
522 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
523 &compare_address_session_it, &cac);
524 return cac.exact_address;
529 GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
530 const char *plugin_name, const void *plugin_addr,
531 size_t plugin_addr_len, uint32_t session_id,
532 const struct GNUNET_ATS_Information *atsi,
535 struct ATS_Address *aa;
536 struct ATS_Address *old;
538 if (GNUNET_NO == handle->running)
541 GNUNET_assert (NULL != handle->addresses);
543 aa = create_address (peer,
545 plugin_addr, plugin_addr_len,
548 aa->mlp_information = NULL;
549 aa->ats = GNUNET_malloc (atsi_count * sizeof (struct GNUNET_ATS_Information));
550 aa->ats_count = atsi_count;
551 memcpy (aa->ats, atsi, atsi_count * sizeof (struct GNUNET_ATS_Information));
553 /* Get existing address or address with session == 0 */
554 old = find_address (peer, aa);
557 /* We have a new address */
558 GNUNET_assert (GNUNET_OK ==
559 GNUNET_CONTAINER_multihashmap_put (handle->addresses,
560 &peer->hashPubKey, aa,
561 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added new address for peer `%s' session id %u, %p\n",
563 GNUNET_i2s (peer), session_id, aa);
567 if (old->session_id == 0)
569 /* We have a base address with out an session, update this address */
570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
571 "Updated existing address for peer `%s' %p with new session %u\n",
572 GNUNET_i2s (peer), old, session_id);
573 GNUNET_free_non_null (old->ats);
574 old->session_id = session_id;
578 old->ats_count = aa->ats_count;
579 GNUNET_free (aa->plugin);
584 /* This address and session is already existing */
585 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
586 "Added already existing address for peer `%s' `%s' %p with new session %u\n",
587 GNUNET_i2s (peer), plugin_name, session_id);
593 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
594 const char *plugin_name, const void *plugin_addr,
595 size_t plugin_addr_len, uint32_t session_id,
596 const struct GNUNET_ATS_Information *atsi,
599 struct ATS_Address *old;
602 if (GNUNET_NO == handle->running)
605 GNUNET_assert (NULL != handle->addresses);
607 /* Get existing address */
608 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
609 session_id, atsi, atsi_count);
612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tried to update unknown address for peer `%s' `%s' session id %u\n",
613 GNUNET_i2s (peer), plugin_name, session_id);
618 for (i = 0; i < atsi_count; i++)
619 switch (ntohl (atsi[i].type))
621 case GNUNET_ATS_UTILIZATION_UP:
622 old->atsp_utilization_out.value__ = atsi[i].value;
624 case GNUNET_ATS_UTILIZATION_DOWN:
625 old->atsp_utilization_in.value__ = atsi[i].value;
627 case GNUNET_ATS_QUALITY_NET_DELAY:
628 old->atsp_latency.rel_value = ntohl (atsi[i].value);
630 case GNUNET_ATS_QUALITY_NET_DISTANCE:
631 old->atsp_distance = ntohl (atsi[i].value);
633 case GNUNET_ATS_COST_WAN:
634 old->atsp_cost_wan = ntohl (atsi[i].value);
636 case GNUNET_ATS_COST_LAN:
637 old->atsp_cost_lan = ntohl (atsi[i].value);
639 case GNUNET_ATS_COST_WLAN:
640 old->atsp_cost_wlan = ntohl (atsi[i].value);
642 case GNUNET_ATS_NETWORK_TYPE:
643 old->atsp_network_type = ntohl (atsi[i].value);
647 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
648 "Received unsupported ATS type %u\n", ntohl (atsi[i].type));
653 /* Tell solver about update */
654 handle->s_update (handle->solver, handle->addresses, old);
661 * If session != 0, just the session is deleted, the address itself still exists
662 * If session == 0, remove full address
663 * If session == 0 and addrlen == 0, destroy inbound address
667 * @param value the 'struct ATS_Address'
668 * @return GNUNET_OK (continue to iterate)
671 destroy_by_session_id (void *cls, const struct GNUNET_HashCode * key, void *value)
673 const struct ATS_Address *info = cls;
674 struct ATS_Address *aa = value;
677 memcmp (&aa->peer, &info->peer,
678 sizeof (struct GNUNET_PeerIdentity)));
679 /* session == 0, remove full address */
680 if ((info->session_id == 0) && (0 == strcmp (info->plugin, aa->plugin)) &&
681 (aa->addr_len == info->addr_len) &&
682 (0 == memcmp (info->addr, aa->addr, aa->addr_len)))
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "Deleting address for peer `%s': `%s' %u\n",
687 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
689 if (GNUNET_YES == destroy_address (aa))
690 recalculate_assigned_bw ();
693 /* session != 0, just remove session */
694 if (aa->session_id != info->session_id)
695 return GNUNET_OK; /* irrelevant */
696 if (aa->session_id != 0)
697 GNUNET_break (0 == strcmp (info->plugin, aa->plugin));
699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
700 "Deleting session for peer `%s': `%s' %u\n",
701 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
704 if (GNUNET_YES == aa->active)
706 aa->active = GNUNET_NO;
707 handle->active_addr_count--;
708 recalculate_assigned_bw ();
711 /* session == 0 and addrlen == 0 : destroy address */
712 if (aa->addr_len == 0)
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "Deleting session and address for peer `%s': `%s' %u\n",
716 GNUNET_i2s (&aa->peer), aa->plugin, aa->session_id);
717 (void) destroy_address (aa);
721 /* session was set to 0, update address */
723 if (handle->ats_mode == MODE_MLP)
724 GAS_mlp_address_update (handle->solver, handle->addresses, aa);
733 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
734 const char *plugin_name, const void *plugin_addr,
735 size_t plugin_addr_len, uint32_t session_id)
737 struct ATS_Address *aa;
738 struct ATS_Address *old;
740 if (GNUNET_NO == handle->running)
743 /* Get existing address */
744 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len,
745 session_id, NULL, 0);
748 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Tried to destroy unknown address for peer `%s' `%s' session id %u\n",
749 GNUNET_i2s (peer), plugin_name, session_id);
754 GNUNET_break (0 < strlen (plugin_name));
755 aa = create_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id);
757 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey,
758 &destroy_by_session_id, aa);
765 GAS_addresses_in_use (const struct GNUNET_PeerIdentity *peer,
766 const char *plugin_name, const void *plugin_addr,
767 size_t plugin_addr_len, uint32_t session_id, int in_use)
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
771 "Received `%s' message for peer `%s': %i\n", "ADDRESS_IN_USE",
772 GNUNET_i2s (peer), in_use);
775 struct ATS_Address *old;
777 if (GNUNET_NO == handle->running)
778 return GNUNET_SYSERR;
780 old = lookup_address (peer, plugin_name, plugin_addr, plugin_addr_len, session_id, NULL, 0);
783 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
784 "Trying to set unknown address `%s', %s %u %s \n",
786 plugin_name, session_id,
787 (GNUNET_NO == in_use) ? "NO" : "YES");
789 return GNUNET_SYSERR;
791 if (old->used == in_use)
794 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
795 "Address in use called multiple times for peer `%s': %s -> %s \n",
797 (GNUNET_NO == old->used) ? "NO" : "YES",
798 (GNUNET_NO == in_use) ? "NO" : "YES");
799 return GNUNET_SYSERR;
803 /* Tell solver about update */
804 handle->s_update (handle->solver, handle->addresses, old);
811 request_address_mlp (const struct GNUNET_PeerIdentity *peer)
813 struct ATS_Address *aa;
817 /* Get preferred address from MODE_MLP */
818 struct ATS_PreferedAddress * paddr = NULL;
819 paddr = GAS_mlp_get_preferred_address (mlp, addresses, peer);
821 aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(paddr->bandwidth_out);
822 /* FIXME use bw in value */
823 paddr->bandwidth_in = paddr->bandwidth_out;
824 aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init (paddr->bandwidth_in);
830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
831 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
834 if (aa->active == GNUNET_NO)
836 aa->active = GNUNET_YES;
837 handle->active_addr_count++;
838 send_bw_notification (aa);
842 /* just to be sure... */
843 GAS_scheduling_transmit_address_suggestion (peer, aa->plugin, aa->addr,
844 aa->addr_len, aa->session_id,
845 aa->ats, aa->ats_count,
855 * Cancel address suggestions for a peer
857 * @param peer the respective peer
860 GAS_addresses_request_address_cancel (const struct GNUNET_PeerIdentity *peer)
862 struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
865 if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
875 GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
881 * Add an address suggestions for a peer
883 * @param peer the respective peer
886 GAS_addresses_request_address (const struct GNUNET_PeerIdentity *peer)
888 struct GAS_Addresses_Suggestion_Requests *cur = handle->r_head;
889 struct ATS_Address *aa;
890 struct GNUNET_ATS_Information *ats;
891 unsigned int ats_count;
893 if (GNUNET_NO == handle->running)
897 if (0 == memcmp (peer, &cur->id, sizeof (cur->id)))
898 break; /* already suggesting */
903 cur = GNUNET_malloc (sizeof (struct GAS_Addresses_Suggestion_Requests));
905 GNUNET_CONTAINER_DLL_insert (handle->r_head, handle->r_tail, cur);
908 aa = handle->s_get (handle->solver, handle->addresses, peer);
910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
911 "Cannot suggest address for peer `%s'\n", GNUNET_i2s (peer));
913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
914 "Suggesting address %p for peer `%s'\n", aa, GNUNET_i2s (peer));
916 ats_count = assemble_ats_information (aa, &ats);
917 GAS_scheduling_transmit_address_suggestion (peer,
919 aa->addr, aa->addr_len,
930 reset_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
932 struct ATS_Address *aa = value;
934 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
935 "Resetting interval for peer `%s' address %p from %llu to 0\n",
936 GNUNET_i2s (&aa->peer), aa, aa->block_interval);
938 aa->blocked_until = GNUNET_TIME_UNIT_ZERO_ABS;
939 aa->block_interval = GNUNET_TIME_UNIT_ZERO;
945 GAS_addresses_handle_backoff_reset (const struct GNUNET_PeerIdentity *peer)
947 GNUNET_break (GNUNET_SYSERR != GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses,
955 GAS_addresses_change_preference (const struct GNUNET_PeerIdentity *peer,
956 enum GNUNET_ATS_PreferenceKind kind,
959 if (GNUNET_NO == handle->running)
962 /* Tell solver about update */
963 handle->s_pref (handle->solver, peer, kind, score);
967 load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned long long *out_dest, unsigned long long *in_dest, int dest_length)
969 int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
970 char * entry_in = NULL;
971 char * entry_out = NULL;
972 char * quota_out_str;
976 for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
981 case GNUNET_ATS_NET_UNSPECIFIED:
982 entry_out = "UNSPECIFIED_QUOTA_OUT";
983 entry_in = "UNSPECIFIED_QUOTA_IN";
985 case GNUNET_ATS_NET_LOOPBACK:
986 entry_out = "LOOPBACK_QUOTA_OUT";
987 entry_in = "LOOPBACK_QUOTA_IN";
989 case GNUNET_ATS_NET_LAN:
990 entry_out = "LAN_QUOTA_OUT";
991 entry_in = "LAN_QUOTA_IN";
993 case GNUNET_ATS_NET_WAN:
994 entry_out = "WAN_QUOTA_OUT";
995 entry_in = "WAN_QUOTA_IN";
997 case GNUNET_ATS_NET_WLAN:
998 entry_out = "WLAN_QUOTA_OUT";
999 entry_in = "WLAN_QUOTA_IN";
1005 if ((entry_in == NULL) || (entry_out == NULL))
1009 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, "a_out_str))
1011 if (0 == strcmp(quota_out_str, BIG_M_STRING) ||
1012 (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &out_dest[c])))
1013 out_dest[c] = UINT32_MAX;
1015 GNUNET_free (quota_out_str);
1016 quota_out_str = NULL;
1018 else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
1019 out_dest[c] = UINT32_MAX;
1021 out_dest[c] = UINT32_MAX;
1024 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, "a_in_str))
1026 if (0 == strcmp(quota_in_str, BIG_M_STRING) ||
1027 (GNUNET_SYSERR == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
1028 in_dest[c] = UINT32_MAX;
1030 GNUNET_free (quota_in_str);
1031 quota_in_str = NULL;
1033 else if (GNUNET_ATS_NET_UNSPECIFIED == quotas[c])
1035 in_dest[c] = UINT32_MAX;
1039 in_dest[c] = UINT32_MAX;
1041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded quota: %s %u, %s %u\n", entry_in, in_dest[c], entry_out, out_dest[c]);
1044 return GNUNET_ATS_NetworkTypeCount;
1050 * Initialize address subsystem.
1052 * @param cfg configuration to use
1053 * @param stats the statistics handle to use
1055 struct GAS_Addresses_Handle *
1056 GAS_addresses_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
1057 const struct GNUNET_STATISTICS_Handle *stats)
1059 struct GAS_Addresses_Handle *ah;
1060 int quotas[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
1061 unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
1062 unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
1067 ah = GNUNET_malloc (sizeof (struct GAS_Addresses_Handle));
1069 handle->running = GNUNET_NO;
1071 /* Initialize the addresses database */
1072 ah->addresses = GNUNET_CONTAINER_multihashmap_create (128, GNUNET_NO);
1073 GNUNET_assert (NULL != ah->addresses);
1075 /* Figure out configured solution method */
1076 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "ats", "MODE", &mode_str))
1078 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No ressource assignment method configured, using simplistic approch\n");
1079 ah->ats_mode = MODE_SIMPLISTIC;
1083 for (c = 0; c < strlen (mode_str); c++)
1084 mode_str[c] = toupper (mode_str[c]);
1085 if (0 == strcmp (mode_str, "SIMPLISTIC"))
1087 ah->ats_mode = MODE_SIMPLISTIC;
1089 else if (0 == strcmp (mode_str, "MLP"))
1091 ah->ats_mode = MODE_MLP;
1093 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Assignment method `%s' configured, but GLPK is not availabe, please install \n", mode_str);
1094 ah->ats_mode = MODE_SIMPLISTIC;
1099 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid ressource assignment method `%s' configured, using simplistic approch\n", mode_str);
1100 ah->ats_mode = MODE_SIMPLISTIC;
1102 GNUNET_free (mode_str);
1104 /* Start configured solution method */
1105 switch (ah->ats_mode)
1108 /* Init the MLP solver with default values */
1110 ah->ats_mode = MODE_MLP;
1111 ah->s_init = &GAS_mlp_init;
1112 ah->s_update = &GAS_mlp_address_update;
1113 ah->s_get = &GAS_mlp_get_preferred_address;
1114 ah->s_pref = &GAS_mlp_address_change_preference;
1115 ah->s_del = &GAS_mlp_address_delete;
1116 ah->s_done = &GAS_mlp_done;
1122 case MODE_SIMPLISTIC:
1123 /* Init the simplistic solver with default values */
1124 ah->ats_mode = MODE_SIMPLISTIC;
1125 ah->s_init = &GAS_simplistic_init;
1126 ah->s_update = &GAS_simplistic_address_update;
1127 ah->s_get = &GAS_simplistic_get_preferred_address;
1128 ah->s_pref = &GAS_simplistic_address_change_preference;
1129 ah->s_del = &GAS_simplistic_address_delete;
1130 ah->s_done = &GAS_simplistic_done;
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS started in %s mode\n", "SIMPLISTIC");
1138 GNUNET_assert (NULL != ah->s_init);
1139 GNUNET_assert (NULL != ah->s_update);
1140 GNUNET_assert (NULL != ah->s_get);
1141 GNUNET_assert (NULL != ah->s_pref);
1142 GNUNET_assert (NULL != ah->s_del);
1143 GNUNET_assert (NULL != ah->s_done);
1145 quota_count = load_quotas(cfg, quotas_in, quotas_out, GNUNET_ATS_NetworkTypeCount);
1147 ah->solver = ah->s_init (cfg, stats, quotas, quotas_in, quotas_out, quota_count);
1148 if (NULL == ah->solver)
1150 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to initialize solver!\n");
1155 /* up and running */
1156 ah->running = GNUNET_YES;
1162 * Free memory of address.
1165 * @param key peer identity (unused)
1166 * @param value the 'struct ATS_Address' to free
1167 * @return GNUNET_OK (continue to iterate)
1170 free_address_it (void *cls, const struct GNUNET_HashCode * key, void *value)
1172 struct ATS_Address *aa = value;
1174 destroy_address (aa);
1180 GAS_addresses_destroy_all ()
1182 if (GNUNET_NO == handle->running)
1185 if (handle->addresses != NULL)
1186 GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &free_address_it, NULL);
1187 GNUNET_assert (handle->active_addr_count == 0);
1192 * Shutdown address subsystem.
1195 GAS_addresses_done (struct GAS_Addresses_Handle *handle)
1197 struct GAS_Addresses_Suggestion_Requests *cur;
1199 GNUNET_assert (NULL != handle);
1200 GAS_addresses_destroy_all ();
1201 handle->running = GNUNET_NO;
1202 GNUNET_CONTAINER_multihashmap_destroy (handle->addresses);
1203 handle->addresses = NULL;
1204 while (NULL != (cur = handle->r_head))
1206 GNUNET_CONTAINER_DLL_remove (handle->r_head, handle->r_tail, cur);
1210 GNUNET_free (handle);
1211 /* Stop configured solution method */
1215 struct PeerIteratorContext
1217 GNUNET_ATS_Peer_Iterator it;
1219 struct GNUNET_CONTAINER_MultiHashMap *peers_returned;
1224 const struct GNUNET_HashCode * key,
1227 struct PeerIteratorContext *ip_ctx = cls;
1228 struct GNUNET_PeerIdentity tmp;
1230 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(ip_ctx->peers_returned, key))
1232 GNUNET_CONTAINER_multihashmap_put(ip_ctx->peers_returned, key, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1233 tmp.hashPubKey = (*key);
1234 ip_ctx->it (ip_ctx->it_cls, &tmp);
1241 * Return all peers currently known to ATS
1243 * @param p_it the iterator to call for every peer, callbach with id == NULL
1245 * @param p_it_cls the closure for the iterator
1248 GAS_addresses_iterate_peers (GNUNET_ATS_Peer_Iterator p_it, void *p_it_cls)
1250 struct PeerIteratorContext ip_ctx;
1255 GNUNET_assert (NULL != handle->addresses);
1257 size = GNUNET_CONTAINER_multihashmap_size(handle->addresses);
1261 ip_ctx.it_cls = p_it_cls;
1262 ip_ctx.peers_returned = GNUNET_CONTAINER_multihashmap_create (size, GNUNET_NO);
1263 GNUNET_CONTAINER_multihashmap_iterate (handle->addresses, &peer_it, &ip_ctx);
1264 GNUNET_CONTAINER_multihashmap_destroy (ip_ctx.peers_returned);
1266 p_it (p_it_cls, NULL);
1269 struct PeerInfoIteratorContext
1271 GNUNET_ATS_PeerInfo_Iterator it;
1277 peerinfo_it (void *cls,
1278 const struct GNUNET_HashCode * key,
1281 struct PeerInfoIteratorContext *pi_ctx = cls;
1282 struct ATS_Address *addr = (struct ATS_Address *) value;
1283 struct GNUNET_ATS_Information *ats;
1286 if (NULL != pi_ctx->it)
1288 ats_count = assemble_ats_information (addr, &ats);
1290 pi_ctx->it (pi_ctx->it_cls,
1293 addr->addr, addr->addr_len,
1296 addr->assigned_bw_out,
1297 addr->assigned_bw_in);
1305 * Return all peers currently known to ATS
1307 * @param peer the respective peer
1308 * @param pi_it the iterator to call for every peer
1309 * @param pi_it_cls the closure for the iterator
1312 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_PeerInfo_Iterator pi_it, void *pi_it_cls)
1314 struct PeerInfoIteratorContext pi_ctx;
1315 struct GNUNET_BANDWIDTH_Value32NBO zero_bw;
1316 GNUNET_assert (NULL != peer);
1317 GNUNET_assert (NULL != handle->addresses);
1319 return; /* does not make sense without callback */
1321 zero_bw = GNUNET_BANDWIDTH_value_init (0);
1323 pi_ctx.it_cls = pi_it_cls;
1325 GNUNET_CONTAINER_multihashmap_get_multiple (handle->addresses, &peer->hashPubKey, &peerinfo_it, &pi_ctx);
1328 pi_it (pi_it_cls, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0, zero_bw, zero_bw);
1333 /* end of gnunet-service-ats_addresses.c */