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