instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / Core / DecentralizedTracking / kadtracker / floodbarrier.py
1 # Copyright (C) 2009 Raul Jimenez
2 # Released under GNU LGPL 2.1
3 # See LICENSE.txt for more information
4
5 """
6 Floodbarrier is a protection mechanism which protects us from
7 host processing too many messages from a single host.
8
9 """
10
11 import time
12 import collections
13 import logging, logging_conf
14
15 logger = logging.getLogger('dht')
16
17
18 CHECKING_PERIOD = 2 # seconds
19 MAX_PACKETS_PER_PERIOD = 20
20 BLOCKING_PERIOD = 100 # seconds
21
22 class HalfPeriodRegister(object):
23
24     """Helper class. Not meant to be used outside this module"""
25
26     def __init__(self):
27         self.ip_dict = {}
28
29     def get_num_packets(self, ip):
30         return self.ip_dict.get(ip, 0)
31
32     def register_ip(self, ip):
33         self.ip_dict[ip] = self.ip_dict.get(ip, 0) + 1
34
35 class FloodBarrier(object):
36
37     """
38     Object which keeps track of packets received from different
39     hosts. Default values are coded but users can choose their own.
40     The main function is ip_blocked().
41
42     """
43
44     def __init__(self, checking_period=CHECKING_PERIOD,
45                  max_packets_per_period=MAX_PACKETS_PER_PERIOD,
46                  blocking_period=BLOCKING_PERIOD):
47         self.checking_period = checking_period
48         self.max_packets_per_period = max_packets_per_period
49         self.blocking_period = blocking_period
50
51         self.last_half_period_time = time.time()
52         self.ip_registers = [HalfPeriodRegister(), HalfPeriodRegister()]
53         self.blocked_ips = {}
54
55     def ip_blocked(self, ip):
56         """
57         Register that a packet has been received from the given IP and return
58         whether the host is blocked and, hence, the packet should be dropped
59         
60         """
61         current_time = time.time()
62         if current_time > self.last_half_period_time + self.checking_period / 2:
63             self.half_period_timeout = current_time
64             self.ip_registers = [self.ip_registers[1], HalfPeriodRegister()]
65             if current_time > self.last_half_period_time + self.checking_period:
66                 self.ip_registers = [self.ip_registers[1], HalfPeriodRegister()]
67         self.ip_registers[1].register_ip(ip)
68         num_packets = self.ip_registers[0].get_num_packets(ip) + \
69             self.ip_registers[1].get_num_packets(ip)
70         if num_packets > self.max_packets_per_period:
71             logger.debug('Got %d packets: blocking %r...' % (
72                     num_packets, ip))
73             self.blocked_ips[ip] = current_time + self.blocking_period
74             return True
75         # At this point there are no enough packets to block ip (in current
76         # period). Now, we need to check whether the ip is currently blocked
77         if ip in self.blocked_ips:
78             logger.debug('Ip %r (%d) currently blocked' % (ip,
79                                                             num_packets))
80             if current_time > self.blocked_ips[ip]:
81                 logger.debug(
82                     'Block for %r (%d) has expired: unblocking...' %
83                     (ip, num_packets))
84                 # Blocking period already expired
85                 del self.blocked_ips[ip]
86                 return False
87             else:
88                 # IP is currently blocked (block hasn't expired)
89                 return True
90         else:
91
92             
93             # IP is not blocked
94             return False
95