| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | """Generic socket server classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This module tries to capture the various aspects of defining a server: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - address family: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         - AF_INET: IP (Internet Protocol) sockets (default) | 
					
						
							|  |  |  |         - AF_UNIX: Unix domain sockets | 
					
						
							|  |  |  |         - others, e.g. AF_DECNET are conceivable (see <socket.h> | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | - socket type: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         - SOCK_STREAM (reliable stream, e.g. TCP) | 
					
						
							|  |  |  |         - SOCK_DGRAM (datagrams, e.g. UDP) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | - client address verification before further looking at the request | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         (This is actually a hook for any processing that needs to look | 
					
						
							|  |  |  |          at the request before anything else, e.g. logging) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | - how to handle multiple requests: | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         - synchronous (one request is handled at a time) | 
					
						
							|  |  |  |         - forking (each request is handled by a new process) | 
					
						
							|  |  |  |         - threading (each request is handled by a new thread) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The classes in this module favor the server type that is simplest to | 
					
						
							|  |  |  | write: a synchronous TCP/IP server.  This is bad class design, but | 
					
						
							|  |  |  | save some typing.  (There's also the issue that a deep class hierarchy | 
					
						
							|  |  |  | slows down method lookups.) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | There are four classes in an inheritance diagram that represent | 
					
						
							|  |  |  | synchronous servers of four types: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         +-----------+        +------------------+ | 
					
						
							|  |  |  |         | TCPServer |------->| UnixStreamServer | | 
					
						
							|  |  |  |         +-----------+        +------------------+ | 
					
						
							|  |  |  |               | | 
					
						
							|  |  |  |               v | 
					
						
							|  |  |  |         +-----------+        +--------------------+ | 
					
						
							|  |  |  |         | UDPServer |------->| UnixDatagramServer | | 
					
						
							|  |  |  |         +-----------+        +--------------------+ | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-07-16 16:21:38 +00:00
										 |  |  | Note that UnixDatagramServer derives from UDPServer, not from | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | UnixStreamServer -- the only difference between an IP and a Unix | 
					
						
							|  |  |  | stream server is the address family, which is simply repeated in both | 
					
						
							| 
									
										
										
										
											1997-07-16 16:21:38 +00:00
										 |  |  | unix server classes. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Forking and threading versions of each type of server can be created | 
					
						
							|  |  |  | using the ForkingServer and ThreadingServer mix-in classes.  For | 
					
						
							|  |  |  | instance, a threading UDP server class is created as follows: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-07-16 16:21:38 +00:00
										 |  |  | The Mix-in class must come first, since it overrides a method defined | 
					
						
							|  |  |  | in UDPServer! | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | To implement a service, you must derive a class from | 
					
						
							|  |  |  | BaseRequestHandler and redefine its handle() method.  You can then run | 
					
						
							|  |  |  | various versions of the service by combining one of the server classes | 
					
						
							|  |  |  | with your request handler class. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The request handler class must be different for datagram or stream | 
					
						
							|  |  |  | services.  This can be hidden by using the mix-in request handler | 
					
						
							|  |  |  | classes StreamRequestHandler or DatagramRequestHandler. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Of course, you still have to use your head! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For instance, it makes no sense to use a forking server if the service | 
					
						
							|  |  |  | contains state in memory that can be modified by requests (since the | 
					
						
							|  |  |  | modifications in the child process would never reach the initial state | 
					
						
							|  |  |  | kept in the parent process and passed to each child).  In this case, | 
					
						
							|  |  |  | you can use a threading server, but you will probably have to use | 
					
						
							|  |  |  | locks to avoid two requests that come in nearly simultaneous to apply | 
					
						
							|  |  |  | conflicting changes to the server state. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | On the other hand, if you are building e.g. an HTTP server, where all | 
					
						
							|  |  |  | data is stored externally (e.g. in the file system), a synchronous | 
					
						
							|  |  |  | class will essentially render the service "deaf" while one request is | 
					
						
							|  |  |  | being handled -- which may be for a very long time if a client is slow | 
					
						
							|  |  |  | to reqd all the data it has requested.  Here a threading or forking | 
					
						
							|  |  |  | server is appropriate. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In some cases, it may be appropriate to process part of a request | 
					
						
							|  |  |  | synchronously, but to finish processing in a forked child depending on | 
					
						
							|  |  |  | the request data.  This can be implemented by using a synchronous | 
					
						
							|  |  |  | server and doing an explicit fork in the request handler class's | 
					
						
							|  |  |  | handle() method. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Another approach to handling multiple simultaneous requests in an | 
					
						
							|  |  |  | environment that supports neither threads nor fork (or where these are | 
					
						
							|  |  |  | too expensive or inappropriate for the service) is to maintain an | 
					
						
							|  |  |  | explicit table of partially finished requests and to use select() to | 
					
						
							|  |  |  | decide which request to work on next (or whether to handle a new | 
					
						
							|  |  |  | incoming request).  This is particularly important for stream services | 
					
						
							|  |  |  | where each client can potentially be connected for a long time (if | 
					
						
							|  |  |  | threads or subprocesses can't be used). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Future work: | 
					
						
							|  |  |  | - Standard classes for Sun RPC (which uses either UDP or TCP) | 
					
						
							|  |  |  | - Standard mix-in classes to implement various authentication | 
					
						
							|  |  |  |   and encryption schemes | 
					
						
							|  |  |  | - Standard framework for select-based multiplexing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | XXX Open problems: | 
					
						
							|  |  |  | - What to do with out-of-band data? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __version__ = "0.2" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import socket | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TCPServer: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Base class for various socket-based server classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Defaults to synchronous IP stream (i.e., TCP). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Methods for the caller: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - __init__(server_address, RequestHandlerClass) | 
					
						
							|  |  |  |     - serve_forever() | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |     - handle_request()  # if you don't use serve_forever() | 
					
						
							|  |  |  |     - fileno() -> int   # for select() | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Methods that may be overridden: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - server_bind() | 
					
						
							|  |  |  |     - server_activate() | 
					
						
							|  |  |  |     - get_request() -> request, client_address | 
					
						
							|  |  |  |     - verify_request(request, client_address) | 
					
						
							|  |  |  |     - process_request(request, client_address) | 
					
						
							|  |  |  |     - handle_error() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Methods for derived classes: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - finish_request(request, client_address) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Class variables that may be overridden by derived classes or | 
					
						
							|  |  |  |     instances: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - address_family | 
					
						
							|  |  |  |     - socket_type | 
					
						
							|  |  |  |     - request_queue_size (only for stream sockets) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Instance variables: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     - server_address | 
					
						
							|  |  |  |     - RequestHandlerClass | 
					
						
							|  |  |  |     - socket | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     address_family = socket.AF_INET | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     socket_type = socket.SOCK_STREAM | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     request_queue_size = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, server_address, RequestHandlerClass): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Constructor.  May be extended, do not override.""" | 
					
						
							|  |  |  |         self.server_address = server_address | 
					
						
							|  |  |  |         self.RequestHandlerClass = RequestHandlerClass | 
					
						
							|  |  |  |         self.socket = socket.socket(self.address_family, | 
					
						
							|  |  |  |                                     self.socket_type) | 
					
						
							|  |  |  |         self.server_bind() | 
					
						
							|  |  |  |         self.server_activate() | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def server_bind(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Called by constructor to bind the socket.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         May be overridden. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.socket.bind(self.server_address) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def server_activate(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Called by constructor to activate the server.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         May be overridden. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.socket.listen(self.request_queue_size) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def fileno(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Return socket file number.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         Interface required by select(). | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         return self.socket.fileno() | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def serve_forever(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Handle one request at a time until doomsday.""" | 
					
						
							|  |  |  |         while 1: | 
					
						
							|  |  |  |             self.handle_request() | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # The distinction between handling, getting, processing and | 
					
						
							|  |  |  |     # finishing a request is fairly arbitrary.  Remember: | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # - handle_request() is the top-level call.  It calls | 
					
						
							|  |  |  |     #   get_request(), verify_request() and process_request() | 
					
						
							|  |  |  |     # - get_request() is different for stream or datagram sockets | 
					
						
							|  |  |  |     # - process_request() is the place that may fork a new process | 
					
						
							|  |  |  |     #   or create a new thread to finish the request | 
					
						
							|  |  |  |     # - finish_request() instantiates the request handler class; | 
					
						
							|  |  |  |     #   this constructor will handle the request all by itself | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def handle_request(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Handle one request, possibly blocking.""" | 
					
						
							|  |  |  |         request, client_address = self.get_request() | 
					
						
							|  |  |  |         if self.verify_request(request, client_address): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self.process_request(request, client_address) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 self.handle_error(request, client_address) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_request(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Get the request and client address from the socket.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         May be overridden. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         return self.socket.accept() | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def verify_request(self, request, client_address): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Verify the request.  May be overridden.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         Return true if we should proceed with this request. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         return 1 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def process_request(self, request, client_address): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Call finish_request.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         Overridden by ForkingMixIn and ThreadingMixIn. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.finish_request(request, client_address) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def finish_request(self, request, client_address): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Finish one request by instantiating RequestHandlerClass.""" | 
					
						
							|  |  |  |         self.RequestHandlerClass(request, client_address, self) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def handle_error(self, request, client_address): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Handle an error gracefully.  May be overridden.
 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         The default is to print a traceback and continue. | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         print '-'*40 | 
					
						
							|  |  |  |         print 'Exception happened during processing of request from', | 
					
						
							|  |  |  |         print client_address | 
					
						
							|  |  |  |         import traceback | 
					
						
							|  |  |  |         traceback.print_exc() | 
					
						
							|  |  |  |         print '-'*40 | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UDPServer(TCPServer): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """UDP server class.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     socket_type = socket.SOCK_DGRAM | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     max_packet_size = 8192 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_request(self): | 
					
						
							| 
									
										
										
										
											1998-06-16 02:27:33 +00:00
										 |  |  |         data, client_addr = self.socket.recvfrom(self.max_packet_size) | 
					
						
							|  |  |  |         return (data, self.socket), client_addr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def server_activate(self): | 
					
						
							|  |  |  |         # No need to call listen() for UDP. | 
					
						
							|  |  |  |         pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ForkingMixIn: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Mix-in class to handle each request in a new process.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     active_children = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def collect_children(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Internal routine to wait for died children.""" | 
					
						
							|  |  |  |         while self.active_children: | 
					
						
							|  |  |  |             pid, status = os.waitpid(0, os.WNOHANG) | 
					
						
							|  |  |  |             if not pid: break | 
					
						
							|  |  |  |             self.active_children.remove(pid) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def process_request(self, request, client_address): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Fork a new subprocess to process the request.""" | 
					
						
							|  |  |  |         self.collect_children() | 
					
						
							|  |  |  |         pid = os.fork() | 
					
						
							|  |  |  |         if pid: | 
					
						
							|  |  |  |             # Parent process | 
					
						
							|  |  |  |             if self.active_children is None: | 
					
						
							|  |  |  |                 self.active_children = [] | 
					
						
							|  |  |  |             self.active_children.append(pid) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # Child process. | 
					
						
							|  |  |  |             # This must never return, hence os._exit()! | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self.finish_request(request, client_address) | 
					
						
							|  |  |  |                 os._exit(0) | 
					
						
							|  |  |  |             except: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     self.handle_error(request, | 
					
						
							|  |  |  |                                       client_address) | 
					
						
							|  |  |  |                 finally: | 
					
						
							|  |  |  |                     os._exit(1) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ThreadingMixIn: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Mix-in class to handle each request in a new thread.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_request(self, request, client_address): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         """Start a new thread to process the request.""" | 
					
						
							|  |  |  |         import thread | 
					
						
							|  |  |  |         thread.start_new_thread(self.finish_request, | 
					
						
							|  |  |  |                                 (request, client_address)) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ForkingUDPServer(ForkingMixIn, UDPServer): pass | 
					
						
							|  |  |  | class ForkingTCPServer(ForkingMixIn, TCPServer): pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass | 
					
						
							|  |  |  | class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-11-30 15:07:01 +00:00
										 |  |  | if hasattr(socket, 'AF_UNIX'): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class UnixStreamServer(TCPServer): | 
					
						
							|  |  |  |         address_family = socket.AF_UNIX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class UnixDatagramServer(UDPServer): | 
					
						
							|  |  |  |         address_family = socket.AF_UNIX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class BaseRequestHandler: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Base class for request handler classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This class is instantiated for each request to be handled.  The | 
					
						
							|  |  |  |     constructor sets the instance variables request, client_address | 
					
						
							|  |  |  |     and server, and then calls the handle() method.  To implement a | 
					
						
							|  |  |  |     specific service, all you need to do is to derive a class which | 
					
						
							|  |  |  |     defines a handle() method. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The handle() method can find the request as self.request, the | 
					
						
							| 
									
										
										
										
											1998-11-16 19:06:30 +00:00
										 |  |  |     client address as self.client_address, and the server (in case it | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  |     needs access to per-server information) as self.server.  Since a | 
					
						
							|  |  |  |     separate instance is created for each request, the handle() method | 
					
						
							|  |  |  |     can define arbitrary other instance variariables. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, request, client_address, server): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         self.request = request | 
					
						
							|  |  |  |         self.client_address = client_address | 
					
						
							|  |  |  |         self.server = server | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.setup() | 
					
						
							|  |  |  |             self.handle() | 
					
						
							|  |  |  |             self.finish() | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             sys.exc_traceback = None    # Help garbage collection | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def setup(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __del__(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def handle(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def finish(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         pass | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # The following two classes make it possible to use the same service | 
					
						
							|  |  |  | # class for stream or datagram servers. | 
					
						
							|  |  |  | # Each class sets up these instance variables: | 
					
						
							|  |  |  | # - rfile: a file object from which receives the request is read | 
					
						
							|  |  |  | # - wfile: a file object to which the reply is written | 
					
						
							|  |  |  | # When the handle() method returns, wfile is flushed properly | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class StreamRequestHandler(BaseRequestHandler): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Define self.rfile and self.wfile for stream sockets.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setup(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         self.connection = self.request | 
					
						
							|  |  |  |         self.rfile = self.connection.makefile('rb', 0) | 
					
						
							|  |  |  |         self.wfile = self.connection.makefile('wb', 0) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def finish(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         self.wfile.flush() | 
					
						
							| 
									
										
										
										
											1998-04-03 16:49:52 +00:00
										 |  |  |         self.wfile.close() | 
					
						
							|  |  |  |         self.rfile.close() | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DatagramRequestHandler(BaseRequestHandler): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Define self.rfile and self.wfile for datagram sockets.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setup(self): | 
					
						
							| 
									
										
										
										
											1998-03-26 21:13:24 +00:00
										 |  |  |         import StringIO | 
					
						
							|  |  |  |         self.packet, self.socket = self.request | 
					
						
							|  |  |  |         self.rfile = StringIO.StringIO(self.packet) | 
					
						
							|  |  |  |         self.wfile = StringIO.StringIO(self.packet) | 
					
						
							| 
									
										
										
										
											1995-08-04 04:00:20 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def finish(self): | 
					
						
							| 
									
										
										
										
											1998-06-16 02:27:33 +00:00
										 |  |  |         self.socket.sendto(self.wfile.getvalue(), self.client_address) |