-doxygen, indentation
[oweals/gnunet.git] / src / ats / gnunet-service-ats_performance.c
1 /*
2      This file is part of GNUnet.
3      (C) 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 /**
22  * @file ats/gnunet-service-ats_performance.c
23  * @brief ats service, interaction with 'performance' API
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet-service-ats.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet-service-ats_performance.h"
31 #include "gnunet-service-ats_reservations.h"
32 #include "ats.h"
33
34 /**
35  * We keep clients that are interested in performance in a linked list.
36  */
37 struct PerformanceClient
38 {
39   /**
40    * Next in doubly-linked list.
41    */
42   struct PerformanceClient *next;
43
44   /**
45    * Previous in doubly-linked list.
46    */
47   struct PerformanceClient *prev;
48
49   /**
50    * Actual handle to the client.
51    */
52   struct GNUNET_SERVER_Client *client;
53
54   /**
55    * Options for the client.
56    */
57   enum StartFlag flag;
58
59 };
60
61
62 /**
63  * We keep clients that are interested in performance in a linked list.
64  */
65 struct AddressIteration
66 {
67   /**
68    * Actual handle to the client.
69    */
70   struct PerformanceClient *pc;
71
72   int all;
73
74   uint32_t id;
75
76   unsigned int msg_type;
77 };
78
79 /**
80  * Address handle
81  */
82 static struct GAS_Addresses_Handle *GSA_addresses;
83
84 /**
85  * Head of linked list of all clients to this service.
86  */
87 static struct PerformanceClient *pc_head;
88
89 /**
90  * Tail of linked list of all clients to this service.
91  */
92 static struct PerformanceClient *pc_tail;
93
94 /**
95  * Context for sending messages to performance clients.
96  */
97 static struct GNUNET_SERVER_NotificationContext *nc;
98
99
100 /**
101  * Find the performance client associated with the given handle.
102  *
103  * @param client server handle
104  * @return internal handle
105  */
106 static struct PerformanceClient *
107 find_client (struct GNUNET_SERVER_Client *client)
108 {
109   struct PerformanceClient *pc;
110
111   for (pc = pc_head; pc != NULL; pc = pc->next)
112     if (pc->client == client)
113       return pc;
114   return NULL;
115 }
116
117
118 /**
119  * Unregister a client (which may have been a performance client,
120  * but this is not assured).
121  *
122  * @param client handle of the (now dead) client
123  */
124 void
125 GAS_performance_remove_client (struct GNUNET_SERVER_Client *client)
126 {
127   struct PerformanceClient *pc;
128
129   pc = find_client (client);
130   if (NULL == pc)
131     return;
132   GNUNET_CONTAINER_DLL_remove (pc_head, pc_tail, pc);
133   GAS_addresses_preference_client_disconnect (GSA_addresses, client);
134   GNUNET_free (pc);
135 }
136
137
138 /**
139  * Transmit the given performance information to all performance
140  * clients.
141  *
142  * @param pc performance client to send to
143  * @param peer peer for which this is an address suggestion
144  * @param plugin_name 0-termintated string specifying the transport plugin
145  * @param plugin_addr binary address for the plugin to use
146  * @param plugin_addr_len number of bytes in plugin_addr
147  * @param active #GNUNET_YES if this address is actively used
148  *        to maintain a connection to a peer;
149  *        #GNUNET_NO if the address is not actively used;
150  *        #GNUNET_SYSERR if this address is no longer available for ATS
151  * @param atsi performance data for the address
152  * @param atsi_count number of performance records in @a atsi
153  * @param bandwidth_out assigned outbound bandwidth
154  * @param bandwidth_in assigned inbound bandwidth
155  */
156 void
157 GAS_performance_notify_client (struct PerformanceClient *pc,
158                                const struct GNUNET_PeerIdentity *peer,
159                                const char *plugin_name,
160                                const void *plugin_addr,
161                                size_t plugin_addr_len,
162                                int active,
163                                const struct GNUNET_ATS_Information *atsi,
164                                uint32_t atsi_count,
165                                struct GNUNET_BANDWIDTH_Value32NBO
166                                bandwidth_out,
167                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
168 {
169
170   struct PeerInformationMessage *msg;
171   size_t plugin_name_length = strlen (plugin_name) + 1;
172   size_t msize =
173       sizeof (struct PeerInformationMessage) +
174       atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len +
175       plugin_name_length;
176   char buf[msize] GNUNET_ALIGN;
177   struct GNUNET_ATS_Information *atsp;
178   char *addrp;
179
180   GNUNET_assert (NULL != pc);
181   if (NULL == find_client (pc->client))
182     return; /* Client disconnected */
183
184   GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
185   GNUNET_assert (atsi_count <
186                  GNUNET_SERVER_MAX_MESSAGE_SIZE /
187                  sizeof (struct GNUNET_ATS_Information));
188   msg = (struct PeerInformationMessage *) buf;
189   msg->header.size = htons (msize);
190   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION);
191   msg->id = htonl (0);
192   msg->ats_count = htonl (atsi_count);
193   msg->peer = *peer;
194   msg->address_length = htons (plugin_addr_len);
195   msg->address_active = ntohl ((uint32_t) active);
196   msg->plugin_name_length = htons (plugin_name_length);
197   msg->bandwidth_out = bandwidth_out;
198   msg->bandwidth_in = bandwidth_in;
199   atsp = (struct GNUNET_ATS_Information *) &msg[1];
200   memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
201   addrp = (char *) &atsp[atsi_count];
202   memcpy (addrp, plugin_addr, plugin_addr_len);
203   strcpy (&addrp[plugin_addr_len], plugin_name);
204   GNUNET_SERVER_notification_context_unicast (nc,
205                                               pc->client,
206                                               &msg->header,
207                                               GNUNET_YES);
208 }
209
210
211 /**
212  * Transmit the given performance information to all performance
213  * clients.
214  *
215  * @param peer peer for which this is an address suggestion
216  * @param plugin_name 0-termintated string specifying the transport plugin
217  * @param plugin_addr binary address for the plugin to use
218  * @param plugin_addr_len number of bytes in @a plugin_addr
219  * @param active #GNUNET_YES if this address is actively used
220  *        to maintain a connection to a peer;
221  *        #GNUNET_NO if the address is not actively used;
222  *        #GNUNET_SYSERR if this address is no longer available for ATS
223  * @param atsi performance data for the address
224  * @param atsi_count number of performance records in @a atsi
225  * @param bandwidth_out assigned outbound bandwidth
226  * @param bandwidth_in assigned inbound bandwidth
227  */
228 void
229 GAS_performance_notify_all_clients (const struct GNUNET_PeerIdentity *peer,
230                                     const char *plugin_name,
231                                     const void *plugin_addr,
232                                     size_t plugin_addr_len,
233                                     int active,
234                                     const struct GNUNET_ATS_Information *atsi,
235                                     uint32_t atsi_count,
236                                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
237                                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
238 {
239   struct PerformanceClient *pc;
240
241   for (pc = pc_head; pc != NULL; pc = pc->next)
242     if (pc->flag == START_FLAG_PERFORMANCE_WITH_PIC)
243     {
244         GAS_performance_notify_client (pc,
245                                        peer,
246                                        plugin_name,
247                                        plugin_addr,
248                                        plugin_addr_len,
249                                        active,
250                                        atsi, atsi_count,
251                                        bandwidth_out, bandwidth_in);
252     }
253   GNUNET_STATISTICS_update (GSA_stats,
254                             "# performance updates given to clients", 1,
255                             GNUNET_NO);
256 }
257
258
259
260 /**
261  * Iterator for called from #GAS_addresses_get_peer_info()
262  *
263  * @param cls closure with the `struct PerformanceClient *`
264  * @param id the peer id
265  * @param plugin_name plugin name
266  * @param plugin_addr address
267  * @param plugin_addr_len length of @a plugin_addr
268  * @param active is address actively used
269  * @param atsi ats performance information
270  * @param atsi_count number of ats performance elements in @a atsi
271  * @param bandwidth_out current outbound bandwidth assigned to address
272  * @param bandwidth_in current inbound bandwidth assigned to address
273  */
274 static void
275 peerinfo_it (void *cls,
276              const struct GNUNET_PeerIdentity *id,
277              const char *plugin_name,
278              const void *plugin_addr,
279              size_t plugin_addr_len,
280              int active,
281              const struct GNUNET_ATS_Information *atsi,
282              uint32_t atsi_count,
283              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
284              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
285 {
286   struct PerformanceClient *pc = cls;
287
288   GNUNET_assert (NULL != pc);
289   if (NULL == id)
290     return;
291   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
292               "Callback for peer `%s' plugin `%s' BW out %u, BW in %u \n",
293               GNUNET_i2s (id),
294               plugin_name,
295               (unsigned int) ntohl (bandwidth_out.value__),
296               (unsigned int) ntohl (bandwidth_in.value__));
297   GAS_performance_notify_client(pc,
298                                 id,
299                                 plugin_name,
300                                 plugin_addr,
301                                 plugin_addr_len,
302                                 active,
303                                 atsi, atsi_count,
304                                 bandwidth_out, bandwidth_in);
305 }
306
307
308 /**
309  * Iterator for #GAS_performance_add_client()
310  *
311  * @param cls the client requesting information
312  * @param id result
313  */
314 static void
315 peer_it (void *cls,
316          const struct GNUNET_PeerIdentity *id)
317 {
318   struct PerformanceClient *pc = cls;
319
320   if (NULL != id)
321   {
322     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323                 "Callback for peer `%s'\n",
324                 GNUNET_i2s (id));
325     GAS_addresses_get_peer_info (GSA_addresses, id,
326                                  &peerinfo_it, pc);
327   }
328 }
329
330
331 /**
332  * Register a new performance client.
333  *
334  * @param client handle of the new client
335  * @param flag flag specifying the type of the client
336  */
337 void
338 GAS_performance_add_client (struct GNUNET_SERVER_Client *client,
339                             enum StartFlag flag)
340 {
341   struct PerformanceClient *pc;
342   GNUNET_break (NULL == find_client (client));
343
344   pc = GNUNET_new (struct PerformanceClient);
345   pc->client = client;
346   pc->flag = flag;
347
348   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
349               "Adding performance client %s PIC\n",
350               (flag == START_FLAG_PERFORMANCE_WITH_PIC) ? "with" : "without");
351
352   GNUNET_SERVER_notification_context_add (nc, client);
353   GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc);
354
355   /* Send information about clients */
356   GAS_addresses_iterate_peers (GSA_addresses,
357                                &peer_it,
358                                pc);
359 }
360
361
362 /**
363  * Send a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE with the
364  * given address details to the client identified in @a ai.
365  *
366  * @param ai our address information context (identifies the client)
367  * @param id the peer id this address is for
368  * @param plugin_name name of the plugin that supports this address
369  * @param plugin_addr address
370  * @param plugin_addr_len length of @a plugin_addr
371  * @param active #GNUNET_YES if this address is actively used
372  * @param atsi ats performance information
373  * @param atsi_count number of ats performance elements in @a atsi
374  * @param bandwidth_out current outbound bandwidth assigned to address
375  * @param bandwidth_in current inbound bandwidth assigned to address
376  */
377 static void
378 transmit_req_addr (struct AddressIteration *ai,
379                    const struct GNUNET_PeerIdentity *id,
380                    const char *plugin_name,
381                    const void *plugin_addr,
382                    size_t plugin_addr_len,
383                    int active,
384                    const struct GNUNET_ATS_Information *atsi,
385                    uint32_t atsi_count,
386                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
387                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
388
389 {
390   struct GNUNET_ATS_Information *atsp;
391   struct PeerInformationMessage *msg;
392   char *addrp;
393   size_t plugin_name_length;
394   size_t msize;
395
396   if (NULL != plugin_name)
397     plugin_name_length = strlen (plugin_name) + 1;
398   else
399     plugin_name_length = 0;
400   msize = sizeof (struct PeerInformationMessage) +
401           atsi_count * sizeof (struct GNUNET_ATS_Information) +
402           plugin_addr_len + plugin_name_length;
403   char buf[msize] GNUNET_ALIGN;
404
405   GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
406   GNUNET_assert (atsi_count <
407                  GNUNET_SERVER_MAX_MESSAGE_SIZE /
408                  sizeof (struct GNUNET_ATS_Information));
409   msg = (struct PeerInformationMessage *) buf;
410   msg->header.size = htons (msize);
411   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
412   msg->ats_count = htonl (atsi_count);
413   msg->id = htonl (ai->id);
414   if (NULL != id)
415     msg->peer = *id;
416   else
417     memset (&msg->peer, '\0', sizeof (struct GNUNET_PeerIdentity));
418   msg->address_length = htons (plugin_addr_len);
419   msg->address_active = ntohl (active);
420   msg->plugin_name_length = htons (plugin_name_length);
421   msg->bandwidth_out = bandwidth_out;
422   msg->bandwidth_in = bandwidth_in;
423   atsp = (struct GNUNET_ATS_Information *) &msg[1];
424   memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
425   addrp = (char *) &atsp[atsi_count];
426   if (NULL != plugin_addr)
427     memcpy (addrp, plugin_addr, plugin_addr_len);
428   if (NULL != plugin_name)
429     strcpy (&addrp[plugin_addr_len], plugin_name);
430   GNUNET_SERVER_notification_context_unicast (nc, ai->pc->client, &msg->header,
431                                               GNUNET_NO);
432 }
433
434
435 /**
436  * Iterator for #GAS_addresses_get_peer_info()
437  *
438  * @param cls closure with our `struct AddressIteration *`
439  * @param id the peer id
440  * @param plugin_name plugin name
441  * @param plugin_addr address
442  * @param plugin_addr_len length of @a plugin_addr
443  * @param active is address actively used
444  * @param atsi ats performance information
445  * @param atsi_count number of ats performance elements in @a atsi
446  * @param bandwidth_out current outbound bandwidth assigned to address
447  * @param bandwidth_in current inbound bandwidth assigned to address
448  */
449 static void
450 req_addr_peerinfo_it (void *cls,
451                       const struct GNUNET_PeerIdentity *id,
452                       const char *plugin_name,
453                       const void *plugin_addr, size_t plugin_addr_len,
454                       int active,
455                       const struct GNUNET_ATS_Information *atsi,
456                       uint32_t atsi_count,
457                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
458                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
459 {
460   struct AddressIteration *ai = cls;
461
462   GNUNET_assert (NULL != ai);
463   GNUNET_assert (NULL != ai->pc);
464   if (NULL == find_client (ai->pc->client))
465     return; /* Client disconnected */
466
467   if ((NULL == id) && (NULL == plugin_name) && (NULL == plugin_addr))
468   {
469     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470                 "Address iteration done\n");
471     return;
472   }
473   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474               "Callback for  %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
475               (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
476               GNUNET_i2s (id),
477               plugin_name,
478               (unsigned int) ntohl (bandwidth_out.value__),
479               (unsigned int) ntohl (bandwidth_in.value__));
480
481   /* Transmit result */
482   if ((GNUNET_YES == ai->all) || (GNUNET_YES == active))
483   {
484     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
485                 "Sending result for  %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
486                 (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
487                 GNUNET_i2s (id),
488                 plugin_name,
489                 (unsigned int) ntohl (bandwidth_out.value__),
490                 (unsigned int) ntohl (bandwidth_in.value__));
491     transmit_req_addr (ai,
492                        id,
493                        plugin_name,
494                        plugin_addr, plugin_addr_len,
495                        active,
496                        atsi,
497                        atsi_count,
498                        bandwidth_out, bandwidth_in);
499   }
500 }
501
502
503 /**
504  * Iterator for GAS_handle_request_address_list
505  *
506  * @param cls the client requesting information, a `struct AddressIteration *`
507  * @param id result
508  */
509 static void
510 req_addr_peer_it (void *cls,
511                   const struct GNUNET_PeerIdentity *id)
512 {
513   struct AddressIteration *ai = cls;
514
515   if (NULL == id)
516   {
517     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518                 "Peer iteration done\n");
519     return;
520   }
521   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
522               "Callback for peer `%s'\n",
523               GNUNET_i2s (id));
524   GAS_addresses_get_peer_info (GSA_addresses, id,
525                                &req_addr_peerinfo_it, ai);
526 }
527
528
529 /**
530  * Handle 'address list request' messages from clients.
531  *
532  * @param cls unused, NULL
533  * @param client client that sent the request
534  * @param message the request message
535  */
536 void
537 GAS_handle_request_address_list (void *cls,
538                                  struct GNUNET_SERVER_Client *client,
539                                  const struct GNUNET_MessageHeader *message)
540 {
541   struct PerformanceClient *pc;
542   struct AddressIteration ai;
543   struct AddressListRequestMessage * alrm = (struct AddressListRequestMessage *) message;
544   struct GNUNET_PeerIdentity allzeros;
545   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
546
547   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548               "Received `%s' message\n",
549               "ADDRESSLIST_REQUEST");
550   if (NULL == (pc = find_client(client)))
551   {
552     GNUNET_break (0);
553     return;
554   }
555
556   ai.all = ntohl (alrm->all);
557   ai.id = ntohl (alrm->id);
558   ai.pc = pc;
559
560   memset (&allzeros, '\0', sizeof (struct GNUNET_PeerIdentity));
561   bandwidth_zero.value__ = htonl (0);
562   if (0 == memcmp (&alrm->peer,
563                    &allzeros,
564                    sizeof (struct GNUNET_PeerIdentity)))
565   {
566     /* Return addresses for all peers */
567     GAS_addresses_iterate_peers (GSA_addresses, &req_addr_peer_it, &ai);
568     transmit_req_addr (&ai, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0,
569                        bandwidth_zero, bandwidth_zero);
570   }
571   else
572   {
573     /* Return addresses for a specific peer */
574     GAS_addresses_get_peer_info (GSA_addresses,
575                                  &alrm->peer,
576                                  &req_addr_peerinfo_it, &ai);
577     transmit_req_addr (&ai, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0,
578                        bandwidth_zero, bandwidth_zero);
579   }
580   GNUNET_SERVER_receive_done (client, GNUNET_OK);
581 }
582
583
584 /**
585  * FIXME.
586  */
587 void
588 GAS_handle_performance_update (struct GNUNET_PeerIdentity *peer,
589                                const char *plugin_name,
590                                const void *plugin_addr, size_t plugin_addr_len,
591                                int active,
592                                struct GNUNET_ATS_Information *ats,
593                                uint32_t ats_count,
594                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
595                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
596 {
597   /* Notify here */
598   GAS_performance_notify_all_clients (peer,
599                                       plugin_name,
600                                       plugin_addr,
601                                       plugin_addr_len,
602                                       active,
603                                       ats, ats_count,
604                                       bandwidth_out,
605                                       bandwidth_in);
606
607 #if 0
608   struct PerformanceClient *cur;
609   struct PerformanceMonitorClient *curm;
610   struct MonitorResponseMessage *mrm;
611   size_t msglen;
612
613   msglen = sizeof (struct MonitorResponseMessage) +
614   ats_count * sizeof (struct GNUNET_ATS_Information);
615   mrm = GNUNET_malloc (msglen);
616
617   mrm->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_MONITOR_RESPONSE);
618   mrm->header.size = htons (msglen);
619   mrm->ats_count = htonl (ats_count);
620   mrm->peer = *peer;
621   memcpy (&mrm[1], ats, ats_count * sizeof (struct GNUNET_ATS_Information));
622
623   for (cur = pc_head; NULL != cur; cur = cur->next)
624   for (curm = cur->pm_head; NULL != curm; curm = curm->next)
625   {
626     /* Notify client about update */
627     mrm->id = htonl (curm->id);
628     GNUNET_SERVER_notification_context_unicast (nc,
629         cur->client,
630         (struct GNUNET_MessageHeader *) mrm,
631         GNUNET_YES);
632   }
633   GNUNET_free (mrm);
634 #endif
635 }
636
637
638 /**
639  * Handle 'reservation request' messages from clients.
640  *
641  * @param cls unused, NULL
642  * @param client client that sent the request
643  * @param message the request message
644  */
645 void
646 GAS_handle_reservation_request (void *cls,
647                                 struct GNUNET_SERVER_Client *client,
648                                 const struct GNUNET_MessageHeader *message)
649 {
650   const struct ReservationRequestMessage *msg =
651       (const struct ReservationRequestMessage *) message;
652   struct ReservationResultMessage result;
653   int32_t amount;
654   struct GNUNET_TIME_Relative res_delay;
655
656   if (NULL == find_client (client))
657   {
658     /* missing start message! */
659     GNUNET_break (0);
660     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
661     return;
662   }
663   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664               "Received `%s' message\n",
665               "RESERVATION_REQUEST");
666   amount = (int32_t) ntohl (msg->amount);
667   res_delay = GAS_reservations_reserve (&msg->peer, amount);
668   if (res_delay.rel_value_us > 0)
669     amount = 0;
670   result.header.size = htons (sizeof (struct ReservationResultMessage));
671   result.header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT);
672   result.amount = htonl (amount);
673   result.peer = msg->peer;
674   result.res_delay = GNUNET_TIME_relative_hton (res_delay);
675   GNUNET_STATISTICS_update (GSA_stats,
676                             "# reservation requests processed", 1,
677                             GNUNET_NO);
678   GNUNET_SERVER_notification_context_unicast (nc, client, &result.header,
679                                               GNUNET_NO);
680   GNUNET_SERVER_receive_done (client, GNUNET_OK);
681 }
682
683
684 /**
685  * Handle 'preference change' messages from clients.
686  *
687  * @param cls unused, NULL
688  * @param client client that sent the request
689  * @param message the request message
690  */
691 void
692 GAS_handle_preference_change (void *cls,
693                               struct GNUNET_SERVER_Client *client,
694                               const struct GNUNET_MessageHeader *message)
695 {
696   const struct ChangePreferenceMessage *msg;
697   const struct PreferenceInformation *pi;
698   uint16_t msize;
699   uint32_t nump;
700   uint32_t i;
701
702   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
703               "PREFERENCE_CHANGE");
704   msize = ntohs (message->size);
705   if (msize < sizeof (struct ChangePreferenceMessage))
706   {
707     GNUNET_break (0);
708     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
709     return;
710   }
711   msg = (const struct ChangePreferenceMessage *) message;
712   nump = ntohl (msg->num_preferences);
713   if (msize !=
714       sizeof (struct ChangePreferenceMessage) +
715       nump * sizeof (struct PreferenceInformation))
716   {
717     GNUNET_break (0);
718     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
719     return;
720   }
721   GNUNET_STATISTICS_update (GSA_stats,
722                             "# preference change requests processed",
723                             1, GNUNET_NO);
724   pi = (const struct PreferenceInformation *) &msg[1];
725   for (i = 0; i < nump; i++)
726     GAS_addresses_preference_change (GSA_addresses,
727                                      client,
728                                      &msg->peer,
729                                      (enum GNUNET_ATS_PreferenceKind)
730                                      ntohl (pi[i].preference_kind),
731                                      pi[i].preference_value);
732   GNUNET_SERVER_receive_done (client, GNUNET_OK);
733 }
734
735
736 /**
737  * Handle 'preference feedback' messages from clients.
738  *
739  * @param cls unused, NULL
740  * @param client client that sent the request
741  * @param message the request message
742  */
743 void
744 GAS_handle_preference_feedback (void *cls,
745                               struct GNUNET_SERVER_Client *client,
746                               const struct GNUNET_MessageHeader *message)
747 {
748   const struct FeedbackPreferenceMessage *msg;
749   const struct PreferenceInformation *pi;
750   uint16_t msize;
751   uint32_t nump;
752   uint32_t i;
753
754   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
755               "Received `%s' message\n",
756               "PREFERENCE_FEEDBACK");
757   msize = ntohs (message->size);
758   if (msize < sizeof (struct FeedbackPreferenceMessage))
759   {
760     GNUNET_break (0);
761     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
762     return;
763   }
764   msg = (const struct FeedbackPreferenceMessage *) message;
765   nump = ntohl (msg->num_feedback);
766   if (msize !=
767       sizeof (struct FeedbackPreferenceMessage) +
768       nump * sizeof (struct PreferenceInformation))
769   {
770     GNUNET_break (0);
771     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
772     return;
773   }
774   GNUNET_STATISTICS_update (GSA_stats,
775                             "# preference feedbacks requests processed",
776                             1, GNUNET_NO);
777   pi = (const struct PreferenceInformation *) &msg[1];
778   for (i = 0; i < nump; i++)
779     GAS_addresses_preference_feedback (GSA_addresses,
780                                      client,
781                                      &msg->peer,
782                                      GNUNET_TIME_relative_ntoh(msg->scope),
783                                      (enum GNUNET_ATS_PreferenceKind)
784                                      ntohl (pi[i].preference_kind),
785                                      pi[i].preference_value);
786   GNUNET_SERVER_receive_done (client, GNUNET_OK);
787 }
788
789
790
791 /**
792  * Initialize performance subsystem.
793  *
794  * @param server handle to our server
795  * @param addresses the address handle to use
796  */
797 void
798 GAS_performance_init (struct GNUNET_SERVER_Handle *server,
799                       struct GAS_Addresses_Handle *addresses)
800 {
801   GSA_addresses = addresses;
802   nc = GNUNET_SERVER_notification_context_create (server, 128);
803 }
804
805
806 /**
807  * Shutdown performance subsystem.
808  */
809 void
810 GAS_performance_done ()
811 {
812   GNUNET_SERVER_notification_context_destroy (nc);
813   nc = NULL;
814 }
815
816 /* end of gnunet-service-ats_performance.c */