blob: 5562fb0ef4edb9b87f88c75d64f355bea2548b94 [file] [log] [blame]
Guido van Rossume7e578f1995-08-04 04:00:20 +00001"""Generic socket server classes.
2
3This module tries to capture the various aspects of defining a server:
4
5- address family:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +00006 - AF_INET: IP (Internet Protocol) sockets (default)
7 - AF_UNIX: Unix domain sockets
8 - others, e.g. AF_DECNET are conceivable (see <socket.h>
Guido van Rossume7e578f1995-08-04 04:00:20 +00009- socket type:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000010 - SOCK_STREAM (reliable stream, e.g. TCP)
11 - SOCK_DGRAM (datagrams, e.g. UDP)
Guido van Rossume7e578f1995-08-04 04:00:20 +000012- client address verification before further looking at the request
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000013 (This is actually a hook for any processing that needs to look
14 at the request before anything else, e.g. logging)
Guido van Rossume7e578f1995-08-04 04:00:20 +000015- how to handle multiple requests:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000016 - synchronous (one request is handled at a time)
17 - forking (each request is handled by a new process)
18 - threading (each request is handled by a new thread)
Guido van Rossume7e578f1995-08-04 04:00:20 +000019
20The classes in this module favor the server type that is simplest to
21write: a synchronous TCP/IP server. This is bad class design, but
22save some typing. (There's also the issue that a deep class hierarchy
23slows down method lookups.)
24
25There are four classes in an inheritance diagram that represent
26synchronous servers of four types:
27
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000028 +-----------+ +------------------+
29 | TCPServer |------->| UnixStreamServer |
30 +-----------+ +------------------+
31 |
32 v
33 +-----------+ +--------------------+
34 | UDPServer |------->| UnixDatagramServer |
35 +-----------+ +--------------------+
Guido van Rossume7e578f1995-08-04 04:00:20 +000036
Guido van Rossumdb2b70c1997-07-16 16:21:38 +000037Note that UnixDatagramServer derives from UDPServer, not from
Guido van Rossume7e578f1995-08-04 04:00:20 +000038UnixStreamServer -- the only difference between an IP and a Unix
39stream server is the address family, which is simply repeated in both
Guido van Rossumdb2b70c1997-07-16 16:21:38 +000040unix server classes.
Guido van Rossume7e578f1995-08-04 04:00:20 +000041
42Forking and threading versions of each type of server can be created
43using the ForkingServer and ThreadingServer mix-in classes. For
44instance, a threading UDP server class is created as follows:
45
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000046 class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
Guido van Rossume7e578f1995-08-04 04:00:20 +000047
Guido van Rossumdb2b70c1997-07-16 16:21:38 +000048The Mix-in class must come first, since it overrides a method defined
49in UDPServer!
Guido van Rossume7e578f1995-08-04 04:00:20 +000050
51To implement a service, you must derive a class from
52BaseRequestHandler and redefine its handle() method. You can then run
53various versions of the service by combining one of the server classes
54with your request handler class.
55
56The request handler class must be different for datagram or stream
57services. This can be hidden by using the mix-in request handler
58classes StreamRequestHandler or DatagramRequestHandler.
59
60Of course, you still have to use your head!
61
62For instance, it makes no sense to use a forking server if the service
63contains state in memory that can be modified by requests (since the
64modifications in the child process would never reach the initial state
65kept in the parent process and passed to each child). In this case,
66you can use a threading server, but you will probably have to use
67locks to avoid two requests that come in nearly simultaneous to apply
68conflicting changes to the server state.
69
70On the other hand, if you are building e.g. an HTTP server, where all
71data is stored externally (e.g. in the file system), a synchronous
72class will essentially render the service "deaf" while one request is
73being handled -- which may be for a very long time if a client is slow
74to reqd all the data it has requested. Here a threading or forking
75server is appropriate.
76
77In some cases, it may be appropriate to process part of a request
78synchronously, but to finish processing in a forked child depending on
79the request data. This can be implemented by using a synchronous
80server and doing an explicit fork in the request handler class's
81handle() method.
82
83Another approach to handling multiple simultaneous requests in an
84environment that supports neither threads nor fork (or where these are
85too expensive or inappropriate for the service) is to maintain an
86explicit table of partially finished requests and to use select() to
87decide which request to work on next (or whether to handle a new
88incoming request). This is particularly important for stream services
89where each client can potentially be connected for a long time (if
90threads or subprocesses can't be used).
91
92Future work:
93- Standard classes for Sun RPC (which uses either UDP or TCP)
94- Standard mix-in classes to implement various authentication
95 and encryption schemes
96- Standard framework for select-based multiplexing
97
98XXX Open problems:
99- What to do with out-of-band data?
100
101"""
102
103
104__version__ = "0.2"
105
106
107import socket
108import sys
109import os
110
111
112class TCPServer:
113
114 """Base class for various socket-based server classes.
115
116 Defaults to synchronous IP stream (i.e., TCP).
117
118 Methods for the caller:
119
120 - __init__(server_address, RequestHandlerClass)
121 - serve_forever()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000122 - handle_request() # if you don't use serve_forever()
123 - fileno() -> int # for select()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000124
125 Methods that may be overridden:
126
127 - server_bind()
128 - server_activate()
129 - get_request() -> request, client_address
130 - verify_request(request, client_address)
131 - process_request(request, client_address)
132 - handle_error()
133
134 Methods for derived classes:
135
136 - finish_request(request, client_address)
137
138 Class variables that may be overridden by derived classes or
139 instances:
140
141 - address_family
142 - socket_type
143 - request_queue_size (only for stream sockets)
Guido van Rossume3c7a5f2000-05-09 14:53:29 +0000144 - reuse_address
Guido van Rossume7e578f1995-08-04 04:00:20 +0000145
146 Instance variables:
147
148 - server_address
149 - RequestHandlerClass
150 - socket
151
152 """
153
154 address_family = socket.AF_INET
155
156 socket_type = socket.SOCK_STREAM
157
158 request_queue_size = 5
159
Guido van Rossume3c7a5f2000-05-09 14:53:29 +0000160 allow_reuse_address = 0
161
Guido van Rossume7e578f1995-08-04 04:00:20 +0000162 def __init__(self, server_address, RequestHandlerClass):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000163 """Constructor. May be extended, do not override."""
164 self.server_address = server_address
165 self.RequestHandlerClass = RequestHandlerClass
166 self.socket = socket.socket(self.address_family,
167 self.socket_type)
168 self.server_bind()
169 self.server_activate()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000170
171 def server_bind(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000172 """Called by constructor to bind the socket.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000173
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000174 May be overridden.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000175
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000176 """
Guido van Rossume3c7a5f2000-05-09 14:53:29 +0000177 if self.allow_reuse_address:
178 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000179 self.socket.bind(self.server_address)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000180
181 def server_activate(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000182 """Called by constructor to activate the server.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000183
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000184 May be overridden.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000185
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000186 """
187 self.socket.listen(self.request_queue_size)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000188
189 def fileno(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000190 """Return socket file number.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000191
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000192 Interface required by select().
Guido van Rossume7e578f1995-08-04 04:00:20 +0000193
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000194 """
195 return self.socket.fileno()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000196
197 def serve_forever(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000198 """Handle one request at a time until doomsday."""
199 while 1:
200 self.handle_request()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000201
202 # The distinction between handling, getting, processing and
203 # finishing a request is fairly arbitrary. Remember:
204 #
205 # - handle_request() is the top-level call. It calls
206 # get_request(), verify_request() and process_request()
207 # - get_request() is different for stream or datagram sockets
208 # - process_request() is the place that may fork a new process
209 # or create a new thread to finish the request
210 # - finish_request() instantiates the request handler class;
211 # this constructor will handle the request all by itself
212
213 def handle_request(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000214 """Handle one request, possibly blocking."""
Guido van Rossumf2f05941999-06-15 22:25:32 +0000215 try:
216 request, client_address = self.get_request()
217 except socket.error:
218 return
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000219 if self.verify_request(request, client_address):
220 try:
221 self.process_request(request, client_address)
222 except:
223 self.handle_error(request, client_address)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000224
225 def get_request(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000226 """Get the request and client address from the socket.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000227
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000228 May be overridden.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000229
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000230 """
231 return self.socket.accept()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000232
233 def verify_request(self, request, client_address):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 """Verify the request. May be overridden.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000235
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000236 Return true if we should proceed with this request.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000237
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000238 """
239 return 1
Guido van Rossume7e578f1995-08-04 04:00:20 +0000240
241 def process_request(self, request, client_address):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000242 """Call finish_request.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000243
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000244 Overridden by ForkingMixIn and ThreadingMixIn.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000245
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000246 """
247 self.finish_request(request, client_address)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000248
249 def finish_request(self, request, client_address):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000250 """Finish one request by instantiating RequestHandlerClass."""
251 self.RequestHandlerClass(request, client_address, self)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000252
253 def handle_error(self, request, client_address):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000254 """Handle an error gracefully. May be overridden.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000255
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000256 The default is to print a traceback and continue.
Guido van Rossume7e578f1995-08-04 04:00:20 +0000257
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000258 """
259 print '-'*40
260 print 'Exception happened during processing of request from',
261 print client_address
262 import traceback
263 traceback.print_exc()
264 print '-'*40
Guido van Rossume7e578f1995-08-04 04:00:20 +0000265
266
267class UDPServer(TCPServer):
268
269 """UDP server class."""
270
271 socket_type = socket.SOCK_DGRAM
272
273 max_packet_size = 8192
274
275 def get_request(self):
Guido van Rossum32490821998-06-16 02:27:33 +0000276 data, client_addr = self.socket.recvfrom(self.max_packet_size)
277 return (data, self.socket), client_addr
278
279 def server_activate(self):
280 # No need to call listen() for UDP.
281 pass
Guido van Rossume7e578f1995-08-04 04:00:20 +0000282
283
Guido van Rossume7e578f1995-08-04 04:00:20 +0000284class ForkingMixIn:
285
286 """Mix-in class to handle each request in a new process."""
287
288 active_children = None
Guido van Rossum2ab455a1999-07-28 21:39:28 +0000289 max_children = 40
Guido van Rossume7e578f1995-08-04 04:00:20 +0000290
291 def collect_children(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000292 """Internal routine to wait for died children."""
293 while self.active_children:
Guido van Rossum2ab455a1999-07-28 21:39:28 +0000294 if len(self.active_children) < self.max_children:
295 options = os.WNOHANG
296 else:
297 # If the maximum number of children are already
298 # running, block while waiting for a child to exit
299 options = 0
Guido van Rossumbfadac01999-06-17 15:41:33 +0000300 try:
Guido van Rossum2ab455a1999-07-28 21:39:28 +0000301 pid, status = os.waitpid(0, options)
Guido van Rossumbfadac01999-06-17 15:41:33 +0000302 except os.error:
303 pid = None
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000304 if not pid: break
305 self.active_children.remove(pid)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000306
307 def process_request(self, request, client_address):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000308 """Fork a new subprocess to process the request."""
309 self.collect_children()
310 pid = os.fork()
311 if pid:
312 # Parent process
313 if self.active_children is None:
314 self.active_children = []
315 self.active_children.append(pid)
316 return
317 else:
318 # Child process.
319 # This must never return, hence os._exit()!
320 try:
Guido van Rossum198e7ca1999-06-01 18:58:34 +0000321 self.socket.close()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000322 self.finish_request(request, client_address)
323 os._exit(0)
324 except:
325 try:
326 self.handle_error(request,
327 client_address)
328 finally:
329 os._exit(1)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000330
331
332class ThreadingMixIn:
Guido van Rossume7e578f1995-08-04 04:00:20 +0000333 """Mix-in class to handle each request in a new thread."""
334
335 def process_request(self, request, client_address):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000336 """Start a new thread to process the request."""
Jeremy Hylton75260271999-10-12 16:20:13 +0000337 import threading
338 t = threading.Thread(target = self.finish_request,
339 args = (request, client_address))
340 t.start()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000341
342
343class ForkingUDPServer(ForkingMixIn, UDPServer): pass
344class ForkingTCPServer(ForkingMixIn, TCPServer): pass
345
346class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
347class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
348
Guido van Rossum67a40e81998-11-30 15:07:01 +0000349if hasattr(socket, 'AF_UNIX'):
350
351 class UnixStreamServer(TCPServer):
352 address_family = socket.AF_UNIX
353
354 class UnixDatagramServer(UDPServer):
355 address_family = socket.AF_UNIX
356
357 class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
358
359 class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
Guido van Rossume7e578f1995-08-04 04:00:20 +0000360
361class BaseRequestHandler:
362
363 """Base class for request handler classes.
364
365 This class is instantiated for each request to be handled. The
366 constructor sets the instance variables request, client_address
367 and server, and then calls the handle() method. To implement a
368 specific service, all you need to do is to derive a class which
369 defines a handle() method.
370
371 The handle() method can find the request as self.request, the
Guido van Rossumfdb3d1a1998-11-16 19:06:30 +0000372 client address as self.client_address, and the server (in case it
Guido van Rossume7e578f1995-08-04 04:00:20 +0000373 needs access to per-server information) as self.server. Since a
374 separate instance is created for each request, the handle() method
375 can define arbitrary other instance variariables.
376
377 """
378
379 def __init__(self, request, client_address, server):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000380 self.request = request
381 self.client_address = client_address
382 self.server = server
383 try:
384 self.setup()
385 self.handle()
386 self.finish()
387 finally:
388 sys.exc_traceback = None # Help garbage collection
Guido van Rossume7e578f1995-08-04 04:00:20 +0000389
390 def setup(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000391 pass
Guido van Rossume7e578f1995-08-04 04:00:20 +0000392
393 def __del__(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000394 pass
Guido van Rossume7e578f1995-08-04 04:00:20 +0000395
396 def handle(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000397 pass
Guido van Rossume7e578f1995-08-04 04:00:20 +0000398
399 def finish(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000400 pass
Guido van Rossume7e578f1995-08-04 04:00:20 +0000401
402
403# The following two classes make it possible to use the same service
404# class for stream or datagram servers.
405# Each class sets up these instance variables:
406# - rfile: a file object from which receives the request is read
407# - wfile: a file object to which the reply is written
408# When the handle() method returns, wfile is flushed properly
409
410
411class StreamRequestHandler(BaseRequestHandler):
412
413 """Define self.rfile and self.wfile for stream sockets."""
414
415 def setup(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000416 self.connection = self.request
417 self.rfile = self.connection.makefile('rb', 0)
418 self.wfile = self.connection.makefile('wb', 0)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000419
420 def finish(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000421 self.wfile.flush()
Guido van Rossum1d5102c1998-04-03 16:49:52 +0000422 self.wfile.close()
423 self.rfile.close()
Guido van Rossume7e578f1995-08-04 04:00:20 +0000424
425
426class DatagramRequestHandler(BaseRequestHandler):
427
428 """Define self.rfile and self.wfile for datagram sockets."""
429
430 def setup(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000431 import StringIO
432 self.packet, self.socket = self.request
433 self.rfile = StringIO.StringIO(self.packet)
434 self.wfile = StringIO.StringIO(self.packet)
Guido van Rossume7e578f1995-08-04 04:00:20 +0000435
436 def finish(self):
Guido van Rossum32490821998-06-16 02:27:33 +0000437 self.socket.sendto(self.wfile.getvalue(), self.client_address)