7bde6e354c3b0cd14a8a5cb631591b7c1fe86cd5
[oweals/gnunet.git] / src / ats / gnunet-service-ats_connectivity.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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file ats/gnunet-service-ats_connectivity.c
23  * @brief ats service, interaction with 'connecivity' 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_connectivity.h"
31 #include "gnunet-service-ats_plugins.h"
32 #include "ats.h"
33
34
35 /**
36  * Active connection requests.
37  */
38 struct ConnectionRequest
39 {
40   /**
41    * Client that made the request.
42    */
43   struct GNUNET_SERVER_Client *client;
44
45   /* TODO: allow client to express a 'strength' for this request */
46 };
47
48
49 /**
50  * Address suggestion requests by peer.
51  */
52 static struct GNUNET_CONTAINER_MultiPeerMap *connection_requests;
53
54
55 /**
56  * Is the given peer in the list of peers for which we
57  * have an address request?
58  *
59  * @param cls unused, NULL
60  * @param peer peer to query for
61  * @return #GNUNET_YES if so, #GNUNET_NO if not
62  */
63 unsigned int
64 GAS_connectivity_has_peer (void *cls,
65                            const struct GNUNET_PeerIdentity *peer)
66 {
67   if (NULL == connection_requests)
68     return 0;
69   /* TODO: return sum of 'strength's of connectivity requests */
70   return GNUNET_CONTAINER_multipeermap_contains (connection_requests,
71                                                  peer);
72 }
73
74
75 /**
76  * Handle #GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS messages from clients.
77  *
78  * @param cls unused, NULL
79  * @param client client that sent the request
80  * @param message the request message
81  */
82 void
83 GAS_handle_request_address (void *cls,
84                             struct GNUNET_SERVER_Client *client,
85                             const struct GNUNET_MessageHeader *message)
86 {
87   const struct RequestAddressMessage *msg =
88       (const struct RequestAddressMessage *) message;
89   struct ConnectionRequest *cr;
90
91   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
92               "Received `%s' message\n",
93               "GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS");
94   /* FIXME: should not ignore "msg->strength" */
95   cr = GNUNET_new (struct ConnectionRequest);
96   cr->client = client;
97   (void) GNUNET_CONTAINER_multipeermap_put (connection_requests,
98                                             &msg->peer,
99                                             cr,
100                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
101   GAS_plugin_request_connect_start (&msg->peer);
102   GNUNET_SERVER_receive_done (client, GNUNET_OK);
103 }
104
105
106 /**
107  * Free the connection request from the map if the
108  * closure matches the client.
109  *
110  * @param cls the client to match
111  * @param pid peer for which the request was made
112  * @param value the `struct ConnectionRequest`
113  * @return #GNUNET_OK (continue to iterate)
114  */
115 static int
116 free_matching_requests (void *cls,
117                         const struct GNUNET_PeerIdentity *pid,
118                         void *value)
119 {
120   struct GNUNET_SERVER_Client *client = cls;
121   struct ConnectionRequest *cr = value;
122
123   if (cr->client == client)
124   {
125     GAS_plugin_request_connect_stop (pid);
126     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127                 "Removed request pending for peer `%s\n",
128                 GNUNET_i2s (pid));
129     GNUNET_assert (GNUNET_YES ==
130                    GNUNET_CONTAINER_multipeermap_remove (connection_requests,
131                                                          pid,
132                                                          cr));
133     GNUNET_free (cr);
134   }
135   return GNUNET_OK;
136 }
137
138
139 /**
140  * Handle #GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL messages
141  * from clients.
142  *
143  * @param cls unused, NULL
144  * @param client client that sent the request
145  * @param message the request message
146  */
147 void
148 GAS_handle_request_address_cancel (void *cls,
149                                    struct GNUNET_SERVER_Client *client,
150                                    const struct GNUNET_MessageHeader *message)
151 {
152   const struct RequestAddressMessage *msg =
153       (const struct RequestAddressMessage *) message;
154
155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156               "Received GNUNET_MESSAGE_TYPE_ATS_REQUEST_ADDRESS_CANCEL message for peer %s\n",
157               GNUNET_i2s (&msg->peer));
158   GNUNET_break (0 == ntohl (msg->strength));
159   GNUNET_CONTAINER_multipeermap_get_multiple (connection_requests,
160                                               &msg->peer,
161                                               &free_matching_requests,
162                                               client);
163   GNUNET_SERVER_receive_done (client, GNUNET_OK);
164 }
165
166
167 /**
168  * Unregister a client (which may have been a connectivity client,
169  * but this is not assured).
170  *
171  * @param client handle of the (now dead) client
172  */
173 void
174 GAS_connectivity_remove_client (struct GNUNET_SERVER_Client *client)
175 {
176   GNUNET_CONTAINER_multipeermap_iterate (connection_requests,
177                                          &free_matching_requests,
178                                          client);
179 }
180
181
182 /**
183  * Shutdown connectivity subsystem.
184  */
185 void
186 GAS_connectivity_init ()
187 {
188   connection_requests = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_NO);
189 }
190
191
192 /**
193  * Free the connection request from the map.
194  *
195  * @param cls NULL
196  * @param pid peer for which the request was made
197  * @param value the `struct ConnectionRequest`
198  * @return #GNUNET_OK (continue to iterate)
199  */
200 static int
201 free_request (void *cls,
202               const struct GNUNET_PeerIdentity *pid,
203               void *value)
204 {
205   struct ConnectionRequest *cr = value;
206
207   free_matching_requests (cr->client,
208                           pid,
209                           cr);
210   return GNUNET_OK;
211 }
212
213
214 /**
215  * Shutdown connectivity subsystem.
216  */
217 void
218 GAS_connectivity_done ()
219 {
220   GNUNET_CONTAINER_multipeermap_iterate (connection_requests,
221                                          &free_request,
222                                          NULL);
223   GNUNET_CONTAINER_multipeermap_destroy (connection_requests);
224   connection_requests = NULL;
225 }
226
227
228 /* end of gnunet-service-ats_connectivity.c */