guix-env: some update.
[oweals/gnunet.git] / src / ats / gnunet-service-ats.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2011 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file ats/gnunet-service-ats.c
22  * @brief ats service
23  * @author Matthias Wachs
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-ats.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet-service-ats_connectivity.h"
31 #include "gnunet-service-ats_normalization.h"
32 #include "gnunet-service-ats_performance.h"
33 #include "gnunet-service-ats_preferences.h"
34 #include "gnunet-service-ats_scheduling.h"
35 #include "gnunet-service-ats_reservations.h"
36 #include "gnunet-service-ats_plugins.h"
37 #include "ats.h"
38
39 /**
40  * Handle for statistics.
41  */
42 struct GNUNET_STATISTICS_Handle *GSA_stats;
43
44
45 /**
46  * We have received a `struct ClientStartMessage` from a client.  Find
47  * out which type of client it is and notify the respective subsystem.
48  *
49  * @param cls handle to the client
50  * @param msg the start message
51  */
52 static void
53 handle_ats_start (void *cls,
54                   const struct ClientStartMessage *msg)
55 {
56   struct GNUNET_SERVICE_Client *client = cls;
57   enum StartFlag flag;
58
59   flag = ntohl (msg->start_flag);
60   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
61               "Received ATS_START (%d) message\n",
62               (int) flag);
63   switch (flag)
64   {
65   case START_FLAG_SCHEDULING:
66     if (GNUNET_OK !=
67         GAS_scheduling_add_client (client))
68     {
69       GNUNET_SERVICE_client_drop (client);
70       return;
71     }
72     break;
73   case START_FLAG_PERFORMANCE_WITH_PIC:
74     GAS_performance_add_client (client,
75                                 flag);
76     break;
77   case START_FLAG_PERFORMANCE_NO_PIC:
78     GAS_performance_add_client (client,
79                                 flag);
80     break;
81   case START_FLAG_CONNECTION_SUGGESTION:
82     /* This client won't receive messages from us, no need to 'add' */
83     break;
84   default:
85     GNUNET_break (0);
86     GNUNET_SERVICE_client_drop (client);
87     return;
88   }
89   GNUNET_SERVICE_client_continue (client);
90 }
91
92
93
94 /**
95  * Handle 'reservation request' messages from clients.
96  *
97  * @param cls client that sent the request
98  * @param message the request message
99  */
100 static void
101 handle_reservation_request (void *cls,
102                             const struct ReservationRequestMessage *message)
103 {
104   struct GNUNET_SERVICE_Client *client = cls;
105
106   GAS_handle_reservation_request (client,
107                                   message);
108   GNUNET_SERVICE_client_continue (client);
109 }
110
111
112 /**
113  * Check 'preference feedback' message is well-formed
114  *
115  * @param cls client that sent the request
116  * @param message the request message
117  * @return #GNUNET_OK if @a message is well-formed
118  */
119 static int
120 check_feedback (void *cls,
121                 const struct FeedbackPreferenceMessage *message)
122 {
123   uint16_t msize;
124   uint32_t nump;
125
126   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127               "Received PREFERENCE_FEEDBACK message\n");
128   msize = ntohs (message->header.size);
129   nump = ntohl (message->num_feedback);
130   if (msize !=
131       sizeof (struct FeedbackPreferenceMessage) +
132       nump * sizeof (struct PreferenceInformation))
133   {
134     GNUNET_break (0);
135     return GNUNET_SYSERR;
136   }
137   return GNUNET_OK;
138 }
139
140
141 /**
142  * Handle 'preference feedback' messages from clients.
143  *
144  * @param cls client that sent the request
145  * @param msg the request message
146  */
147 static void
148 handle_feedback (void *cls,
149                  const struct FeedbackPreferenceMessage *msg)
150 {
151   struct GNUNET_SERVICE_Client *client = cls;
152   const struct PreferenceInformation *pi;
153   uint32_t nump;
154
155   nump = ntohl (msg->num_feedback);
156   if (GNUNET_NO ==
157       GNUNET_CONTAINER_multipeermap_contains (GSA_addresses,
158                                               &msg->peer))
159   {
160     GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
161                "Received PREFERENCE FEEDBACK for unknown peer `%s'\n",
162                GNUNET_i2s (&msg->peer));
163     GNUNET_SERVICE_client_continue (client);
164     return;
165   }
166
167   GNUNET_STATISTICS_update (GSA_stats,
168                             "# preference feedbacks requests processed",
169                             1,
170                             GNUNET_NO);
171   pi = (const struct PreferenceInformation *) &msg[1];
172   for (uint32_t i = 0; i < nump; i++)
173   {
174     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175                 "Received PREFERENCE FEEDBACK for peer `%s'\n",
176                 GNUNET_i2s (&msg->peer));
177     GAS_plugin_notify_feedback (client,
178                                 &msg->peer,
179                                 GNUNET_TIME_relative_ntoh (msg->scope),
180                                 (enum GNUNET_ATS_PreferenceKind) ntohl (pi[i].preference_kind),
181                                 pi[i].preference_value);
182   }
183   GNUNET_SERVICE_client_continue (client);
184 }
185
186
187 /**
188  * Handle 'request address list' messages from clients.
189  *
190  * @param cls client that sent the request
191  * @param message the request message
192  */
193 static void
194 handle_request_address_list (void *cls,
195                              const struct AddressListRequestMessage *message)
196 {
197   struct GNUNET_SERVICE_Client *client = cls;
198
199   GAS_handle_request_address_list (client,
200                                    message);
201   GNUNET_SERVICE_client_continue (client);
202 }
203
204
205 /**
206  * Handle 'request address' messages from clients.
207  *
208  * @param cls client that sent the request
209  * @param message the request message
210  */
211 static void
212 handle_request_address (void *cls,
213                         const struct RequestAddressMessage * message)
214 {
215   struct GNUNET_SERVICE_Client *client = cls;
216
217   GAS_handle_request_address (client,
218                               message);
219   GNUNET_SERVICE_client_continue (client);
220 }
221
222
223 /**
224  * Cancel 'request address' messages from clients.
225  *
226  * @param cls client that sent the request
227  * @param message the request message
228  */
229 static void
230 handle_request_address_cancel (void *cls,
231                                const struct RequestAddressMessage *message)
232 {
233   struct GNUNET_SERVICE_Client *client = cls;
234
235   GAS_handle_request_address_cancel (client,
236                                      message);
237   GNUNET_SERVICE_client_continue (client);
238 }
239
240
241 /**
242  * Handle 'address add' messages from clients.
243  *
244  * @param cls client that sent the request
245  * @param m the request message
246  */
247 static int
248 check_address_add (void *cls,
249                    const struct AddressAddMessage *m)
250 {
251   const char *address;
252   const char *plugin_name;
253   uint16_t address_length;
254   uint16_t plugin_name_length;
255   uint16_t size;
256
257   size = ntohs (m->header.size);
258   address_length = ntohs (m->address_length);
259   plugin_name_length = ntohs (m->plugin_name_length);
260   address = (const char *) &m[1];
261   if (plugin_name_length != 0)
262     plugin_name = &address[address_length];
263   else
264     plugin_name = "";
265
266   if ( (address_length + plugin_name_length +
267         sizeof (struct AddressAddMessage) != size) ||
268        ( (plugin_name_length > 0) &&
269          (plugin_name[plugin_name_length - 1] != '\0') ) )
270   {
271     GNUNET_break (0);
272     return GNUNET_SYSERR;
273   }
274   return GNUNET_OK;
275 }
276
277
278 /**
279  * Handle 'address add' messages from clients.
280  *
281  * @param cls client that sent the request
282  * @param message the request message
283  */
284 static void
285 handle_address_add (void *cls,
286                     const struct AddressAddMessage *message)
287 {
288   struct GNUNET_SERVICE_Client *client = cls;
289
290   GAS_handle_address_add (message);
291   GNUNET_SERVICE_client_continue (client);
292 }
293
294
295 /**
296  * Handle 'address update' messages from clients.
297  *
298  * @param cls client that sent the request
299  * @param message the request message
300  */
301 static void
302 handle_address_update (void *cls,
303                        const struct AddressUpdateMessage *message)
304 {
305   struct GNUNET_SERVICE_Client *client = cls;
306
307   GAS_handle_address_update (message);
308   GNUNET_SERVICE_client_continue (client);
309 }
310
311
312 /**
313  * Handle 'address destroyed' messages from clients.
314  *
315  * @param cls client that sent the request
316  * @param message the request message
317  */
318 static void
319 handle_address_destroyed (void *cls,
320                           const struct AddressDestroyedMessage *message)
321 {
322   struct GNUNET_SERVICE_Client *client = cls;
323
324   GAS_handle_address_destroyed (message);
325   GNUNET_SERVICE_client_continue (client);
326 }
327
328
329 /**
330  * Check that 'change preference' message is well-formed.
331  *
332  * @param cls client that sent the request
333  * @param message the request message
334  * @return #GNUNET_OK if @a message is well-formed
335  */
336 static int
337 check_preference_change (void *cls,
338                          const struct ChangePreferenceMessage *message)
339 {
340   uint16_t msize;
341   uint32_t nump;
342
343   msize = ntohs (message->header.size);
344   nump = ntohl (message->num_preferences);
345   if ( (msize !=
346         sizeof (struct ChangePreferenceMessage) +
347         nump * sizeof (struct PreferenceInformation)) ||
348        (UINT16_MAX / sizeof (struct PreferenceInformation) < nump) )
349   {
350     GNUNET_break (0);
351     return GNUNET_SYSERR;
352   }
353   return GNUNET_OK;
354 }
355
356
357 /**
358  * Handle 'change preference' messages from clients.
359  *
360  * @param cls client that sent the request
361  * @param message the request message
362  */
363 static void
364 handle_preference_change (void *cls,
365                           const struct ChangePreferenceMessage *message)
366 {
367   struct GNUNET_SERVICE_Client *client = cls;
368
369   GAS_handle_preference_change (client,
370                                 message);
371   GNUNET_SERVICE_client_continue (client);
372 }
373
374
375 /**
376  * A client connected to us. Setup the local client
377  * record.
378  *
379  * @param cls unused
380  * @param client handle of the client
381  * @param mq message queue to talk to @a client
382  * @return @a client
383  */
384 static void *
385 client_connect_cb (void *cls,
386                    struct GNUNET_SERVICE_Client *client,
387                    struct GNUNET_MQ_Handle *mq)
388 {
389   return client;
390 }
391
392
393 /**
394  * A client disconnected from us.  Tear down the local client
395  * record.
396  *
397  * @param cls unused
398  * @param client handle of the client
399  * @param app_ctx
400  */
401 static void
402 client_disconnect_cb (void *cls,
403                       struct GNUNET_SERVICE_Client *client,
404                       void *app_ctx)
405 {
406   if (NULL == client)
407     return;
408   GAS_scheduling_remove_client (client);
409   GAS_connectivity_remove_client (client);
410   GAS_preference_client_disconnect (client);
411 }
412
413
414 /**
415  * Task run during shutdown.
416  *
417  * @param cls unused
418  */
419 static void
420 cleanup_task (void *cls)
421 {
422   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423               "ATS shutdown initiated\n");
424   GAS_connectivity_done ();
425   GAS_addresses_done ();
426   GAS_plugin_done ();
427   GAS_normalization_stop ();
428   GAS_performance_done ();
429   GAS_preference_done ();
430   GAS_reservations_done ();
431   if (NULL != GSA_stats)
432   {
433     GNUNET_STATISTICS_destroy (GSA_stats, GNUNET_NO);
434     GSA_stats = NULL;
435   }
436 }
437
438
439 /**
440  * Process template requests.
441  *
442  * @param cls closure
443  * @param cfg configuration to use
444  * @param service the initialized service
445  */
446 static void
447 run (void *cls,
448      const struct GNUNET_CONFIGURATION_Handle *cfg,
449      struct GNUNET_SERVICE_Handle *service)
450 {
451   GSA_stats = GNUNET_STATISTICS_create ("ats",
452                                         cfg);
453   GAS_reservations_init ();
454   GAS_connectivity_init ();
455   GAS_preference_init ();
456   GAS_normalization_start ();
457   GAS_addresses_init ();
458   if (GNUNET_OK !=
459       GAS_plugin_init (cfg))
460   {
461     GNUNET_break (0);
462     GAS_addresses_done ();
463     GAS_normalization_stop ();
464     GAS_reservations_done ();
465     GAS_connectivity_done ();
466     GAS_preference_done ();
467     if (NULL != GSA_stats)
468     {
469       GNUNET_STATISTICS_destroy (GSA_stats,
470                                  GNUNET_NO);
471       GSA_stats = NULL;
472     }
473     return;
474   }
475   GAS_performance_init ();
476   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
477                                  NULL);
478 }
479
480
481 /**
482  * Define "main" method using service macro.
483  */
484 GNUNET_SERVICE_MAIN
485 ("ats",
486  GNUNET_SERVICE_OPTION_NONE,
487  &run,
488  &client_connect_cb,
489  &client_disconnect_cb,
490  NULL,
491  GNUNET_MQ_hd_fixed_size (ats_start,
492                           GNUNET_MESSAGE_TYPE_ATS_START,
493                           struct ClientStartMessage,
494                           NULL),
495  GNUNET_MQ_hd_fixed_size (request_address,
496                           GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS,
497                           struct RequestAddressMessage,
498                           NULL),
499  GNUNET_MQ_hd_fixed_size (request_address_cancel, 
500                           GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL,
501                           struct RequestAddressMessage,
502                           NULL),
503  GNUNET_MQ_hd_fixed_size (request_address_list, 
504                           GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_REQUEST,
505                           struct AddressListRequestMessage,
506                           NULL),
507  GNUNET_MQ_hd_var_size (address_add, 
508                         GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD,
509                         struct AddressAddMessage,
510                         NULL),
511  GNUNET_MQ_hd_fixed_size (address_update, 
512                           GNUNET_MESSAGE_TYPE_ATS_ADDRESS_UPDATE,
513                           struct AddressUpdateMessage,
514                           NULL),
515  GNUNET_MQ_hd_fixed_size (address_destroyed, 
516                           GNUNET_MESSAGE_TYPE_ATS_ADDRESS_DESTROYED,
517                           struct AddressDestroyedMessage,
518                           NULL),
519  GNUNET_MQ_hd_fixed_size (reservation_request, 
520                           GNUNET_MESSAGE_TYPE_ATS_RESERVATION_REQUEST,
521                           struct ReservationRequestMessage,
522                           NULL),
523  GNUNET_MQ_hd_var_size (preference_change, 
524                         GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_CHANGE,
525                         struct ChangePreferenceMessage,
526                         NULL),
527  GNUNET_MQ_hd_var_size (feedback, 
528                         GNUNET_MESSAGE_TYPE_ATS_PREFERENCE_FEEDBACK,
529                         struct FeedbackPreferenceMessage,
530                         NULL),
531  GNUNET_MQ_handler_end ());
532
533
534 /* end of gnunet-service-ats.c */