08155eaeff1be09bd32d5ca7cd3a6b50dbc80a4b
[oweals/gnunet.git] / src / ats / ats_api_scheduling.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010-2015 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20 /**
21  * @file ats/ats_api_scheduling.c
22  * @brief automatic transport selection and outbound bandwidth determination
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_ats_service.h"
28 #include "ats.h"
29
30 /**
31  * How frequently do we scan the interfaces for changes to the addresses?
32  */
33 #define INTERFACE_PROCESSING_INTERVAL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
34
35
36 /**
37  * Session ID we use if there is no session / slot.
38  */
39 #define NOT_FOUND 0
40
41
42 /**
43  * Information we track per session.
44  */
45 struct SessionRecord
46 {
47   /**
48    * Identity of the peer (just needed for error checking).
49    */
50   struct GNUNET_PeerIdentity peer;
51
52   /**
53    * Session handle.
54    */
55   struct Session *session;
56
57   /**
58    * Set to #GNUNET_YES if the slot is used.
59    */
60   int slot_used;
61 };
62
63
64 /**
65  * We keep a list of our local networks so we can answer
66  * LAN vs. WAN questions.  Note: WLAN is not detected yet.
67  * (maybe we can do that heuristically based on interface
68  * name in the future?)
69  */
70 struct ATS_Network
71 {
72   /**
73    * Kept in a DLL.
74    */
75   struct ATS_Network *next;
76
77   /**
78    * Kept in a DLL.
79    */
80   struct ATS_Network *prev;
81
82   /**
83    * Network address.
84    */
85   struct sockaddr *network;
86
87   /**
88    * Netmask to determine what is in the LAN.
89    */
90   struct sockaddr *netmask;
91
92   /**
93    * How long are @e network and @e netmask?
94    */
95   socklen_t length;
96 };
97
98
99 /**
100  * Handle for ATS address suggestion requests.
101  */
102 struct GNUNET_ATS_SuggestHandle
103 {
104   /**
105    * ID of the peer for which address suggestion was requested.
106    */
107   struct GNUNET_PeerIdentity id;
108 };
109
110
111 /**
112  * Handle to the ATS subsystem for bandwidth/transport scheduling information.
113  */
114 struct GNUNET_ATS_SchedulingHandle
115 {
116
117   /**
118    * Our configuration.
119    */
120   const struct GNUNET_CONFIGURATION_Handle *cfg;
121
122   /**
123    * Callback to invoke on suggestions.
124    */
125   GNUNET_ATS_AddressSuggestionCallback suggest_cb;
126
127   /**
128    * Closure for @e suggest_cb.
129    */
130   void *suggest_cb_cls;
131
132   /**
133    * Map with the identities of all the peers for which we would
134    * like to have address suggestions.  The key is the PID, the
135    * value is currently the `struct GNUNET_ATS_SuggestHandle`
136    */
137   struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
138
139   /**
140    * Connection to ATS service.
141    */
142   struct GNUNET_CLIENT_Connection *client;
143
144   /**
145    * Message queue for sending requests to the ATS service.
146    */
147   struct GNUNET_MQ_Handle *mq;
148
149   /**
150    * Head of LAN networks list.
151    */
152   struct ATS_Network *net_head;
153
154   /**
155    * Tail of LAN networks list.
156    */
157   struct ATS_Network *net_tail;
158
159   /**
160    * Array of session objects (we need to translate them to numbers and back
161    * for the protocol; the offset in the array is the session number on the
162    * network).  Index 0 is always NULL and reserved to represent the NULL pointer.
163    * Unused entries are also NULL.
164    */
165   struct SessionRecord *session_array;
166
167   /**
168    * Task to trigger reconnect.
169    */
170   struct GNUNET_SCHEDULER_Task *task;
171
172   /**
173    * Task for periodically refreshing our LAN network list.
174    */
175   struct GNUNET_SCHEDULER_Task *interface_task;
176
177   /**
178    * Size of the @e session_array.
179    */
180   unsigned int session_array_size;
181
182 };
183
184
185 /**
186  * Re-establish the connection to the ATS service.
187  *
188  * @param sh handle to use to re-connect.
189  */
190 static void
191 reconnect (struct GNUNET_ATS_SchedulingHandle *sh);
192
193
194 /**
195  * Re-establish the connection to the ATS service.
196  *
197  * @param cls handle to use to re-connect.
198  * @param tc scheduler context
199  */
200 static void
201 reconnect_task (void *cls,
202                 const struct GNUNET_SCHEDULER_TaskContext *tc)
203 {
204   struct GNUNET_ATS_SchedulingHandle *sh = cls;
205
206   sh->task = NULL;
207   reconnect (sh);
208 }
209
210
211 /**
212  * Disconnect from ATS and then reconnect.
213  *
214  * @param sh our handle
215  */
216 static void
217 force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
218 {
219   if (NULL != sh->mq)
220   {
221     GNUNET_MQ_destroy (sh->mq);
222     sh->mq = NULL;
223   }
224   if (NULL != sh->client)
225   {
226     GNUNET_CLIENT_disconnect (sh->client);
227     sh->client = NULL;
228   }
229   sh->task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
230                                            &reconnect_task,
231                                            sh);
232 }
233
234
235 /**
236  * Find the session object corresponding to the given session ID.
237  *
238  * @param sh our handle
239  * @param session_id current session ID
240  * @param peer peer the session belongs to
241  * @return the session object (or NULL)
242  */
243 static struct Session *
244 find_session (struct GNUNET_ATS_SchedulingHandle *sh,
245               uint32_t session_id,
246               const struct GNUNET_PeerIdentity *peer)
247 {
248   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
249               "Find session %u from peer %s in %p\n",
250               (unsigned int) session_id, GNUNET_i2s (peer), sh);
251
252   if (session_id >= sh->session_array_size)
253   {
254     GNUNET_break (0);
255     return NULL;
256   }
257   if (0 == session_id)
258     return NULL;
259   if (sh->session_array[session_id].session == NULL)
260   {
261     GNUNET_break (0 ==
262                   memcmp (peer, &sh->session_array[session_id].peer,
263                           sizeof (struct GNUNET_PeerIdentity)));
264     return NULL;
265   }
266
267   if (0 !=
268       memcmp (peer, &sh->session_array[session_id].peer,
269               sizeof (struct GNUNET_PeerIdentity)))
270   {
271     GNUNET_break (0);
272     force_reconnect (sh);
273     return NULL;
274   }
275   /* This check exploits the fact that first field of a session object
276    * is peer identity.
277    */
278   if (0 !=
279       memcmp (peer, sh->session_array[session_id].session,
280               sizeof (struct GNUNET_PeerIdentity)))
281   {
282     GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
283                      "ats-scheduling-api",
284                      "Session %p belongs to peer `%s'\n",
285                      sh->session_array[session_id].session,
286                      GNUNET_i2s_full ((struct GNUNET_PeerIdentity *) &sh->session_array[session_id].peer));
287 /*
288     GNUNET_break (0);
289     sh->reconnect = GNUNET_YES;
290     return NULL;
291 */
292   }
293   return sh->session_array[session_id].session;
294 }
295
296
297 /**
298  * Get an available session ID for the given session object.
299  *
300  * @param sh our handle
301  * @param session session object
302  * @param peer peer the session belongs to
303  * @return the session id
304  */
305 static uint32_t
306 find_empty_session_slot (struct GNUNET_ATS_SchedulingHandle *sh,
307                          struct Session *session,
308                          const struct GNUNET_PeerIdentity *peer)
309 {
310   unsigned int i;
311   unsigned int f;
312
313   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
314                    "ats-scheduling-api",
315                    "Get session ID for session %p from peer %s in %p\n",
316                    session,
317                    GNUNET_i2s (peer),
318                    sh);
319   if (NULL == session)
320     return NOT_FOUND;
321   f = 0;
322   for (i = 1; i < sh->session_array_size; i++)
323   {
324     if ((f == 0) && (sh->session_array[i].slot_used == GNUNET_NO))
325       f = i;
326   }
327   if (f == 0)
328   {
329     f = sh->session_array_size;
330     GNUNET_array_grow (sh->session_array, sh->session_array_size,
331                        sh->session_array_size * 2);
332   }
333   GNUNET_assert (f > 0);
334   sh->session_array[f].session = session;
335   sh->session_array[f].peer = *peer;
336   sh->session_array[f].slot_used = GNUNET_YES;
337
338   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
339               "Assigning session ID %u for session %p of peer %s in %p\n", f,
340               session, GNUNET_i2s (peer), sh);
341
342   return f;
343 }
344
345
346 /**
347  * Get the ID for the given session object.
348  *
349  * @param sh our handle
350  * @param session session object
351  * @param peer peer the session belongs to
352  * @return the session id or NOT_FOUND for error
353  */
354 static uint32_t
355 find_session_id (struct GNUNET_ATS_SchedulingHandle *sh,
356                  struct Session *session,
357                  const struct GNUNET_PeerIdentity *peer)
358 {
359   unsigned int i;
360   char * p2;
361
362   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
363               "Get session ID for session %p from peer %s in %p\n", session,
364               GNUNET_i2s (peer), sh);
365
366   if (NULL == session)
367     return NOT_FOUND;
368   for (i = 1; i < sh->session_array_size; i++)
369   {
370     if (session == sh->session_array[i].session)
371     {
372       if (0 != memcmp (peer, &sh->session_array[i].peer,
373                        sizeof (struct GNUNET_PeerIdentity)))
374       {
375         p2 = strdup (GNUNET_i2s (&sh->session_array[i].peer));
376         GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "ats-scheduling-api",
377                     "Session %p did not match: old session was for peer `%s' new session is for `%s'\n",
378                     session, GNUNET_i2s (peer), p2);
379         GNUNET_free (p2);
380         return NOT_FOUND;
381       }
382       return i;
383     }
384   }
385   return NOT_FOUND;
386 }
387
388
389 /**
390  * Remove the session of the given session ID from the session
391  * table (it is no longer valid).
392  *
393  * @param sh our handle
394  * @param session_id identifies session that is no longer valid
395  * @param peer peer the session belongs to
396  */
397 static void
398 remove_session (struct GNUNET_ATS_SchedulingHandle *sh,
399                 uint32_t session_id,
400                 const struct GNUNET_PeerIdentity *peer)
401 {
402   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
403                    "ats-scheduling-api",
404                    "Release sessionID %u from peer %s in %p\n",
405                    (unsigned int) session_id,
406                    GNUNET_i2s (peer),
407                    sh);
408
409   if (0 == session_id)
410     return;
411
412   GNUNET_assert (session_id < sh->session_array_size);
413   GNUNET_assert (GNUNET_YES == sh->session_array[session_id].slot_used);
414   GNUNET_assert (0 == memcmp (peer,
415                               &sh->session_array[session_id].peer,
416                               sizeof (struct GNUNET_PeerIdentity)));
417   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
418               "Session %p for peer `%s' removed from slot %u \n",
419               sh->session_array[session_id].session,
420               GNUNET_i2s (peer),
421               session_id);
422   sh->session_array[session_id].session = NULL;
423 }
424
425
426 /**
427  * Release the session slot from the session table (ATS service is
428  * also done using it).
429  *
430  * @param sh our handle
431  * @param session_id identifies session that is no longer valid
432  * @param peer peer the session belongs to
433  */
434 static void
435 release_session (struct GNUNET_ATS_SchedulingHandle *sh,
436                  uint32_t session_id,
437                  const struct GNUNET_PeerIdentity *peer)
438 {
439   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
440                    "ats-scheduling-api",
441                    "Release sessionID %u from peer %s in %p\n",
442                    (unsigned int) session_id,
443                    GNUNET_i2s (peer),
444                    sh);
445   if (session_id >= sh->session_array_size)
446   {
447     GNUNET_break (0);
448     force_reconnect (sh);
449     return;
450   }
451   /* this slot should have been removed from remove_session before */
452   GNUNET_assert (sh->session_array[session_id].session == NULL);
453
454   if (0 !=
455       memcmp (peer, &sh->session_array[session_id].peer,
456               sizeof (struct GNUNET_PeerIdentity)))
457   {
458     GNUNET_break (0);
459     force_reconnect (sh);
460     return;
461   }
462   sh->session_array[session_id].slot_used = GNUNET_NO;
463   memset (&sh->session_array[session_id].peer,
464           0,
465           sizeof (struct GNUNET_PeerIdentity));
466 }
467
468
469 /**
470  * Type of a function to call when we receive a session release
471  * message from the service.
472  *
473  * @param cls the `struct GNUNET_ATS_SchedulingHandle`
474  * @param msg message received, NULL on timeout or fatal error
475  */
476 static void
477 process_ats_session_release_message (void *cls,
478                                      const struct GNUNET_MessageHeader *msg)
479 {
480   struct GNUNET_ATS_SchedulingHandle *sh = cls;
481   const struct SessionReleaseMessage *srm;
482
483   srm = (const struct SessionReleaseMessage *) msg;
484
485   release_session (sh,
486                    ntohl (srm->session_id),
487                    &srm->peer);
488 }
489
490
491 /**
492  * Type of a function to call when we receive a address suggestion
493  * message from the service.
494  *
495  * @param cls the `struct GNUNET_ATS_SchedulingHandle`
496  * @param msg message received, NULL on timeout or fatal error
497  */
498 static void
499 process_ats_address_suggestion_message (void *cls,
500                                         const struct GNUNET_MessageHeader *msg)
501 {
502   struct GNUNET_ATS_SchedulingHandle *sh = cls;
503   const struct AddressSuggestionMessage *m;
504   const struct GNUNET_ATS_Information *atsi;
505   const char *plugin_address;
506   const char *plugin_name;
507   uint16_t plugin_address_length;
508   uint16_t plugin_name_length;
509   uint32_t ats_count;
510   struct GNUNET_HELLO_Address address;
511   struct Session *s;
512
513   if (ntohs (msg->size) <= sizeof (struct AddressSuggestionMessage))
514   {
515     GNUNET_break (0);
516     force_reconnect (sh);
517     return;
518   }
519   m = (const struct AddressSuggestionMessage *) msg;
520   ats_count = ntohl (m->ats_count);
521   plugin_address_length = ntohs (m->address_length);
522   atsi = (const struct GNUNET_ATS_Information *) &m[1];
523   plugin_address = (const char *) &atsi[ats_count];
524   plugin_name = &plugin_address[plugin_address_length];
525   plugin_name_length = ntohs (m->plugin_name_length);
526   if ((plugin_address_length + plugin_name_length +
527        ats_count * sizeof (struct GNUNET_ATS_Information) +
528        sizeof (struct AddressSuggestionMessage) != ntohs (msg->size)) ||
529       (ats_count >
530        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
531       || (plugin_name[plugin_name_length - 1] != '\0'))
532   {
533     GNUNET_break (0);
534     force_reconnect (sh);
535     return;
536   }
537   uint32_t session_id = ntohl (m->session_id);
538
539   if (session_id == 0)
540     s = NULL;
541   else
542   {
543     s = find_session (sh, session_id, &m->peer);
544     if (NULL == s)
545     {
546       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
547                        "ats-scheduling-api",
548                        "ATS tries to use outdated session `%s'\n",
549                        GNUNET_i2s (&m->peer));
550       return;
551     }
552   }
553   if (NULL == sh->suggest_cb)
554     return;
555   address.peer = m->peer;
556   address.address = plugin_address;
557   address.address_length = plugin_address_length;
558   address.transport_name = plugin_name;
559   address.local_info = ntohl(m->address_local_info);
560
561   if ((s == NULL) && (0 == address.address_length))
562   {
563     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
564                 "ATS returned invalid address for peer `%s' transport `%s' address length %i, session_id %i\n",
565                 GNUNET_i2s (&address.peer),
566                 address.transport_name,
567                 plugin_address_length,
568                 session_id);
569     GNUNET_break_op (0);
570     return;
571   }
572   sh->suggest_cb (sh->suggest_cb_cls,
573                   &m->peer,
574                   &address,
575                   s,
576                   m->bandwidth_out,
577                   m->bandwidth_in,
578                   atsi, ats_count);
579 }
580
581
582 /**
583  * We encountered an error handling the MQ to the
584  * ATS service.  Reconnect.
585  *
586  * @param cls the `struct GNUNET_ATS_SchedulingHandle`
587  * @param error details about the error
588  */
589 static void
590 error_handler (void *cls,
591                enum GNUNET_MQ_Error error)
592 {
593   struct GNUNET_ATS_SchedulingHandle *sh = cls;
594
595   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
596               "ATS connection died (code %d), reconnecting\n",
597               (int) error);
598   force_reconnect (sh);
599 }
600
601
602 /**
603  * Re-establish the connection to the ATS service.
604  *
605  * @param sh handle to use to re-connect.
606  */
607 static void
608 reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
609 {
610   static const struct GNUNET_MQ_MessageHandler handlers[] =
611     { { &process_ats_session_release_message,
612         GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE,
613         sizeof (struct SessionReleaseMessage) },
614       { &process_ats_address_suggestion_message,
615         GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION,
616         0 },
617       { NULL, 0, 0 } };
618   struct GNUNET_MQ_Envelope *ev;
619   struct ClientStartMessage *init;
620
621   GNUNET_assert (NULL == sh->client);
622   sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg);
623   if (NULL == sh->client)
624   {
625     force_reconnect (sh);
626     return;
627   }
628   sh->mq = GNUNET_MQ_queue_for_connection_client (sh->client,
629                                                   handlers,
630                                                   &error_handler,
631                                                   sh);
632   ev = GNUNET_MQ_msg (init,
633                       GNUNET_MESSAGE_TYPE_ATS_START);
634   init->start_flag = htonl (START_FLAG_SCHEDULING);
635   GNUNET_MQ_send (sh->mq, ev);
636   // FIXME: iterate over addresses...
637   // FIXME: iterate over peermap for address suggestion requests!
638 }
639
640
641 /**
642  * Delete all entries from the current network list.
643  *
644  * @param sh scheduling handle to clean up
645  */
646 static void
647 delete_networks (struct GNUNET_ATS_SchedulingHandle *sh)
648 {
649   struct ATS_Network *cur;
650
651   while (NULL != (cur = sh->net_head))
652   {
653     GNUNET_CONTAINER_DLL_remove (sh->net_head,
654                                  sh->net_tail,
655                                  cur);
656     GNUNET_free (cur);
657   }
658 }
659
660
661 /**
662  * Function invoked for each interface found.  Adds the interface's
663  * network addresses to the respective DLL, so we can distinguish
664  * between LAN and WAN.
665  *
666  * @param cls closure
667  * @param name name of the interface (can be NULL for unknown)
668  * @param isDefault is this presumably the default interface
669  * @param addr address of this interface (can be NULL for unknown or unassigned)
670  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
671  * @param netmask the network mask (can be NULL for unknown or unassigned)
672  * @param addrlen length of the address
673  * @return #GNUNET_OK to continue iteration
674  */
675 static int
676 interface_proc (void *cls,
677                 const char *name,
678                 int isDefault,
679                 const struct sockaddr *addr,
680                 const struct sockaddr *broadcast_addr,
681                 const struct sockaddr *netmask,
682                 socklen_t addrlen)
683 {
684   struct GNUNET_ATS_SchedulingHandle *sh = cls;
685   /* Calculate network */
686   struct ATS_Network *net = NULL;
687
688   /* Skipping IPv4 loopback addresses since we have special check  */
689   if  (addr->sa_family == AF_INET)
690   {
691     const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
692
693     if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
694        return GNUNET_OK;
695   }
696   /* Skipping IPv6 loopback addresses since we have special check  */
697   if  (addr->sa_family == AF_INET6)
698   {
699     const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
700     if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
701       return GNUNET_OK;
702   }
703
704   if (addr->sa_family == AF_INET)
705   {
706     const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr;
707     const struct sockaddr_in *netmask4 = (const struct sockaddr_in *) netmask;
708     struct sockaddr_in *tmp;
709     struct sockaddr_in network4;
710
711     net = GNUNET_malloc (sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in));
712     tmp = (struct sockaddr_in *) &net[1];
713     net->network = (struct sockaddr *) &tmp[0];
714     net->netmask = (struct sockaddr *) &tmp[1];
715     net->length = addrlen;
716
717     memset (&network4, 0, sizeof (network4));
718     network4.sin_family = AF_INET;
719 #if HAVE_SOCKADDR_IN_SIN_LEN
720     network4.sin_len = sizeof (network4);
721 #endif
722     network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr);
723
724     memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in));
725     memcpy (net->network, &network4, sizeof (struct sockaddr_in));
726   }
727
728   if (addr->sa_family == AF_INET6)
729   {
730     const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr;
731     const struct sockaddr_in6 *netmask6 = (const struct sockaddr_in6 *) netmask;
732     struct sockaddr_in6 * tmp;
733     struct sockaddr_in6 network6;
734
735     net = GNUNET_malloc (sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6));
736     tmp = (struct sockaddr_in6 *) &net[1];
737     net->network = (struct sockaddr *) &tmp[0];
738     net->netmask = (struct sockaddr *) &tmp[1];
739     net->length = addrlen;
740
741     memset (&network6, 0, sizeof (network6));
742     network6.sin6_family = AF_INET6;
743 #if HAVE_SOCKADDR_IN_SIN_LEN
744     network6.sin6_len = sizeof (network6);
745 #endif
746     unsigned int c = 0;
747     uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr;
748     uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr;
749     uint32_t *net_elem = (uint32_t *) &network6.sin6_addr;
750     for (c = 0; c < 4; c++)
751       net_elem[c] = addr_elem[c] & mask_elem[c];
752
753     memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6));
754     memcpy (net->network, &network6, sizeof (struct sockaddr_in6));
755   }
756   if (NULL == net)
757     return GNUNET_OK; /* odd / unsupported address family */
758
759   /* Store in list */
760 #if VERBOSE_ATS
761   char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
762   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763               "Adding network `%s', netmask `%s'\n",
764               GNUNET_a2s ((struct sockaddr *) net->network,
765                           addrlen),
766               netmask);
767   GNUNET_free (netmask);
768 #endif
769   GNUNET_CONTAINER_DLL_insert (sh->net_head,
770                                sh->net_tail,
771                                net);
772
773   return GNUNET_OK;
774 }
775
776
777 /**
778  * Periodically get list of network addresses from our interfaces.
779  *
780  * @param cls closure
781  * @param tc Task context
782  */
783 static void
784 get_addresses (void *cls,
785                const struct GNUNET_SCHEDULER_TaskContext *tc)
786 {
787   struct GNUNET_ATS_SchedulingHandle *sh = cls;
788
789   sh->interface_task = NULL;
790   delete_networks (sh);
791   GNUNET_OS_network_interfaces_list (&interface_proc,
792                                      sh);
793   sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL,
794                                                      &get_addresses,
795                                                      sh);
796 }
797
798
799 /**
800  * Convert a `enum GNUNET_ATS_Network_Type` to a string
801  *
802  * @param net the network type
803  * @return a string or NULL if invalid
804  */
805 const char *
806 GNUNET_ATS_print_network_type (enum GNUNET_ATS_Network_Type net)
807 {
808   switch (net)
809     {
810     case GNUNET_ATS_NET_UNSPECIFIED:
811       return "UNSPECIFIED";
812     case GNUNET_ATS_NET_LOOPBACK:
813       return "LOOPBACK";
814     case GNUNET_ATS_NET_LAN:
815       return "LAN";
816     case GNUNET_ATS_NET_WAN:
817       return "WAN";
818     case GNUNET_ATS_NET_WLAN:
819       return "WLAN";
820     case GNUNET_ATS_NET_BT:
821       return "BLUETOOTH";
822     default:
823       return NULL;
824     }
825 }
826
827
828 /**
829  * Convert a ATS property to a string
830  *
831  * @param type the property type
832  * @return a string or NULL if invalid
833  */
834 const char *
835 GNUNET_ATS_print_property_type (enum GNUNET_ATS_Property type)
836 {
837   switch (type)
838   {
839   case GNUNET_ATS_ARRAY_TERMINATOR:
840     return "TERMINATOR";
841   case GNUNET_ATS_UTILIZATION_OUT:
842     return "UTILIZATION_UP";
843   case GNUNET_ATS_UTILIZATION_IN:
844     return "UTILIZATION_DOWN";
845   case GNUNET_ATS_UTILIZATION_PAYLOAD_OUT:
846     return "UTILIZATION_PAYLOAD_UP";
847   case GNUNET_ATS_UTILIZATION_PAYLOAD_IN:
848     return "UTILIZATION_PAYLOAD_DOWN";
849   case GNUNET_ATS_NETWORK_TYPE:
850     return "NETWORK_TYPE";
851   case GNUNET_ATS_QUALITY_NET_DELAY:
852     return "DELAY";
853   case GNUNET_ATS_QUALITY_NET_DISTANCE:
854     return "DISTANCE";
855   case GNUNET_ATS_COST_WAN:
856     return "COST_WAN";
857   case GNUNET_ATS_COST_LAN:
858     return "COST_LAN";
859   case GNUNET_ATS_COST_WLAN:
860     return "COST_WLAN";
861   default:
862     return NULL;
863   }
864 }
865
866
867 /**
868  * Returns where the address is located: LAN or WAN or ...
869  *
870  * @param sh the scheduling handle
871  * @param addr address
872  * @param addrlen address length
873  * @return type of the network the address belongs to
874  */
875 enum GNUNET_ATS_Network_Type
876 GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle *sh,
877                              const struct sockaddr *addr,
878                              socklen_t addrlen)
879 {
880   struct ATS_Network *cur = sh->net_head;
881   enum GNUNET_ATS_NetworkType type = GNUNET_ATS_NET_UNSPECIFIED;
882
883   switch (addr->sa_family)
884     {
885     case AF_UNIX:
886       type = GNUNET_ATS_NET_LOOPBACK;
887       break;
888     case AF_INET:
889       {
890         const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
891
892         if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
893           type = GNUNET_ATS_NET_LOOPBACK;
894         break;
895       }
896     case AF_INET6:
897       {
898         const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
899
900         if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
901           type = GNUNET_ATS_NET_LOOPBACK;
902         break;
903       }
904     default:
905       GNUNET_break (0);
906       break;
907    }
908
909   /* Check local networks */
910   while ((NULL != cur) && (GNUNET_ATS_NET_UNSPECIFIED == type))
911   {
912     if (addrlen != cur->length)
913     {
914       cur = cur->next;
915       continue;
916     }
917     if (addr->sa_family == AF_INET)
918     {
919       const struct sockaddr_in *a4 = (const struct sockaddr_in *) addr;
920       const struct sockaddr_in *net4 = (const struct sockaddr_in *) cur->network;
921       const struct sockaddr_in *mask4 = (const struct sockaddr_in *) cur->netmask;
922
923       if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr)
924         type = GNUNET_ATS_NET_LAN;
925     }
926     if (addr->sa_family == AF_INET6)
927     {
928       const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *) addr;
929       const struct sockaddr_in6 *net6 = (const struct sockaddr_in6 *) cur->network;
930       const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *) cur->netmask;
931
932       int res = GNUNET_YES;
933       int c = 0;
934       uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr;
935       uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr;
936       uint32_t *net_elem = (uint32_t *) &net6->sin6_addr;
937       for (c = 0; c < 4; c++)
938         if ((addr_elem[c] & mask_elem[c]) != net_elem[c])
939           res = GNUNET_NO;
940
941       if (res == GNUNET_YES)
942         type = GNUNET_ATS_NET_LAN;
943     }
944     cur = cur->next;
945   }
946
947   /* no local network found for this address, default: WAN */
948   if (type == GNUNET_ATS_NET_UNSPECIFIED)
949     type = GNUNET_ATS_NET_WAN;
950   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
951                    "ats-scheduling-api",
952                    "`%s' is in network `%s'\n",
953                    GNUNET_a2s (addr,
954                                addrlen),
955                    GNUNET_ATS_print_network_type (type));
956   return type;
957 }
958
959
960 /**
961  * Initialize the ATS subsystem.
962  *
963  * @param cfg configuration to use
964  * @param suggest_cb notification to call whenever the suggestation changed
965  * @param suggest_cb_cls closure for @a suggest_cb
966  * @return ats context
967  */
968 struct GNUNET_ATS_SchedulingHandle *
969 GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
970                             GNUNET_ATS_AddressSuggestionCallback suggest_cb,
971                             void *suggest_cb_cls)
972 {
973   struct GNUNET_ATS_SchedulingHandle *sh;
974
975   sh = GNUNET_new (struct GNUNET_ATS_SchedulingHandle);
976   sh->cfg = cfg;
977   sh->suggest_cb = suggest_cb;
978   sh->suggest_cb_cls = suggest_cb_cls;
979   GNUNET_array_grow (sh->session_array,
980                      sh->session_array_size,
981                      4);
982   sh->sug_requests = GNUNET_CONTAINER_multipeermap_create (32,
983                                                            GNUNET_YES);
984   GNUNET_OS_network_interfaces_list (&interface_proc,
985                                      sh);
986   sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVAL,
987                                                      &get_addresses,
988                                                      sh);
989   reconnect (sh);
990   return sh;
991 }
992
993
994 /**
995  * Function called to free all `struct GNUNET_ATS_SuggestHandles`
996  * in the map.
997  *
998  * @param cls NULL
999  * @param key the key
1000  * @param value the value to free
1001  * @return #GNUNET_OK (continue to iterate)
1002  */
1003 static int
1004 free_sug_handle (void *cls,
1005                  const struct GNUNET_PeerIdentity *key,
1006                  void *value)
1007 {
1008   struct GNUNET_ATS_SuggestHandle *cur = value;
1009
1010   GNUNET_free (cur);
1011   return GNUNET_OK;
1012 }
1013
1014
1015
1016 /**
1017  * Client is done with ATS scheduling, release resources.
1018  *
1019  * @param sh handle to release
1020  */
1021 void
1022 GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
1023 {
1024   if (NULL != sh->mq)
1025   {
1026     GNUNET_MQ_destroy (sh->mq);
1027     sh->mq = NULL;
1028   }
1029   if (NULL != sh->client)
1030   {
1031     GNUNET_CLIENT_disconnect (sh->client);
1032     sh->client = NULL;
1033   }
1034   if (NULL != sh->task)
1035   {
1036     GNUNET_SCHEDULER_cancel (sh->task);
1037     sh->task = NULL;
1038   }
1039   GNUNET_CONTAINER_multipeermap_iterate (sh->sug_requests,
1040                                          &free_sug_handle,
1041                                          NULL);
1042   GNUNET_CONTAINER_multipeermap_destroy (sh->sug_requests);
1043   if (NULL != sh->interface_task)
1044   {
1045     GNUNET_SCHEDULER_cancel (sh->interface_task);
1046     sh->interface_task = NULL;
1047   }
1048   delete_networks (sh);
1049   GNUNET_array_grow (sh->session_array,
1050                      sh->session_array_size,
1051                      0);
1052   GNUNET_free (sh);
1053 }
1054
1055
1056 /**
1057  * We would like to reset the address suggestion block time for this
1058  * peer
1059  *
1060  * @param sh handle
1061  * @param peer identity of the peer we want to reset
1062  */
1063 void
1064 GNUNET_ATS_reset_backoff (struct GNUNET_ATS_SchedulingHandle *sh,
1065                           const struct GNUNET_PeerIdentity *peer)
1066 {
1067   struct GNUNET_MQ_Envelope *ev;
1068   struct ResetBackoffMessage *m;
1069
1070   ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF);
1071   m->reserved = htonl (0);
1072   m->peer = *peer;
1073   GNUNET_MQ_send (sh->mq, ev);
1074 }
1075
1076
1077 /**
1078  * We would like to receive address suggestions for a peer. ATS will
1079  * respond with a call to the continuation immediately containing an address or
1080  * no address if none is available. ATS can suggest more addresses until we call
1081  * #GNUNET_ATS_suggest_address_cancel().
1082  *
1083  * @param sh handle
1084  * @param peer identity of the peer we need an address for
1085  * @return suggest handle
1086  */
1087 struct GNUNET_ATS_SuggestHandle *
1088 GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh,
1089                             const struct GNUNET_PeerIdentity *peer)
1090 {
1091   struct GNUNET_MQ_Envelope *ev;
1092   struct RequestAddressMessage *m;
1093   struct GNUNET_ATS_SuggestHandle *s;
1094
1095   s = GNUNET_new (struct GNUNET_ATS_SuggestHandle);
1096   s->id = *peer;
1097   GNUNET_break (GNUNET_OK ==
1098                 GNUNET_CONTAINER_multipeermap_put (sh->sug_requests,
1099                                                    &s->id,
1100                                                    s,
1101                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1102   if (NULL == sh->mq)
1103     return s;
1104   ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
1105   m->reserved = htonl (0);
1106   m->peer = *peer;
1107   GNUNET_MQ_send (sh->mq, ev);
1108   return s;
1109 }
1110
1111
1112 /**
1113  * We would like to stop receiving address updates for this peer
1114  *
1115  * @param sh handle
1116  * @param peer identity of the peer
1117  */
1118 void
1119 GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh,
1120                                    const struct GNUNET_PeerIdentity *peer)
1121 {
1122   struct GNUNET_MQ_Envelope *ev;
1123   struct RequestAddressMessage *m;
1124   struct GNUNET_ATS_SuggestHandle *s;
1125
1126   s = GNUNET_CONTAINER_multipeermap_get (sh->sug_requests,
1127                                          peer);
1128   if (NULL == s)
1129   {
1130     GNUNET_break (0);
1131     return;
1132   }
1133   GNUNET_assert (GNUNET_OK ==
1134                  GNUNET_CONTAINER_multipeermap_remove (sh->sug_requests,
1135                                                        &s->id,
1136                                                        s));
1137   GNUNET_free (s);
1138   if (NULL == sh->mq)
1139     return;
1140   ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
1141   m->reserved = htonl (0);
1142   m->peer = *peer;
1143   GNUNET_MQ_send (sh->mq, ev);
1144 }
1145
1146
1147 /**
1148  * Test if a address and a session is known to ATS
1149  *
1150  * @param sh the scheduling handle
1151  * @param address the address
1152  * @param session the session
1153  * @return #GNUNET_YES or #GNUNET_NO
1154  */
1155 int
1156 GNUNET_ATS_session_known (struct GNUNET_ATS_SchedulingHandle *sh,
1157                           const struct GNUNET_HELLO_Address *address,
1158                           struct Session *session)
1159 {
1160   if (NULL == session)
1161     return GNUNET_NO;
1162   if (NOT_FOUND != find_session_id (sh,
1163                                     session,
1164                                     &address->peer))
1165     return GNUNET_YES;  /* Exists */
1166   return GNUNET_NO;
1167 }
1168
1169
1170 /**
1171  * We have a new address ATS should know. Addresses have to be added
1172  * with this function before they can be: updated, set in use and
1173  * destroyed.
1174  *
1175  * @param sh handle
1176  * @param address the address
1177  * @param session session handle, can be NULL
1178  * @param ats performance data for the address
1179  * @param ats_count number of performance records in @a ats
1180  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1181  */
1182 int
1183 GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh,
1184                         const struct GNUNET_HELLO_Address *address,
1185                         struct Session *session,
1186                         const struct GNUNET_ATS_Information *ats,
1187                         uint32_t ats_count)
1188 {
1189   struct GNUNET_MQ_Envelope *ev;
1190   struct AddressUpdateMessage *m;
1191   struct GNUNET_ATS_Information *am;
1192   char *pm;
1193   size_t namelen;
1194   size_t msize;
1195   uint32_t s = 0;
1196
1197   if (NULL == address)
1198   {
1199     GNUNET_break (0);
1200     return GNUNET_SYSERR;
1201   }
1202
1203   namelen = (NULL == address->transport_name)
1204     ? 0
1205     : strlen (address->transport_name) + 1;
1206
1207   msize = address->address_length +
1208     ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
1209   if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1210       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1211       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1212       (ats_count >=
1213        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
1214   {
1215     GNUNET_break (0);
1216     return GNUNET_SYSERR;
1217   }
1218
1219   if (NULL != session)
1220   {
1221     if (NOT_FOUND != (s = find_session_id (sh, session, &address->peer)))
1222     {
1223       /* Already existing, nothing todo */
1224       return GNUNET_SYSERR;
1225     }
1226     s = find_empty_session_slot (sh,
1227                                  session,
1228                                  &address->peer);
1229     GNUNET_break (NOT_FOUND != s);
1230   }
1231
1232   ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD);
1233   m->ats_count = htonl (ats_count);
1234   m->peer = address->peer;
1235   m->address_length = htons (address->address_length);
1236   m->address_local_info = htonl ((uint32_t) address->local_info);
1237   m->plugin_name_length = htons (namelen);
1238   m->session_id = htonl (s);
1239
1240   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1241               "Adding address for peer `%s', plugin `%s', session %p id %u\n",
1242               GNUNET_i2s (&address->peer),
1243               address->transport_name,
1244               session,
1245               s);
1246   am = (struct GNUNET_ATS_Information *) &m[1];
1247   memcpy (am,
1248           ats,
1249           ats_count * sizeof (struct GNUNET_ATS_Information));
1250   pm = (char *) &am[ats_count];
1251   memcpy (pm, address->address, address->address_length);
1252   if (NULL != address->transport_name)
1253     memcpy (&pm[address->address_length],
1254             address->transport_name,
1255             namelen);
1256   GNUNET_MQ_send (sh->mq, ev);
1257   return GNUNET_OK;
1258 }
1259
1260
1261 /**
1262  * We have updated performance statistics for a given address.  Note
1263  * that this function can be called for addresses that are currently
1264  * in use as well as addresses that are valid but not actively in use.
1265  * Furthermore, the peer may not even be connected to us right now (in
1266  * which case the call may be ignored or the information may be stored
1267  * for later use).  Update bandwidth assignments.
1268  *
1269  * @param sh handle
1270  * @param address the address
1271  * @param session session handle, can be NULL
1272  * @param ats performance data for the address
1273  * @param ats_count number of performance records in @a ats
1274  * @return #GNUNET_YES on success, #GNUNET_NO if address or session are unknown,
1275  * #GNUNET_SYSERR on hard failure
1276  */
1277 int
1278 GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh,
1279                            const struct GNUNET_HELLO_Address *address,
1280                            struct Session *session,
1281                            const struct GNUNET_ATS_Information *ats,
1282                            uint32_t ats_count)
1283 {
1284   struct GNUNET_MQ_Envelope *ev;
1285   struct AddressUpdateMessage *m;
1286   struct GNUNET_ATS_Information *am;
1287   char *pm;
1288   size_t namelen;
1289   size_t msize;
1290   uint32_t s = 0;
1291
1292   if (NULL == address)
1293   {
1294     GNUNET_break (0);
1295     return GNUNET_SYSERR;
1296   }
1297   if (NULL == sh)
1298   {
1299     GNUNET_break (0);
1300     return GNUNET_SYSERR;
1301   }
1302
1303   namelen = (address->transport_name ==
1304        NULL) ? 0 : strlen (address->transport_name) + 1;
1305   msize = address->address_length +
1306       ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
1307   if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1308       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1309       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1310       (ats_count >=
1311        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
1312   {
1313     GNUNET_break (0);
1314     return GNUNET_SYSERR;
1315   }
1316
1317   if (NULL != session)
1318   {
1319     s = find_session_id (sh, session, &address->peer);
1320     if (NOT_FOUND == s)
1321       return GNUNET_NO;
1322   }
1323
1324   ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
1325   m->ats_count = htonl (ats_count);
1326   m->peer = address->peer;
1327   m->address_length = htons (address->address_length);
1328   m->address_local_info = htonl ((uint32_t) address->local_info);
1329   m->plugin_name_length = htons (namelen);
1330   m->session_id = htonl (s);
1331
1332   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333               "Updating address for peer `%s', plugin `%s', session %p id %u\n",
1334               GNUNET_i2s (&address->peer),
1335               address->transport_name,
1336               session,
1337               s);
1338
1339   am = (struct GNUNET_ATS_Information *) &m[1];
1340   memcpy (am,
1341           ats,
1342           ats_count * sizeof (struct GNUNET_ATS_Information));
1343   pm = (char *) &am[ats_count];
1344   memcpy (pm, address->address, address->address_length);
1345   memcpy (&pm[address->address_length], address->transport_name, namelen);
1346   GNUNET_MQ_send (sh->mq, ev);
1347   return GNUNET_YES;
1348 }
1349
1350
1351 /**
1352  * An address is now in use or not used any more.
1353  *
1354  * @param sh handle
1355  * @param address the address
1356  * @param session session handle, can be NULL
1357  * @param in_use #GNUNET_YES if this address is now used, #GNUNET_NO
1358  * if address is not used any more
1359  */
1360 void
1361 GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh,
1362                            const struct GNUNET_HELLO_Address *address,
1363                            struct Session *session,
1364                            int in_use)
1365 {
1366   struct GNUNET_MQ_Envelope *ev;
1367   struct AddressUseMessage *m;
1368   char *pm;
1369   size_t namelen;
1370   size_t msize;
1371   uint32_t s = 0;
1372
1373   namelen =
1374       (address->transport_name ==
1375        NULL) ? 0 : strlen (address->transport_name) + 1;
1376   msize = address->address_length + namelen;
1377   if ((msize + sizeof (struct AddressUseMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1378       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1379       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
1380   {
1381     GNUNET_break (0);
1382     return;
1383   }
1384
1385   if (NULL != session)
1386   {
1387     s = find_session_id (sh, session, &address->peer);
1388     if ((s == NOT_FOUND) && (GNUNET_NO == in_use))
1389     {
1390       /* trying to set unknown address to NO */
1391       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1392                   "Trying to set unknown address to unused for peer `%s', plugin `%s', session %p\n",
1393                   GNUNET_i2s (&address->peer), address->transport_name, session);
1394       GNUNET_break (0);
1395       return;
1396     }
1397     if ((s == NOT_FOUND) && (GNUNET_YES == in_use))
1398     {
1399       /* trying to set new address to YES */
1400       s = find_empty_session_slot (sh, session, &address->peer);
1401       GNUNET_assert (NOT_FOUND != s);
1402     }
1403   }
1404
1405   ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE);
1406   m->peer = address->peer;
1407   m->in_use = htons (in_use);
1408   m->address_length = htons (address->address_length);
1409   m->address_local_info = htonl ((uint32_t) address->local_info);
1410   m->plugin_name_length = htons (namelen);
1411
1412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413               "Setting address used to %s for peer `%s', plugin `%s', session %p\n",
1414               (GNUNET_YES == in_use) ? "YES" : "NO",
1415               GNUNET_i2s (&address->peer), address->transport_name, session);
1416
1417   m->session_id = htonl (s);
1418   pm = (char *) &m[1];
1419   memcpy (pm, address->address, address->address_length);
1420   memcpy (&pm[address->address_length], address->transport_name, namelen);
1421   GNUNET_MQ_send (sh->mq, ev);
1422 }
1423
1424
1425 /**
1426  * An address got destroyed, stop including it as a valid address.
1427  *
1428  * If a session is given, only the session will be removed, if no session is
1429  * given the full address will be deleted.
1430  *
1431  * @param sh handle
1432  * @param address the address
1433  * @param session session handle that is no longer valid, can be NULL
1434  */
1435 void
1436 GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh,
1437                               const struct GNUNET_HELLO_Address *address,
1438                               struct Session *session)
1439 {
1440   struct GNUNET_MQ_Envelope *ev;
1441   struct AddressDestroyedMessage *m;
1442   char *pm;
1443   size_t namelen;
1444   size_t msize;
1445   uint32_t s;
1446
1447   if (NULL == address)
1448   {
1449     GNUNET_break (0);
1450     return;
1451   }
1452   GNUNET_assert (NULL != address->transport_name);
1453   namelen = strlen (address->transport_name) + 1;
1454   GNUNET_assert (namelen > 1);
1455   msize = address->address_length + namelen;
1456   if ((msize + sizeof (struct AddressDestroyedMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1457       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1458       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
1459   {
1460     GNUNET_break (0);
1461     return;
1462   }
1463
1464   s = find_session_id (sh, session, &address->peer);
1465   if ((NULL != session) && (NOT_FOUND == s))
1466   {
1467     /* trying to delete unknown address */
1468     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1469                 "Trying to delete unknown address for peer `%s', plugin `%s', session %p\n",
1470                 GNUNET_i2s (&address->peer), address->transport_name, session);
1471     return;
1472   }
1473
1474   ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
1475   m->peer = address->peer;
1476   m->address_length = htons (address->address_length);
1477   m->address_local_info = htonl ((uint32_t) address->local_info);
1478   m->plugin_name_length = htons (namelen);
1479
1480   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1481               "Deleting address for peer `%s', plugin `%s', session %p\n",
1482               GNUNET_i2s (&address->peer), address->transport_name, session);
1483
1484   m->session_id = htonl (s);
1485   pm = (char *) &m[1];
1486   memcpy (pm, address->address, address->address_length);
1487   memcpy (&pm[address->address_length], address->transport_name, namelen);
1488   GNUNET_MQ_send (sh->mq, ev);
1489   remove_session (sh, s, &address->peer);
1490 }
1491
1492 /* end of ats_api_scheduling.c */