5ddf9c1bfea56aaae246510ad184614a3a2f03c6
[oweals/gnunet.git] / src / transport / gnunet-service-transport_blacklist.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 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 2, 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 transport/gnunet-service-transport_blacklist.c
23  * @brief low-level P2P messaging
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_protocols.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_service_lib.h"
30 #include "transport.h"
31 #include "gnunet-service-transport_blacklist.h"
32
33
34 /**
35  * Information kept for each blacklisted peer.
36  */
37 struct BlacklistEntry
38 {
39   /**
40    * Identity of the peer being blacklisted by this entry.
41    * (also equivalent to the key)  
42    */
43   struct GNUNET_PeerIdentity peer;
44
45   /**
46    * How long until this entry times out?
47    */
48   struct GNUNET_TIME_Absolute until;
49
50   /**
51    * Task scheduled to run the moment the time does run out.
52    */
53   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
54 };
55
56
57 /**
58  * Map of blacklisted peers (maps from peer identities
59  * to 'struct BlacklistEntry*' values).
60  */
61 static struct GNUNET_CONTAINER_MultiHashMap *blacklist;
62
63 /**
64  * Notifications for blacklisting.
65  */
66 static struct GNUNET_SERVER_NotificationContext *blacklist_notifiers;
67
68 /**
69  * Our scheduler.
70  */
71 static struct GNUNET_SCHEDULER_Handle *sched;
72
73
74 /**
75  * Free the entries in the blacklist hash map.
76  *
77  * @param cls closure, unused
78  * @param key current key code
79  * @param value value in the hash map
80  * @return GNUNET_YES (continue to iterate)
81  */
82 static int
83 free_blacklist_entry (void *cls,
84                       const GNUNET_HashCode *key,
85                       void *value)
86 {
87   struct BlacklistEntry *be = value;
88
89   GNUNET_SCHEDULER_cancel (sched,
90                            be->timeout_task);
91   GNUNET_free (be);
92   return GNUNET_YES;
93 }
94
95
96 /**
97  * Task run when we are shutting down.  Cleans up.
98  *
99  * @param cls closure (unused)
100  * @param tc scheduler context (unused)
101  */
102 static void 
103 shutdown_task (void *cls,
104                const struct GNUNET_SCHEDULER_TaskContext *tc)
105 {
106   GNUNET_CONTAINER_multihashmap_iterate (blacklist,
107                                          &free_blacklist_entry,
108                                          NULL);
109   GNUNET_CONTAINER_multihashmap_destroy (blacklist);
110   blacklist = NULL;
111   GNUNET_SERVER_notification_context_destroy (blacklist_notifiers);
112   blacklist_notifiers = NULL;
113 }
114
115
116 /**
117  * Task run when a blacklist entry times out.
118  *
119  * @param cls closure (the 'struct BlacklistEntry*')
120  * @param tc scheduler context (unused)
121  */
122 static void
123 timeout_task (void *cls,
124               const struct GNUNET_SCHEDULER_TaskContext *tc)
125 {
126   struct BlacklistEntry *be = cls;
127   struct BlacklistMessage msg;
128   
129   be->timeout_task = GNUNET_SCHEDULER_NO_TASK; 
130   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST);
131   msg.header.size = htons (sizeof (struct BlacklistMessage));
132   msg.reserved = htonl (0);
133   msg.peer = be->peer;
134   msg.until = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_ZERO_ABS);
135   GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (blacklist,
136                                                                      &be->peer.hashPubKey,
137                                                                      be));
138   GNUNET_free (be);
139   GNUNET_SERVER_notification_context_broadcast (blacklist_notifiers,
140                                                 &msg.header,
141                                                 GNUNET_NO);
142 }
143
144
145 /**
146  * Handle a request to blacklist a peer.
147  *
148  * @param cls closure (always NULL)
149  * @param client identification of the client
150  * @param message the actual message
151  */
152 void
153 GNUNET_TRANSPORT_handle_blacklist (void *cls,
154                                    struct GNUNET_SERVER_Client *client,
155                                    const struct GNUNET_MessageHeader *message)
156 {
157   struct BlacklistEntry *be;
158   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
159
160   be = GNUNET_CONTAINER_multihashmap_get (blacklist,
161                                           &be->peer.hashPubKey);
162   if (be != NULL)
163     {
164       GNUNET_SCHEDULER_cancel (sched,
165                                be->timeout_task);
166     }
167   else
168     {
169       be = GNUNET_malloc (sizeof (struct BlacklistEntry));
170       be->peer = msg->peer;
171       GNUNET_CONTAINER_multihashmap_put (blacklist,
172                                          &be->peer.hashPubKey,
173                                          be,
174                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
175     }
176   be->until = GNUNET_TIME_absolute_ntoh (msg->until);
177   be->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
178                                                    GNUNET_TIME_absolute_get_remaining (be->until),
179                                                    &timeout_task,
180                                                    be);
181   GNUNET_SERVER_notification_context_broadcast (blacklist_notifiers,
182                                                 &msg->header,
183                                                 GNUNET_NO);
184   GNUNET_SERVER_receive_done (client, GNUNET_OK);
185 }
186
187
188 /**
189  * Notify the given client about all entries in the blacklist.
190  *
191  * @param cls closure, refers to the 'struct GNUNET_SERVER_Client' to notify
192  * @param key current key code (peer identity, not used)
193  * @param value value in the hash map, the 'struct BlacklistEntry*'
194  * @return GNUNET_YES (continue to iterate)
195  */
196 static int
197 notify_blacklist_entry (void *cls,
198                         const GNUNET_HashCode *key,
199                         void *value)
200 {
201   struct GNUNET_SERVER_Client *client = cls;
202   struct BlacklistEntry *be = value;
203   struct BlacklistMessage msg;
204
205   msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST);
206   msg.header.size = htons (sizeof (struct BlacklistMessage));
207   msg.reserved = htonl (0);
208   msg.peer = be->peer;
209   msg.until = GNUNET_TIME_absolute_hton (be->until);
210   GNUNET_SERVER_notification_context_unicast (blacklist_notifiers,
211                                               client,
212                                               &msg.header,
213                                               GNUNET_NO);
214   return GNUNET_YES;
215 }
216
217
218 /**
219  * Handle a request for notification of blacklist changes.
220  *
221  * @param cls closure (always NULL)
222  * @param client identification of the client
223  * @param message the actual message
224  */
225 void
226 GNUNET_TRANSPORT_handle_blacklist_notify (void *cls,
227                                           struct GNUNET_SERVER_Client *client,
228                                           const struct GNUNET_MessageHeader *message)
229 {
230   GNUNET_SERVER_notification_context_add (blacklist_notifiers, client);
231   GNUNET_CONTAINER_multihashmap_iterate (blacklist,
232                                          &notify_blacklist_entry,
233                                          client);
234 }
235
236
237 /**
238  * Is the given peer currently blacklisted?
239  *
240  * @param id identity of the peer
241  * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
242  */
243 int
244 GNUNET_TRANSPORT_blacklist_check (const struct GNUNET_PeerIdentity *id)
245 {
246   return GNUNET_CONTAINER_multihashmap_contains (blacklist, &id->hashPubKey);
247 }
248
249
250 /**
251  * Initialize the blacklisting subsystem.
252  *
253  * @param s scheduler to use
254  */
255 void 
256 GNUNET_TRANSPORT_blacklist_init (struct GNUNET_SERVER_Handle *server,
257                                  struct GNUNET_SCHEDULER_Handle *s)
258 {
259   sched = s;
260   blacklist = GNUNET_CONTAINER_multihashmap_create (4);
261   GNUNET_SCHEDULER_add_delayed (sched,
262                                 GNUNET_TIME_UNIT_FOREVER_REL,
263                                 &shutdown_task,
264                                 NULL);
265   blacklist_notifiers = GNUNET_SERVER_notification_context_create (server, 0);
266 }
267
268
269 /* end of gnunet-service-transport_blacklist.c */