2 """Network code for the Breadcrumb server."""
4 # Copyright (C) 2008 Laurens Van Houtven <lvh at laurensvh.be>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 from twisted
.internet
import reactor
19 from twisted
.internet
.protocol
import DatagramProtocol
# UDP
20 from twisted
.internet
.protocol
import Protocol
, Factory
# TCP
29 sys
.path
.append(os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
30 import common
.consts
as consts
32 class BreadcrumbServer
:
33 """A superclass for Breadcrumb servers."""
34 def __init__(self
, handler
= None):
35 self
.handler
= handler
36 atexit
.register(self
.clean_up
)
38 self
.keepdatapoints
= False
41 def new_crumb(self
, packed
):
42 """Unpacks a new crumb, checks it, and passes it to the handler."""
44 logging
.debug('Got a new crumb, sending to decoder...')
45 point
= decoding
.decode_crumb(packed
)
47 if self
.keepdatapoints
:
48 self
.datapoints
.append(point
)
50 if 'handlerid' in point
and 'handlermsg' in point
:
51 id, msg
= point
['handlerid'], point
['handlermsg']
52 self
.handler
.newmessage(id, msg
)
54 self
.handler
.newpoint(point
)
57 """Cleans up before closing.
59 This tells the handler that we're about to shut down, so it has a
60 chance to close connections, finalize files...
63 logging
.info('Cleaning up (calling the clean_up method)...')
64 self
.handler
.clean_up()
65 except AttributeError:
66 logging
.error('... but the handler has no cleanup method!')
67 logging
.error('Does it inherit from BaseHandler properly?')
68 except NotImplementedError:
69 logging
.debug("... but the handler didn't implement it.")
71 class BreadcrumbTCPServer(BreadcrumbServer
, Protocol
):
72 """A TCP server for the breadcrumb protocol."""
73 def __init__(self
, handler
= None):
74 BreadcrumbServer
.__init
__(self
, handler
)
76 def dataReceived(self
, crumb
):
77 """Handles a new crumb, received over TCP."""
80 class BreadcrumbUDPServer(BreadcrumbServer
, DatagramProtocol
):
81 """A UDP server for the breadcrumb protocol."""
82 def __init__(self
, handler
= None):
83 BreadcrumbServer
.__init
__(self
, handler
)
84 logging
.debug("New BreadcrumbUDPServer instance created.")
86 def datagramReceived(self
, crumb
, (host
, port
)):
87 """Handles a new crumb, received over UDP."""
88 logging
.debug("received something from %s:%d" % (host
, port
))
91 def start_server(port
= None, handler
= None, encap
= 'UDP', **kwargs
):
92 """Runs the Breadcrumb server.
94 The server argument is either the server proper (for UDP servers) or the
95 relevant factory (for TCP and derived protocols).
97 logging
.info("Booting the Breadcrumb server (version %s)" % consts
.VERSION
)
98 logging
.debug("Server started at %s." % time
.ctime())
103 logging
.error("Got noninteger port %s, can't start server..." % port
)
104 raise RuntimeError, 'Bad port: %s' % port
106 encap
= encap
.upper()
108 server
= BreadcrumbTCPServer(handler
= handler
)
111 factory
.protocol
= server
114 port
= consts
.DEFAULT_TCP_PORT
116 logging
.debug("Prepared TCP reactor on port %d" % port
)
117 reactor
.listenTCP(port
, factory
)
120 server
= BreadcrumbUDPServer(handler
= handler
)
123 port
= consts
.DEFAULT_UDP_PORT
125 logging
.debug("Prepared UDP reactor on port %d" % port
)
126 reactor
.listenUDP(port
, server
)
129 raise RuntimeError, 'Unknown encapsulation %s' % encap