- add send kx for axolotl
[oweals/gnunet.git] / src / ats / gnunet-service-ats_addresses.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-2015 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_addresses.c
23  * @brief ats service address management
24  * @author Matthias Wachs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet-service-ats_addresses.h"
29 #include "gnunet-service-ats_performance.h"
30 #include "gnunet-service-ats_normalization.h"
31 #include "gnunet-service-ats_plugins.h"
32
33
34 /**
35  * A multihashmap to store all addresses
36  */
37 struct GNUNET_CONTAINER_MultiPeerMap *GSA_addresses;
38
39
40
41 /**
42  * Update statistic on number of addresses.
43  */
44 static void
45 update_addresses_stat ()
46 {
47   GNUNET_STATISTICS_set (GSA_stats,
48                          "# addresses",
49                          GNUNET_CONTAINER_multipeermap_size (GSA_addresses),
50                          GNUNET_NO);
51 }
52
53
54 /**
55  * Free the given address
56  *
57  * @param addr address to destroy
58  */
59 static void
60 free_address (struct ATS_Address *addr)
61 {
62   GNUNET_assert (GNUNET_YES ==
63                  GNUNET_CONTAINER_multipeermap_remove (GSA_addresses,
64                                                        &addr->peer,
65                                                        addr));
66   update_addresses_stat ();
67   GAS_plugin_delete_address (addr);
68   GAS_performance_notify_all_clients (&addr->peer,
69                                       addr->plugin,
70                                       addr->addr,
71                                       addr->addr_len,
72                                       GNUNET_NO,
73                                       NULL,
74                                       GNUNET_BANDWIDTH_ZERO,
75                                       GNUNET_BANDWIDTH_ZERO);
76   GNUNET_free (addr->plugin);
77   GNUNET_free (addr);
78 }
79
80
81 /**
82  * Initialize @a norm.  Sets all historic values to undefined.
83  *
84  * @param norm normalization data to initialize
85  */
86 static void
87 init_norm (struct GAS_NormalizationInfo *norm)
88 {
89   unsigned int c;
90
91   for (c = 0; c < GAS_normalization_queue_length; c++)
92     norm->atsi_abs[c] = UINT64_MAX;
93 }
94
95
96 /**
97  * Create a ATS_address with the given information
98  *
99  * @param peer peer
100  * @param plugin_name plugin
101  * @param plugin_addr address
102  * @param plugin_addr_len address length
103  * @param local_address_info additional local info for the address
104  * @param session_id session identifier, can never be 0
105  * @return the ATS_Address
106  */
107 static struct ATS_Address *
108 create_address (const struct GNUNET_PeerIdentity *peer,
109                 const char *plugin_name,
110                 const void *plugin_addr,
111                 size_t plugin_addr_len,
112                 uint32_t local_address_info,
113                 uint32_t session_id)
114 {
115   struct ATS_Address *aa;
116
117   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len);
118   aa->peer = *peer;
119   aa->addr_len = plugin_addr_len;
120   aa->addr = &aa[1];
121   memcpy (&aa[1],
122           plugin_addr,
123           plugin_addr_len);
124   aa->plugin = GNUNET_strdup (plugin_name);
125   aa->session_id = session_id;
126   aa->local_address_info = local_address_info;
127   init_norm (&aa->norm_delay);
128   init_norm (&aa->norm_distance);
129   init_norm (&aa->norm_utilization_in);
130   init_norm (&aa->norm_utilization_out);
131   return aa;
132 }
133
134
135 /**
136  * Closure for #find_address_cb()
137  */
138 struct FindAddressContext
139 {
140   /**
141    * Session Id to look for.
142    */
143   uint32_t session_id;
144
145   /**
146    * Where to store matching address result.
147    */
148   struct ATS_Address *exact_address;
149
150 };
151
152
153 /**
154  * Find session matching given session ID.
155  *
156  * @param cls a `struct FindAddressContext`
157  * @param key peer id
158  * @param value the address to compare with
159  * @return #GNUNET_YES to continue, #GNUNET_NO if address is found
160  */
161 static int
162 find_address_cb (void *cls,
163                  const struct GNUNET_PeerIdentity *key,
164                  void *value)
165 {
166   struct FindAddressContext *fac = cls;
167   struct ATS_Address *aa = value;
168
169   if (aa->session_id == fac->session_id)
170   {
171     fac->exact_address = aa;
172     return GNUNET_NO;
173   }
174   return GNUNET_YES;
175 }
176
177
178 /**
179  * Find the exact address
180  *
181  * @param peer peer
182  * @param session_id session id, can never be 0
183  * @return an ATS_address or NULL
184  */
185 static struct ATS_Address *
186 find_exact_address (const struct GNUNET_PeerIdentity *peer,
187                     uint32_t session_id)
188 {
189   struct FindAddressContext fac;
190
191   fac.exact_address = NULL;
192   fac.session_id = session_id;
193   GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
194                                               peer,
195                                               &find_address_cb, &fac);
196   return fac.exact_address;
197 }
198
199
200 /**
201  * Add a new address for a peer.
202  *
203  * @param peer peer
204  * @param plugin_name transport plugin name
205  * @param plugin_addr plugin address
206  * @param plugin_addr_len length of the plugin address in @a plugin_addr
207  * @param local_address_info the local address for the address
208  * @param session_id session id, can be 0
209  * @param prop performance information for this address
210  */
211 void
212 GAS_addresses_add (const struct GNUNET_PeerIdentity *peer,
213                    const char *plugin_name,
214                    const void *plugin_addr,
215                    size_t plugin_addr_len,
216                    uint32_t local_address_info,
217                    uint32_t session_id,
218                    const struct GNUNET_ATS_Properties *prop)
219 {
220   struct ATS_Address *new_address;
221
222   if (NULL != find_exact_address (peer,
223                                   session_id))
224   {
225     GNUNET_break (0);
226     return;
227   }
228   new_address = create_address (peer,
229                                 plugin_name,
230                                 plugin_addr,
231                                 plugin_addr_len,
232                                 local_address_info,
233                                 session_id);
234   /* Add a new address */
235   new_address->properties = *prop;
236   new_address->t_added = GNUNET_TIME_absolute_get();
237   new_address->t_last_activity = GNUNET_TIME_absolute_get();
238   GNUNET_assert(GNUNET_OK ==
239                 GNUNET_CONTAINER_multipeermap_put (GSA_addresses,
240                                                    peer,
241                                                    new_address,
242                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
243   update_addresses_stat ();
244   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
245               "Adding new address for peer `%s' slot %u\n",
246               GNUNET_i2s (peer),
247               session_id);
248   /* Tell solver about new address */
249   GAS_plugin_solver_lock ();
250   GAS_plugin_new_address (new_address);
251   GAS_normalization_update_property (new_address); // FIXME: needed?
252   GAS_plugin_solver_unlock ();
253   /* Notify performance clients about new address */
254   GAS_performance_notify_all_clients (&new_address->peer,
255                                       new_address->plugin,
256                                       new_address->addr,
257                                       new_address->addr_len,
258                                       new_address->active,
259                                       &new_address->properties,
260                                       GNUNET_BANDWIDTH_value_init (new_address->assigned_bw_out),
261                                       GNUNET_BANDWIDTH_value_init (new_address->assigned_bw_in));
262 }
263
264
265 /**
266  * Update an address with new performance information for a peer.
267  *
268  * @param peer peer
269  * @param session_id session id, never 0
270  * @param prop performance information for this address
271  */
272 void
273 GAS_addresses_update (const struct GNUNET_PeerIdentity *peer,
274                       uint32_t session_id,
275                       const struct GNUNET_ATS_Properties *prop)
276 {
277   struct ATS_Address *aa;
278
279   /* Get existing address */
280   aa = find_exact_address (peer,
281                            session_id);
282   if (NULL == aa)
283   {
284     GNUNET_break (0);
285     return;
286   }
287   if (NULL == aa->solver_information)
288   {
289     GNUNET_break (0);
290     return;
291   }
292   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293               "Received ADDRESS_UPDATE for peer `%s' slot %u\n",
294               GNUNET_i2s (peer),
295               (unsigned int) session_id);
296
297   /* Update address */
298   aa->t_last_activity = GNUNET_TIME_absolute_get();
299   aa->properties = *prop;
300   /* Notify performance clients about updated address */
301   GAS_performance_notify_all_clients (&aa->peer,
302                                       aa->plugin,
303                                       aa->addr,
304                                       aa->addr_len,
305                                       aa->active,
306                                       prop,
307                                       GNUNET_BANDWIDTH_value_init (aa->assigned_bw_out),
308                                       GNUNET_BANDWIDTH_value_init (aa->assigned_bw_in));
309
310   GAS_normalization_update_property (aa);
311 }
312
313
314 /**
315  * Remove an address for a peer.
316  *
317  * @param peer peer
318  * @param session_id session id, can never be 0
319  */
320 void
321 GAS_addresses_destroy (const struct GNUNET_PeerIdentity *peer,
322                        uint32_t session_id)
323 {
324   struct ATS_Address *ea;
325
326   /* Get existing address */
327   ea = find_exact_address (peer,
328                            session_id);
329   if (NULL == ea)
330   {
331     GNUNET_break (0);
332     return;
333   }
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335               "Received ADDRESS_DESTROYED for peer `%s' session %u\n",
336               GNUNET_i2s (peer),
337               session_id);
338   free_address (ea);
339 }
340
341
342 /**
343  * Initialize address subsystem. The addresses subsystem manages the addresses
344  * known and current performance information. It has a solver component
345  * responsible for the resource allocation. It tells the solver about changes
346  * and receives updates when the solver changes the resource allocation.
347  *
348  * @param server handle to our server
349  */
350 void
351 GAS_addresses_init (struct GNUNET_SERVER_Handle *server)
352 {
353   GSA_addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
354   update_addresses_stat ();
355 }
356
357
358 /**
359  * Destroy all addresses iterator
360  *
361  * @param cls NULL
362  * @param key peer identity (unused)
363  * @param value the 'struct ATS_Address' to free
364  * @return #GNUNET_OK (continue to iterate)
365  */
366 static int
367 destroy_all_address_it (void *cls,
368                         const struct GNUNET_PeerIdentity *key,
369                         void *value)
370 {
371   struct ATS_Address *aa = value;
372
373   free_address (aa);
374   return GNUNET_OK;
375 }
376
377
378 /**
379  * Remove all addresses
380  */
381 void
382 GAS_addresses_destroy_all ()
383 {
384   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
385               "Destroying all addresses\n");
386   if (0 ==
387       GNUNET_CONTAINER_multipeermap_size (GSA_addresses))
388     return;
389   GAS_plugin_solver_lock ();
390   GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
391                                          &destroy_all_address_it,
392                                          NULL);
393   GAS_plugin_solver_unlock ();
394 }
395
396
397 /**
398  * Shutdown address subsystem.
399  */
400 void
401 GAS_addresses_done ()
402 {
403   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
404              "Shutting down addresses\n");
405   GAS_addresses_destroy_all ();
406   GNUNET_CONTAINER_multipeermap_destroy (GSA_addresses);
407   GSA_addresses = NULL;
408 }
409
410
411 /**
412  * Closure for #peerinfo_it().
413  */
414 struct PeerInfoIteratorContext
415 {
416   /**
417    * Function to call for each address.
418    */
419   GNUNET_ATS_PeerInfo_Iterator it;
420
421   /**
422    * Closure for @e it.
423    */
424   void *it_cls;
425 };
426
427
428 /**
429  * Iterator to iterate over a peer's addresses
430  *
431  * @param cls a `struct PeerInfoIteratorContext`
432  * @param key the peer id
433  * @param value the `struct ATS_address`
434  * @return #GNUNET_OK to continue
435  */
436 static int
437 peerinfo_it (void *cls,
438              const struct GNUNET_PeerIdentity *key,
439              void *value)
440 {
441   struct PeerInfoIteratorContext *pi_ctx = cls;
442   struct ATS_Address *addr = value;
443
444   pi_ctx->it (pi_ctx->it_cls,
445               &addr->peer,
446               addr->plugin,
447               addr->addr,
448               addr->addr_len,
449               addr->active,
450               &addr->properties,
451               GNUNET_BANDWIDTH_value_init (addr->assigned_bw_out),
452               GNUNET_BANDWIDTH_value_init (addr->assigned_bw_in));
453   return GNUNET_OK;
454 }
455
456
457 /**
458  * Return information all peers currently known to ATS
459  *
460  * @param peer the respective peer, NULL for 'all' peers
461  * @param pi_it the iterator to call for every peer
462  * @param pi_it_cls the closure for @a pi_it
463  */
464 void
465 GAS_addresses_get_peer_info (const struct GNUNET_PeerIdentity *peer,
466                              GNUNET_ATS_PeerInfo_Iterator pi_it,
467                              void *pi_it_cls)
468 {
469   struct PeerInfoIteratorContext pi_ctx;
470
471   if (NULL == pi_it)
472   {
473     /* does not make sense without callback */
474     GNUNET_break (0);
475     return;
476   }
477   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478               "Returning information for %s from a total of %u known addresses\n",
479               (NULL == peer)
480               ? "all peers"
481               : GNUNET_i2s (peer),
482               (unsigned int) GNUNET_CONTAINER_multipeermap_size (GSA_addresses));
483   pi_ctx.it = pi_it;
484   pi_ctx.it_cls = pi_it_cls;
485   if (NULL == peer)
486     GNUNET_CONTAINER_multipeermap_iterate (GSA_addresses,
487                                            &peerinfo_it,
488                                            &pi_ctx);
489   else
490     GNUNET_CONTAINER_multipeermap_get_multiple (GSA_addresses,
491                                                 peer,
492                                                 &peerinfo_it, &pi_ctx);
493   pi_it (pi_it_cls,
494          NULL, NULL, NULL, 0,
495          GNUNET_NO,
496          NULL,
497          GNUNET_BANDWIDTH_ZERO,
498          GNUNET_BANDWIDTH_ZERO);
499 }
500
501
502 /**
503  * Information we need for the callbacks to return a list of addresses
504  * back to the client.
505  */
506 struct AddressIteration
507 {
508   /**
509    * Actual handle to the client.
510    */
511   struct GNUNET_SERVER_Client *client;
512
513   /**
514    * Are we sending all addresses, or only those that are active?
515    */
516   int all;
517
518   /**
519    * Which ID should be included in the response?
520    */
521   uint32_t id;
522
523 };
524
525
526 /**
527  * Send a #GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE with the
528  * given address details to the client identified in @a ai.
529  *
530  * @param ai our address information context (identifies the client)
531  * @param id the peer id this address is for
532  * @param plugin_name name of the plugin that supports this address
533  * @param plugin_addr address
534  * @param plugin_addr_len length of @a plugin_addr
535  * @param active #GNUNET_YES if this address is actively used
536  * @param prop performance information
537  * @param bandwidth_out current outbound bandwidth assigned to address
538  * @param bandwidth_in current inbound bandwidth assigned to address
539  */
540 static void
541 transmit_req_addr (struct AddressIteration *ai,
542                    const struct GNUNET_PeerIdentity *id,
543                    const char *plugin_name,
544                    const void *plugin_addr,
545                    size_t plugin_addr_len,
546                    int active,
547                    const struct GNUNET_ATS_Properties *prop,
548                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
549                    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
550
551 {
552   struct PeerInformationMessage *msg;
553   char *addrp;
554   size_t plugin_name_length;
555   size_t msize;
556   struct GNUNET_SERVER_NotificationContext **uc;
557   struct GNUNET_SERVER_NotificationContext *nc;
558
559   if (NULL != plugin_name)
560     plugin_name_length = strlen (plugin_name) + 1;
561   else
562     plugin_name_length = 0;
563   msize = sizeof (struct PeerInformationMessage) +
564           plugin_addr_len + plugin_name_length;
565   char buf[msize] GNUNET_ALIGN;
566
567   GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
568   msg = (struct PeerInformationMessage *) buf;
569   msg->header.size = htons (msize);
570   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
571   msg->id = htonl (ai->id);
572   if (NULL != id)
573     msg->peer = *id;
574   else
575     memset (&msg->peer, '\0', sizeof (struct GNUNET_PeerIdentity));
576   msg->address_length = htons (plugin_addr_len);
577   msg->address_active = ntohl (active);
578   msg->plugin_name_length = htons (plugin_name_length);
579   msg->bandwidth_out = bandwidth_out;
580   msg->bandwidth_in = bandwidth_in;
581   if (NULL != prop)
582     GNUNET_ATS_properties_hton (&msg->properties,
583                                 prop);
584   else
585     memset (&msg->properties,
586             0,
587             sizeof (struct GNUNET_ATS_Properties));
588   addrp = (char *) &msg[1];
589   if (NULL != plugin_addr)
590     memcpy (addrp, plugin_addr, plugin_addr_len);
591   if (NULL != plugin_name)
592     strcpy (&addrp[plugin_addr_len], plugin_name);
593   uc = GNUNET_SERVER_client_get_user_context (ai->client,
594                                               struct GNUNET_SERVER_NotificationContext *);
595   if (NULL == uc)
596   {
597     GNUNET_break (0);
598     return;
599   }
600   nc = *uc;
601   GNUNET_SERVER_notification_context_unicast (nc,
602                                               ai->client,
603                                               &msg->header,
604                                               GNUNET_NO);
605 }
606
607
608 /**
609  * Iterator for #GAS_addresses_get_peer_info(), called with peer-specific
610  * information to be passed back to the client.
611  *
612  * @param cls closure with our `struct AddressIteration *`
613  * @param id the peer id
614  * @param plugin_name plugin name
615  * @param plugin_addr address
616  * @param plugin_addr_len length of @a plugin_addr
617  * @param active is address actively used
618  * @param prop performance information
619  * @param bandwidth_out current outbound bandwidth assigned to address
620  * @param bandwidth_in current inbound bandwidth assigned to address
621  */
622 static void
623 req_addr_peerinfo_it (void *cls,
624                       const struct GNUNET_PeerIdentity *id,
625                       const char *plugin_name,
626                       const void *plugin_addr,
627                       size_t plugin_addr_len,
628                       int active,
629                       const struct GNUNET_ATS_Properties *prop,
630                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
631                       struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
632 {
633   struct AddressIteration *ai = cls;
634
635   if ( (NULL == id) &&
636        (NULL == plugin_name) &&
637        (NULL == plugin_addr) )
638   {
639     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
640                 "Address iteration done for one peer\n");
641     return;
642   }
643   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
644               "Callback for %s peer `%s' plugin `%s' BW out %u, BW in %u\n",
645               (active == GNUNET_YES) ? "ACTIVE" : "INACTIVE",
646               GNUNET_i2s (id),
647               plugin_name,
648               (unsigned int) ntohl (bandwidth_out.value__),
649               (unsigned int) ntohl (bandwidth_in.value__));
650   /* Transmit result (either if address is active, or if
651      client wanted all addresses) */
652   if ( (GNUNET_YES != ai->all) &&
653        (GNUNET_YES != active))
654     return;
655   transmit_req_addr (ai,
656                      id,
657                      plugin_name,
658                      plugin_addr, plugin_addr_len,
659                      active,
660                      prop,
661                      bandwidth_out,
662                      bandwidth_in);
663 }
664
665
666 /**
667  * Handle 'address list request' messages from clients.
668  *
669  * @param cls unused, NULL
670  * @param client client that sent the request
671  * @param message the request message
672  */
673 void
674 GAS_handle_request_address_list (void *cls,
675                                  struct GNUNET_SERVER_Client *client,
676                                  const struct GNUNET_MessageHeader *message)
677 {
678   struct AddressIteration ai;
679   const struct AddressListRequestMessage *alrm;
680   struct GNUNET_PeerIdentity allzeros;
681
682   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
683               "Received ADDRESSLIST_REQUEST message\n");
684   alrm = (const struct AddressListRequestMessage *) message;
685   ai.all = ntohl (alrm->all);
686   ai.id = ntohl (alrm->id);
687   ai.client = client;
688
689   memset (&allzeros,
690           '\0',
691           sizeof (struct GNUNET_PeerIdentity));
692   if (0 == memcmp (&alrm->peer,
693                    &allzeros,
694                    sizeof (struct GNUNET_PeerIdentity)))
695   {
696     /* Return addresses for all peers */
697     GAS_addresses_get_peer_info (NULL,
698                                  &req_addr_peerinfo_it,
699                                  &ai);
700   }
701   else
702   {
703     /* Return addresses for a specific peer */
704     GAS_addresses_get_peer_info (&alrm->peer,
705                                  &req_addr_peerinfo_it,
706                                  &ai);
707   }
708   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709               "Finished handling `%s' message\n",
710               "ADDRESSLIST_REQUEST");
711   transmit_req_addr (&ai,
712                      NULL, NULL, NULL,
713                      0, GNUNET_NO,
714                      NULL,
715                      GNUNET_BANDWIDTH_ZERO,
716                      GNUNET_BANDWIDTH_ZERO);
717   GNUNET_SERVER_receive_done (client,
718                               GNUNET_OK);
719 }
720
721
722
723 /* end of gnunet-service-ats_addresses.c */