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