2 This file is part of GNUnet.
3 (C) 2010,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.
21 * @file ats/ats_api_scheduling.c
22 * @brief automatic transport selection and outbound bandwidth determination
23 * @author Christian Grothoff
24 * @author Matthias Wachs
27 #include "gnunet_ats_service.h"
31 #define INTERFACE_PROCESSING_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
34 * Message in linked list we should send to the ATS service. The
35 * actual binary message follows this struct.
43 struct PendingMessage *next;
48 struct PendingMessage *prev;
51 * Size of the message.
56 * Is this the 'ATS_START' message?
63 * Information we track per session.
68 * Identity of the peer (just needed for error checking).
70 struct GNUNET_PeerIdentity peer;
75 struct Session *session;
78 * Set to GNUNET_YES if the slot is used.
86 struct ATS_Network * next;
88 struct ATS_Network * prev;
90 struct sockaddr *network;
91 struct sockaddr *netmask;
98 * Handle to the ATS subsystem for bandwidth/transport scheduling information.
100 struct GNUNET_ATS_SchedulingHandle
106 const struct GNUNET_CONFIGURATION_Handle *cfg;
109 * Callback to invoke on suggestions.
111 GNUNET_ATS_AddressSuggestionCallback suggest_cb;
114 * Closure for 'suggest_cb'.
116 void *suggest_cb_cls;
119 * Connection to ATS service.
121 struct GNUNET_CLIENT_Connection *client;
124 * Head of list of messages for the ATS service.
126 struct PendingMessage *pending_head;
129 * Tail of list of messages for the ATS service
131 struct PendingMessage *pending_tail;
134 * Current request for transmission to ATS.
136 struct GNUNET_CLIENT_TransmitHandle *th;
139 * Head of network list
141 struct ATS_Network * net_head;
144 * Tail of network list
146 struct ATS_Network * net_tail;
150 * Array of session objects (we need to translate them to numbers and back
151 * for the protocol; the offset in the array is the session number on the
152 * network). Index 0 is always NULL and reserved to represent the NULL pointer.
153 * Unused entries are also NULL.
155 struct SessionRecord *session_array;
158 * Task to trigger reconnect.
160 GNUNET_SCHEDULER_TaskIdentifier task;
163 * Task retrieving interfaces from the system
166 GNUNET_SCHEDULER_TaskIdentifier interface_task;
170 * Size of the session array.
172 unsigned int session_array_size;
175 * Should we reconnect to ATS due to some serious error?
182 * Re-establish the connection to the ATS service.
184 * @param sh handle to use to re-connect.
187 reconnect (struct GNUNET_ATS_SchedulingHandle *sh);
191 * Re-establish the connection to the ATS service.
193 * @param cls handle to use to re-connect.
194 * @param tc scheduler context
197 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
199 struct GNUNET_ATS_SchedulingHandle *sh = cls;
201 sh->task = GNUNET_SCHEDULER_NO_TASK;
207 * Disconnect from ATS and then reconnect.
209 * @param sh our handle
212 force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
214 sh->reconnect = GNUNET_NO;
215 GNUNET_CLIENT_disconnect (sh->client);
218 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
224 * Transmit messages from the message queue to the service
225 * (if there are any, and if we are not already trying).
227 * @param sh handle to use
230 do_transmit (struct GNUNET_ATS_SchedulingHandle *sh);
234 * Type of a function to call when we receive a message
237 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
238 * @param msg message received, NULL on timeout or fatal error
241 process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg);
245 * We can now transmit a message to ATS. Do it.
247 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
248 * @param size number of bytes we can transmit to ATS
249 * @param buf where to copy the messages
250 * @return number of bytes copied into buf
253 transmit_message_to_ats (void *cls, size_t size, void *buf)
255 struct GNUNET_ATS_SchedulingHandle *sh = cls;
256 struct PendingMessage *p;
261 if ((size == 0) || (buf == NULL))
263 force_reconnect (sh);
268 while ((NULL != (p = sh->pending_head)) && (p->size <= size))
270 memcpy (&cbuf[ret], &p[1], p->size);
273 GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
274 if (GNUNET_YES == p->is_init)
275 GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
276 GNUNET_TIME_UNIT_FOREVER_REL);
285 * Transmit messages from the message queue to the service
286 * (if there are any, and if we are not already trying).
288 * @param sh handle to use
291 do_transmit (struct GNUNET_ATS_SchedulingHandle *sh)
293 struct PendingMessage *p;
297 if (NULL == (p = sh->pending_head))
299 if (NULL == sh->client)
300 return; /* currently reconnecting */
302 GNUNET_CLIENT_notify_transmit_ready (sh->client, p->size,
303 GNUNET_TIME_UNIT_FOREVER_REL,
304 GNUNET_NO, &transmit_message_to_ats,
310 * Find the session object corresponding to the given session ID.
312 * @param sh our handle
313 * @param session_id current session ID
314 * @param peer peer the session belongs to
315 * @return the session object (or NULL)
317 static struct Session *
318 find_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
319 const struct GNUNET_PeerIdentity *peer)
322 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
323 "Find session %u from peer %s in %p\n",
324 (unsigned int) session_id, GNUNET_i2s (peer), sh);
326 if (session_id >= sh->session_array_size)
333 if (sh->session_array[session_id].session == NULL)
336 memcmp (peer, &sh->session_array[session_id].peer,
337 sizeof (struct GNUNET_PeerIdentity)));
342 memcmp (peer, &sh->session_array[session_id].peer,
343 sizeof (struct GNUNET_PeerIdentity)))
346 sh->reconnect = GNUNET_YES;
349 return sh->session_array[session_id].session;
354 * Get the ID for the given session object. If we do not have an ID for
355 * the given session object, allocate one.
357 * @param sh our handle
358 * @param session session object
359 * @param peer peer the session belongs to
360 * @return the session id
363 get_session_id (struct GNUNET_ATS_SchedulingHandle *sh, struct Session *session,
364 const struct GNUNET_PeerIdentity *peer)
370 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
371 "Get session ID for session %p from peer %s in %p\n", session,
372 GNUNET_i2s (peer), sh);
377 for (i = 1; i < sh->session_array_size; i++)
379 if (session == sh->session_array[i].session)
382 memcmp (peer, &sh->session_array[i].peer,
383 sizeof (struct GNUNET_PeerIdentity)));
386 if ((f == 0) && (sh->session_array[i].slot_used == GNUNET_NO))
391 f = sh->session_array_size;
392 GNUNET_array_grow (sh->session_array, sh->session_array_size,
393 sh->session_array_size * 2);
395 GNUNET_assert (f > 0);
396 sh->session_array[f].session = session;
397 sh->session_array[f].peer = *peer;
398 sh->session_array[f].slot_used = GNUNET_YES;
400 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
401 "Assigning session ID %u for session %p of peer %s in %p\n", f,
402 session, GNUNET_i2s (peer), sh);
409 * Remove the session of the given session ID from the session
410 * table (it is no longer valid).
412 * @param sh our handle
413 * @param session_id identifies session that is no longer valid
414 * @param peer peer the session belongs to
417 remove_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
418 const struct GNUNET_PeerIdentity *peer)
420 GNUNET_assert (peer != NULL);
421 GNUNET_assert (sh != NULL);
423 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
424 "Release sessionID %u from peer %s in %p\n",
425 (unsigned int) session_id, GNUNET_i2s (peer), sh);
429 GNUNET_assert (session_id < sh->session_array_size);
430 GNUNET_assert (GNUNET_YES == sh->session_array[session_id].slot_used);
432 memcmp (peer, &sh->session_array[session_id].peer,
433 sizeof (struct GNUNET_PeerIdentity)));
434 sh->session_array[session_id].session = NULL;
439 * Release the session slot from the session table (ATS service is
440 * also done using it).
442 * @param sh our handle
443 * @param session_id identifies session that is no longer valid
444 * @param peer peer the session belongs to
447 release_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
448 const struct GNUNET_PeerIdentity *peer)
451 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
452 "Release sessionID %u from peer %s in %p\n",
453 (unsigned int) session_id, GNUNET_i2s (peer), sh);
455 if (session_id >= sh->session_array_size)
458 sh->reconnect = GNUNET_YES;
462 /* this slot should have been removed from remove_session before */
463 GNUNET_assert (sh->session_array[session_id].session == NULL);
466 memcmp (peer, &sh->session_array[session_id].peer,
467 sizeof (struct GNUNET_PeerIdentity)))
470 sh->reconnect = GNUNET_YES;
473 sh->session_array[session_id].slot_used = GNUNET_NO;
474 memset (&sh->session_array[session_id].peer, 0,
475 sizeof (struct GNUNET_PeerIdentity));
480 process_release_message (struct GNUNET_ATS_SchedulingHandle *sh,
481 const struct SessionReleaseMessage *srm)
483 release_session (sh, ntohl (srm->session_id), &srm->peer);
488 * Type of a function to call when we receive a message
491 * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
492 * @param msg message received, NULL on timeout or fatal error
495 process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg)
497 struct GNUNET_ATS_SchedulingHandle *sh = cls;
498 const struct AddressSuggestionMessage *m;
499 const struct GNUNET_ATS_Information *atsi;
500 const char *plugin_address;
501 const char *plugin_name;
502 uint16_t plugin_address_length;
503 uint16_t plugin_name_length;
505 struct GNUNET_HELLO_Address address;
510 force_reconnect (sh);
513 if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE) &&
514 (ntohs (msg->size) == sizeof (struct SessionReleaseMessage)))
516 process_release_message (sh, (const struct SessionReleaseMessage *) msg);
517 GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
518 GNUNET_TIME_UNIT_FOREVER_REL);
519 if (GNUNET_YES == sh->reconnect)
520 force_reconnect (sh);
523 if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION) ||
524 (ntohs (msg->size) <= sizeof (struct AddressSuggestionMessage)))
527 force_reconnect (sh);
530 m = (const struct AddressSuggestionMessage *) msg;
531 ats_count = ntohl (m->ats_count);
532 plugin_address_length = ntohs (m->address_length);
533 atsi = (const struct GNUNET_ATS_Information *) &m[1];
534 plugin_address = (const char *) &atsi[ats_count];
535 plugin_name = &plugin_address[plugin_address_length];
536 plugin_name_length = ntohs (m->plugin_name_length);
537 if ((plugin_address_length + plugin_name_length +
538 ats_count * sizeof (struct GNUNET_ATS_Information) +
539 sizeof (struct AddressSuggestionMessage) != ntohs (msg->size)) ||
541 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
542 || (plugin_name[plugin_name_length - 1] != '\0'))
545 force_reconnect (sh);
548 uint32_t session_id = ntohl (m->session_id);
554 s = find_session (sh, session_id, &m->peer);
558 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
559 "ATS tries to use outdated session `%s'\n",
560 GNUNET_i2s (&m->peer));
561 GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
562 GNUNET_TIME_UNIT_FOREVER_REL);
566 address.peer = m->peer;
567 address.address = plugin_address;
568 address.address_length = plugin_address_length;
569 address.transport_name = plugin_name;
571 if ((s == NULL) && (0 == address.address_length))
573 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
574 "ATS returned invalid address for peer `%s' transport `%s' address length %i, session_id %i\n",
575 GNUNET_i2s (&address.peer), address.transport_name,
576 plugin_address_length, session_id);
578 GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
579 GNUNET_TIME_UNIT_FOREVER_REL);
583 sh->suggest_cb (sh->suggest_cb_cls, &address, s, m->bandwidth_out,
584 m->bandwidth_in, atsi, ats_count);
586 GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
587 GNUNET_TIME_UNIT_FOREVER_REL);
588 if (GNUNET_YES == sh->reconnect)
589 force_reconnect (sh);
594 * Re-establish the connection to the ATS service.
596 * @param sh handle to use to re-connect.
599 reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
601 struct PendingMessage *p;
602 struct ClientStartMessage *init;
604 GNUNET_assert (NULL == sh->client);
605 sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg);
606 GNUNET_assert (NULL != sh->client);
607 if ((NULL == (p = sh->pending_head)) || (GNUNET_YES != p->is_init))
609 p = GNUNET_malloc (sizeof (struct PendingMessage) +
610 sizeof (struct ClientStartMessage));
611 p->size = sizeof (struct ClientStartMessage);
612 p->is_init = GNUNET_YES;
613 init = (struct ClientStartMessage *) &p[1];
614 init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
615 init->header.size = htons (sizeof (struct ClientStartMessage));
616 init->start_flag = htonl (START_FLAG_SCHEDULING);
617 GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, p);
623 * delete the current network list
627 delete_networks (struct GNUNET_ATS_SchedulingHandle *sh)
629 struct ATS_Network * cur = sh->net_head;
632 GNUNET_CONTAINER_DLL_remove(sh->net_head, sh->net_tail, cur);
640 interface_proc (void *cls, const char *name,
642 const struct sockaddr *
644 const struct sockaddr *
646 const struct sockaddr *
647 netmask, socklen_t addrlen)
649 struct GNUNET_ATS_SchedulingHandle * sh = cls;
650 /* Calculate network */
651 struct ATS_Network *net = NULL;
653 /* Skipping IPv4 loopback addresses since we have special check */
654 if (addr->sa_family == AF_INET)
656 struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
658 if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
661 /* Skipping IPv6 loopback addresses since we have special check */
662 if (addr->sa_family == AF_INET6)
664 struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
665 if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
669 if (addr->sa_family == AF_INET)
671 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
672 struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask;
673 struct sockaddr_in *tmp = NULL;
674 struct sockaddr_in network4;
676 net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in));
677 tmp = (struct sockaddr_in *) &net[1];
678 net->network = (struct sockaddr *) &tmp[0];
679 net->netmask = (struct sockaddr *) &tmp[1];
680 net->length = addrlen;
682 memset (&network4, 0, sizeof (network4));
683 network4.sin_family = AF_INET;
684 #if HAVE_SOCKADDR_IN_SIN_LEN
685 network4.sin_len = sizeof (network4);
687 network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr);
689 memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in));
690 memcpy (net->network, &network4, sizeof (struct sockaddr_in));
693 if (addr->sa_family == AF_INET6)
695 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
696 struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask;
697 struct sockaddr_in6 * tmp = NULL;
698 struct sockaddr_in6 network6;
700 net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6));
701 tmp = (struct sockaddr_in6 *) &net[1];
702 net->network = (struct sockaddr *) &tmp[0];
703 net->netmask = (struct sockaddr *) &tmp[1];
704 net->length = addrlen;
706 memset (&network6, 0, sizeof (network6));
707 network6.sin6_family = AF_INET6;
708 #if HAVE_SOCKADDR_IN_SIN_LEN
709 network6.sin6_len = sizeof (network6);
712 uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr;
713 uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr;
714 uint32_t *net_elem = (uint32_t *) &network6.sin6_addr;
715 for (c = 0; c < 4; c++)
716 net_elem[c] = addr_elem[c] & mask_elem[c];
718 memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6));
719 memcpy (net->network, &network6, sizeof (struct sockaddr_in6));
726 char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n",
728 GNUNET_a2s((struct sockaddr *) net->network, addrlen),
730 GNUNET_free (netmask);
732 GNUNET_CONTAINER_DLL_insert(sh->net_head, sh->net_tail, net);
740 * Periodically get list of addresses
742 * @param tc Task context
745 get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
747 struct GNUNET_ATS_SchedulingHandle * sh = cls;
748 sh->interface_task = GNUNET_SCHEDULER_NO_TASK;
749 delete_networks (sh);
750 GNUNET_OS_network_interfaces_list(interface_proc, sh);
751 sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL,
757 * Returns where the address is located: LAN or WAN or ...
758 * @param sh the scheduling handle
759 * @param addr address
760 * @param addrlen address length
761 * @return location as GNUNET_ATS_Information
764 struct GNUNET_ATS_Information
765 GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle * sh, const struct sockaddr * addr, socklen_t addrlen)
767 GNUNET_assert (sh != NULL);
768 struct GNUNET_ATS_Information ats;
769 struct ATS_Network * cur = sh->net_head;
770 int type = GNUNET_ATS_NET_UNSPECIFIED;
772 if (addr->sa_family == AF_UNIX)
774 type = GNUNET_ATS_NET_LOOPBACK;
777 /* IPv4 loopback check */
778 if (addr->sa_family == AF_INET)
780 struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
782 if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
783 type = GNUNET_ATS_NET_LOOPBACK;
785 /* IPv6 loopback check */
786 if (addr->sa_family == AF_INET6)
788 struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
789 if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
790 type = GNUNET_ATS_NET_LOOPBACK;
793 /* Check local networks */
794 while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED))
796 if (addrlen != cur->length)
802 if (addr->sa_family == AF_INET)
804 struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
805 struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network;
806 struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask;
808 if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr)
810 char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen));
811 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
812 "`%s' is in network `%s'\n",
813 GNUNET_a2s ((const struct sockaddr *)a4, addrlen),
816 type = GNUNET_ATS_NET_LAN;
819 if (addr->sa_family == AF_INET6)
821 struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
822 struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network;
823 struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask;
825 int res = GNUNET_YES;
827 uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr;
828 uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr;
829 uint32_t *net_elem = (uint32_t *) &net6->sin6_addr;
830 for (c = 0; c < 4; c++)
831 if ((addr_elem[c] & mask_elem[c]) != net_elem[c])
834 if (res == GNUNET_YES)
836 char * net = GNUNET_strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen));
837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n",
838 GNUNET_a2s ((const struct sockaddr *) a6, addrlen),
841 type = GNUNET_ATS_NET_LAN;
847 /* no local network found for this address, default: WAN */
848 if (type == GNUNET_ATS_NET_UNSPECIFIED)
849 type = GNUNET_ATS_NET_WAN;
850 ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
851 ats.value = htonl (type);
852 return (const struct GNUNET_ATS_Information) ats;
856 * Initialize the ATS subsystem.
858 * @param cfg configuration to use
859 * @param suggest_cb notification to call whenever the suggestation changed
860 * @param suggest_cb_cls closure for 'suggest_cb'
861 * @return ats context
863 struct GNUNET_ATS_SchedulingHandle *
864 GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
865 GNUNET_ATS_AddressSuggestionCallback suggest_cb,
866 void *suggest_cb_cls)
868 struct GNUNET_ATS_SchedulingHandle *sh;
870 sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SchedulingHandle));
872 sh->suggest_cb = suggest_cb;
873 sh->suggest_cb_cls = suggest_cb_cls;
874 GNUNET_array_grow (sh->session_array, sh->session_array_size, 4);
875 GNUNET_OS_network_interfaces_list(interface_proc, sh);
876 sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL,
885 * Client is done with ATS scheduling, release resources.
887 * @param sh handle to release
890 GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
892 struct PendingMessage *p;
894 while (NULL != (p = sh->pending_head))
896 GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
899 if (NULL != sh->client)
901 GNUNET_CLIENT_disconnect (sh->client);
904 if (GNUNET_SCHEDULER_NO_TASK != sh->task)
906 GNUNET_SCHEDULER_cancel (sh->task);
907 sh->task = GNUNET_SCHEDULER_NO_TASK;
910 delete_networks (sh);
911 if (sh->interface_task != GNUNET_SCHEDULER_NO_TASK)
913 GNUNET_SCHEDULER_cancel(sh->interface_task);
914 sh->interface_task = GNUNET_SCHEDULER_NO_TASK;
916 GNUNET_array_grow (sh->session_array, sh->session_array_size, 0);
922 * We would like to reset the address suggestion block time for this
926 * @param peer identity of the peer we want to reset
929 GNUNET_ATS_reset_backoff (struct GNUNET_ATS_SchedulingHandle *sh,
930 const struct GNUNET_PeerIdentity *peer)
932 struct PendingMessage *p;
933 struct ResetBackoffMessage *m;
935 p = GNUNET_malloc (sizeof (struct PendingMessage) +
936 sizeof (struct ResetBackoffMessage));
937 p->size = sizeof (struct ResetBackoffMessage);
938 p->is_init = GNUNET_NO;
939 m = (struct ResetBackoffMessage *) &p[1];
940 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF);
941 m->header.size = htons (sizeof (struct ResetBackoffMessage));
942 m->reserved = htonl (0);
944 GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
949 * We would like to establish a new connection with a peer. ATS
950 * should suggest a good address to begin with.
953 * @param peer identity of the peer we need an address for
956 GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh,
957 const struct GNUNET_PeerIdentity *peer)
959 struct PendingMessage *p;
960 struct RequestAddressMessage *m;
962 p = GNUNET_malloc (sizeof (struct PendingMessage) +
963 sizeof (struct RequestAddressMessage));
964 p->size = sizeof (struct RequestAddressMessage);
965 p->is_init = GNUNET_NO;
966 m = (struct RequestAddressMessage *) &p[1];
967 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
968 m->header.size = htons (sizeof (struct RequestAddressMessage));
969 m->reserved = htonl (0);
971 GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
977 * We would like to stop receiving address updates for this peer
980 * @param peer identity of the peer
983 GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh,
984 const struct GNUNET_PeerIdentity *peer)
986 struct PendingMessage *p;
987 struct RequestAddressMessage *m;
989 p = GNUNET_malloc (sizeof (struct PendingMessage) +
990 sizeof (struct RequestAddressMessage));
991 p->size = sizeof (struct RequestAddressMessage);
992 p->is_init = GNUNET_NO;
993 m = (struct RequestAddressMessage *) &p[1];
994 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
995 m->header.size = htons (sizeof (struct RequestAddressMessage));
996 m->reserved = htonl (0);
998 GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1003 * We have updated performance statistics for a given address. Note
1004 * that this function can be called for addresses that are currently
1005 * in use as well as addresses that are valid but not actively in use.
1006 * Furthermore, the peer may not even be connected to us right now (in
1007 * which case the call may be ignored or the information may be stored
1008 * for later use). Update bandwidth assignments.
1011 * @param address the address
1012 * @param session session handle (if available)
1013 * @param ats performance data for the address
1014 * @param ats_count number of performance records in 'ats'
1017 GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh,
1018 const struct GNUNET_HELLO_Address *address,
1019 struct Session *session,
1020 const struct GNUNET_ATS_Information *ats,
1023 struct PendingMessage *p;
1024 struct AddressUpdateMessage *m;
1025 struct GNUNET_ATS_Information *am;
1030 if (address == NULL)
1035 if ((address == NULL) && (session == NULL))
1042 (address->transport_name ==
1043 NULL) ? 0 : strlen (address->transport_name) + 1;
1045 sizeof (struct AddressUpdateMessage) + address->address_length +
1046 ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
1047 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1048 (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1049 (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1051 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
1057 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1059 p->is_init = GNUNET_NO;
1060 m = (struct AddressUpdateMessage *) &p[1];
1061 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
1062 m->header.size = htons (msize);
1063 m->ats_count = htonl (ats_count);
1064 m->peer = address->peer;
1065 m->address_length = htons (address->address_length);
1066 m->plugin_name_length = htons (namelen);
1067 m->session_id = htonl (get_session_id (sh, session, &address->peer));
1068 am = (struct GNUNET_ATS_Information *) &m[1];
1069 memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
1070 pm = (char *) &am[ats_count];
1071 memcpy (pm, address->address, address->address_length);
1072 memcpy (&pm[address->address_length], address->transport_name, namelen);
1073 GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1079 * An address is now in use or not used any more.
1082 * @param address the address
1083 * @param session session handle
1084 * @param in_use GNUNET_YES if this address is now used, GNUNET_NO
1085 * if address is not used any more
1088 GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh,
1089 const struct GNUNET_HELLO_Address *address,
1090 struct Session *session, int in_use)
1092 struct PendingMessage *p;
1093 struct AddressUseMessage *m;
1098 GNUNET_assert (NULL != address);
1100 (address->transport_name ==
1101 NULL) ? 0 : strlen (address->transport_name) + 1;
1102 msize = sizeof (struct AddressUseMessage) + address->address_length + namelen;
1103 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1104 (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1105 (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
1111 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1113 p->is_init = GNUNET_NO;
1114 m = (struct AddressUseMessage *) &p[1];
1115 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE);
1116 m->header.size = htons (msize);
1117 m->peer = address->peer;
1118 m->in_use = htons (in_use);
1119 m->address_length = htons (address->address_length);
1120 m->plugin_name_length = htons (namelen);
1121 m->session_id = htonl (get_session_id (sh, session, &address->peer));
1122 pm = (char *) &m[1];
1123 memcpy (pm, address->address, address->address_length);
1124 memcpy (&pm[address->address_length], address->transport_name, namelen);
1125 GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1131 * A session got destroyed, stop including it as a valid address.
1134 * @param address the address
1135 * @param session session handle that is no longer valid
1138 GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh,
1139 const struct GNUNET_HELLO_Address *address,
1140 struct Session *session)
1142 struct PendingMessage *p;
1143 struct AddressDestroyedMessage *m;
1147 uint32_t session_id;
1149 GNUNET_assert (address->transport_name != NULL);
1150 namelen = strlen (address->transport_name) + 1;
1151 GNUNET_assert (namelen > 1);
1153 sizeof (struct AddressDestroyedMessage) + address->address_length +
1155 if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1156 (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1157 (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
1163 p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1165 p->is_init = GNUNET_NO;
1166 m = (struct AddressDestroyedMessage *) &p[1];
1167 m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
1168 m->header.size = htons (msize);
1169 m->reserved = htonl (0);
1170 m->peer = address->peer;
1171 m->address_length = htons (address->address_length);
1172 m->plugin_name_length = htons (namelen);
1173 session_id = get_session_id (sh, session, &address->peer);
1174 m->session_id = htonl (session_id);
1175 pm = (char *) &m[1];
1176 memcpy (pm, address->address, address->address_length);
1177 memcpy (&pm[address->address_length], address->transport_name, namelen);
1178 GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1180 remove_session (sh, session_id, &address->peer);
1183 /* end of ats_api_scheduling.c */