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