-check RV
[oweals/gnunet.git] / src / ats / gnunet-service-ats_scheduling.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_scheduling.c
23  * @brief ats service, interaction with 'scheduling' 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_scheduling.h"
31 #include "ats.h"
32
33
34 /**
35  * Context for sending messages to clients.
36  */
37 static struct GNUNET_SERVER_NotificationContext *nc;
38
39 /**
40  * Actual handle to the client.
41  */
42 static struct GNUNET_SERVER_Client *my_client;
43
44 /**
45  * Handle to address subsystem
46  */
47 static struct GAS_Addresses_Handle *address_handle;
48
49
50 /**
51  * Register a new scheduling client.
52  *
53  * @param client handle of the new client
54  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
55  */
56 int
57 GAS_scheduling_add_client (struct GNUNET_SERVER_Client *client)
58 {
59   if (my_client != NULL)
60   {
61     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62                 "This ATS already has a scheduling client, refusing new scheduling client for now.\n");
63     return GNUNET_SYSERR;
64   }
65   my_client = client;
66   GNUNET_SERVER_notification_context_add (nc, client);
67   return GNUNET_OK;
68 }
69
70
71 /**
72  * Unregister a client (which may have been a scheduling client,
73  * but this is not assured).
74  *
75  * @param client handle of the (now dead) client
76  */
77 void
78 GAS_scheduling_remove_client (struct GNUNET_SERVER_Client *client)
79 {
80   if (my_client != client)
81     return;
82   GAS_addresses_destroy_all (address_handle);
83   my_client = NULL;
84 }
85
86
87 /**
88  * Transmit the given address suggestion and bandwidth update to all scheduling
89  * clients.
90  *
91  * @param peer peer for which this is an address suggestion
92  * @param plugin_name 0-termintated string specifying the transport plugin
93  * @param plugin_addr binary address for the plugin to use
94  * @param plugin_addr_len number of bytes in @a plugin_addr
95  * @param local_address_info the local address for the address
96  * @param session_id session ID to use for the given client (other clients will see 0)
97  * @param atsi performance data for the address
98  * @param atsi_count number of performance records in @a atsi
99  * @param bandwidth_out assigned outbound bandwidth
100  * @param bandwidth_in assigned inbound bandwidth
101  */
102 void
103 GAS_scheduling_transmit_address_suggestion (const struct GNUNET_PeerIdentity *peer,
104                                             const char *plugin_name,
105                                             const void *plugin_addr,
106                                             size_t plugin_addr_len,
107                                             uint32_t local_address_info,
108                                             uint32_t session_id,
109                                             const struct GNUNET_ATS_Information *atsi,
110                                             uint32_t atsi_count,
111                                             struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
112                                             struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
113 {
114   struct AddressSuggestionMessage *msg;
115   size_t plugin_name_length = strlen (plugin_name) + 1;
116   size_t msize =
117       sizeof (struct AddressSuggestionMessage) +
118       atsi_count * sizeof (struct GNUNET_ATS_Information) + plugin_addr_len +
119       plugin_name_length;
120   char buf[msize] GNUNET_ALIGN;
121   struct GNUNET_ATS_Information *atsp;
122   char *addrp;
123
124   if (my_client == NULL)
125     return;
126   GNUNET_STATISTICS_update (GSA_stats, "# address suggestions made", 1,
127                             GNUNET_NO);
128   GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
129   GNUNET_assert (atsi_count <
130                  GNUNET_SERVER_MAX_MESSAGE_SIZE /
131                  sizeof (struct GNUNET_ATS_Information));
132   msg = (struct AddressSuggestionMessage *) buf;
133   msg->header.size = htons (msize);
134   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESS_SUGGESTION);
135   msg->ats_count = htonl (atsi_count);
136   msg->peer = *peer;
137   msg->address_length = htons (plugin_addr_len);
138   msg->plugin_name_length = htons (plugin_name_length);
139   msg->address_local_info = htonl (local_address_info);
140   msg->session_id = htonl (session_id);
141   msg->bandwidth_out = bandwidth_out;
142   msg->bandwidth_in = bandwidth_in;
143   atsp = (struct GNUNET_ATS_Information *) &msg[1];
144   memcpy (atsp, atsi, sizeof (struct GNUNET_ATS_Information) * atsi_count);
145   addrp = (char *) &atsp[atsi_count];
146   memcpy (addrp, plugin_addr, plugin_addr_len);
147   strcpy (&addrp[plugin_addr_len], plugin_name);
148
149   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150               "ATS sends quota for peer `%s': (in/out) %u/%u\n",
151               GNUNET_i2s (peer),
152               (unsigned int) ntohl (bandwidth_in.value__),
153               (unsigned int) ntohl (bandwidth_out.value__));
154
155   GNUNET_SERVER_notification_context_unicast (nc, my_client, &msg->header,
156                                               GNUNET_YES);
157 }
158
159
160 /**
161  * Handle 'request address' messages from clients.
162  *
163  * @param cls unused, NULL
164  * @param client client that sent the request
165  * @param message the request message
166  */
167 void
168 GAS_handle_request_address (void *cls,
169                             struct GNUNET_SERVER_Client *client,
170                             const struct GNUNET_MessageHeader *message)
171 {
172   const struct RequestAddressMessage *msg =
173       (const struct RequestAddressMessage *) message;
174
175   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
176               "REQUEST_ADDRESS");
177   GNUNET_break (0 == ntohl (msg->reserved));
178   GAS_addresses_request_address (address_handle, &msg->peer);
179   GNUNET_SERVER_receive_done (client, GNUNET_OK);
180 }
181
182
183 /**
184  * Handle 'request address' messages from clients.
185  *
186  * @param cls unused, NULL
187  * @param client client that sent the request
188  * @param message the request message
189  */
190 void
191 GAS_handle_request_address_cancel (void *cls,
192                                    struct GNUNET_SERVER_Client *client,
193                                    const struct GNUNET_MessageHeader *message)
194 {
195   const struct RequestAddressMessage *msg =
196       (const struct RequestAddressMessage *) message;
197
198   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
199               "REQUEST_ADDRESS_CANCEL");
200   GNUNET_break (0 == ntohl (msg->reserved));
201
202   GAS_addresses_request_address_cancel (address_handle, &msg->peer);
203
204   GNUNET_SERVER_receive_done (client, GNUNET_OK);
205 }
206
207
208 /**
209  * Handle 'reset backoff' messages from clients.
210  *
211  * @param cls unused, NULL
212  * @param client client that sent the request
213  * @param message the request message
214  */
215 void
216 GAS_handle_reset_backoff (void *cls,
217                           struct GNUNET_SERVER_Client *client,
218                           const struct GNUNET_MessageHeader *message)
219 {
220   const struct ResetBackoffMessage *msg =
221       (const struct ResetBackoffMessage *) message;
222
223   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224               "Received `%s' message\n",
225               "RESET_BACKOFF");
226   GNUNET_break (0 == ntohl (msg->reserved));
227   GAS_addresses_handle_backoff_reset (address_handle, &msg->peer);
228   GNUNET_SERVER_receive_done (client, GNUNET_OK);
229 }
230
231
232 /**
233  * Handle 'address add' messages from clients.
234  *
235  * @param cls unused, NULL
236  * @param client client that sent the request
237  * @param message the request message
238  */
239 void
240 GAS_handle_address_add (void *cls,
241                         struct GNUNET_SERVER_Client *client,
242                         const struct GNUNET_MessageHeader *message)
243 {
244   const struct AddressUpdateMessage *m;
245   const struct GNUNET_ATS_Information *atsi;
246   const char *address;
247   const char *plugin_name;
248   uint16_t address_length;
249   uint16_t plugin_name_length;
250   uint32_t ats_count;
251   uint16_t size;
252
253   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
254               "Received `%s' message\n",
255               "ADDRESS_ADD");
256   size = ntohs (message->size);
257   if (size < sizeof (struct AddressUpdateMessage))
258   {
259     GNUNET_break (0);
260     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
261     return;
262   }
263   m = (const struct AddressUpdateMessage *) message;
264   ats_count = ntohl (m->ats_count);
265   address_length = ntohs (m->address_length);
266   plugin_name_length = ntohs (m->plugin_name_length);
267   atsi = (const struct GNUNET_ATS_Information *) &m[1];
268   address = (const char *) &atsi[ats_count];
269   if (plugin_name_length != 0)
270     plugin_name = &address[address_length];
271   else
272     plugin_name = "";
273
274   if ((address_length + plugin_name_length +
275        ats_count * sizeof (struct GNUNET_ATS_Information) +
276        sizeof (struct AddressUpdateMessage) != ntohs (message->size)) ||
277       (ats_count >
278        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) ||
279        ((plugin_name_length > 0) && (plugin_name[plugin_name_length - 1] != '\0')))
280   {
281     GNUNET_break (0);
282     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
283     return;
284   }
285   GNUNET_STATISTICS_update (GSA_stats,
286                             "# addresses created", 1,
287                             GNUNET_NO);
288   GAS_addresses_add (address_handle,
289                      &m->peer,
290                      plugin_name,
291                      address,
292                      address_length,
293                      ntohl(m->address_local_info),
294                      ntohl (m->session_id),
295                      atsi, ats_count);
296   GNUNET_SERVER_receive_done (client, GNUNET_OK);
297 }
298
299
300 /**
301  * Handle 'address update' messages from clients.
302  *
303  * @param cls unused, NULL
304  * @param client client that sent the request
305  * @param message the request message
306  */
307 void
308 GAS_handle_address_update (void *cls,
309                            struct GNUNET_SERVER_Client *client,
310                            const struct GNUNET_MessageHeader *message)
311 {
312   const struct AddressUpdateMessage *m;
313   const struct GNUNET_ATS_Information *atsi;
314   const char *address;
315   const char *plugin_name;
316   uint16_t address_length;
317   uint16_t plugin_name_length;
318   uint32_t ats_count;
319   uint16_t size;
320
321   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
322               "Received `%s' message\n",
323               "ADDRESS_UPDATE");
324   size = ntohs (message->size);
325   if (size < sizeof (struct AddressUpdateMessage))
326   {
327     GNUNET_break (0);
328     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
329     return;
330   }
331   m = (const struct AddressUpdateMessage *) message;
332   ats_count = ntohl (m->ats_count);
333   address_length = ntohs (m->address_length);
334   plugin_name_length = ntohs (m->plugin_name_length);
335   atsi = (const struct GNUNET_ATS_Information *) &m[1];
336   address = (const char *) &atsi[ats_count];
337   if (plugin_name_length != 0)
338     plugin_name = &address[address_length];
339   else
340     plugin_name = "";
341
342   if ((address_length + plugin_name_length +
343        ats_count * sizeof (struct GNUNET_ATS_Information) +
344        sizeof (struct AddressUpdateMessage) != ntohs (message->size)) ||
345       (ats_count >
346        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_ATS_Information)) ||
347        ((plugin_name_length > 0) && (plugin_name[plugin_name_length - 1] != '\0')))
348   {
349     GNUNET_break (0);
350     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
351     return;
352   }
353   GNUNET_STATISTICS_update (GSA_stats,
354                             "# address updates received",
355                             1,
356                             GNUNET_NO);
357   GAS_addresses_update (address_handle,
358                         &m->peer,
359                         plugin_name,
360                         address,
361                         address_length,
362                         ntohl (m->address_local_info),
363                         ntohl (m->session_id), atsi, ats_count);
364   GNUNET_SERVER_receive_done (client, GNUNET_OK);
365 }
366
367
368 /**
369  * Handle 'address in use' messages from clients.
370  *
371  * @param cls unused, NULL
372  * @param client client that sent the request
373  * @param message the request message
374  */
375 void
376 GAS_handle_address_in_use (void *cls,
377                            struct GNUNET_SERVER_Client *client,
378                            const struct GNUNET_MessageHeader *message)
379 {
380   const struct AddressUseMessage *m;
381   const char *address;
382   const char *plugin_name;
383   int res;
384   uint16_t address_length;
385   uint16_t plugin_name_length;
386   uint16_t size;
387   uint16_t in_use;
388
389   size = ntohs (message->size);
390   if (size < sizeof (struct AddressUseMessage))
391   {
392     GNUNET_break (0);
393     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
394     return;
395   }
396   m = (const struct AddressUseMessage *) message;
397
398   address_length = ntohs (m->address_length);
399   plugin_name_length = ntohs (m->plugin_name_length);
400
401   address = (const char *) &m[1];
402   if (plugin_name_length != 0)
403     plugin_name = &address[address_length];
404   else
405     plugin_name = "";
406
407   if ((address_length + plugin_name_length +
408        sizeof (struct AddressUseMessage) != ntohs (message->size)) ||
409       ((plugin_name_length > 0) &&
410       (plugin_name[plugin_name_length - 1] != '\0')))
411   {
412     GNUNET_break (0);
413     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
414     return;
415   }
416
417   in_use = ntohs (m->in_use);
418   res = GAS_addresses_in_use (address_handle,
419                               &m->peer,
420                               plugin_name,
421                               address,
422                               address_length,
423                               ntohl (m->address_local_info),
424                               ntohl (m->session_id),
425                               in_use);
426
427   if (GNUNET_OK != res)
428   {
429     GNUNET_break (0);
430     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
431     return;
432   }
433   GNUNET_SERVER_receive_done (client, GNUNET_OK);
434 }
435
436
437 /**
438  * Handle 'address destroyed' messages from clients.
439  *
440  * @param cls unused, NULL
441  * @param client client that sent the request
442  * @param message the request message
443  */
444 void
445 GAS_handle_address_destroyed (void *cls,
446                               struct GNUNET_SERVER_Client *client,
447                               const struct GNUNET_MessageHeader *message)
448 {
449   const struct AddressDestroyedMessage *m;
450   struct SessionReleaseMessage srm;
451   const char *address;
452   const char *plugin_name;
453   uint16_t address_length;
454   uint16_t plugin_name_length;
455   uint16_t size;
456
457   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458               "Received `%s' message of size %u %u\n",
459               "ADDRESS_DESTROYED",
460               ntohs (message->size),
461               sizeof (struct AddressDestroyedMessage));
462   size = ntohs (message->size);
463   if ((size < sizeof (struct AddressDestroyedMessage)) || (client != my_client))
464   {
465     GNUNET_break (0);
466     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
467     return;
468   }
469   m = (const struct AddressDestroyedMessage *) message;
470   GNUNET_break (0 == ntohl (m->reserved));
471   address_length = ntohs (m->address_length);
472   plugin_name_length = ntohs (m->plugin_name_length);
473   address = (const char *) &m[1];
474   if (plugin_name_length != 0)
475     plugin_name = &address[address_length];
476   else
477     plugin_name = "";
478   if ((address_length + plugin_name_length +
479        sizeof (struct AddressDestroyedMessage) != ntohs (message->size)))
480   {
481     GNUNET_break (0);
482     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
483     return;
484   }
485   if ((plugin_name_length == 0) ||
486       (plugin_name[plugin_name_length - 1] != '\0'))
487   {
488     GNUNET_break (0);
489     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
490     return;
491   }
492   GNUNET_STATISTICS_update (GSA_stats,
493                             "# addresses destroyed",
494                             1,
495                             GNUNET_NO);
496   GAS_addresses_destroy (address_handle, &m->peer, plugin_name,
497                          address, address_length,
498                          ntohl (m->address_local_info),
499                          ntohl (m->session_id));
500   if (0 != ntohl (m->session_id))
501   {
502     srm.header.type = ntohs (GNUNET_MESSAGE_TYPE_ATS_SESSION_RELEASE);
503     srm.header.size = ntohs (sizeof (struct SessionReleaseMessage));
504     srm.session_id = m->session_id;
505     srm.peer = m->peer;
506     GNUNET_SERVER_notification_context_unicast (nc, client, &srm.header,
507                                                 GNUNET_NO);
508   }
509   GNUNET_SERVER_receive_done (client, GNUNET_OK);
510 }
511
512
513 /**
514  * Initialize scheduling subsystem.
515  *
516  * @param server handle to our server
517  * @param ah the address handle to use
518  */
519 void
520 GAS_scheduling_init (struct GNUNET_SERVER_Handle *server,
521                      struct GAS_Addresses_Handle *ah)
522 {
523   GNUNET_assert (NULL != ah);
524   address_handle = ah;
525   nc = GNUNET_SERVER_notification_context_create (server, 128);
526 }
527
528
529 /**
530  * Shutdown scheduling subsystem.
531  */
532 void
533 GAS_scheduling_done ()
534 {
535   if (NULL != my_client)
536   {
537     my_client = NULL;
538   }
539   GNUNET_SERVER_notification_context_destroy (nc);
540   nc = NULL;
541 }
542
543
544 /* end of gnunet-service-ats_scheduling.c */