1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep"""Generic socket server classes. 2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThis module tries to capture the various aspects of defining a server: 4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFor socket-based servers: 6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- address family: 8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - AF_INET{,6}: IP (Internet Protocol) sockets (default) 9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - AF_UNIX: Unix domain sockets 10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - others, e.g. AF_DECNET are conceivable (see <socket.h> 11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- socket type: 12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - SOCK_STREAM (reliable stream, e.g. TCP) 13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - SOCK_DGRAM (datagrams, e.g. UDP) 14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFor request-based servers (including socket-based): 16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- client address verification before further looking at the request 18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep (This is actually a hook for any processing that needs to look 19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep at the request before anything else, e.g. logging) 20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- how to handle multiple requests: 21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - synchronous (one request is handled at a time) 22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - forking (each request is handled by a new process) 23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - threading (each request is handled by a new thread) 24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThe classes in this module favor the server type that is simplest to 26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepwrite: a synchronous TCP/IP server. This is bad class design, but 27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsave some typing. (There's also the issue that a deep class hierarchy 28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepslows down method lookups.) 29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThere are five classes in an inheritance diagram, four of which represent 31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsynchronous servers of four types: 32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep +------------+ 34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep | BaseServer | 35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep +------------+ 36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep | 37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep v 38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep +-----------+ +------------------+ 39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep | TCPServer |------->| UnixStreamServer | 40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep +-----------+ +------------------+ 41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep | 42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep v 43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep +-----------+ +--------------------+ 44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep | UDPServer |------->| UnixDatagramServer | 45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep +-----------+ +--------------------+ 46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepNote that UnixDatagramServer derives from UDPServer, not from 48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepUnixStreamServer -- the only difference between an IP and a Unix 49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepstream server is the address family, which is simply repeated in both 50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepunix server classes. 51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepForking and threading versions of each type of server can be created 53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepusing the ForkingMixIn and ThreadingMixIn mix-in classes. For 54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepinstance, a threading UDP server class is created as follows: 55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass 57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThe Mix-in class must come first, since it overrides a method defined 59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepin UDPServer! Setting the various member variables also changes 60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepthe behavior of the underlying server mechanism. 61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepTo implement a service, you must derive a class from 63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepBaseRequestHandler and redefine its handle() method. You can then run 64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepvarious versions of the service by combining one of the server classes 65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepwith your request handler class. 66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepThe request handler class must be different for datagram or stream 68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepservices. This can be hidden by using the request handler 69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsubclasses StreamRequestHandler or DatagramRequestHandler. 70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepOf course, you still have to use your head! 72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFor instance, it makes no sense to use a forking server if the service 74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepcontains state in memory that can be modified by requests (since the 75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepmodifications in the child process would never reach the initial state 76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepkept in the parent process and passed to each child). In this case, 77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepyou can use a threading server, but you will probably have to use 78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeplocks to avoid two requests that come in nearly simultaneous to apply 79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepconflicting changes to the server state. 80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepOn the other hand, if you are building e.g. an HTTP server, where all 82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdata is stored externally (e.g. in the file system), a synchronous 83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass will essentially render the service "deaf" while one request is 84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepbeing handled -- which may be for a very long time if a client is slow 85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepto read all the data it has requested. Here a threading or forking 86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepserver is appropriate. 87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepIn some cases, it may be appropriate to process part of a request 89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepsynchronously, but to finish processing in a forked child depending on 90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepthe request data. This can be implemented by using a synchronous 91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepserver and doing an explicit fork in the request handler class 92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoephandle() method. 93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepAnother approach to handling multiple simultaneous requests in an 95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepenvironment that supports neither threads nor fork (or where these are 96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptoo expensive or inappropriate for the service) is to maintain an 97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepexplicit table of partially finished requests and to use select() to 98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdecide which request to work on next (or whether to handle a new 99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepincoming request). This is particularly important for stream services 100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepwhere each client can potentially be connected for a long time (if 101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepthreads or subprocesses cannot be used). 102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepFuture work: 104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- Standard classes for Sun RPC (which uses either UDP or TCP) 105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- Standard mix-in classes to implement various authentication 106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep and encryption schemes 107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- Standard framework for select-based multiplexing 108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepXXX Open problems: 110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- What to do with out-of-band data? 111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander StoepBaseServer: 113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep- split generic "request" functionality out into BaseServer class. 114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org> 115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep example: read entries from a SQL database (requires overriding 117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep get_request() to return a table entry from the database). 118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep entry is processed by a RequestHandlerClass. 119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep""" 121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Author of the BaseServer patch: Luke Kenneth Casson Leighton 123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# XXX Warning! 125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# There is a test suite for this module, but it cannot be run by the 126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# standard regression test. 127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# To run it manually, run Lib/test/test_socketserver.py. 128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep__version__ = "0.4" 130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport socket 133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport select 134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport sys 135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport os 136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport errno 137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptry: 138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep import threading 139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepexcept ImportError: 140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep import dummy_threading as threading 141edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 142edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", 143edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", 144edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "StreamRequestHandler","DatagramRequestHandler", 145edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "ThreadingMixIn", "ForkingMixIn"] 146edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepif hasattr(socket, "AF_UNIX"): 147edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep __all__.extend(["UnixStreamServer","UnixDatagramServer", 148edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "ThreadingUnixStreamServer", 149edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep "ThreadingUnixDatagramServer"]) 150edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 151edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef _eintr_retry(func, *args): 152edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """restart a system call interrupted by EINTR""" 153edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep while True: 154edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 155edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return func(*args) 156edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except (OSError, select.error) as e: 157edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if e.args[0] != errno.EINTR: 158edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep raise 159edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 160edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass BaseServer: 161edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 162edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Base class for server classes. 163edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 164edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Methods for the caller: 165edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 166edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - __init__(server_address, RequestHandlerClass) 167edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - serve_forever(poll_interval=0.5) 168edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - shutdown() 169edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - handle_request() # if you do not use serve_forever() 170edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - fileno() -> int # for select() 171edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 172edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Methods that may be overridden: 173edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 174edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - server_bind() 175edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - server_activate() 176edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - get_request() -> request, client_address 177edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - handle_timeout() 178edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - verify_request(request, client_address) 179edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - server_close() 180edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - process_request(request, client_address) 181edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - shutdown_request(request) 182edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - close_request(request) 183edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - handle_error() 184edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 185edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Methods for derived classes: 186edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 187edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - finish_request(request, client_address) 188edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 189edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Class variables that may be overridden by derived classes or 190edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep instances: 191edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 192edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - timeout 193edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - address_family 194edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - socket_type 195edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - allow_reuse_address 196edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 197edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Instance variables: 198edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 199edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - RequestHandlerClass 200edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - socket 201edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 202edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 203edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 204edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep timeout = None 205edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 206edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def __init__(self, server_address, RequestHandlerClass): 207edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Constructor. May be extended, do not override.""" 208edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.server_address = server_address 209edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.RequestHandlerClass = RequestHandlerClass 210edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__is_shut_down = threading.Event() 211edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__shutdown_request = False 212edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 213edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def server_activate(self): 214edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called by constructor to activate the server. 215edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 216edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be overridden. 217edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 218edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 219edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 220edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 221edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def serve_forever(self, poll_interval=0.5): 222edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Handle one request at a time until shutdown. 223edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 224edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Polls for shutdown every poll_interval seconds. Ignores 225edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.timeout. If you need to do periodic tasks, do them in 226edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep another thread. 227edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 228edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__is_shut_down.clear() 229edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 230edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep while not self.__shutdown_request: 231edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # XXX: Consider using another file descriptor or 232edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # connecting to the socket to wake this up instead of 233edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # polling. Polling reduces our responsiveness to a 234edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # shutdown request and wastes cpu at all other times. 235edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep r, w, e = _eintr_retry(select.select, [self], [], [], 236edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep poll_interval) 237edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self in r: 238edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self._handle_request_noblock() 239edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep finally: 240edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__shutdown_request = False 241edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__is_shut_down.set() 242edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 243edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def shutdown(self): 244edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Stops the serve_forever loop. 245edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 246edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Blocks until the loop has finished. This must be called while 247edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep serve_forever() is running in another thread, or it will 248edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep deadlock. 249edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 250edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__shutdown_request = True 251edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.__is_shut_down.wait() 252edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 253edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # The distinction between handling, getting, processing and 254edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # finishing a request is fairly arbitrary. Remember: 255edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # 256edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # - handle_request() is the top-level call. It calls 257edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # select, get_request(), verify_request() and process_request() 258edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # - get_request() is different for stream or datagram sockets 259edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # - process_request() is the place that may fork a new process 260edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # or create a new thread to finish the request 261edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # - finish_request() instantiates the request handler class; 262edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # this constructor will handle the request all by itself 263edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 264edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def handle_request(self): 265edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Handle one request, possibly blocking. 266edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 267edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Respects self.timeout. 268edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 269edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Support people who used socket.settimeout() to escape 270edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # handle_request before self.timeout was available. 271edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep timeout = self.socket.gettimeout() 272edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if timeout is None: 273edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep timeout = self.timeout 274edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep elif self.timeout is not None: 275edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep timeout = min(timeout, self.timeout) 276edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep fd_sets = _eintr_retry(select.select, [self], [], [], timeout) 277edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not fd_sets[0]: 278edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.handle_timeout() 279edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return 280edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self._handle_request_noblock() 281edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 282edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def _handle_request_noblock(self): 283edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Handle one request, without blocking. 284edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 285edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep I assume that select.select has returned that the socket is 286edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep readable before this function was called, so there should be 287edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep no risk of blocking in get_request(). 288edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 289edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 290edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep request, client_address = self.get_request() 291edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except socket.error: 292edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return 293edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self.verify_request(request, client_address): 294edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 295edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.process_request(request, client_address) 296edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except: 297edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.handle_error(request, client_address) 298edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.shutdown_request(request) 299edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 300edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def handle_timeout(self): 301edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called if no new request arrives within self.timeout. 302edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 303edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Overridden by ForkingMixIn. 304edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 305edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 306edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 307edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def verify_request(self, request, client_address): 308edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Verify the request. May be overridden. 309edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 310edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Return True if we should proceed with this request. 311edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 312edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 313edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return True 314edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 315edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def process_request(self, request, client_address): 316edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Call finish_request. 317edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 318edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Overridden by ForkingMixIn and ThreadingMixIn. 319edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 320edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 321edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.finish_request(request, client_address) 322edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.shutdown_request(request) 323edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 324edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def server_close(self): 325edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called to clean-up the server. 326edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 327edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be overridden. 328edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 329edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 330edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 331edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 332edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def finish_request(self, request, client_address): 333edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Finish one request by instantiating RequestHandlerClass.""" 334edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.RequestHandlerClass(request, client_address, self) 335edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 336edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def shutdown_request(self, request): 337edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called to shutdown and close an individual request.""" 338edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.close_request(request) 339edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 340edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def close_request(self, request): 341edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called to clean up an individual request.""" 342edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 343edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 344edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def handle_error(self, request, client_address): 345edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Handle an error gracefully. May be overridden. 346edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 347edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep The default is to print a traceback and continue. 348edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 349edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 350edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep print '-'*40 351edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep print 'Exception happened during processing of request from', 352edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep print client_address 353edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep import traceback 354edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep traceback.print_exc() # XXX But this goes to stderr! 355edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep print '-'*40 356edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 357edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 358edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TCPServer(BaseServer): 359edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 360edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Base class for various socket-based server classes. 361edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 362edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Defaults to synchronous IP stream (i.e., TCP). 363edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 364edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Methods for the caller: 365edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 366edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - __init__(server_address, RequestHandlerClass, bind_and_activate=True) 367edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - serve_forever(poll_interval=0.5) 368edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - shutdown() 369edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - handle_request() # if you don't use serve_forever() 370edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - fileno() -> int # for select() 371edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 372edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Methods that may be overridden: 373edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 374edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - server_bind() 375edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - server_activate() 376edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - get_request() -> request, client_address 377edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - handle_timeout() 378edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - verify_request(request, client_address) 379edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - process_request(request, client_address) 380edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - shutdown_request(request) 381edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - close_request(request) 382edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - handle_error() 383edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 384edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Methods for derived classes: 385edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 386edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - finish_request(request, client_address) 387edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 388edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Class variables that may be overridden by derived classes or 389edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep instances: 390edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 391edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - timeout 392edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - address_family 393edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - socket_type 394edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - request_queue_size (only for stream sockets) 395edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - allow_reuse_address 396edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 397edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Instance variables: 398edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 399edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - server_address 400edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - RequestHandlerClass 401edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep - socket 402edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 403edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 404edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 405edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep address_family = socket.AF_INET 406edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 407edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep socket_type = socket.SOCK_STREAM 408edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 409edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep request_queue_size = 5 410edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 411edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep allow_reuse_address = False 412edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 413edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): 414edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Constructor. May be extended, do not override.""" 415edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep BaseServer.__init__(self, server_address, RequestHandlerClass) 416edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket = socket.socket(self.address_family, 417edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket_type) 418edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if bind_and_activate: 419edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.server_bind() 420edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.server_activate() 421edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 422edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def server_bind(self): 423edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called by constructor to bind the socket. 424edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 425edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be overridden. 426edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 427edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 428edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self.allow_reuse_address: 429edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 430edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket.bind(self.server_address) 431edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.server_address = self.socket.getsockname() 432edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 433edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def server_activate(self): 434edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called by constructor to activate the server. 435edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 436edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be overridden. 437edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 438edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 439edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket.listen(self.request_queue_size) 440edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 441edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def server_close(self): 442edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called to clean-up the server. 443edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 444edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be overridden. 445edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 446edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 447edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket.close() 448edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 449edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def fileno(self): 450edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Return socket file number. 451edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 452edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep Interface required by select(). 453edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 454edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 455edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return self.socket.fileno() 456edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 457edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def get_request(self): 458edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Get the request and client address from the socket. 459edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 460edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be overridden. 461edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 462edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 463edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return self.socket.accept() 464edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 465edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def shutdown_request(self, request): 466edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called to shutdown and close an individual request.""" 467edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 468edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep #explicitly shutdown. socket.close() merely releases 469edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep #the socket and waits for GC to perform the actual close. 470edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep request.shutdown(socket.SHUT_WR) 471edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except socket.error: 472edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass #some platforms may raise ENOTCONN here 473edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.close_request(request) 474edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 475edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def close_request(self, request): 476edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Called to clean up an individual request.""" 477edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep request.close() 478edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 479edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 480edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass UDPServer(TCPServer): 481edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 482edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """UDP server class.""" 483edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 484edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep allow_reuse_address = False 485edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 486edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep socket_type = socket.SOCK_DGRAM 487edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 488edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep max_packet_size = 8192 489edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 490edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def get_request(self): 491edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep data, client_addr = self.socket.recvfrom(self.max_packet_size) 492edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return (data, self.socket), client_addr 493edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 494edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def server_activate(self): 495edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # No need to call listen() for UDP. 496edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 497edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 498edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def shutdown_request(self, request): 499edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # No need to shutdown anything. 500edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.close_request(request) 501edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 502edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def close_request(self, request): 503edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # No need to close anything. 504edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 505edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 506edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass ForkingMixIn: 507edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 508edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Mix-in class to handle each request in a new process.""" 509edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 510edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep timeout = 300 511edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep active_children = None 512edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep max_children = 40 513edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 514edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def collect_children(self): 515edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Internal routine to wait for children that have exited.""" 516edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self.active_children is None: return 517edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep while len(self.active_children) >= self.max_children: 518edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # XXX: This will wait for any child process, not just ones 519edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # spawned by this library. This could confuse other 520edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # libraries that expect to be able to wait for their own 521edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # children. 522edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 523edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pid, status = os.waitpid(0, 0) 524edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except os.error: 525edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pid = None 526edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if pid not in self.active_children: continue 527edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.active_children.remove(pid) 528edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 529edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # XXX: This loop runs more system calls than it ought 530edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # to. There should be a way to put the active_children into a 531edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # process group and then use os.waitpid(-pgid) to wait for any 532edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # of that set, but I couldn't find a way to allocate pgids 533edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # that couldn't collide. 534edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep for child in self.active_children: 535edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 536edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pid, status = os.waitpid(child, os.WNOHANG) 537edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except os.error: 538edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pid = None 539edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not pid: continue 540edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 541edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.active_children.remove(pid) 542edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except ValueError, e: 543edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep raise ValueError('%s. x=%d and list=%r' % (e.message, pid, 544edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.active_children)) 545edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 546edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def handle_timeout(self): 547edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Wait for zombies after self.timeout seconds of inactivity. 548edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 549edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep May be extended, do not override. 550edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 551edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.collect_children() 552edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 553edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def process_request(self, request, client_address): 554edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Fork a new subprocess to process the request.""" 555edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.collect_children() 556edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pid = os.fork() 557edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if pid: 558edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Parent process 559edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self.active_children is None: 560edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.active_children = [] 561edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.active_children.append(pid) 562edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.close_request(request) #close handle in parent process 563edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep return 564edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep else: 565edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Child process. 566edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # This must never return, hence os._exit()! 567edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 568edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.finish_request(request, client_address) 569edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.shutdown_request(request) 570edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep os._exit(0) 571edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except: 572edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 573edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.handle_error(request, client_address) 574edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.shutdown_request(request) 575edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep finally: 576edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep os._exit(1) 577edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 578edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 579edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass ThreadingMixIn: 580edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Mix-in class to handle each request in a new thread.""" 581edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 582edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Decides how threads will act upon termination of the 583edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # main process 584edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep daemon_threads = False 585edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 586edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def process_request_thread(self, request, client_address): 587edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Same as in BaseServer but as a thread. 588edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 589edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep In addition, exception handling is done here. 590edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 591edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 592edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 593edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.finish_request(request, client_address) 594edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.shutdown_request(request) 595edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except: 596edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.handle_error(request, client_address) 597edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.shutdown_request(request) 598edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 599edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def process_request(self, request, client_address): 600edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Start a new thread to process the request.""" 601edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep t = threading.Thread(target = self.process_request_thread, 602edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep args = (request, client_address)) 603edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep t.daemon = self.daemon_threads 604edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep t.start() 605edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 606edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 607edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass ForkingUDPServer(ForkingMixIn, UDPServer): pass 608edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass ForkingTCPServer(ForkingMixIn, TCPServer): pass 609edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 610edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass ThreadingUDPServer(ThreadingMixIn, UDPServer): pass 611edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass ThreadingTCPServer(ThreadingMixIn, TCPServer): pass 612edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 613edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepif hasattr(socket, 'AF_UNIX'): 614edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 615edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep class UnixStreamServer(TCPServer): 616edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep address_family = socket.AF_UNIX 617edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 618edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep class UnixDatagramServer(UDPServer): 619edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep address_family = socket.AF_UNIX 620edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 621edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass 622edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 623edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass 624edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 625edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass BaseRequestHandler: 626edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 627edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Base class for request handler classes. 628edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 629edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep This class is instantiated for each request to be handled. The 630edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep constructor sets the instance variables request, client_address 631edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep and server, and then calls the handle() method. To implement a 632edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep specific service, all you need to do is to derive a class which 633edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep defines a handle() method. 634edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 635edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep The handle() method can find the request as self.request, the 636edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep client address as self.client_address, and the server (in case it 637edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep needs access to per-server information) as self.server. Since a 638edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep separate instance is created for each request, the handle() method 639edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep can define arbitrary other instance variariables. 640edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 641edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """ 642edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 643edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def __init__(self, request, client_address, server): 644edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.request = request 645edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.client_address = client_address 646edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.server = server 647edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.setup() 648edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 649edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.handle() 650edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep finally: 651edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.finish() 652edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 653edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def setup(self): 654edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 655edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 656edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def handle(self): 657edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 658edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 659edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def finish(self): 660edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 661edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 662edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 663edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# The following two classes make it possible to use the same service 664edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# class for stream or datagram servers. 665edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Each class sets up these instance variables: 666edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# - rfile: a file object from which receives the request is read 667edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# - wfile: a file object to which the reply is written 668edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# When the handle() method returns, wfile is flushed properly 669edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 670edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 671edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass StreamRequestHandler(BaseRequestHandler): 672edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 673edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Define self.rfile and self.wfile for stream sockets.""" 674edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 675edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Default buffer sizes for rfile, wfile. 676edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # We default rfile to buffered because otherwise it could be 677edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # really slow for large data (a getc() call per byte); we make 678edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # wfile unbuffered because (a) often after a write() we want to 679edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # read and we need to flush the line; (b) big writes to unbuffered 680edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # files are typically optimized by stdio even when big reads 681edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # aren't. 682edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep rbufsize = -1 683edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep wbufsize = 0 684edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 685edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # A timeout to apply to the request socket, if not None. 686edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep timeout = None 687edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 688edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Disable nagle algorithm for this socket, if True. 689edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # Use only when wbufsize != 0, to avoid small packets. 690edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep disable_nagle_algorithm = False 691edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 692edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def setup(self): 693edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.connection = self.request 694edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self.timeout is not None: 695edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.connection.settimeout(self.timeout) 696edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if self.disable_nagle_algorithm: 697edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.connection.setsockopt(socket.IPPROTO_TCP, 698edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep socket.TCP_NODELAY, True) 699edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.rfile = self.connection.makefile('rb', self.rbufsize) 700edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.wfile = self.connection.makefile('wb', self.wbufsize) 701edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 702edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def finish(self): 703edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep if not self.wfile.closed: 704edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 705edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.wfile.flush() 706edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except socket.error: 707edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # An final socket error may have occurred here, such as 708edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # the local error ECONNABORTED. 709edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep pass 710edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.wfile.close() 711edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.rfile.close() 712edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 713edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 714edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass DatagramRequestHandler(BaseRequestHandler): 715edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 716edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # XXX Regrettably, I cannot get this working on Linux; 717edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep # s.recvfrom() doesn't return a meaningful client address. 718edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 719edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep """Define self.rfile and self.wfile for datagram sockets.""" 720edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 721edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def setup(self): 722edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep try: 723edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep from cStringIO import StringIO 724edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep except ImportError: 725edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep from StringIO import StringIO 726edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.packet, self.socket = self.request 727edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.rfile = StringIO(self.packet) 728edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.wfile = StringIO() 729edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep 730edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep def finish(self): 731edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep self.socket.sendto(self.wfile.getvalue(), self.client_address) 732