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