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