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