asyncserver.py

Go to the documentation of this file.
00001 # This file is part of Fail2Ban.
00002 #
00003 # Fail2Ban is free software; you can redistribute it and/or modify
00004 # it under the terms of the GNU General Public License as published by
00005 # the Free Software Foundation; either version 2 of the License, or
00006 # (at your option) any later version.
00007 #
00008 # Fail2Ban is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 # GNU General Public License for more details.
00012 #
00013 # You should have received a copy of the GNU General Public License
00014 # along with Fail2Ban; if not, write to the Free Software
00015 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00016 
00017 # Author: Cyril Jaquier
00018 # 
00019 # $Revision: 567 $
00020 
00021 __author__ = "Cyril Jaquier"
00022 __version__ = "$Revision: 567 $"
00023 __date__ = "$Date: 2007-03-26 23:17:31 +0200 (Mon, 26 Mar 2007) $"
00024 __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
00025 __license__ = "GPL"
00026 
00027 from pickle import dumps, loads, HIGHEST_PROTOCOL
00028 import asyncore, asynchat, socket, os, logging
00029 
00030 # Gets the instance of the logger.
00031 logSys = logging.getLogger("fail2ban.server")
00032 
00033 ##
00034 # Request handler class.
00035 #
00036 # This class extends asynchat in order to provide a request handler for
00037 # incoming query.
00038 
00039 class RequestHandler(asynchat.async_chat):
00040     
00041     END_STRING = "<F2B_END_COMMAND>"
00042 
00043     def __init__(self, conn, transmitter):
00044         asynchat.async_chat.__init__(self, conn)
00045         self.__transmitter = transmitter
00046         self.__buffer = []
00047         # Sets the terminator.
00048         self.set_terminator(RequestHandler.END_STRING)
00049 
00050     def collect_incoming_data(self, data):
00051         #logSys.debug("Received raw data: " + str(data))
00052         self.__buffer.append(data)
00053 
00054     ##
00055     # Handles a new request.
00056     #
00057     # This method is called once we have a complete request.
00058 
00059     def found_terminator(self):
00060         # Joins the buffer items.
00061         message = loads("".join(self.__buffer))
00062         # Gives the message to the transmitter.
00063         message = self.__transmitter.proceed(message)
00064         # Serializes the response.
00065         message = dumps(message, HIGHEST_PROTOCOL)
00066         # Sends the response to the client.
00067         self.send(message + RequestHandler.END_STRING)
00068         # Closes the channel.
00069         self.close_when_done()
00070         
00071     def handle_error(self):
00072         logSys.error("Unexpected communication error")
00073         self.close()
00074         
00075 ##
00076 # Asynchronous server class.
00077 #
00078 # This class extends asyncore and dispatches connection requests to
00079 # RequestHandler.
00080 
00081 class AsyncServer(asyncore.dispatcher):
00082 
00083     def __init__(self, transmitter):
00084         asyncore.dispatcher.__init__(self)
00085         self.__transmitter = transmitter
00086         self.__sock = "/var/run/fail2ban/fail2ban.sock"
00087         self.__init = False
00088 
00089     ##
00090     # Returns False as we only read the socket first.
00091 
00092     def writable(self):
00093         return False
00094 
00095     def handle_accept(self):
00096         try:
00097             conn, addr = self.accept()
00098         except socket.error:
00099             logSys.warning("Socket error")
00100             return
00101         except TypeError:
00102             logSys.warning("Type error")
00103             return
00104         # Creates an instance of the handler class to handle the
00105         # request/response on the incoming connection.
00106         RequestHandler(conn, self.__transmitter)
00107     
00108     ##
00109     # Starts the communication server.
00110     #
00111     # @param sock: socket file.
00112     # @param force: remove the socket file if exists.
00113     
00114     def start(self, sock, force):
00115         self.__sock = sock
00116         # Remove socket
00117         if os.path.exists(sock):
00118             logSys.error("Fail2ban seems to be already running")
00119             if force:
00120                 logSys.warn("Forcing execution of the server")
00121                 os.remove(sock)
00122             else:
00123                 raise AsyncServerException("Server already running")
00124         # Creates the socket.
00125         self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
00126         self.set_reuse_addr()
00127         try:
00128             self.bind(sock)
00129         except Exception:
00130             raise AsyncServerException("Unable to bind socket %s" % self.__sock)
00131         self.listen(1)
00132         # Sets the init flag.
00133         self.__init = True
00134         # TODO Add try..catch
00135         asyncore.loop()
00136     
00137     ##
00138     # Stops the communication server.
00139     
00140     def stop(self):
00141         if self.__init:
00142             # Only closes the socket if it was initialized first.
00143             self.close()
00144         # Remove socket
00145         if os.path.exists(self.__sock):
00146             logSys.debug("Removed socket file " + self.__sock)
00147             os.remove(self.__sock)
00148         logSys.debug("Socket shutdown")
00149 
00150 
00151 ##
00152 # AsyncServerException is used to wrap communication exceptions.
00153 
00154 class AsyncServerException(Exception):
00155     pass
Generated on Mon May 20 03:01:58 2013 for Fail2Ban by  doxygen 1.6.3