blob: fb30d0e1d0c83c524607e8d3b9dffa0a3966ed45 [file] [log] [blame]
Fred Drake526a1822000-09-11 04:00:46 +00001# -*- Mode: Python -*-
Tim Peters146965a2001-01-14 18:09:23 +00002# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
Fred Drake526a1822000-09-11 04:00:46 +00003# Author: Sam Rushing <rushing@nightmare.com>
Guido van Rossum0039d7b1999-01-12 20:19:27 +00004
5# ======================================================================
6# Copyright 1996 by Sam Rushing
Tim Peters146965a2001-01-14 18:09:23 +00007#
Guido van Rossum0039d7b1999-01-12 20:19:27 +00008# All Rights Reserved
Tim Peters146965a2001-01-14 18:09:23 +00009#
Guido van Rossum0039d7b1999-01-12 20:19:27 +000010# Permission to use, copy, modify, and distribute this software and
11# its documentation for any purpose and without fee is hereby
12# granted, provided that the above copyright notice appear in all
13# copies and that both that copyright notice and this permission
14# notice appear in supporting documentation, and that the name of Sam
15# Rushing not be used in advertising or publicity pertaining to
16# distribution of the software without specific, written prior
17# permission.
Tim Peters146965a2001-01-14 18:09:23 +000018#
Guido van Rossum0039d7b1999-01-12 20:19:27 +000019# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
21# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
23# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
25# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26# ======================================================================
27
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000028"""Basic infrastructure for asynchronous socket service clients and servers.
29
30There are only two ways to have a program on a single processor do "more
Tim Peters146965a2001-01-14 18:09:23 +000031than one thing at a time". Multi-threaded programming is the simplest and
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000032most popular way to do it, but there is another very different technique,
33that lets you have nearly all the advantages of multi-threading, without
34actually using multiple threads. it's really only practical if your program
35is largely I/O bound. If your program is CPU bound, then pre-emptive
36scheduled threads are probably what you really need. Network servers are
Tim Peters146965a2001-01-14 18:09:23 +000037rarely CPU-bound, however.
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000038
Tim Peters146965a2001-01-14 18:09:23 +000039If your operating system supports the select() system call in its I/O
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000040library (and nearly all do), then you can use it to juggle multiple
41communication channels at once; doing other work while your I/O is taking
42place in the "background." Although this strategy can seem strange and
43complex, especially at first, it is in many ways easier to understand and
44control than multi-threaded programming. The module documented here solves
45many of the difficult problems for you, making the task of building
Tim Peters146965a2001-01-14 18:09:23 +000046sophisticated high-performance network servers and clients a snap.
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000047"""
48
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +000049import exceptions
Guido van Rossum0039d7b1999-01-12 20:19:27 +000050import select
51import socket
Guido van Rossum0039d7b1999-01-12 20:19:27 +000052import sys
Jeremy Hylton12e73bb2001-04-20 19:04:55 +000053import types
Guido van Rossum0039d7b1999-01-12 20:19:27 +000054
55import os
Jeremy Hyltona8b5f7d2001-08-10 14:30:35 +000056from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
Tim Peters7c005af2001-08-20 21:48:00 +000057 ENOTCONN, ESHUTDOWN
Guido van Rossum0039d7b1999-01-12 20:19:27 +000058
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +000059try:
Fred Drake526a1822000-09-11 04:00:46 +000060 socket_map
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +000061except NameError:
Fred Drake526a1822000-09-11 04:00:46 +000062 socket_map = {}
Guido van Rossum0039d7b1999-01-12 20:19:27 +000063
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +000064class ExitNow (exceptions.Exception):
Fred Drake526a1822000-09-11 04:00:46 +000065 pass
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +000066
67DEBUG = 0
68
69def poll (timeout=0.0, map=None):
Fred Drake526a1822000-09-11 04:00:46 +000070 global DEBUG
71 if map is None:
72 map = socket_map
73 if map:
74 r = []; w = []; e = []
75 for fd, obj in map.items():
76 if obj.readable():
77 r.append (fd)
78 if obj.writable():
79 w.append (fd)
80 r,w,e = select.select (r,w,e, timeout)
Guido van Rossum0039d7b1999-01-12 20:19:27 +000081
Fred Drake526a1822000-09-11 04:00:46 +000082 if DEBUG:
83 print r,w,e
Guido van Rossum0039d7b1999-01-12 20:19:27 +000084
Fred Drake526a1822000-09-11 04:00:46 +000085 for fd in r:
86 try:
87 obj = map[fd]
88 try:
89 obj.handle_read_event()
90 except ExitNow:
91 raise ExitNow
92 except:
93 obj.handle_error()
94 except KeyError:
95 pass
Guido van Rossum0039d7b1999-01-12 20:19:27 +000096
Fred Drake526a1822000-09-11 04:00:46 +000097 for fd in w:
98 try:
99 obj = map[fd]
100 try:
101 obj.handle_write_event()
102 except ExitNow:
103 raise ExitNow
104 except:
105 obj.handle_error()
106 except KeyError:
107 pass
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +0000108
109def poll2 (timeout=0.0, map=None):
Fred Drake526a1822000-09-11 04:00:46 +0000110 import poll
111 if map is None:
112 map=socket_map
113 # timeout is in milliseconds
114 timeout = int(timeout*1000)
115 if map:
116 l = []
117 for fd, obj in map.items():
118 flags = 0
119 if obj.readable():
120 flags = poll.POLLIN
121 if obj.writable():
122 flags = flags | poll.POLLOUT
123 if flags:
124 l.append ((fd, flags))
125 r = poll.poll (l, timeout)
126 for fd, flags in r:
127 try:
128 obj = map[fd]
129 try:
130 if (flags & poll.POLLIN):
131 obj.handle_read_event()
132 if (flags & poll.POLLOUT):
133 obj.handle_write_event()
134 except ExitNow:
135 raise ExitNow
136 except:
137 obj.handle_error()
138 except KeyError:
139 pass
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000140
Andrew M. Kuchlingaf6963c2001-01-24 15:50:19 +0000141def poll3 (timeout=0.0, map=None):
142 # Use the poll() support added to the select module in Python 2.0
143 if map is None:
144 map=socket_map
145 # timeout is in milliseconds
146 timeout = int(timeout*1000)
147 pollster = select.poll()
148 if map:
Andrew M. Kuchlingaf6963c2001-01-24 15:50:19 +0000149 for fd, obj in map.items():
150 flags = 0
151 if obj.readable():
152 flags = select.POLLIN
153 if obj.writable():
154 flags = flags | select.POLLOUT
155 if flags:
156 pollster.register(fd, flags)
157 r = pollster.poll (timeout)
158 for fd, flags in r:
159 try:
160 obj = map[fd]
161 try:
162 if (flags & select.POLLIN):
163 obj.handle_read_event()
164 if (flags & select.POLLOUT):
165 obj.handle_write_event()
166 except ExitNow:
167 raise ExitNow
168 except:
169 obj.handle_error()
170 except KeyError:
171 pass
172
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +0000173def loop (timeout=30.0, use_poll=0, map=None):
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000174
Andrew M. Kuchlingaf6963c2001-01-24 15:50:19 +0000175 if map is None:
176 map=socket_map
177
Fred Drake526a1822000-09-11 04:00:46 +0000178 if use_poll:
Andrew M. Kuchlingaf6963c2001-01-24 15:50:19 +0000179 if hasattr (select, 'poll'):
180 poll_fun = poll3
181 else:
182 poll_fun = poll2
Fred Drake526a1822000-09-11 04:00:46 +0000183 else:
184 poll_fun = poll
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000185
Fred Drake526a1822000-09-11 04:00:46 +0000186 while map:
187 poll_fun (timeout, map)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000188
189class dispatcher:
Fred Drake526a1822000-09-11 04:00:46 +0000190 debug = 0
191 connected = 0
192 accepting = 0
193 closing = 0
194 addr = None
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000195
Fred Drake526a1822000-09-11 04:00:46 +0000196 def __init__ (self, sock=None, map=None):
197 if sock:
198 self.set_socket (sock, map)
199 # I think it should inherit this anyway
200 self.socket.setblocking (0)
201 self.connected = 1
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000202
Fred Drake526a1822000-09-11 04:00:46 +0000203 def __repr__ (self):
204 try:
205 status = []
206 if self.accepting and self.addr:
207 status.append ('listening')
208 elif self.connected:
209 status.append ('connected')
210 if self.addr:
Jeremy Hylton12e73bb2001-04-20 19:04:55 +0000211 if self.addr == types.TupleType:
212 status.append ('%s:%d' % self.addr)
213 else:
214 status.append (self.addr)
215 return '<%s %s at %x>' % (self.__class__.__name__,
216 ' '.join (status), id (self))
Fred Drake526a1822000-09-11 04:00:46 +0000217 except:
Jeremy Hylton12e73bb2001-04-20 19:04:55 +0000218 pass
Tim Peters8ae2df42001-05-02 05:54:44 +0000219
Jeremy Hylton12e73bb2001-04-20 19:04:55 +0000220 try:
221 ar = repr (self.addr)
222 except AttributeError:
223 ar = 'no self.addr!'
Tim Peters146965a2001-01-14 18:09:23 +0000224
Jeremy Hylton12e73bb2001-04-20 19:04:55 +0000225 return '<__repr__() failed for %s instance at %x (addr=%s)>' % \
226 (self.__class__.__name__, id (self), ar)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000227
Fred Drake526a1822000-09-11 04:00:46 +0000228 def add_channel (self, map=None):
229 #self.log_info ('adding channel %s' % self)
230 if map is None:
231 map=socket_map
232 map [self._fileno] = self
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000233
Fred Drake526a1822000-09-11 04:00:46 +0000234 def del_channel (self, map=None):
235 fd = self._fileno
236 if map is None:
237 map=socket_map
238 if map.has_key (fd):
239 #self.log_info ('closing channel %d:%s' % (fd, self))
240 del map [fd]
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000241
Fred Drake526a1822000-09-11 04:00:46 +0000242 def create_socket (self, family, type):
243 self.family_and_type = family, type
244 self.socket = socket.socket (family, type)
245 self.socket.setblocking(0)
246 self._fileno = self.socket.fileno()
247 self.add_channel()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000248
Fred Drake526a1822000-09-11 04:00:46 +0000249 def set_socket (self, sock, map=None):
250 self.__dict__['socket'] = sock
251 self._fileno = sock.fileno()
252 self.add_channel (map)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000253
Fred Drake526a1822000-09-11 04:00:46 +0000254 def set_reuse_addr (self):
255 # try to re-use a server port if possible
256 try:
257 self.socket.setsockopt (
258 socket.SOL_SOCKET, socket.SO_REUSEADDR,
Jeremy Hyltona8b5f7d2001-08-10 14:30:35 +0000259 self.socket.getsockopt (socket.SOL_SOCKET,
260 socket.SO_REUSEADDR) | 1
Fred Drake526a1822000-09-11 04:00:46 +0000261 )
Fred Drake9f9b5932001-05-11 18:28:54 +0000262 except socket.error:
Fred Drake526a1822000-09-11 04:00:46 +0000263 pass
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000264
Fred Drake526a1822000-09-11 04:00:46 +0000265 # ==================================================
266 # predicates for select()
267 # these are used as filters for the lists of sockets
268 # to pass to select().
269 # ==================================================
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000270
Fred Drake526a1822000-09-11 04:00:46 +0000271 def readable (self):
272 return 1
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000273
Fred Drake526a1822000-09-11 04:00:46 +0000274 if os.name == 'mac':
275 # The macintosh will select a listening socket for
276 # write if you let it. What might this mean?
277 def writable (self):
278 return not self.accepting
279 else:
280 def writable (self):
281 return 1
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000282
Fred Drake526a1822000-09-11 04:00:46 +0000283 # ==================================================
284 # socket object methods.
285 # ==================================================
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000286
Fred Drake526a1822000-09-11 04:00:46 +0000287 def listen (self, num):
288 self.accepting = 1
289 if os.name == 'nt' and num > 5:
290 num = 1
291 return self.socket.listen (num)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000292
Fred Drake526a1822000-09-11 04:00:46 +0000293 def bind (self, addr):
294 self.addr = addr
295 return self.socket.bind (addr)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000296
Fred Drake526a1822000-09-11 04:00:46 +0000297 def connect (self, address):
298 self.connected = 0
Jeremy Hylton12e73bb2001-04-20 19:04:55 +0000299 # XXX why not use connect_ex?
Fred Drake526a1822000-09-11 04:00:46 +0000300 try:
301 self.socket.connect (address)
302 except socket.error, why:
303 if why[0] in (EINPROGRESS, EALREADY, EWOULDBLOCK):
304 return
305 else:
306 raise socket.error, why
307 self.connected = 1
308 self.handle_connect()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000309
Fred Drake526a1822000-09-11 04:00:46 +0000310 def accept (self):
311 try:
312 conn, addr = self.socket.accept()
313 return conn, addr
314 except socket.error, why:
315 if why[0] == EWOULDBLOCK:
316 pass
317 else:
318 raise socket.error, why
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000319
Fred Drake526a1822000-09-11 04:00:46 +0000320 def send (self, data):
321 try:
322 result = self.socket.send (data)
323 return result
324 except socket.error, why:
325 if why[0] == EWOULDBLOCK:
326 return 0
327 else:
328 raise socket.error, why
329 return 0
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000330
Fred Drake526a1822000-09-11 04:00:46 +0000331 def recv (self, buffer_size):
332 try:
333 data = self.socket.recv (buffer_size)
334 if not data:
335 # a closed connection is indicated by signaling
336 # a read condition, and having recv() return 0.
337 self.handle_close()
338 return ''
339 else:
340 return data
341 except socket.error, why:
342 # winsock sometimes throws ENOTCONN
343 if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
344 self.handle_close()
345 return ''
346 else:
347 raise socket.error, why
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000348
Fred Drake526a1822000-09-11 04:00:46 +0000349 def close (self):
350 self.del_channel()
351 self.socket.close()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000352
Fred Drake526a1822000-09-11 04:00:46 +0000353 # cheap inheritance, used to pass all other attribute
354 # references to the underlying socket object.
355 def __getattr__ (self, attr):
356 return getattr (self.socket, attr)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000357
Fred Drake526a1822000-09-11 04:00:46 +0000358 # log and log_info maybe overriden to provide more sophisitcated
359 # logging and warning methods. In general, log is for 'hit' logging
Tim Peters146965a2001-01-14 18:09:23 +0000360 # and 'log_info' is for informational, warning and error logging.
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +0000361
Fred Drake526a1822000-09-11 04:00:46 +0000362 def log (self, message):
363 sys.stderr.write ('log: %s\n' % str(message))
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +0000364
Fred Drake526a1822000-09-11 04:00:46 +0000365 def log_info (self, message, type='info'):
366 if __debug__ or type != 'info':
367 print '%s: %s' % (type, message)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000368
Fred Drake526a1822000-09-11 04:00:46 +0000369 def handle_read_event (self):
370 if self.accepting:
371 # for an accepting socket, getting a read implies
372 # that we are connected
373 if not self.connected:
374 self.connected = 1
375 self.handle_accept()
376 elif not self.connected:
377 self.handle_connect()
378 self.connected = 1
379 self.handle_read()
380 else:
381 self.handle_read()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000382
Fred Drake526a1822000-09-11 04:00:46 +0000383 def handle_write_event (self):
384 # getting a write implies that we are connected
385 if not self.connected:
386 self.handle_connect()
387 self.connected = 1
388 self.handle_write()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000389
Fred Drake526a1822000-09-11 04:00:46 +0000390 def handle_expt_event (self):
391 self.handle_expt()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000392
Fred Drake526a1822000-09-11 04:00:46 +0000393 def handle_error (self):
Jeremy Hyltona8b5f7d2001-08-10 14:30:35 +0000394 nil, t, v, tbinfo = compact_traceback()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000395
Fred Drake526a1822000-09-11 04:00:46 +0000396 # sometimes a user repr method will crash.
397 try:
398 self_repr = repr (self)
399 except:
400 self_repr = '<__repr__ (self) failed for object at %0x>' % id(self)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000401
Fred Drake526a1822000-09-11 04:00:46 +0000402 self.log_info (
403 'uncaptured python exception, closing channel %s (%s:%s %s)' % (
404 self_repr,
405 t,
406 v,
407 tbinfo
408 ),
409 'error'
410 )
411 self.close()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000412
Fred Drake526a1822000-09-11 04:00:46 +0000413 def handle_expt (self):
414 self.log_info ('unhandled exception', 'warning')
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000415
Fred Drake526a1822000-09-11 04:00:46 +0000416 def handle_read (self):
417 self.log_info ('unhandled read event', 'warning')
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000418
Fred Drake526a1822000-09-11 04:00:46 +0000419 def handle_write (self):
420 self.log_info ('unhandled write event', 'warning')
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000421
Fred Drake526a1822000-09-11 04:00:46 +0000422 def handle_connect (self):
423 self.log_info ('unhandled connect event', 'warning')
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000424
Fred Drake526a1822000-09-11 04:00:46 +0000425 def handle_accept (self):
426 self.log_info ('unhandled accept event', 'warning')
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000427
Fred Drake526a1822000-09-11 04:00:46 +0000428 def handle_close (self):
429 self.log_info ('unhandled close event', 'warning')
430 self.close()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000431
432# ---------------------------------------------------------------------------
433# adds simple buffered output capability, useful for simple clients.
434# [for more sophisticated usage use asynchat.async_chat]
435# ---------------------------------------------------------------------------
436
437class dispatcher_with_send (dispatcher):
Fred Drake526a1822000-09-11 04:00:46 +0000438 def __init__ (self, sock=None):
439 dispatcher.__init__ (self, sock)
440 self.out_buffer = ''
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000441
Fred Drake526a1822000-09-11 04:00:46 +0000442 def initiate_send (self):
443 num_sent = 0
444 num_sent = dispatcher.send (self, self.out_buffer[:512])
445 self.out_buffer = self.out_buffer[num_sent:]
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000446
Fred Drake526a1822000-09-11 04:00:46 +0000447 def handle_write (self):
448 self.initiate_send()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000449
Fred Drake526a1822000-09-11 04:00:46 +0000450 def writable (self):
451 return (not self.connected) or len(self.out_buffer)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000452
Fred Drake526a1822000-09-11 04:00:46 +0000453 def send (self, data):
454 if self.debug:
455 self.log_info ('sending %s' % repr(data))
456 self.out_buffer = self.out_buffer + data
457 self.initiate_send()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000458
459# ---------------------------------------------------------------------------
460# used for debugging.
461# ---------------------------------------------------------------------------
462
Guido van Rossuma8d0f4f1999-06-08 13:20:05 +0000463def compact_traceback ():
Fred Drake526a1822000-09-11 04:00:46 +0000464 t,v,tb = sys.exc_info()
465 tbinfo = []
466 while 1:
467 tbinfo.append ((
468 tb.tb_frame.f_code.co_filename,
Tim Peters146965a2001-01-14 18:09:23 +0000469 tb.tb_frame.f_code.co_name,
Fred Drake526a1822000-09-11 04:00:46 +0000470 str(tb.tb_lineno)
471 ))
472 tb = tb.tb_next
473 if not tb:
474 break
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000475
Fred Drake526a1822000-09-11 04:00:46 +0000476 # just to be safe
477 del tb
Guido van Rossuma8d0f4f1999-06-08 13:20:05 +0000478
Fred Drake526a1822000-09-11 04:00:46 +0000479 file, function, line = tbinfo[-1]
Eric S. Raymondb49f4a42001-02-09 05:07:04 +0000480 info = '[' + '] ['.join(map(lambda x: '|'.join(x), tbinfo)) + ']'
Fred Drake526a1822000-09-11 04:00:46 +0000481 return (file, function, line), t, v, info
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000482
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +0000483def close_all (map=None):
Fred Drake526a1822000-09-11 04:00:46 +0000484 if map is None:
485 map=socket_map
486 for x in map.values():
487 x.socket.close()
488 map.clear()
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000489
490# Asynchronous File I/O:
491#
492# After a little research (reading man pages on various unixen, and
493# digging through the linux kernel), I've determined that select()
494# isn't meant for doing doing asynchronous file i/o.
495# Heartening, though - reading linux/mm/filemap.c shows that linux
496# supports asynchronous read-ahead. So _MOST_ of the time, the data
497# will be sitting in memory for us already when we go to read it.
498#
499# What other OS's (besides NT) support async file i/o? [VMS?]
500#
501# Regardless, this is useful for pipes, and stdin/stdout...
502
503import os
504if os.name == 'posix':
Fred Drake526a1822000-09-11 04:00:46 +0000505 import fcntl
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000506
Fred Drake526a1822000-09-11 04:00:46 +0000507 class file_wrapper:
508 # here we override just enough to make a file
509 # look like a socket for the purposes of asyncore.
510 def __init__ (self, fd):
511 self.fd = fd
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000512
Fred Drake526a1822000-09-11 04:00:46 +0000513 def recv (self, *args):
514 return apply (os.read, (self.fd,)+args)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000515
Fred Drake526a1822000-09-11 04:00:46 +0000516 def send (self, *args):
517 return apply (os.write, (self.fd,)+args)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000518
Fred Drake526a1822000-09-11 04:00:46 +0000519 read = recv
520 write = send
Andrew M. Kuchlingda85a272000-09-08 20:30:39 +0000521
Fred Drake526a1822000-09-11 04:00:46 +0000522 def close (self):
523 return os.close (self.fd)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000524
Fred Drake526a1822000-09-11 04:00:46 +0000525 def fileno (self):
526 return self.fd
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000527
Fred Drake526a1822000-09-11 04:00:46 +0000528 class file_dispatcher (dispatcher):
529 def __init__ (self, fd):
530 dispatcher.__init__ (self)
531 self.connected = 1
532 # set it to non-blocking mode
Fred Drakea94414a2001-05-10 15:33:31 +0000533 flags = fcntl.fcntl (fd, fcntl.F_GETFL, 0)
534 flags = flags | os.O_NONBLOCK
535 fcntl.fcntl (fd, fcntl.F_SETFL, flags)
Fred Drake526a1822000-09-11 04:00:46 +0000536 self.set_file (fd)
Guido van Rossum0039d7b1999-01-12 20:19:27 +0000537
Fred Drake526a1822000-09-11 04:00:46 +0000538 def set_file (self, fd):
539 self._fileno = fd
540 self.socket = file_wrapper (fd)
541 self.add_channel()