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