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