]> git.ipfire.org Git - oddments/cappie.git/blob - cappie/__init__.py
Remove database instance from each interface thread.
[oddments/cappie.git] / cappie / __init__.py
1 #!/usr/bin/python
2 ###############################################################################
3 # #
4 # Cappie #
5 # Copyright (C) 2010 Michael Tremer #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 import logging
23 import logging.handlers
24 import pcapy
25 import time
26
27 from ConfigParser import ConfigParser
28 from threading import Thread
29
30 import protocol
31 import queue
32
33 from errors import *
34
35 def getAllInterfaces():
36 filters = ("lo", "any")
37 ret = []
38 for dev in pcapy.findalldevs():
39 if not dev in filters:
40 ret.append(dev)
41 return ret
42
43 class Cappie(object):
44 def __init__(self):
45 self.__interfaces = []
46
47 self.log = logging.getLogger("cappie")
48 self.log.setLevel(logging.INFO)
49
50 # Log to console
51 handler = logging.StreamHandler()
52 handler.setFormatter(logging.Formatter("%(levelname)7s %(message)s"))
53 self.log.addHandler(handler)
54
55 # Setup syslog
56 handler = logging.handlers.SysLogHandler("/dev/log")
57 handler.setFormatter(logging.Formatter("cappie: %(message)s"))
58 self.log.addHandler(handler)
59
60 self.queue = queue.Queue(self.log)
61
62 self.log.info("Cappie successfully started")
63
64 def __del__(self):
65 self.shutdown()
66 self.log.info("Exiting")
67
68 def setDebug(self, debug):
69 if debug:
70 self.log.setLevel(logging.DEBUG)
71 else:
72 self.log.setLevel(logging.INFO)
73
74 def addInterface(self, dev, **kwargs):
75 if not dev in getAllInterfaces():
76 raise InterfaceError, "No such interface %s" % dev
77
78 kwargs["cappie"] = self
79
80 iface = Interface(dev, **kwargs)
81 self.__interfaces.append(iface)
82
83 def run(self):
84 if not self.__interfaces:
85 raise RuntimeError, "No interfaces were configured"
86
87 # Start queue
88 self.queue.start()
89
90 # Start a thread for each interface
91 for iface in self.__interfaces:
92 iface.start()
93
94 while True:
95 if not self.queue.isAlive():
96 self.log.critical("Queue thread died unexpectedly.")
97 return
98
99 for iface in self.__interfaces:
100 if not iface.isAlive():
101 self.log.critical("Thread died unexpectedly. %s" % iface.dev)
102 return
103 time.sleep(60)
104
105 def readConfig(self, configfile):
106 config = ConfigParser()
107 config.read([configfile])
108
109 global_opts = {}
110 if config.has_section("global"):
111 for option, value in config.items("global"):
112 global_opts[option] = value
113
114 config.remove_section("global")
115
116 for iface in config.sections():
117 options = {}
118 for option, value in config.items(iface):
119 options[option] = value
120 self.addInterface(iface, **options)
121
122 def shutdown(self):
123 for iface in self.__interfaces:
124 iface.shutdown()
125
126 self.queue.shutdown()
127
128
129 class Interface(Thread):
130 heartbeat = 0.1
131
132 def __init__(self, dev, cappie, promisc=False, mtu=1500):
133 Thread.__init__(self)
134
135 self.cappie = cappie
136 self.dev = dev
137 self.log = self.cappie.log
138 self.mtu = mtu
139 self.promisc = promisc
140 self.queue = self.cappie.queue
141
142 self.log.debug("Created new interface %s" % self.dev)
143
144 self.__running = True
145
146 def _callback(self, header, data):
147 self.log.debug("Received packet on %s" % self.dev)
148 try:
149 p = protocol.decode_packet(data)
150 except PacketTypeError, e:
151 self.log.error("Got unknown packet: %s" % e)
152 return
153 except DecodeError, e:
154 self.log.warning("Got decoding error: %s" % e)
155 return
156
157 # Dump packet information
158 for key, val in p.items():
159 self.log.debug(" %s: %s" % (key, val))
160
161 def run(self):
162 self.log.info("Starting interface %s" % self.dev)
163
164 p = pcapy.open_live(self.dev, self.mtu, self.promisc, 0)
165 p.setfilter(self.filter)
166 #p.loop(0, self._callback)
167
168 p.setnonblock(1)
169 while True:
170 if not self.__running:
171 return
172
173 if p.dispatch(1, self._callback):
174 continue
175
176 time.sleep(self.heartbeat)
177
178 def shutdown(self):
179 if not self.__running:
180 return
181
182 self.log.debug("Sending shutdown signal to %s" % self.dev)
183 self.__running = False
184
185 @property
186 def filter(self):
187 return "arp or rarp"
188