session pointers can rarely be identical due to timing issues
[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 /**
32  * Message in linked list we should send to the ATS service.  The
33  * actual binary message follows this struct.
34  */
35 struct PendingMessage
36 {
37
38   /**
39    * Kept in a DLL.
40    */
41   struct PendingMessage *next;
42
43   /**
44    * Kept in a DLL.
45    */
46   struct PendingMessage *prev;
47
48   /**
49    * Size of the message.
50    */
51   size_t size;
52
53   /**
54    * Is this the 'ATS_START' message?
55    */
56   int is_init;
57 };
58
59
60 /**
61  * Information we track per session.
62  */
63 struct SessionRecord
64 {
65   /**
66    * Identity of the peer (just needed for error checking).
67    */
68   struct GNUNET_PeerIdentity peer;
69
70   /**
71    * Session handle.
72    */
73   struct Session *session;
74
75   /**
76    * Set to GNUNET_YES if the slot is used.
77    */
78   int slot_used;
79 };
80
81
82 /**
83  * Handle to the ATS subsystem for bandwidth/transport scheduling information.
84  */
85 struct GNUNET_ATS_SchedulingHandle
86 {
87
88   /**
89    * Our configuration.
90    */
91   const struct GNUNET_CONFIGURATION_Handle *cfg;
92
93   /**
94    * Callback to invoke on suggestions.
95    */
96   GNUNET_ATS_AddressSuggestionCallback suggest_cb;
97
98   /**
99    * Closure for 'suggest_cb'.
100    */
101   void *suggest_cb_cls;
102
103   /**
104    * Connection to ATS service.
105    */
106   struct GNUNET_CLIENT_Connection *client;
107
108   /**
109    * Head of list of messages for the ATS service.
110    */
111   struct PendingMessage *pending_head;
112
113   /**
114    * Tail of list of messages for the ATS service
115    */
116   struct PendingMessage *pending_tail;
117
118   /**
119    * Current request for transmission to ATS.
120    */
121   struct GNUNET_CLIENT_TransmitHandle *th;
122
123   /**
124    * Array of session objects (we need to translate them to numbers and back
125    * for the protocol; the offset in the array is the session number on the
126    * network).  Index 0 is always NULL and reserved to represent the NULL pointer.
127    * Unused entries are also NULL.
128    */
129   struct SessionRecord *session_array;
130
131   /**
132    * Task to trigger reconnect.
133    */
134   GNUNET_SCHEDULER_TaskIdentifier task;
135
136   /**
137    * Size of the session array.
138    */
139   unsigned int session_array_size;
140
141   /**
142    * Should we reconnect to ATS due to some serious error?
143    */
144   int reconnect;
145 };
146
147
148 /**
149  * Re-establish the connection to the ATS service.
150  *
151  * @param sh handle to use to re-connect.
152  */
153 static void
154 reconnect (struct GNUNET_ATS_SchedulingHandle *sh);
155
156
157 /**
158  * Re-establish the connection to the ATS service.
159  *
160  * @param cls handle to use to re-connect.
161  * @param tc scheduler context
162  */
163 static void
164 reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
165 {
166   struct GNUNET_ATS_SchedulingHandle *sh = cls;
167
168   sh->task = GNUNET_SCHEDULER_NO_TASK;
169   reconnect (sh);
170 }
171
172
173 /**
174  * Disconnect from ATS and then reconnect.
175  *
176  * @param sh our handle
177  */
178 static void
179 force_reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
180 {
181   sh->reconnect = GNUNET_NO;
182   GNUNET_CLIENT_disconnect (sh->client, GNUNET_NO);
183   sh->client = NULL;
184   sh->task =
185       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect_task,
186                                     sh);
187 }
188
189
190 /**
191  * Transmit messages from the message queue to the service
192  * (if there are any, and if we are not already trying).
193  *
194  * @param sh handle to use
195  */
196 static void
197 do_transmit (struct GNUNET_ATS_SchedulingHandle *sh);
198
199
200 /**
201  * Type of a function to call when we receive a message
202  * from the service.
203  *
204  * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
205  * @param msg message received, NULL on timeout or fatal error
206  */
207 static void
208 process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg);
209
210
211 /**
212  * We can now transmit a message to ATS. Do it.
213  *
214  * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
215  * @param size number of bytes we can transmit to ATS
216  * @param buf where to copy the messages
217  * @return number of bytes copied into buf
218  */
219 static size_t
220 transmit_message_to_ats (void *cls, size_t size, void *buf)
221 {
222   struct GNUNET_ATS_SchedulingHandle *sh = cls;
223   struct PendingMessage *p;
224   size_t ret;
225   char *cbuf;
226
227   sh->th = NULL;
228   if ((size == 0) || (buf == NULL))
229   {
230     force_reconnect (sh);
231     return 0;
232   }
233   ret = 0;
234   cbuf = buf;
235   while ((NULL != (p = sh->pending_head)) && (p->size <= size))
236   {
237     memcpy (&cbuf[ret], &p[1], p->size);
238     ret += p->size;
239     size -= p->size;
240     GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
241     if (GNUNET_YES == p->is_init)
242       GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
243                              GNUNET_TIME_UNIT_FOREVER_REL);
244     GNUNET_free (p);
245   }
246   do_transmit (sh);
247   return ret;
248 }
249
250
251 /**
252  * Transmit messages from the message queue to the service
253  * (if there are any, and if we are not already trying).
254  *
255  * @param sh handle to use
256  */
257 static void
258 do_transmit (struct GNUNET_ATS_SchedulingHandle *sh)
259 {
260   struct PendingMessage *p;
261
262   if (NULL != sh->th)
263     return;
264   if (NULL == (p = sh->pending_head))
265     return;
266   if (NULL == sh->client)
267     return;                     /* currently reconnecting */
268   sh->th =
269       GNUNET_CLIENT_notify_transmit_ready (sh->client, p->size,
270                                            GNUNET_TIME_UNIT_FOREVER_REL,
271                                            GNUNET_NO, &transmit_message_to_ats,
272                                            sh);
273 }
274
275
276 /**
277  * Find the session object corresponding to the given session ID.
278  *
279  * @param sh our handle
280  * @param session_id current session ID
281  * @param peer peer the session belongs to
282  * @return the session object (or NULL)
283  */
284 static struct Session *
285 find_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
286               const struct GNUNET_PeerIdentity *peer)
287 {
288   if (session_id >= sh->session_array_size)
289   {
290     GNUNET_break (0);
291     return NULL;
292   }
293   if (0 == session_id)
294     return NULL;
295   /* Check if this session was:
296    *  removed by remove_session (transport service)
297    *  released by release_session (ATS)
298    *  */
299   if (sh->session_array[session_id].session == NULL)
300     return NULL;
301
302   return sh->session_array[session_id].session;
303 }
304
305
306 /**
307  * Get the ID for the given session object.  If we do not have an ID for
308  * the given session object, allocate one.
309  *
310  * @param sh our handle
311  * @param session session object
312  * @param peer peer the session belongs to
313  * @return the session id
314  */
315 static uint32_t
316 get_session_id (struct GNUNET_ATS_SchedulingHandle *sh, struct Session *session,
317                 const struct GNUNET_PeerIdentity *peer)
318 {
319   unsigned int i;
320   unsigned int f;
321
322   if (NULL == session)
323     return 0;
324   f = 0;
325   for (i = 1; i < sh->session_array_size; i++)
326   {
327     if (session == sh->session_array[i].session)
328     {
329       if (0 !=  memcmp (peer, &sh->session_array[i].peer,
330                              sizeof (struct GNUNET_PeerIdentity)))
331         continue;
332       else
333         return i;
334     }
335     if ((f == 0) && (sh->session_array[i].slot_used == GNUNET_NO))
336       f = i;
337   }
338   if (f == 0)
339   {
340     f = sh->session_array_size;
341     GNUNET_array_grow (sh->session_array, sh->session_array_size,
342                        sh->session_array_size * 2);
343   }
344   GNUNET_assert (f > 0);
345   sh->session_array[f].session = session;
346   sh->session_array[f].peer = *peer;
347   sh->session_array[f].slot_used = GNUNET_YES;
348   return f;
349 }
350
351
352 /**
353  * Remove the session of the given session ID from the session
354  * table (it is no longer valid).
355  *
356  * @param sh our handle
357  * @param session_id identifies session that is no longer valid
358  * @param peer peer the session belongs to
359  */
360 static void
361 remove_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
362                 const struct GNUNET_PeerIdentity *peer)
363 {
364   if (0 == session_id)
365     return;
366   GNUNET_assert (session_id < sh->session_array_size);
367   GNUNET_assert (GNUNET_YES == sh->session_array[session_id].slot_used);
368   GNUNET_assert (0 == memcmp (peer, &sh->session_array[session_id].peer,
369                          sizeof (struct GNUNET_PeerIdentity)));
370   sh->session_array[session_id].session = NULL;
371 }
372
373
374 /**
375  * Release the session slot from the session table (ATS service is
376  * also done using it).
377  *
378  * @param sh our handle
379  * @param session_id identifies session that is no longer valid
380  * @param peer peer the session belongs to
381  */
382 static void
383 release_session (struct GNUNET_ATS_SchedulingHandle *sh, uint32_t session_id,
384                  const struct GNUNET_PeerIdentity *peer)
385 {
386   if (session_id >= sh->session_array_size)
387   {
388     GNUNET_break (0);
389     sh->reconnect = GNUNET_YES;
390     return;
391   }
392
393   /* this slot should have been removed from remove_session before */
394   GNUNET_assert (sh->session_array[session_id].session == NULL);
395
396   if (0 != memcmp (peer, &sh->session_array[session_id].peer,
397               sizeof (struct GNUNET_PeerIdentity)))
398   {
399     GNUNET_break (0);
400     sh->reconnect = GNUNET_YES;
401     return;
402   }
403   sh->session_array[session_id].slot_used = GNUNET_NO;
404   memset (&sh->session_array[session_id].peer, 0,
405           sizeof (struct GNUNET_PeerIdentity));
406 }
407
408
409 static void
410 process_release_message (struct GNUNET_ATS_SchedulingHandle *sh,
411                          const struct SessionReleaseMessage *srm)
412 {
413   release_session (sh, ntohl (srm->session_id), &srm->peer);
414 }
415
416
417 /**
418  * Type of a function to call when we receive a message
419  * from the service.
420  *
421  * @param cls the 'struct GNUNET_ATS_SchedulingHandle'
422  * @param msg message received, NULL on timeout or fatal error
423  */
424 static void
425 process_ats_message (void *cls, const struct GNUNET_MessageHeader *msg)
426 {
427   struct GNUNET_ATS_SchedulingHandle *sh = cls;
428   const struct AddressSuggestionMessage *m;
429   const struct GNUNET_ATS_Information *atsi;
430   const char *plugin_address;
431   const char *plugin_name;
432   uint16_t plugin_address_length;
433   uint16_t plugin_name_length;
434   uint32_t ats_count;
435   struct GNUNET_HELLO_Address address;
436
437   if (NULL == msg)
438   {
439     force_reconnect (sh);
440     return;
441   }
442   if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE) &&
443       (ntohs (msg->size) == sizeof (struct SessionReleaseMessage)))
444   {
445     process_release_message (sh, (const struct SessionReleaseMessage *) msg);
446     GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
447                            GNUNET_TIME_UNIT_FOREVER_REL);
448     if (GNUNET_YES == sh->reconnect)
449       force_reconnect (sh);
450     return;
451   }
452   if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION) ||
453       (ntohs (msg->size) <= sizeof (struct AddressSuggestionMessage)))
454   {
455     GNUNET_break (0);
456     force_reconnect (sh);
457     return;
458   }
459   m = (const struct AddressSuggestionMessage *) msg;
460   ats_count = ntohl (m->ats_count);
461   plugin_address_length = ntohs (m->address_length);
462   atsi = (const struct GNUNET_ATS_Information *) &m[1];
463   plugin_address = (const char *) &atsi[ats_count];
464   plugin_name = &plugin_address[plugin_address_length];
465   plugin_name_length = ntohs (m->plugin_name_length);
466   if ((plugin_address_length + plugin_name_length +
467        ats_count * sizeof (struct GNUNET_ATS_Information) +
468        sizeof (struct AddressSuggestionMessage) != ntohs (msg->size)) ||
469       (ats_count >
470        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information))
471       || (plugin_name[plugin_name_length - 1] != '\0'))
472   {
473     GNUNET_break (0);
474     force_reconnect (sh);
475     return;
476   }
477   uint32_t session_id =  ntohl (m->session_id);
478
479   struct Session * s = NULL;
480   if (session_id == 0)
481     s = NULL;
482   else
483   {
484     s = find_session (sh, session_id, &m->peer);
485     if (s == NULL)
486     {
487       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS tries to use outdated session `%s'\n", GNUNET_i2s(&m->peer));
488       //GNUNET_break (0);
489       return;
490     }
491   }
492   address.peer = m->peer;
493   address.address = plugin_address;
494   address.address_length = plugin_address_length;
495   address.transport_name = plugin_name;
496   sh->suggest_cb (sh->suggest_cb_cls, &address, s, m->bandwidth_out,
497                   m->bandwidth_in, atsi, ats_count);
498
499   GNUNET_CLIENT_receive (sh->client, &process_ats_message, sh,
500                          GNUNET_TIME_UNIT_FOREVER_REL);
501   if (GNUNET_YES == sh->reconnect)
502     force_reconnect (sh);
503 }
504
505
506 /**
507  * Re-establish the connection to the ATS service.
508  *
509  * @param sh handle to use to re-connect.
510  */
511 static void
512 reconnect (struct GNUNET_ATS_SchedulingHandle *sh)
513 {
514   struct PendingMessage *p;
515   struct ClientStartMessage *init;
516
517   GNUNET_assert (NULL == sh->client);
518   sh->client = GNUNET_CLIENT_connect ("ats", sh->cfg);
519   GNUNET_assert (NULL != sh->client);
520   if ((NULL == (p = sh->pending_head)) || (GNUNET_YES != p->is_init))
521   {
522     p = GNUNET_malloc (sizeof (struct PendingMessage) +
523                        sizeof (struct ClientStartMessage));
524     p->size = sizeof (struct ClientStartMessage);
525     p->is_init = GNUNET_YES;
526     init = (struct ClientStartMessage *) &p[1];
527     init->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_START);
528     init->header.size = htons (sizeof (struct ClientStartMessage));
529     init->start_flag = htonl (START_FLAG_SCHEDULING);
530     GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, p);
531   }
532   do_transmit (sh);
533 }
534
535
536 /**
537  * Initialize the ATS subsystem.
538  *
539  * @param cfg configuration to use
540  * @param suggest_cb notification to call whenever the suggestation changed
541  * @param suggest_cb_cls closure for 'suggest_cb'
542  * @return ats context
543  */
544 struct GNUNET_ATS_SchedulingHandle *
545 GNUNET_ATS_scheduling_init (const struct GNUNET_CONFIGURATION_Handle *cfg,
546                             GNUNET_ATS_AddressSuggestionCallback suggest_cb,
547                             void *suggest_cb_cls)
548 {
549   struct GNUNET_ATS_SchedulingHandle *sh;
550
551   sh = GNUNET_malloc (sizeof (struct GNUNET_ATS_SchedulingHandle));
552   sh->cfg = cfg;
553   sh->suggest_cb = suggest_cb;
554   sh->suggest_cb_cls = suggest_cb_cls;
555   GNUNET_array_grow (sh->session_array, sh->session_array_size, 4);
556   reconnect (sh);
557   return sh;
558 }
559
560
561 /**
562  * Client is done with ATS scheduling, release resources.
563  *
564  * @param sh handle to release
565  */
566 void
567 GNUNET_ATS_scheduling_done (struct GNUNET_ATS_SchedulingHandle *sh)
568 {
569   struct PendingMessage *p;
570
571   while (NULL != (p = sh->pending_head))
572   {
573     GNUNET_CONTAINER_DLL_remove (sh->pending_head, sh->pending_tail, p);
574     GNUNET_free (p);
575   }
576   if (NULL != sh->client)
577   {
578     GNUNET_CLIENT_disconnect (sh->client, GNUNET_NO);
579     sh->client = NULL;
580   }
581   if (GNUNET_SCHEDULER_NO_TASK != sh->task)
582   {
583     GNUNET_SCHEDULER_cancel (sh->task);
584     sh->task = GNUNET_SCHEDULER_NO_TASK;
585   }
586   GNUNET_array_grow (sh->session_array, sh->session_array_size, 0);
587   GNUNET_free (sh);
588 }
589
590
591 /**
592  * We would like to establish a new connection with a peer.  ATS
593  * should suggest a good address to begin with.
594  *
595  * @param sh handle
596  * @param peer identity of the peer we need an address for
597  */
598 void
599 GNUNET_ATS_suggest_address (struct GNUNET_ATS_SchedulingHandle *sh,
600                             const struct GNUNET_PeerIdentity *peer)
601 {
602   struct PendingMessage *p;
603   struct RequestAddressMessage *m;
604
605   p = GNUNET_malloc (sizeof (struct PendingMessage) +
606                      sizeof (struct RequestAddressMessage));
607   p->size = sizeof (struct RequestAddressMessage);
608   p->is_init = GNUNET_NO;
609   m = (struct RequestAddressMessage *) &p[1];
610   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS);
611   m->header.size = htons (sizeof (struct RequestAddressMessage));
612   m->reserved = htonl (0);
613   m->peer = *peer;
614   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
615   do_transmit (sh);
616 }
617
618
619 /**
620  * We would like to stop receiving address updates for this peer
621  *
622  * @param sh handle
623  * @param peer identity of the peer
624  */
625 void
626 GNUNET_ATS_suggest_address_cancel (struct GNUNET_ATS_SchedulingHandle *sh,
627                                    const struct GNUNET_PeerIdentity *peer)
628 {
629   struct PendingMessage *p;
630   struct RequestAddressMessage *m;
631
632   p = GNUNET_malloc (sizeof (struct PendingMessage) +
633                      sizeof (struct RequestAddressMessage));
634   p->size = sizeof (struct RequestAddressMessage);
635   p->is_init = GNUNET_NO;
636   m = (struct RequestAddressMessage *) &p[1];
637   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL);
638   m->header.size = htons (sizeof (struct RequestAddressMessage));
639   m->reserved = htonl (0);
640   m->peer = *peer;
641   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
642   do_transmit (sh);
643 }
644
645 /**
646  * We have updated performance statistics for a given address.  Note
647  * that this function can be called for addresses that are currently
648  * in use as well as addresses that are valid but not actively in use.
649  * Furthermore, the peer may not even be connected to us right now (in
650  * which case the call may be ignored or the information may be stored
651  * for later use).  Update bandwidth assignments.
652  *
653  * @param sh handle
654  * @param address the address
655  * @param session session handle (if available)
656  * @param ats performance data for the address
657  * @param ats_count number of performance records in 'ats'
658  */
659 void
660 GNUNET_ATS_address_update (struct GNUNET_ATS_SchedulingHandle *sh,
661                            const struct GNUNET_HELLO_Address *address,
662                            struct Session *session,
663                            const struct GNUNET_ATS_Information *ats,
664                            uint32_t ats_count)
665 {
666   struct PendingMessage *p;
667   struct AddressUpdateMessage *m;
668   struct GNUNET_ATS_Information *am;
669   char *pm;
670   size_t namelen;
671   size_t msize;
672
673   namelen = (address->transport_name == NULL) ? 0 : strlen (address->transport_name) + 1;
674   msize =
675       sizeof (struct AddressUpdateMessage) + address->address_length +
676       ats_count * sizeof (struct GNUNET_ATS_Information) + namelen;
677   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
678       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
679       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
680       (ats_count >=
681        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)))
682   {
683     GNUNET_break (0);
684     return;
685   }
686
687   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
688   p->size = msize;
689   p->is_init = GNUNET_NO;
690   m = (struct AddressUpdateMessage *) &p[1];
691   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE);
692   m->header.size = htons (msize);
693   m->ats_count = htonl (ats_count);
694   m->peer = address->peer;
695   m->address_length = htons (address->address_length);
696   m->plugin_name_length = htons (namelen);
697   m->session_id = htonl (get_session_id (sh, session, &address->peer));
698   am = (struct GNUNET_ATS_Information *) &m[1];
699   memcpy (am, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
700   pm = (char *) &am[ats_count];
701   memcpy (pm, address->address, address->address_length);
702   memcpy (&pm[address->address_length], address->transport_name, namelen);
703   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
704   do_transmit (sh);
705 }
706
707
708 /**
709  * An address is now in use or not used any more.
710  *
711  * @param sh handle
712  * @param address the address
713  * @param session session handle
714  * @param in_use GNUNET_YES if this address is now used, GNUNET_NO
715  * if address is not used any more
716  */
717 void
718 GNUNET_ATS_address_in_use (struct GNUNET_ATS_SchedulingHandle *sh,
719                            const struct GNUNET_HELLO_Address *address,
720                            struct Session *session,
721                            int in_use)
722 {
723   struct PendingMessage *p;
724   struct AddressUseMessage *m;
725   char *pm;
726   size_t namelen;
727   size_t msize;
728
729   GNUNET_assert (NULL != address);
730   namelen = (address->transport_name == NULL) ? 0 : strlen (address->transport_name) + 1;
731   msize = sizeof (struct AddressUseMessage) + address->address_length + namelen;
732   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
733       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
734       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
735   {
736     GNUNET_break (0);
737     return;
738   }
739
740   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
741   p->size = msize;
742   p->is_init = GNUNET_NO;
743   m = (struct AddressUseMessage *) &p[1];
744   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_IN_USE);
745   m->header.size = htons (msize);
746   m->peer = address->peer;
747   m->in_use = htons (in_use);
748   m->address_length = htons (address->address_length);
749   m->plugin_name_length = htons (namelen);
750   m->session_id = htonl (get_session_id (sh, session, &address->peer));
751   pm = (char *) &m[1];
752   memcpy (pm, address->address, address->address_length);
753   memcpy (&pm[address->address_length], address->transport_name, namelen);
754   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
755
756   do_transmit (sh);
757 }
758
759 /**
760  * A session got destroyed, stop including it as a valid address.
761  *
762  * @param sh handle
763  * @param address the address
764  * @param session session handle that is no longer valid
765  */
766 void
767 GNUNET_ATS_address_destroyed (struct GNUNET_ATS_SchedulingHandle *sh,
768                               const struct GNUNET_HELLO_Address *address,
769                               struct Session *session)
770 {
771   struct PendingMessage *p;
772   struct AddressDestroyedMessage *m;
773   char *pm;
774   size_t namelen;
775   size_t msize;
776   uint32_t session_id;
777
778   namelen = (address->transport_name == NULL) ? 0 : strlen (address->transport_name) + 1;
779   msize = sizeof (struct AddressDestroyedMessage) + address->address_length + namelen;
780   if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
781       (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
782       (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
783   {
784     GNUNET_break (0);
785     return;
786   }
787
788
789   p = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
790   p->size = msize;
791   p->is_init = GNUNET_NO;
792   m = (struct AddressDestroyedMessage *) &p[1];
793   m->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED);
794   m->header.size = htons (msize);
795   m->reserved = htonl (0);
796   m->peer = address->peer;
797   m->address_length = htons (address->address_length);
798   m->plugin_name_length = htons (namelen);
799   session_id = get_session_id (sh, session, &address->peer);
800   m->session_id = htonl (session_id);
801   pm = (char *) &m[1];
802   memcpy (pm, address->address, address->address_length);
803   memcpy (&pm[address->address_length], address->transport_name, namelen);
804   GNUNET_CONTAINER_DLL_insert_tail (sh->pending_head, sh->pending_tail, p);
805   do_transmit (sh);
806   remove_session (sh, session_id, &address->peer);
807 }
808
809 /* end of ats_api_scheduling.c */