ats change, done
[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
642   if (NULL == sh->suggest_cb)
643         return;
644
645   address.peer = m->peer;
646   address.address = plugin_address;
647   address.address_length = plugin_address_length;
648   address.transport_name = plugin_name;
649
650   if ((s == NULL) && (0 == address.address_length))
651   {
652     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
653                 "ATS returned invalid address for peer `%s' transport `%s' address length %i, session_id %i\n",
654                 GNUNET_i2s (&address.peer), address.transport_name,
655                 plugin_address_length, session_id);
656     GNUNET_break_op (0);
657     GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
658                            GNUNET_TIME_UNIT_FOREVER_REL);
659     return;
660   }
661
662   sh->suggest_cb (sh->suggest_cb_cls, &address, s, m->bandwidth_out,
663                   m->bandwidth_in, atsi, ats_count);
664
665   GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
666                          GNUNET_TIME_UNIT_FOREVER_REL);
667   if (GNUNET_YES == sh->reconnect)
668     force_reconnect (sh);
669 }
670
671
672 /**
673  * Re-establish the connection to the ATS service.
674  *
675  * @param sh handle to use to re-connect.
676  */
677 static void
678 reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
679 {
680   struct PendingMessage *p;
681   struct ClientStartMessage *init;
682
683   GNUNET_assert (NULL == sh->client);
684   sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg);
685   GNUNET_assert (NULL != sh->client);
686   if ((NULL == (p = sh->pending_head)) || (GNUNET_YES != p->is_init))
687   {
688     p = GNUNET_malloc (sizeof (struct PendingMessage) +
689                        sizeof (struct ClientStartMessage));
690     p->size = sizeof (struct ClientStartMessage);
691     p->is_init = GNUNET_YES;
692     init = (struct ClientStartMessage *) &p[1];
693     init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
694     init->header.size = htons (sizeof (struct ClientStartMessage));
695     init->start_flag = htonl (START_FLAG_SCHEDULING);
696     GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, p);
697   }
698   do_transmit (sh);
699 }
700
701
702 /**
703  * delete the current network list
704  */
705 static void
706 delete_networks (struct GNUNET_ATS_SchedulingHandle *sh)
707 {
708   struct ATS_Network * cur = sh->net_head;
709   while (cur != NULL)
710   {
711     GNUNET_CONTAINER_DLL_remove(sh->net_head, sh->net_tail, cur);
712     GNUNET_free (cur);
713     cur = sh->net_head;
714   }
715 }
716
717
718 static int
719 interface_proc (void *cls, const char *name,
720                 int isDefault,
721                 const struct sockaddr *
722                 addr,
723                 const struct sockaddr *
724                 broadcast_addr,
725                 const struct sockaddr *
726                 netmask, socklen_t addrlen)
727 {
728   struct GNUNET_ATS_SchedulingHandle * sh = cls;
729   /* Calculate network */
730   struct ATS_Network *net = NULL;
731
732   /* Skipping IPv4 loopback addresses since we have special check  */
733   if  (addr->sa_family == AF_INET)
734   {
735     struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
736
737     if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
738        return GNUNET_OK;
739   }
740   /* Skipping IPv6 loopback addresses since we have special check  */
741   if  (addr->sa_family == AF_INET6)
742   {
743     struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
744     if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
745       return GNUNET_OK;
746   }
747
748   if (addr->sa_family == AF_INET)
749   {
750     struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
751     struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask;
752     struct sockaddr_in *tmp = NULL;
753     struct sockaddr_in network4;
754
755     net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in));
756     tmp = (struct sockaddr_in *) &net[1];
757     net->network = (struct sockaddr *) &tmp[0];
758     net->netmask = (struct sockaddr *) &tmp[1];
759     net->length = addrlen;
760
761     memset (&network4, 0, sizeof (network4));
762     network4.sin_family = AF_INET;
763 #if HAVE_SOCKADDR_IN_SIN_LEN
764     network4.sin_len = sizeof (network4);
765 #endif
766     network4.sin_addr.s_addr = (addr4->sin_addr.s_addr & netmask4->sin_addr.s_addr);
767
768     memcpy (net->netmask, netmask4, sizeof (struct sockaddr_in));
769     memcpy (net->network, &network4, sizeof (struct sockaddr_in));
770   }
771
772   if (addr->sa_family == AF_INET6)
773   {
774     struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
775     struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask;
776     struct sockaddr_in6 * tmp = NULL;
777     struct sockaddr_in6 network6;
778
779     net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6));
780     tmp = (struct sockaddr_in6 *) &net[1];
781     net->network = (struct sockaddr *) &tmp[0];
782     net->netmask = (struct sockaddr *) &tmp[1];
783     net->length = addrlen;
784
785     memset (&network6, 0, sizeof (network6));
786     network6.sin6_family = AF_INET6;
787 #if HAVE_SOCKADDR_IN_SIN_LEN
788     network6.sin6_len = sizeof (network6);
789 #endif
790     int c = 0;
791     uint32_t *addr_elem = (uint32_t *) &addr6->sin6_addr;
792     uint32_t *mask_elem = (uint32_t *) &netmask6->sin6_addr;
793     uint32_t *net_elem = (uint32_t *) &network6.sin6_addr;
794     for (c = 0; c < 4; c++)
795       net_elem[c] = addr_elem[c] & mask_elem[c];
796
797     memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6));
798     memcpy (net->network, &network6, sizeof (struct sockaddr_in6));
799   }
800
801   /* Store in list */
802   if (net != NULL)
803   {
804 #if VERBOSE_ATS
805     char * netmask = GNUNET_strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen));
806     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n",
807         GNUNET_a2s((struct sockaddr *) net->network, addrlen),
808         netmask);
809     GNUNET_free (netmask);
810 # endif
811     GNUNET_CONTAINER_DLL_insert(sh->net_head, sh->net_tail, net);
812   }
813   return GNUNET_OK;
814 }
815
816
817 /**
818  * Periodically get list of addresses
819  * @param cls closure
820  * @param tc Task context
821  */
822 static void
823 get_addresses (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
824 {
825   struct GNUNET_ATS_SchedulingHandle * sh = cls;
826   sh->interface_task = GNUNET_SCHEDULER_NO_TASK;
827   delete_networks (sh);
828   GNUNET_OS_network_interfaces_list(interface_proc, sh);
829   sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL,
830                                                      get_addresses,
831                                                      sh);
832 }
833
834 /**
835  * Convert a GNUNET_ATS_NetworkType to a string
836  *
837  * @param net the network type
838  * @return a string or NULL if invalid
839  */
840 const char *
841 GNUNET_ATS_print_network_type (uint32_t net)
842 {
843   char *networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
844   if (net < GNUNET_ATS_NetworkTypeCount)
845     return networks[net];
846   return NULL;
847 }
848
849
850 /**
851  * Returns where the address is located: LAN or WAN or ...
852  *
853  * @param sh the scheduling handle
854  * @param addr address
855  * @param addrlen address length
856  * @return location as GNUNET_ATS_Information
857  */
858 struct GNUNET_ATS_Information
859 GNUNET_ATS_address_get_type (struct GNUNET_ATS_SchedulingHandle * sh, const struct sockaddr * addr, socklen_t addrlen)
860 {
861   GNUNET_assert (sh != NULL);
862   struct ATS_Network * cur = sh->net_head;
863
864   int type = GNUNET_ATS_NET_UNSPECIFIED;
865   struct GNUNET_ATS_Information ats;
866
867   if  (addr->sa_family == AF_UNIX)
868   {
869     type = GNUNET_ATS_NET_LOOPBACK;
870   }
871
872   /* IPv4 loopback check */
873   if  (addr->sa_family == AF_INET)
874   {
875     struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
876
877     if ((a4->sin_addr.s_addr & htonl(0xff000000)) == htonl (0x7f000000))
878       type = GNUNET_ATS_NET_LOOPBACK;
879   }
880   /* IPv6 loopback check */
881   if  (addr->sa_family == AF_INET6)
882   {
883     struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
884     if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr))
885       type = GNUNET_ATS_NET_LOOPBACK;
886   }
887
888   /* Check local networks */
889   while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED))
890   {
891     if (addrlen != cur->length)
892     {
893       cur = cur->next;
894       continue;
895     }
896
897     if (addr->sa_family == AF_INET)
898     {
899       struct sockaddr_in * a4 = (struct sockaddr_in *) addr;
900       struct sockaddr_in * net4 = (struct sockaddr_in *) cur->network;
901       struct sockaddr_in * mask4 = (struct sockaddr_in *) cur->netmask;
902
903       if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr)) == net4->sin_addr.s_addr)
904         type = GNUNET_ATS_NET_LAN;
905     }
906     if (addr->sa_family == AF_INET6)
907     {
908       struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr;
909       struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network;
910       struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask;
911
912       int res = GNUNET_YES;
913       int c = 0;
914       uint32_t *addr_elem = (uint32_t *) &a6->sin6_addr;
915       uint32_t *mask_elem = (uint32_t *) &mask6->sin6_addr;
916       uint32_t *net_elem = (uint32_t *) &net6->sin6_addr;
917       for (c = 0; c < 4; c++)
918         if ((addr_elem[c] & mask_elem[c]) != net_elem[c])
919           res = GNUNET_NO;
920
921       if (res == GNUNET_YES)
922         type = GNUNET_ATS_NET_LAN;
923     }
924     cur = cur->next;
925   }
926
927   /* no local network found for this address, default: WAN */
928   if (type == GNUNET_ATS_NET_UNSPECIFIED)
929     type = GNUNET_ATS_NET_WAN;
930   ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
931   ats.value = htonl (type);
932
933   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "ats-scheduling-api",
934                    "`%s' is in network `%s'\n",
935                    GNUNET_a2s ((const struct sockaddr *) addr, addrlen),
936                    GNUNET_ATS_print_network_type(type));
937   return ats;
938 }
939
940
941 /**
942  * Initialize the ATS subsystem.
943  *
944  * @param cfg configuration to use
945  * @param suggest_cb notification to call whenever the suggestation changed
946  * @param suggest_cb_cls closure for 'suggest_cb'
947  * @return ats context
948  */
949 struct GNUNET_ATS_SchedulingHandle *
950 GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
951                             GNUNET_ATS_AddressSuggestionCallback suggest_cb,
952                             void *suggest_cb_cls)
953 {
954   struct GNUNET_ATS_SchedulingHandle *sh;
955
956   sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SchedulingHandle));
957   sh->cfg = cfg;
958   sh->suggest_cb = suggest_cb;
959   sh->suggest_cb_cls = suggest_cb_cls;
960   GNUNET_array_grow (sh->session_array, sh->session_array_size, 4);
961   GNUNET_OS_network_interfaces_list(interface_proc, sh);
962   sh->interface_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_PROCESSING_INTERVALL,
963       get_addresses,
964       sh);
965   reconnect (sh);
966   return sh;
967 }
968
969
970 /**
971  * Client is done with ATS scheduling, release resources.
972  *
973  * @param sh handle to release
974  */
975 void
976 GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
977 {
978   struct PendingMessage *p;
979   struct GNUNET_ATS_SuggestHandle *cur;
980   struct GNUNET_ATS_SuggestHandle *next;
981   while (NULL != (p = sh->pending_head))
982   {
983     GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
984     GNUNET_free (p);
985   }
986   if (NULL != sh->client)
987   {
988     GNUNET_CLIENT_disconnect (sh->client);
989     sh->client = NULL;
990   }
991   if (GNUNET_SCHEDULER_NO_TASK != sh->task)
992   {
993     GNUNET_SCHEDULER_cancel (sh->task);
994     sh->task = GNUNET_SCHEDULER_NO_TASK;
995   }
996
997   next = sh->sug_head;
998   while (NULL != (cur = next))
999   {
1000                 next = cur->next;
1001                 GNUNET_CONTAINER_DLL_remove (sh->sug_head, sh->sug_tail, cur);
1002                 GNUNET_free (cur);
1003   }
1004
1005   delete_networks (sh);
1006   if (sh->interface_task != GNUNET_SCHEDULER_NO_TASK)
1007   {
1008     GNUNET_SCHEDULER_cancel(sh->interface_task);
1009     sh->interface_task = GNUNET_SCHEDULER_NO_TASK;
1010   }
1011   GNUNET_array_grow (sh->session_array, sh->session_array_size, 0);
1012   GNUNET_free (sh);
1013   sh = NULL;
1014 }
1015
1016 /**
1017  * We would like to reset the address suggestion block time for this
1018  * peer
1019  *
1020  * @param sh handle
1021  * @param peer identity of the peer we want to reset
1022  */
1023 void
1024 GNUNET_ATS_reset_backoff (struct GNUNET_ATS_SchedulingHandle *sh,
1025                           const struct GNUNET_PeerIdentity *peer)
1026 {
1027   struct PendingMessage *p;
1028   struct ResetBackoffMessage *m;
1029
1030   p = GNUNET_malloc (sizeof (struct PendingMessage) +
1031                      sizeof (struct ResetBackoffMessage));
1032   p->size = sizeof (struct ResetBackoffMessage);
1033   p->is_init = GNUNET_NO;
1034   m = (struct ResetBackoffMessage *) &p[1];
1035   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESET_BACKOFF);
1036   m->header.size = htons (sizeof (struct ResetBackoffMessage));
1037   m->reserved = htonl (0);
1038   m->peer = *peer;
1039   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1040   do_transmit (sh);
1041 }
1042
1043 /**
1044  * We would like to establish a new connection with a peer.  ATS
1045  * should suggest a good address to begin with.
1046  *
1047  * @param sh handle
1048  * @param peer identity of the peer we need an address for
1049  * @return suggest handle
1050  */
1051 struct GNUNET_ATS_SuggestHandle *
1052 GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh,
1053                             const struct GNUNET_PeerIdentity *peer)
1054 {
1055   struct PendingMessage *p;
1056   struct RequestAddressMessage *m;
1057   struct GNUNET_ATS_SuggestHandle *s;
1058
1059   // FIXME: ATS needs to remember this in case of
1060   // a disconnect!
1061   p = GNUNET_malloc (sizeof (struct PendingMessage) +
1062                      sizeof (struct RequestAddressMessage));
1063   p->size = sizeof (struct RequestAddressMessage);
1064   p->is_init = GNUNET_NO;
1065   m = (struct RequestAddressMessage *) &p[1];
1066   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
1067   m->header.size = htons (sizeof (struct RequestAddressMessage));
1068   m->reserved = htonl (0);
1069   m->peer = *peer;
1070   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1071   do_transmit (sh);
1072   s = GNUNET_malloc (sizeof (struct GNUNET_ATS_SuggestHandle));
1073   s->id = (*peer);
1074   GNUNET_CONTAINER_DLL_insert_tail (sh->sug_head, sh->sug_tail, s);
1075   return s;
1076 }
1077
1078
1079 /**
1080  * We would like to stop receiving address updates for this peer
1081  *
1082  * @param sh handle
1083  * @param peer identity of the peer
1084  */
1085 void
1086 GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh,
1087                                    const struct GNUNET_PeerIdentity *peer)
1088 {
1089   struct PendingMessage *p;
1090   struct RequestAddressMessage *m;
1091   struct GNUNET_ATS_SuggestHandle *s;
1092
1093   for (s = sh->sug_head; NULL != s; s = s->next)
1094         if (0 == memcmp(peer, &s->id, sizeof (s->id)))
1095                 break;
1096   if (NULL == s)
1097   {
1098         GNUNET_break (0);
1099         return;
1100   }
1101   else
1102   {
1103         GNUNET_CONTAINER_DLL_remove (sh->sug_head, sh->sug_tail, s);
1104         GNUNET_free (s);
1105   }
1106
1107   p = GNUNET_malloc (sizeof (struct PendingMessage) +
1108                      sizeof (struct RequestAddressMessage));
1109   p->size = sizeof (struct RequestAddressMessage);
1110   p->is_init = GNUNET_NO;
1111   m = (struct RequestAddressMessage *) &p[1];
1112   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
1113   m->header.size = htons (sizeof (struct RequestAddressMessage));
1114   m->reserved = htonl (0);
1115   m->peer = *peer;
1116   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1117   do_transmit (sh);
1118 }
1119
1120
1121 /**
1122  * We have a new address ATS should know. Addresses have to be added with this
1123  * function before they can be: updated, set in use and destroyed
1124  *
1125  * @param sh handle
1126  * @param address the address
1127  * @param session session handle, can be NULL
1128  * @param ats performance data for the address
1129  * @param ats_count number of performance records in 'ats'
1130  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1131  */
1132 int
1133 GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh,
1134                         const struct GNUNET_HELLO_Address *address,
1135                         struct Session *session,
1136                         const struct GNUNET_ATS_Information *ats,
1137                         uint32_t ats_count)
1138 {
1139
1140   struct PendingMessage *p;
1141   struct AddressUpdateMessage *m;
1142   struct GNUNET_ATS_Information *am;
1143   char *pm;
1144   size_t namelen;
1145   size_t msize;
1146   uint32_t s = 0;
1147
1148   if (address == NULL)
1149   {
1150     GNUNET_break (0);
1151     return GNUNET_SYSERR;
1152   }
1153
1154   namelen =
1155       (address->transport_name ==
1156        NULL) ? 0 : strlen (address->transport_name) + 1;
1157   msize =
1158       sizeof (struct AddressUpdateMessage) + address->address_length +
1159       ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
1160   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1161       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1162       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1163       (ats_count >=
1164        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
1165   {
1166     GNUNET_break (0);
1167     return GNUNET_SYSERR;
1168   }
1169
1170   if (NULL != session)
1171   {
1172     s = find_session_id (sh, session, &address->peer);
1173     if (NOT_FOUND != s)
1174     {
1175       /* Already existing, nothing todo */
1176       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177                   "Adding duplicate address for peer `%s', plugin `%s', session %p id %u\n",
1178                   GNUNET_i2s (&address->peer),
1179                   address->transport_name, session, s);
1180       return GNUNET_SYSERR;
1181     }
1182     s = find_empty_session_slot (sh, session, &address->peer);
1183     GNUNET_break (NOT_FOUND != s);
1184   }
1185
1186   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1187   p->size = msize;
1188   p->is_init = GNUNET_NO;
1189   m = (struct AddressUpdateMessage *) &p[1];
1190   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD);
1191   m->header.size = htons (msize);
1192   m->ats_count = htonl (ats_count);
1193   m->peer = address->peer;
1194   m->address_length = htons (address->address_length);
1195   m->plugin_name_length = htons (namelen);
1196   m->session_id = htonl (s);
1197
1198   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1199               "Adding address for peer `%s', plugin `%s', session %p id %u\n",
1200               GNUNET_i2s (&address->peer),
1201               address->transport_name, session, s);
1202
1203   am = (struct GNUNET_ATS_Information *) &m[1];
1204   memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
1205   pm = (char *) &am[ats_count];
1206   memcpy (pm, address->address, address->address_length);
1207   if (NULL != address->transport_name)
1208         memcpy (&pm[address->address_length], address->transport_name, namelen);
1209   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1210   do_transmit (sh);
1211   return GNUNET_OK;
1212
1213 }
1214
1215
1216 /**
1217  * We have updated performance statistics for a given address.  Note
1218  * that this function can be called for addresses that are currently
1219  * in use as well as addresses that are valid but not actively in use.
1220  * Furthermore, the peer may not even be connected to us right now (in
1221  * which case the call may be ignored or the information may be stored
1222  * for later use).  Update bandwidth assignments.
1223  *
1224  * @param sh handle
1225  * @param address the address
1226  * @param session session handle, can be NULL
1227  * @param ats performance data for the address
1228  * @param ats_count number of performance records in 'ats'
1229  */
1230 void
1231 GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh,
1232                            const struct GNUNET_HELLO_Address *address,
1233                            struct Session *session,
1234                            const struct GNUNET_ATS_Information *ats,
1235                            uint32_t ats_count)
1236 {
1237   struct PendingMessage *p;
1238   struct AddressUpdateMessage *m;
1239   struct GNUNET_ATS_Information *am;
1240   char *pm;
1241   size_t namelen;
1242   size_t msize;
1243   uint32_t s = 0;
1244
1245   if (address == NULL)
1246   {
1247     GNUNET_break (0);
1248     return;
1249   }
1250
1251   namelen =
1252       (address->transport_name ==
1253        NULL) ? 0 : strlen (address->transport_name) + 1;
1254   msize =
1255       sizeof (struct AddressUpdateMessage) + address->address_length +
1256       ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
1257   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1258       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1259       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1260       (ats_count >=
1261        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
1262   {
1263     GNUNET_break (0);
1264     return;
1265   }
1266
1267   if (NULL != session)
1268   {
1269     s = find_session_id (sh, session, &address->peer);
1270     if (NOT_FOUND == s)
1271     {
1272         return;
1273         /* FIXME */
1274       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1275                   "Update for unknown address for peer `%s', plugin `%s', session %p id %u\n",
1276                   GNUNET_i2s (&address->peer),
1277                   address->transport_name, session, s);
1278
1279       GNUNET_break (0);
1280     }
1281   }
1282
1283   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1284   p->size = msize;
1285   p->is_init = GNUNET_NO;
1286   m = (struct AddressUpdateMessage *) &p[1];
1287   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
1288   m->header.size = htons (msize);
1289   m->ats_count = htonl (ats_count);
1290   m->peer = address->peer;
1291   m->address_length = htons (address->address_length);
1292   m->plugin_name_length = htons (namelen);
1293
1294   m->session_id = htonl (s);
1295
1296   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1297               "Updating address for peer `%s', plugin `%s', session %p id %u\n",
1298               GNUNET_i2s (&address->peer),
1299               address->transport_name, session, s);
1300
1301   am = (struct GNUNET_ATS_Information *) &m[1];
1302   memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
1303   pm = (char *) &am[ats_count];
1304   memcpy (pm, address->address, address->address_length);
1305   memcpy (&pm[address->address_length], address->transport_name, namelen);
1306   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1307   do_transmit (sh);
1308   return;
1309 }
1310
1311
1312 /**
1313  * An address is now in use or not used any more.
1314  *
1315  * @param sh handle
1316  * @param address the address
1317  * @param session session handle, can be NULL
1318  * @param in_use GNUNET_YES if this address is now used, GNUNET_NO
1319  * if address is not used any more
1320  */
1321 void
1322 GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh,
1323                            const struct GNUNET_HELLO_Address *address,
1324                            struct Session *session, int in_use)
1325 {
1326   struct PendingMessage *p;
1327   struct AddressUseMessage *m;
1328   char *pm;
1329   size_t namelen;
1330   size_t msize;
1331   uint32_t s = 0;
1332
1333   GNUNET_assert (NULL != address);
1334   namelen =
1335       (address->transport_name ==
1336        NULL) ? 0 : strlen (address->transport_name) + 1;
1337   msize = sizeof (struct AddressUseMessage) + address->address_length + namelen;
1338   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1339       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1340       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
1341   {
1342     GNUNET_break (0);
1343     return;
1344   }
1345
1346   if (session != NULL)
1347   {
1348     s = find_session_id (sh, session, &address->peer);
1349     if ((s == NOT_FOUND) && (GNUNET_NO == in_use))
1350     {
1351       /* trying to set unknown address to NO */
1352       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1353                   "Trying to set unknown address to unused for peer `%s', plugin `%s', session %p\n",
1354                   GNUNET_i2s (&address->peer), address->transport_name, session);
1355       GNUNET_break (0);
1356       return;
1357     }
1358     if ((s == NOT_FOUND) && (GNUNET_YES == in_use))
1359     {
1360       /* trying to set new address to YES */
1361       s = find_empty_session_slot (sh, session, &address->peer);
1362       GNUNET_assert (NOT_FOUND != s);
1363     }
1364   }
1365
1366   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1367   p->size = msize;
1368   p->is_init = GNUNET_NO;
1369   m = (struct AddressUseMessage *) &p[1];
1370   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE);
1371   m->header.size = htons (msize);
1372   m->peer = address->peer;
1373   m->in_use = htons (in_use);
1374   m->address_length = htons (address->address_length);
1375   m->plugin_name_length = htons (namelen);
1376
1377   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1378               "Setting address used to %s for peer `%s', plugin `%s', session %p\n",
1379               (GNUNET_YES == in_use) ? "YES" : "NO",
1380               GNUNET_i2s (&address->peer), address->transport_name, session);
1381
1382   m->session_id = htonl (s);
1383   pm = (char *) &m[1];
1384   memcpy (pm, address->address, address->address_length);
1385   memcpy (&pm[address->address_length], address->transport_name, namelen);
1386   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1387   do_transmit (sh);
1388   return;
1389 }
1390
1391
1392 /**
1393  * A session got destroyed, stop including it as a valid address.
1394  *
1395  * @param sh handle
1396  * @param address the address
1397  * @param session session handle that is no longer valid, can be NULL
1398  */
1399 void
1400 GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh,
1401                               const struct GNUNET_HELLO_Address *address,
1402                               struct Session *session)
1403 {
1404   struct PendingMessage *p;
1405   struct AddressDestroyedMessage *m;
1406   char *pm;
1407   size_t namelen;
1408   size_t msize;
1409   uint32_t s = 0;
1410
1411   if (address == NULL)
1412   {
1413     GNUNET_break (0);
1414     return;
1415   }
1416
1417   GNUNET_assert (address->transport_name != NULL);
1418   namelen = strlen (address->transport_name) + 1;
1419   GNUNET_assert (namelen > 1);
1420   msize =
1421       sizeof (struct AddressDestroyedMessage) + address->address_length +
1422       namelen;
1423   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1424       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
1425       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
1426   {
1427     GNUNET_break (0);
1428     return;
1429   }
1430
1431   s = find_session_id (sh, session, &address->peer);
1432   if ((NULL != session) && (NOT_FOUND == s))
1433   {
1434     /* trying to delete unknown address */
1435     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1436                 "Trying to delete unknown address for peer `%s', plugin `%s', session %p\n",
1437                 GNUNET_i2s (&address->peer), address->transport_name, session);
1438     return;
1439   }
1440
1441   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
1442   p->size = msize;
1443   p->is_init = GNUNET_NO;
1444   m = (struct AddressDestroyedMessage *) &p[1];
1445   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
1446   m->header.size = htons (msize);
1447   m->reserved = htonl (0);
1448   m->peer = address->peer;
1449   m->address_length = htons (address->address_length);
1450   m->plugin_name_length = htons (namelen);
1451
1452   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1453               "Deleting address for peer `%s', plugin `%s', session %p\n",
1454               GNUNET_i2s (&address->peer), address->transport_name, session);
1455
1456   m->session_id = htonl (s);
1457   pm = (char *) &m[1];
1458   memcpy (pm, address->address, address->address_length);
1459   memcpy (&pm[address->address_length], address->transport_name, namelen);
1460   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
1461   do_transmit (sh);
1462   remove_session (sh, s, &address->peer);
1463 }
1464
1465 /* end of ats_api_scheduling.c */