docu
[oweals/gnunet.git] / src / transport / gnunet-service-transport_blacklist.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 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 transport/gnunet-service-transport_blacklist.c
23  * @brief blacklisting implementation
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet-service-transport.h"
28 #include "gnunet-service-transport_blacklist.h"
29 #include "gnunet-service-transport_neighbours.h"
30 #include "transport.h"
31
32
33 /**
34  * Size of the blacklist hash map.
35  */
36 #define TRANSPORT_BLACKLIST_HT_SIZE 64
37
38
39 /**
40  * Context we use when performing a blacklist check.
41  */
42 struct GST_BlacklistCheck;
43
44
45 /**
46  * Information kept for each client registered to perform
47  * blacklisting.
48  */
49 struct Blacklisters
50 {
51   /**
52    * This is a linked list.
53    */
54   struct Blacklisters *next;
55
56   /**
57    * This is a linked list.
58    */
59   struct Blacklisters *prev;
60
61   /**
62    * Client responsible for this entry.
63    */
64   struct GNUNET_SERVER_Client *client;
65
66   /**
67    * Blacklist check that we're currently performing (or NULL
68    * if we're performing one that has been cancelled).
69    */
70   struct GST_BlacklistCheck *bc;
71
72   /**
73    * Set to GNUNET_YES if we're currently waiting for a reply.
74    */
75   int waiting_for_reply;
76
77 };
78
79
80
81 /**
82  * Context we use when performing a blacklist check.
83  */
84 struct GST_BlacklistCheck
85 {
86
87   /**
88    * This is a linked list.
89    */
90   struct GST_BlacklistCheck *next;
91
92   /**
93    * This is a linked list.
94    */
95   struct GST_BlacklistCheck *prev;
96
97   /**
98    * Peer being checked.
99    */
100   struct GNUNET_PeerIdentity peer;
101
102   /**
103    * Continuation to call with the result.
104    */
105   GST_BlacklistTestContinuation cont;
106
107   /**
108    * Closure for cont.
109    */
110   void *cont_cls;
111
112   /**
113    * Current transmission request handle for this client, or NULL if no
114    * request is pending.
115    */
116   struct GNUNET_SERVER_TransmitHandle *th;
117
118   /**
119    * Our current position in the blacklisters list.
120    */
121   struct Blacklisters *bl_pos;
122
123   /**
124    * Current task performing the check.
125    */
126   GNUNET_SCHEDULER_TaskIdentifier task;
127
128 };
129
130
131 /**
132  * Head of DLL of active blacklisting queries.
133  */
134 static struct GST_BlacklistCheck *bc_head;
135
136 /**
137  * Tail of DLL of active blacklisting queries.
138  */
139 static struct GST_BlacklistCheck *bc_tail;
140
141 /**
142  * Head of DLL of blacklisting clients.
143  */
144 static struct Blacklisters *bl_head;
145
146 /**
147  * Tail of DLL of blacklisting clients.
148  */
149 static struct Blacklisters *bl_tail;
150
151 /**
152  * Hashmap of blacklisted peers.  Values are of type 'char *' (transport names),
153  * can be NULL if we have no static blacklist.
154  */
155 static struct GNUNET_CONTAINER_MultiHashMap *blacklist;
156
157
158 /**
159  * Perform next action in the blacklist check.
160  *
161  * @param cls the 'struct BlacklistCheck*'
162  * @param tc unused
163  */
164 static void
165 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
166
167
168 /**
169  * Called whenever a client is disconnected.  Frees our
170  * resources associated with that client.
171  *
172  * @param cls closure (unused)
173  * @param client identification of the client
174  */
175 static void
176 client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
177 {
178   struct Blacklisters *bl;
179   struct GST_BlacklistCheck *bc;
180
181   if (client == NULL)
182     return;
183   for (bl = bl_head; bl != NULL; bl = bl->next)
184   {
185     if (bl->client != client)
186       continue;
187     for (bc = bc_head; bc != NULL; bc = bc->next)
188     {
189       if (bc->bl_pos != bl)
190         continue;
191       bc->bl_pos = bl->next;
192       if (bc->th != NULL)
193       {
194         GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
195         bc->th = NULL;
196       }
197       if (bc->task == GNUNET_SCHEDULER_NO_TASK)
198         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
199       break;
200     }
201     GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
202     GNUNET_SERVER_client_drop (bl->client);
203     GNUNET_free (bl);
204     break;
205   }
206 }
207
208
209 /**
210  * Read the blacklist file, containing transport:peer entries.
211  * Provided the transport is loaded, set up hashmap with these
212  * entries to blacklist peers by transport.
213  *
214  */
215 static void
216 read_blacklist_file ()
217 {
218   char *fn;
219   char *data;
220   size_t pos;
221   size_t colon_pos;
222   int tsize;
223   struct GNUNET_PeerIdentity pid;
224   uint64_t fsize;
225   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
226   unsigned int entries_found;
227   char *transport_name;
228
229   if (GNUNET_OK !=
230       GNUNET_CONFIGURATION_get_value_filename (GST_cfg, "TRANSPORT",
231                                                "BLACKLIST_FILE", &fn))
232   {
233     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_DEBUG,
234                                "transport", "BLACKLIST_FILE");
235     return;
236   }
237   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
238     GNUNET_DISK_fn_write (fn, NULL, 0,
239                           GNUNET_DISK_PERM_USER_READ |
240                           GNUNET_DISK_PERM_USER_WRITE);
241   if (GNUNET_OK != GNUNET_DISK_file_size (fn,
242       &fsize, GNUNET_NO, GNUNET_YES))
243   {
244     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
245                 _("Could not read blacklist file `%s'\n"), fn);
246     GNUNET_free (fn);
247     return;
248   }
249   if (fsize == 0)
250   {
251     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Blacklist file `%s' is empty.\n"),
252                 fn);
253     GNUNET_free (fn);
254     return;
255   }
256   /* FIXME: use mmap */
257   data = GNUNET_malloc_large (fsize);
258   GNUNET_assert (data != NULL);
259   if (fsize != GNUNET_DISK_fn_read (fn, data, fsize))
260   {
261     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
262                 _("Failed to read blacklist from `%s'\n"), fn);
263     GNUNET_free (fn);
264     GNUNET_free (data);
265     return;
266   }
267   entries_found = 0;
268   pos = 0;
269   while ((pos < fsize) && isspace ((unsigned char) data[pos]))
270     pos++;
271   while ((fsize >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
272          (pos <=
273           fsize - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
274   {
275     colon_pos = pos;
276     while ((colon_pos < fsize) && (data[colon_pos] != ':') &&
277            (!isspace ((unsigned char) data[colon_pos])))
278       colon_pos++;
279     if (colon_pos >= fsize)
280     {
281       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
282                   _
283                   ("Syntax error in blacklist file at offset %llu, giving up!\n"),
284                   (unsigned long long) colon_pos);
285       GNUNET_free (fn);
286       GNUNET_free (data);
287       return;
288     }
289
290     if (isspace ((unsigned char) data[colon_pos]))
291     {
292       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
293                   _
294                   ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
295                   (unsigned long long) colon_pos);
296       pos = colon_pos;
297       while ((pos < fsize) && isspace ((unsigned char) data[pos]))
298         pos++;
299       continue;
300     }
301     tsize = colon_pos - pos;
302     if ((pos >= fsize) || (pos + tsize >= fsize) ||
303         (tsize == 0))
304     {
305       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
306                   _
307                   ("Syntax error in blacklist file at offset %llu, giving up!\n"),
308                   (unsigned long long) colon_pos);
309       GNUNET_free (fn);
310       GNUNET_free (data);
311       return;
312     }
313
314     if (tsize < 1)
315       continue;
316
317     transport_name = GNUNET_malloc (tsize + 1);
318     memcpy (transport_name, &data[pos], tsize);
319     pos = colon_pos + 1;
320     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321                 "Read transport name `%s' in blacklist file.\n",
322                 transport_name);
323     memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
324     if (!isspace
325         ((unsigned char)
326          enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
327     {
328       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
329                   _
330                   ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
331                   (unsigned long long) pos);
332       pos++;
333       while ((pos < fsize) && (!isspace ((unsigned char) data[pos])))
334         pos++;
335       GNUNET_free_non_null (transport_name);
336       continue;
337     }
338     enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
339     if (GNUNET_OK !=
340         GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
341     {
342       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
343                   _
344                   ("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
345                   (unsigned long long) pos, &enc);
346     }
347     else
348     {
349       if (0 !=
350           memcmp (&pid, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
351       {
352         entries_found++;
353         GST_blacklist_add_peer (&pid, transport_name);
354       }
355       else
356       {
357         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
358                     _("Found myself `%s' in blacklist (useless, ignored)\n"),
359                     GNUNET_i2s (&pid));
360       }
361     }
362     pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
363     GNUNET_free_non_null (transport_name);
364     while ((pos < fsize) && isspace ((unsigned char) data[pos]))
365       pos++;
366   }
367   GNUNET_STATISTICS_update (GST_stats, "# Transport entries blacklisted",
368                             entries_found, GNUNET_NO);
369   GNUNET_free (data);
370   GNUNET_free (fn);
371 }
372
373
374 /**
375  * Start blacklist subsystem.
376  *
377  * @param server server used to accept clients from
378  */
379 void
380 GST_blacklist_start (struct GNUNET_SERVER_Handle *server)
381 {
382   read_blacklist_file ();
383   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
384                                    NULL);
385 }
386
387
388 /**
389  * Free the given entry in the blacklist.
390  *
391  * @param cls unused
392  * @param key host identity (unused)
393  * @param value the blacklist entry
394  * @return GNUNET_OK (continue to iterate)
395  */
396 static int
397 free_blacklist_entry (void *cls, const struct GNUNET_HashCode * key, void *value)
398 {
399   char *be = value;
400
401   GNUNET_free (be);
402   return GNUNET_OK;
403 }
404
405
406 /**
407  * Stop blacklist subsystem.
408  */
409 void
410 GST_blacklist_stop ()
411 {
412   if (NULL != blacklist)
413   {
414     GNUNET_CONTAINER_multihashmap_iterate (blacklist, &free_blacklist_entry,
415                                            NULL);
416     GNUNET_CONTAINER_multihashmap_destroy (blacklist);
417     blacklist = NULL;
418   }
419 }
420
421
422 /**
423  * Transmit blacklist query to the client.
424  *
425  * @param cls the 'struct GST_BlacklistCheck'
426  * @param size number of bytes allowed
427  * @param buf where to copy the message
428  * @return number of bytes copied to buf
429  */
430 static size_t
431 transmit_blacklist_message (void *cls, size_t size, void *buf)
432 {
433   struct GST_BlacklistCheck *bc = cls;
434   struct Blacklisters *bl;
435   struct BlacklistMessage bm;
436
437   bc->th = NULL;
438   if (size == 0)
439   {
440     GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
441     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
442     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
443                 "Failed to send blacklist test for peer `%s' to client\n",
444                 GNUNET_i2s (&bc->peer));
445     return 0;
446   }
447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448               "Sending blacklist test for peer `%s' to client\n",
449               GNUNET_i2s (&bc->peer));
450   bl = bc->bl_pos;
451   bm.header.size = htons (sizeof (struct BlacklistMessage));
452   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
453   bm.is_allowed = htonl (0);
454   bm.peer = bc->peer;
455   memcpy (buf, &bm, sizeof (bm));
456   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
457   bl->waiting_for_reply = GNUNET_YES;
458   return sizeof (bm);
459 }
460
461
462 /**
463  * Perform next action in the blacklist check.
464  *
465  * @param cls the 'struct GST_BlacklistCheck*'
466  * @param tc unused
467  */
468 static void
469 do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
470 {
471   struct GST_BlacklistCheck *bc = cls;
472   struct Blacklisters *bl;
473
474   bc->task = GNUNET_SCHEDULER_NO_TASK;
475   bl = bc->bl_pos;
476   if (bl == NULL)
477   {
478     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
479                 "No other blacklist clients active, will allow neighbour `%s'\n",
480                 GNUNET_i2s (&bc->peer));
481     bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK);
482     GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
483     GNUNET_free (bc);
484     return;
485   }
486   if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO))
487     return;                     /* someone else busy with this client */
488   bl->bc = bc;
489   bc->th =
490       GNUNET_SERVER_notify_transmit_ready (bl->client,
491                                            sizeof (struct BlacklistMessage),
492                                            GNUNET_TIME_UNIT_FOREVER_REL,
493                                            &transmit_blacklist_message, bc);
494 }
495
496
497 /**
498  * Got the result about an existing connection from a new blacklister.
499  * Shutdown the neighbour if necessary.
500  *
501  * @param cls unused
502  * @param peer the neighbour that was investigated
503  * @param allowed GNUNET_OK if we can keep it,
504  *                GNUNET_NO if we must shutdown the connection
505  */
506 static void
507 confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer,
508                            int allowed)
509 {
510   if (GNUNET_OK == allowed)
511     return;                     /* we're done */
512   GNUNET_STATISTICS_update (GST_stats,
513                             gettext_noop ("# disconnects due to blacklist"), 1,
514                             GNUNET_NO);
515   GST_neighbours_force_disconnect (peer);
516 }
517
518
519 /**
520  * Closure for 'test_connection_ok'.
521  */
522 struct TestConnectionContext
523 {
524   /**
525    * Is this the first neighbour we're checking?
526    */
527   int first;
528
529   /**
530    * Handle to the blacklisting client we need to ask.
531    */
532   struct Blacklisters *bl;
533 };
534
535
536 /**
537  * Test if an existing connection is still acceptable given a new
538  * blacklisting client.
539  *
540  * @param cls the 'struct TestConnectionContest'
541  * @param neighbour neighbour's identity
542  * @param ats performance data
543  * @param ats_count number of entries in ats (excluding 0-termination)
544  * @param address the address
545  * @param bandwidth_in inbound quota in NBO
546  * @param bandwidth_out outbound quota in NBO
547  */
548 static void
549 test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour,
550                     const struct GNUNET_ATS_Information *ats,
551                     uint32_t ats_count,
552                     const struct GNUNET_HELLO_Address *address,
553                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
554                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
555 {
556   struct TestConnectionContext *tcc = cls;
557   struct GST_BlacklistCheck *bc;
558
559   bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
560   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
561   bc->peer = *neighbour;
562   bc->cont = &confirm_or_drop_neighbour;
563   bc->cont_cls = NULL;
564   bc->bl_pos = tcc->bl;
565   if (GNUNET_YES == tcc->first)
566   {
567     /* all would wait for the same client, no need to
568      * create more than just the first task right now */
569     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
570     tcc->first = GNUNET_NO;
571   }
572 }
573
574
575 /**
576  * Initialize a blacklisting client.  We got a blacklist-init
577  * message from this client, add him to the list of clients
578  * to query for blacklisting.
579  *
580  * @param cls unused
581  * @param client the client
582  * @param message the blacklist-init message that was sent
583  */
584 void
585 GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
586                            const struct GNUNET_MessageHeader *message)
587 {
588   struct Blacklisters *bl;
589   struct TestConnectionContext tcc;
590
591   bl = bl_head;
592   while (bl != NULL)
593   {
594     if (bl->client == client)
595     {
596       GNUNET_break (0);
597       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
598       return;
599     }
600     bl = bl->next;
601   }
602   GNUNET_SERVER_client_mark_monitor (client);
603   bl = GNUNET_malloc (sizeof (struct Blacklisters));
604   bl->client = client;
605   GNUNET_SERVER_client_keep (client);
606   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
607
608   /* confirm that all existing connections are OK! */
609   tcc.bl = bl;
610   tcc.first = GNUNET_YES;
611   GST_neighbours_iterate (&test_connection_ok, &tcc);
612 }
613
614
615 /**
616  * A blacklisting client has sent us reply. Process it.
617  *
618  * @param cls unused
619  * @param client the client
620  * @param message the blacklist-init message that was sent
621  */
622 void
623 GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
624                             const struct GNUNET_MessageHeader *message)
625 {
626   const struct BlacklistMessage *msg =
627       (const struct BlacklistMessage *) message;
628   struct Blacklisters *bl;
629   struct GST_BlacklistCheck *bc;
630
631   bl = bl_head;
632   while ((bl != NULL) && (bl->client != client))
633     bl = bl->next;
634   if (bl == NULL)
635   {
636     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
637     /* FIXME: other error handling here!? */
638     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
639     return;
640   }
641   bc = bl->bc;
642   bl->bc = NULL;
643   bl->waiting_for_reply = GNUNET_NO;
644   if (NULL != bc)
645   {
646     /* only run this if the blacklist check has not been
647      * cancelled in the meantime... */
648     if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
649     {
650       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651                   "Blacklist check failed, peer not allowed\n");
652       bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
653       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
654       GNUNET_free (bc);
655     }
656     else
657     {
658       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659                   "Blacklist check succeeded, continuing with checks\n");
660       bc->bl_pos = bc->bl_pos->next;
661       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
662     }
663   }
664   /* check if any other bc's are waiting for this blacklister */
665   bc = bc_head;
666   for (bc = bc_head; bc != NULL; bc = bc->next)
667     if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
668     {
669       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
670       break;
671     }
672 }
673
674
675 /**
676  * Add the given peer to the blacklist (for the given transport).
677  *
678  * @param peer peer to blacklist
679  * @param transport_name transport to blacklist for this peer, NULL for all
680  */
681 void
682 GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
683                         const char *transport_name)
684 {
685   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686               "Adding peer `%s' with plugin `%s' to blacklist\n",
687               GNUNET_i2s (peer), transport_name);
688   if (blacklist == NULL)
689     blacklist =
690       GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE,
691                                             GNUNET_NO);
692   GNUNET_CONTAINER_multihashmap_put (blacklist, &peer->hashPubKey,
693                                      GNUNET_strdup (transport_name),
694                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
695 }
696
697
698 /**
699  * Test if the given blacklist entry matches.  If so,
700  * abort the iteration.
701  *
702  * @param cls the transport name to match (const char*)
703  * @param key the key (unused)
704  * @param value the 'char *' (name of a blacklisted transport)
705  * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches
706  */
707 static int
708 test_blacklisted (void *cls, const struct GNUNET_HashCode * key, void *value)
709 {
710   const char *transport_name = cls;
711   char *be = value;
712
713   /* blacklist check for specific no specific transport*/
714   if (transport_name == NULL)
715     return GNUNET_NO;
716
717   /* blacklist check for specific transport */
718   if (0 == strcmp (transport_name, be))
719     return GNUNET_NO;           /* abort iteration! */
720   return GNUNET_OK;
721 }
722
723
724 /**
725  * Test if a peer/transport combination is blacklisted.
726  *
727  * @param peer the identity of the peer to test
728  * @param transport_name name of the transport to test, never NULL
729  * @param cont function to call with result
730  * @param cont_cls closure for 'cont'
731  * @return handle to the blacklist check, NULL if the decision
732  *        was made instantly and 'cont' was already called
733  */
734 struct GST_BlacklistCheck *
735 GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
736                             const char *transport_name,
737                             GST_BlacklistTestContinuation cont, void *cont_cls)
738 {
739   struct GST_BlacklistCheck *bc;
740
741   GNUNET_assert (peer != NULL);
742
743   if ((blacklist != NULL) &&
744       (GNUNET_SYSERR ==
745        GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, &peer->hashPubKey,
746                                                    &test_blacklisted,
747                                                    (void *) transport_name)))
748   {
749     /* disallowed by config, disapprove instantly */
750     GNUNET_STATISTICS_update (GST_stats,
751                               gettext_noop ("# disconnects due to blacklist"),
752                               1, GNUNET_NO);
753     if (cont != NULL)
754       cont (cont_cls, peer, GNUNET_NO);
755     return NULL;
756   }
757
758   if (bl_head == NULL)
759   {
760     /* no blacklist clients, approve instantly */
761     if (cont != NULL)
762       cont (cont_cls, peer, GNUNET_OK);
763     return NULL;
764   }
765
766   /* need to query blacklist clients */
767   bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
768   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
769   bc->peer = *peer;
770   bc->cont = cont;
771   bc->cont_cls = cont_cls;
772   bc->bl_pos = bl_head;
773   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
774   return bc;
775 }
776
777
778 /**
779  * Cancel a blacklist check.
780  *
781  * @param bc check to cancel
782  */
783 void
784 GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
785 {
786   GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
787   if (bc->bl_pos != NULL)
788   {
789     if (bc->bl_pos->bc == bc)
790     {
791       /* we're at the head of the queue, remove us! */
792       bc->bl_pos->bc = NULL;
793     }
794   }
795   if (GNUNET_SCHEDULER_NO_TASK != bc->task)
796   {
797     GNUNET_SCHEDULER_cancel (bc->task);
798     bc->task = GNUNET_SCHEDULER_NO_TASK;
799   }
800   if (NULL != bc->th)
801   {
802     GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
803     bc->th = NULL;
804   }
805   GNUNET_free (bc);
806 }
807
808
809 /* end of file gnunet-service-transport_blacklist.c */