do not use session_id in GAS_performance_notify_all_clients, needs to be 'active...
[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 is this address active
148  * @param atsi performance data for the address
149  * @param atsi_count number of performance records in 'ats'
150  * @param bandwidth_out assigned outbound bandwidth
151  * @param bandwidth_in assigned inbound bandwidth
152  */
153 void
154 GAS_performance_notify_client (struct PerformanceClient *pc,
155                                const struct GNUNET_PeerIdentity *peer,
156                                const char *plugin_name,
157                                const void *plugin_addr,
158                                size_t plugin_addr_len,
159                                int active,
160                                const struct GNUNET_ATS_Information *atsi,
161                                uint32_t atsi_count,
162                                struct GNUNET_BANDWIDTH_Value32NBO
163                                bandwidth_out,
164                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
165 {
166
167   struct PeerInformationMessage *msg;
168   size_t plugin_name_length = strlen (plugin_name) + 1;
169   size_t msize =
170       sizeof (struct PeerInformationMessage) +
171       atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len +
172       plugin_name_length;
173   char buf[msize] GNUNET_ALIGN;
174   struct GNUNET_ATS_Information *atsp;
175   char *addrp;
176
177   GNUNET_assert (NULL != pc);
178   if (NULL == find_client (pc->client))
179     return; /* Client disconnected */
180
181   GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
182   GNUNET_assert (atsi_count <
183                  GNUNET_SERVER_MAX_MESSAGE_SIZE /
184                  sizeof (struct GNUNET_ATS_Information));
185   msg = (struct PeerInformationMessage *) buf;
186   msg->header.size = htons (msize);
187   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION);
188   msg->id = htonl (0);
189   msg->ats_count = htonl (atsi_count);
190   msg->peer = *peer;
191   msg->address_length = htons (plugin_addr_len);
192   msg->address_active = ntohl (active);
193   msg->plugin_name_length = htons (plugin_name_length);
194   msg->bandwidth_out = bandwidth_out;
195   msg->bandwidth_in = bandwidth_in;
196   atsp = (struct GNUNET_ATS_Information *) &msg[1];
197   memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
198   addrp = (char *) &atsp[atsi_count];
199   memcpy (addrp, plugin_addr, plugin_addr_len);
200   strcpy (&addrp[plugin_addr_len], plugin_name);
201   GNUNET_SERVER_notification_context_unicast (nc,
202                                               pc->client,
203                                               &msg->header,
204                                               GNUNET_YES);
205 }
206
207
208 /**
209  * Transmit the given performance information to all performance
210  * clients.
211  *
212  * @param peer peer for which this is an address suggestion
213  * @param plugin_name 0-termintated string specifying the transport plugin
214  * @param plugin_addr binary address for the plugin to use
215  * @param plugin_addr_len number of bytes in @a plugin_addr
216  * @param active is this address active
217  * @param atsi performance data for the address
218  * @param atsi_count number of performance records in @a atsi
219  * @param bandwidth_out assigned outbound bandwidth
220  * @param bandwidth_in assigned inbound bandwidth
221  */
222 void
223 GAS_performance_notify_all_clients (const struct GNUNET_PeerIdentity *peer,
224                                     const char *plugin_name,
225                                     const void *plugin_addr,
226                                     size_t plugin_addr_len,
227                                     int active,
228                                     const struct GNUNET_ATS_Information *atsi,
229                                     uint32_t atsi_count,
230                                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
231                                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
232 {
233   struct PerformanceClient *pc;
234
235   for (pc = pc_head; pc != NULL; pc = pc->next)
236     if (pc->flag == START_FLAG_PERFORMANCE_WITH_PIC)
237     {
238         GAS_performance_notify_client (pc,
239                                        peer,
240                                        plugin_name,
241                                        plugin_addr,
242                                        plugin_addr_len,
243                                        active,
244                                        atsi, atsi_count,
245                                        bandwidth_out, bandwidth_in);
246     }
247   GNUNET_STATISTICS_update (GSA_stats,
248                             "# performance updates given to clients", 1,
249                             GNUNET_NO);
250 }
251
252
253
254 /**
255  * Iterator for called from #GAS_addresses_get_peer_info()
256  *
257  * @param p_it_cls closure with the `struct PerformanceClient *`
258  * @param id the peer id
259  * @param plugin_name plugin name
260  * @param plugin_addr address
261  * @param plugin_addr_len length of @a plugin_addr
262  * @param address_active is address actively used
263  * @param atsi ats performance information
264  * @param atsi_count number of ats performance elements in @a atsi
265  * @param bandwidth_out current outbound bandwidth assigned to address
266  * @param bandwidth_in current inbound bandwidth assigned to address
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 bandwidth_out,
277              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
278 {
279   struct PerformanceClient *pc = cls;
280
281   GNUNET_assert (NULL != pc);
282   if (NULL == id)
283     return;
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285               "Callback for peer `%s' plugin `%s' BW out %u, BW in %u \n",
286               GNUNET_i2s (id),
287               plugin_name,
288               (unsigned int) ntohl (bandwidth_out.value__),
289               (unsigned int) ntohl (bandwidth_in.value__));
290   GAS_performance_notify_client(pc,
291                                 id,
292                                 plugin_name,
293                                 plugin_addr,
294                                 plugin_addr_len,
295                                 active,
296                                 atsi, atsi_count,
297                                 bandwidth_out, bandwidth_in);
298 }
299
300
301 /**
302  * Iterator for #GAS_performance_add_client()
303  *
304  * @param cls the client requesting information
305  * @param id result
306  */
307 static void
308 peer_it (void *cls,
309          const struct GNUNET_PeerIdentity *id)
310 {
311   struct PerformanceClient *pc = cls;
312
313   if (NULL != id)
314   {
315     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316                 "Callback for peer `%s'\n",
317                 GNUNET_i2s (id));
318     GAS_addresses_get_peer_info (GSA_addresses, id,
319                                  &peerinfo_it, pc);
320   }
321 }
322
323
324 /**
325  * Register a new performance client.
326  *
327  * @param client handle of the new client
328  * @param flag flag specifying the type of the client
329  */
330 void
331 GAS_performance_add_client (struct GNUNET_SERVER_Client *client,
332                             enum StartFlag flag)
333 {
334   struct PerformanceClient *pc;
335   GNUNET_break (NULL == find_client (client));
336
337   pc = GNUNET_new (struct PerformanceClient);
338   pc->client = client;
339   pc->flag = flag;
340
341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342               "Adding performance client %s PIC\n",
343               (flag == START_FLAG_PERFORMANCE_WITH_PIC) ? "with" : "without");
344
345   GNUNET_SERVER_notification_context_add (nc, client);
346   GNUNET_CONTAINER_DLL_insert (pc_head, pc_tail, pc);
347
348   /* Send information about clients */
349   GAS_addresses_iterate_peers (GSA_addresses,
350                                &peer_it,
351                                pc);
352 }
353
354
355 /**
356  * FIXME.
357  */
358 static void
359 transmit_req_addr (struct AddressIteration *ai,
360                    const struct GNUNET_PeerIdentity *id,
361                    const char *plugin_name,
362                    const void *plugin_addr, size_t plugin_addr_len,
363                    const 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, ai->pc->client, &msg->header,
411                                               GNUNET_NO);
412 }
413
414
415 /**
416  * Iterator for #GAS_addresses_get_peer_info()
417  *
418  * @param p_it_cls closure with our `struct AddressIteration *`
419  * @param id the peer id
420  * @param plugin_name plugin name
421  * @param plugin_addr address
422  * @param plugin_addr_len length of @a plugin_addr
423  * @param address_active is address actively used
424  * @param atsi ats performance information
425  * @param atsi_count number of ats performance elements in @a atsi
426  * @param bandwidth_out current outbound bandwidth assigned to address
427  * @param bandwidth_in current inbound bandwidth assigned to address
428  */
429 static void
430 req_addr_peerinfo_it (void *cls,
431              const struct GNUNET_PeerIdentity *id,
432              const char *plugin_name,
433              const void *plugin_addr, size_t plugin_addr_len,
434              const int active,
435              const struct GNUNET_ATS_Information *atsi,
436              uint32_t atsi_count,
437              struct GNUNET_BANDWIDTH_Value32NBO
438              bandwidth_out,
439              struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
440 {
441   struct AddressIteration *ai = cls;
442
443   GNUNET_assert (NULL != ai);
444   GNUNET_assert (NULL != ai->pc);
445   if (NULL == find_client (ai->pc->client))
446     return; /* Client disconnected */
447
448   if ((NULL == id) && (NULL == plugin_name) && (NULL == plugin_addr))
449   {
450     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
451                 "Address iteration done\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 */
463   if ((GNUNET_YES == ai->all) || (GNUNET_YES == active))
464   {
465       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466                   "Sending result for  %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
467                   (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
468                   GNUNET_i2s (id),
469                   plugin_name,
470                   (unsigned int) ntohl (bandwidth_out.value__),
471                   (unsigned int) ntohl (bandwidth_in.value__));
472     transmit_req_addr (cls,
473                        id,
474                        plugin_name,
475                        plugin_addr, plugin_addr_len,
476                        active,
477                        atsi,
478                        atsi_count,
479                        bandwidth_out, bandwidth_in);
480   }
481 }
482
483
484 /**
485  * Iterator for GAS_handle_request_address_list
486  *
487  * @param cls the client requesting information, a `struct AddressIteration *`
488  * @param id result
489  */
490 static void
491 req_addr_peer_it (void *cls,
492                   const struct GNUNET_PeerIdentity *id)
493 {
494   struct AddressIteration *ai = cls;
495
496   if (NULL == id)
497   {
498     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
499                 "Peer iteration done\n");
500     return;
501   }
502   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503               "Callback for peer `%s'\n",
504               GNUNET_i2s (id));
505   GAS_addresses_get_peer_info (GSA_addresses, id,
506                                &req_addr_peerinfo_it, ai);
507 }
508
509
510 /**
511  * Handle 'address list request' messages from clients.
512  *
513  * @param cls unused, NULL
514  * @param client client that sent the request
515  * @param message the request message
516  */
517 void
518 GAS_handle_request_address_list (void *cls, struct GNUNET_SERVER_Client *client,
519                                  const struct GNUNET_MessageHeader *message)
520 {
521   struct PerformanceClient *pc;
522   struct AddressIteration ai;
523   struct AddressListRequestMessage * alrm = (struct AddressListRequestMessage *) message;
524   struct GNUNET_PeerIdentity allzeros;
525   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_zero;
526
527   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528               "Received `%s' message\n",
529               "ADDRESSLIST_REQUEST");
530   if (NULL == (pc = find_client(client)))
531   {
532     GNUNET_break (0);
533     return;
534   }
535
536   ai.all = ntohl (alrm->all);
537   ai.id = ntohl (alrm->id);
538   ai.pc = pc;
539
540   memset (&allzeros, '\0', sizeof (struct GNUNET_PeerIdentity));
541   bandwidth_zero.value__ = htonl (0);
542   if (0 == memcmp (&alrm->peer,
543                    &allzeros,
544                    sizeof (struct GNUNET_PeerIdentity)))
545   {
546     /* Return addresses for all peers */
547     GAS_addresses_iterate_peers (GSA_addresses, &req_addr_peer_it, &ai);
548     transmit_req_addr (&ai, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0,
549                        bandwidth_zero, bandwidth_zero);
550   }
551   else
552   {
553     /* Return addresses for a specific peer */
554     GAS_addresses_get_peer_info (GSA_addresses,
555                                  &alrm->peer,
556                                  &req_addr_peerinfo_it, &ai);
557     transmit_req_addr (&ai, NULL, NULL, NULL, 0, GNUNET_NO, NULL, 0,
558                        bandwidth_zero, bandwidth_zero);
559   }
560   GNUNET_SERVER_receive_done (client, GNUNET_OK);
561 }
562
563
564 /**
565  * FIXME.
566  */
567 void
568 GAS_handle_performance_update (struct GNUNET_PeerIdentity *peer,
569                                const char *plugin_name,
570                                const void *plugin_addr, size_t plugin_addr_len,
571                                const int active,
572                                struct GNUNET_ATS_Information *ats,
573                                uint32_t ats_count,
574                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
575                                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
576 {
577   /* Notify here */
578   GAS_performance_notify_all_clients (peer, plugin_name, plugin_addr,
579       plugin_addr_len, active, ats, ats_count, bandwidth_out, bandwidth_in);
580
581 #if 0
582   struct PerformanceClient *cur;
583   struct PerformanceMonitorClient *curm;
584   struct MonitorResponseMessage *mrm;
585   size_t msglen;
586
587   msglen = sizeof (struct MonitorResponseMessage) +
588   ats_count * sizeof (struct GNUNET_ATS_Information);
589   mrm = GNUNET_malloc (msglen);
590
591   mrm->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_MONITOR_RESPONSE);
592   mrm->header.size = htons (msglen);
593   mrm->ats_count = htonl (ats_count);
594   mrm->peer = *peer;
595   memcpy (&mrm[1], ats, ats_count * sizeof (struct GNUNET_ATS_Information));
596
597   for (cur = pc_head; NULL != cur; cur = cur->next)
598   for (curm = cur->pm_head; NULL != curm; curm = curm->next)
599   {
600     /* Notify client about update */
601     mrm->id = htonl (curm->id);
602     GNUNET_SERVER_notification_context_unicast (nc,
603         cur->client,
604         (struct GNUNET_MessageHeader *) mrm,
605         GNUNET_YES);
606   }
607   GNUNET_free (mrm);
608 #endif
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,
637               "Received `%s' message\n",
638               "RESERVATION_REQUEST");
639   amount = (int32_t) ntohl (msg->amount);
640   res_delay = GAS_reservations_reserve (&msg->peer, amount);
641   if (res_delay.rel_value_us > 0)
642     amount = 0;
643   result.header.size = htons (sizeof (struct ReservationResultMessage));
644   result.header.type = htons (GNUNET_MESSAGE_TYPE_ATS_RESERVATION_RESULT);
645   result.amount = htonl (amount);
646   result.peer = msg->peer;
647   result.res_delay = GNUNET_TIME_relative_hton (res_delay);
648   GNUNET_STATISTICS_update (GSA_stats,
649                             "# reservation requests processed", 1,
650                             GNUNET_NO);
651   GNUNET_SERVER_notification_context_unicast (nc, client, &result.header,
652                                               GNUNET_NO);
653   GNUNET_SERVER_receive_done (client, GNUNET_OK);
654 }
655
656
657 /**
658  * Handle 'preference change' messages from clients.
659  *
660  * @param cls unused, NULL
661  * @param client client that sent the request
662  * @param message the request message
663  */
664 void
665 GAS_handle_preference_change (void *cls,
666                               struct GNUNET_SERVER_Client *client,
667                               const struct GNUNET_MessageHeader *message)
668 {
669   const struct ChangePreferenceMessage *msg;
670   const struct PreferenceInformation *pi;
671   uint16_t msize;
672   uint32_t nump;
673   uint32_t i;
674
675   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
676               "PREFERENCE_CHANGE");
677   msize = ntohs (message->size);
678   if (msize < sizeof (struct ChangePreferenceMessage))
679   {
680     GNUNET_break (0);
681     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
682     return;
683   }
684   msg = (const struct ChangePreferenceMessage *) message;
685   nump = ntohl (msg->num_preferences);
686   if (msize !=
687       sizeof (struct ChangePreferenceMessage) +
688       nump * sizeof (struct PreferenceInformation))
689   {
690     GNUNET_break (0);
691     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
692     return;
693   }
694   GNUNET_STATISTICS_update (GSA_stats,
695                             "# preference change requests processed",
696                             1, GNUNET_NO);
697   pi = (const struct PreferenceInformation *) &msg[1];
698   for (i = 0; i < nump; i++)
699     GAS_addresses_preference_change (GSA_addresses,
700                                      client,
701                                      &msg->peer,
702                                      (enum GNUNET_ATS_PreferenceKind)
703                                      ntohl (pi[i].preference_kind),
704                                      pi[i].preference_value);
705   GNUNET_SERVER_receive_done (client, GNUNET_OK);
706 }
707
708
709 /**
710  * Handle 'preference feedback' messages from clients.
711  *
712  * @param cls unused, NULL
713  * @param client client that sent the request
714  * @param message the request message
715  */
716 void
717 GAS_handle_preference_feedback (void *cls,
718                               struct GNUNET_SERVER_Client *client,
719                               const struct GNUNET_MessageHeader *message)
720 {
721   const struct FeedbackPreferenceMessage *msg;
722   const struct PreferenceInformation *pi;
723   uint16_t msize;
724   uint32_t nump;
725   uint32_t i;
726
727   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
728               "Received `%s' message\n",
729               "PREFERENCE_FEEDBACK");
730   msize = ntohs (message->size);
731   if (msize < sizeof (struct FeedbackPreferenceMessage))
732   {
733     GNUNET_break (0);
734     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
735     return;
736   }
737   msg = (const struct FeedbackPreferenceMessage *) message;
738   nump = ntohl (msg->num_feedback);
739   if (msize !=
740       sizeof (struct FeedbackPreferenceMessage) +
741       nump * sizeof (struct PreferenceInformation))
742   {
743     GNUNET_break (0);
744     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
745     return;
746   }
747   GNUNET_STATISTICS_update (GSA_stats,
748                             "# preference feedbacks requests processed",
749                             1, GNUNET_NO);
750   pi = (const struct PreferenceInformation *) &msg[1];
751   for (i = 0; i < nump; i++)
752     GAS_addresses_preference_feedback (GSA_addresses,
753                                      client,
754                                      &msg->peer,
755                                      GNUNET_TIME_relative_ntoh(msg->scope),
756                                      (enum GNUNET_ATS_PreferenceKind)
757                                      ntohl (pi[i].preference_kind),
758                                      pi[i].preference_value);
759   GNUNET_SERVER_receive_done (client, GNUNET_OK);
760 }
761
762
763
764 /**
765  * Initialize performance subsystem.
766  *
767  * @param server handle to our server
768  * @param addresses the address handle to use
769  */
770 void
771 GAS_performance_init (struct GNUNET_SERVER_Handle *server,
772                       struct GAS_Addresses_Handle *addresses)
773 {
774   GSA_addresses = addresses;
775   nc = GNUNET_SERVER_notification_context_create (server, 128);
776 }
777
778
779 /**
780  * Shutdown performance subsystem.
781  */
782 void
783 GAS_performance_done ()
784 {
785   GNUNET_SERVER_notification_context_destroy (nc);
786   nc = NULL;
787 }
788
789 /* end of gnunet-service-ats_performance.c */