]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/asyncore.py
2 # Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
3 # Author: Sam Rushing <rushing@nightmare.com>
5 # ======================================================================
6 # Copyright 1996 by Sam Rushing
10 # 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
19 # 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 # ======================================================================
28 """Basic infrastructure for asynchronous socket service clients and servers.
30 There are only two ways to have a program on a single processor do "more
31 than one thing at a time". Multi-threaded programming is the simplest and
32 most popular way to do it, but there is another very different technique,
33 that lets you have nearly all the advantages of multi-threading, without
34 actually using multiple threads. it's really only practical if your program
35 is largely I/O bound. If your program is CPU bound, then pre-emptive
36 scheduled threads are probably what you really need. Network servers are
37 rarely CPU-bound, however.
39 If your operating system supports the select() system call in its I/O
40 library (and nearly all do), then you can use it to juggle multiple
41 communication channels at once; doing other work while your I/O is taking
42 place in the "background." Although this strategy can seem strange and
43 complex, especially at first, it is in many ways easier to understand and
44 control than multi-threaded programming. The module documented here solves
45 many of the difficult problems for you, making the task of building
46 sophisticated high-performance network servers and clients a snap.
56 from errno
import EALREADY
, EINPROGRESS
, EWOULDBLOCK
, ECONNRESET
, EINVAL
, \
57 ENOTCONN
, ESHUTDOWN
, EINTR
, EISCONN
, EBADF
, ECONNABORTED
, EPIPE
, EAGAIN
, \
60 _DISCONNECTED
= frozenset((ECONNRESET
, ENOTCONN
, ESHUTDOWN
, ECONNABORTED
, EPIPE
,
70 return os
.strerror(err
)
71 except (ValueError, OverflowError, NameError):
74 return "Unknown error %s" %err
76 class ExitNow(Exception):
79 _reraised_exceptions
= (ExitNow
, KeyboardInterrupt, SystemExit)
83 obj
.handle_read_event()
84 except _reraised_exceptions
:
91 obj
.handle_write_event()
92 except _reraised_exceptions
:
99 obj
.handle_expt_event()
100 except _reraised_exceptions
:
105 def readwrite(obj
, flags
):
107 if flags
& select
.POLLIN
:
108 obj
.handle_read_event()
109 if flags
& select
.POLLOUT
:
110 obj
.handle_write_event()
111 if flags
& select
.POLLPRI
:
112 obj
.handle_expt_event()
113 if flags
& (select
.POLLHUP | select
.POLLERR | select
.POLLNVAL
):
115 except socket
.error
, e
:
116 if e
.args
[0] not in _DISCONNECTED
:
120 except _reraised_exceptions
:
125 def poll(timeout
=0.0, map=None):
129 r
= []; w
= []; e
= []
130 for fd
, obj
in map.items():
131 is_r
= obj
.readable()
132 is_w
= obj
.writable()
139 if [] == r
== w
== e
:
144 r
, w
, e
= select
.select(r
, w
, e
, timeout
)
145 except select
.error
, err
:
146 if err
.args
[0] != EINTR
:
169 def poll2(timeout
=0.0, map=None):
170 # Use the poll() support added to the select module in Python 2.0
173 if timeout
is not None:
174 # timeout is in milliseconds
175 timeout
= int(timeout
*1000)
176 pollster
= select
.poll()
178 for fd
, obj
in map.items():
181 flags |
= select
.POLLIN | select
.POLLPRI
183 flags |
= select
.POLLOUT
185 # Only check for exceptions if object was either readable
187 flags |
= select
.POLLERR | select
.POLLHUP | select
.POLLNVAL
188 pollster
.register(fd
, flags
)
190 r
= pollster
.poll(timeout
)
191 except select
.error
, err
:
192 if err
.args
[0] != EINTR
:
199 readwrite(obj
, flags
)
201 poll3
= poll2
# Alias for backward compatibility
203 def loop(timeout
=30.0, use_poll
=False, map=None, count
=None):
207 if use_poll
and hasattr(select
, 'poll'):
214 poll_fun(timeout
, map)
217 while map and count
> 0:
218 poll_fun(timeout
, map)
228 ignore_log_types
= frozenset(['warning'])
230 def __init__(self
, sock
=None, map=None):
232 self
._map
= socket_map
239 # Set to nonblocking just to make sure for cases where we
240 # get a socket from a blocking source.
242 self
.set_socket(sock
, map)
243 self
.connected
= True
244 # The constructor no longer requires that the socket
245 # passed be connected.
247 self
.addr
= sock
.getpeername()
248 except socket
.error
, err
:
249 if err
.args
[0] == ENOTCONN
:
250 # To handle the case where we got an unconnected
252 self
.connected
= False
254 # The socket is broken in some unknown way, alert
255 # the user and remove it from the map (to prevent
256 # polling of broken sockets).
257 self
.del_channel(map)
263 status
= [self
.__class
__.__module
__+"."+self
.__class
__.__name
__]
264 if self
.accepting
and self
.addr
:
265 status
.append('listening')
267 status
.append('connected')
268 if self
.addr
is not None:
270 status
.append('%s:%d' % self
.addr
)
272 status
.append(repr(self
.addr
))
273 return '<%s at %#x>' % (' '.join(status
), id(self
))
277 def add_channel(self
, map=None):
278 #self.log_info('adding channel %s' % self)
281 map[self
._fileno
] = self
283 def del_channel(self
, map=None):
288 #self.log_info('closing channel %d:%s' % (fd, self))
292 def create_socket(self
, family
, type):
293 self
.family_and_type
= family
, type
294 sock
= socket
.socket(family
, type)
296 self
.set_socket(sock
)
298 def set_socket(self
, sock
, map=None):
300 ## self.__dict__['socket'] = sock
301 self
._fileno
= sock
.fileno()
302 self
.add_channel(map)
304 def set_reuse_addr(self
):
305 # try to re-use a server port if possible
307 self
.socket
.setsockopt(
308 socket
.SOL_SOCKET
, socket
.SO_REUSEADDR
,
309 self
.socket
.getsockopt(socket
.SOL_SOCKET
,
310 socket
.SO_REUSEADDR
) |
1
315 # ==================================================
316 # predicates for select()
317 # these are used as filters for the lists of sockets
318 # to pass to select().
319 # ==================================================
327 # ==================================================
328 # socket object methods.
329 # ==================================================
331 def listen(self
, num
):
332 self
.accepting
= True
333 if os
.name
== 'nt' and num
> 5:
335 return self
.socket
.listen(num
)
337 def bind(self
, addr
):
339 return self
.socket
.bind(addr
)
341 def connect(self
, address
):
342 self
.connected
= False
343 err
= self
.socket
.connect_ex(address
)
344 if err
in (EINPROGRESS
, EALREADY
, EWOULDBLOCK
) \
345 or err
== EINVAL
and os
.name
in ('nt', 'ce'):
347 if err
in (0, EISCONN
):
349 self
.handle_connect_event()
351 raise socket
.error(err
, errorcode
[err
])
354 # XXX can return either an address pair or None
356 conn
, addr
= self
.socket
.accept()
359 except socket
.error
as why
:
360 if why
.args
[0] in (EWOULDBLOCK
, ECONNABORTED
, EAGAIN
):
367 def send(self
, data
):
369 result
= self
.socket
.send(data
)
371 except socket
.error
, why
:
372 if why
.args
[0] == EWOULDBLOCK
:
374 elif why
.args
[0] in _DISCONNECTED
:
380 def recv(self
, buffer_size
):
382 data
= self
.socket
.recv(buffer_size
)
384 # a closed connection is indicated by signaling
385 # a read condition, and having recv() return 0.
390 except socket
.error
, why
:
391 # winsock sometimes throws ENOTCONN
392 if why
.args
[0] in _DISCONNECTED
:
399 self
.connected
= False
400 self
.accepting
= False
404 except socket
.error
, why
:
405 if why
.args
[0] not in (ENOTCONN
, EBADF
):
408 # cheap inheritance, used to pass all other attribute
409 # references to the underlying socket object.
410 def __getattr__(self
, attr
):
412 retattr
= getattr(self
.socket
, attr
)
413 except AttributeError:
414 raise AttributeError("%s instance has no attribute '%s'"
415 %(self
.__class
__.__name
__, attr
))
417 msg
= "%(me)s.%(attr)s is deprecated. Use %(me)s.socket.%(attr)s " \
418 "instead." % {'me': self
.__class
__.__name
__, 'attr':attr
}
419 warnings
.warn(msg
, DeprecationWarning, stacklevel
=2)
422 # log and log_info may be overridden to provide more sophisticated
423 # logging and warning methods. In general, log is for 'hit' logging
424 # and 'log_info' is for informational, warning and error logging.
426 def log(self
, message
):
427 sys
.stderr
.write('log: %s\n' % str(message
))
429 def log_info(self
, message
, type='info'):
430 if type not in self
.ignore_log_types
:
431 print '%s: %s' % (type, message
)
433 def handle_read_event(self
):
435 # accepting sockets are never connected, they "spawn" new
436 # sockets that are connected
438 elif not self
.connected
:
439 self
.handle_connect_event()
444 def handle_connect_event(self
):
445 err
= self
.socket
.getsockopt(socket
.SOL_SOCKET
, socket
.SO_ERROR
)
447 raise socket
.error(err
, _strerror(err
))
448 self
.handle_connect()
449 self
.connected
= True
451 def handle_write_event(self
):
453 # Accepting sockets shouldn't get a write event.
454 # We will pretend it didn't happen.
457 if not self
.connected
:
459 err
= self
.socket
.getsockopt(socket
.SOL_SOCKET
, socket
.SO_ERROR
)
461 raise socket
.error(err
, _strerror(err
))
463 self
.handle_connect_event()
466 def handle_expt_event(self
):
467 # handle_expt_event() is called if there might be an error on the
468 # socket, or if there is OOB data
469 # check for the error condition first
470 err
= self
.socket
.getsockopt(socket
.SOL_SOCKET
, socket
.SO_ERROR
)
472 # we can get here when select.select() says that there is an
473 # exceptional condition on the socket
474 # since there is an error, we'll go ahead and close the socket
475 # like we would in a subclassed handle_read() that received no
481 def handle_error(self
):
482 nil
, t
, v
, tbinfo
= compact_traceback()
484 # sometimes a user repr method will crash.
486 self_repr
= repr(self
)
488 self_repr
= '<__repr__(self) failed for object at %0x>' % id(self
)
491 'uncaptured python exception, closing channel %s (%s:%s %s)' % (
501 def handle_expt(self
):
502 self
.log_info('unhandled incoming priority event', 'warning')
504 def handle_read(self
):
505 self
.log_info('unhandled read event', 'warning')
507 def handle_write(self
):
508 self
.log_info('unhandled write event', 'warning')
510 def handle_connect(self
):
511 self
.log_info('unhandled connect event', 'warning')
513 def handle_accept(self
):
514 self
.log_info('unhandled accept event', 'warning')
516 def handle_close(self
):
517 self
.log_info('unhandled close event', 'warning')
520 # ---------------------------------------------------------------------------
521 # adds simple buffered output capability, useful for simple clients.
522 # [for more sophisticated usage use asynchat.async_chat]
523 # ---------------------------------------------------------------------------
525 class dispatcher_with_send(dispatcher
):
527 def __init__(self
, sock
=None, map=None):
528 dispatcher
.__init
__(self
, sock
, map)
531 def initiate_send(self
):
533 num_sent
= dispatcher
.send(self
, self
.out_buffer
[:512])
534 self
.out_buffer
= self
.out_buffer
[num_sent
:]
536 def handle_write(self
):
540 return (not self
.connected
) or len(self
.out_buffer
)
542 def send(self
, data
):
544 self
.log_info('sending %s' % repr(data
))
545 self
.out_buffer
= self
.out_buffer
+ data
548 # ---------------------------------------------------------------------------
549 # used for debugging.
550 # ---------------------------------------------------------------------------
552 def compact_traceback():
553 t
, v
, tb
= sys
.exc_info()
555 if not tb
: # Must have a traceback
556 raise AssertionError("traceback does not exist")
559 tb
.tb_frame
.f_code
.co_filename
,
560 tb
.tb_frame
.f_code
.co_name
,
568 file, function
, line
= tbinfo
[-1]
569 info
= ' '.join(['[%s|%s|%s]' % x
for x
in tbinfo
])
570 return (file, function
, line
), t
, v
, info
572 def close_all(map=None, ignore_all
=False):
575 for x
in map.values():
579 if x
.args
[0] == EBADF
:
583 except _reraised_exceptions
:
590 # Asynchronous File I/O:
592 # After a little research (reading man pages on various unixen, and
593 # digging through the linux kernel), I've determined that select()
594 # isn't meant for doing asynchronous file i/o.
595 # Heartening, though - reading linux/mm/filemap.c shows that linux
596 # supports asynchronous read-ahead. So _MOST_ of the time, the data
597 # will be sitting in memory for us already when we go to read it.
599 # What other OS's (besides NT) support async file i/o? [VMS?]
601 # Regardless, this is useful for pipes, and stdin/stdout...
603 if os
.name
== 'posix':
607 # Here we override just enough to make a file
608 # look like a socket for the purposes of asyncore.
609 # The passed fd is automatically os.dup()'d
611 def __init__(self
, fd
):
614 def recv(self
, *args
):
615 return os
.read(self
.fd
, *args
)
617 def send(self
, *args
):
618 return os
.write(self
.fd
, *args
)
620 def getsockopt(self
, level
, optname
, buflen
=None):
621 if (level
== socket
.SOL_SOCKET
and
622 optname
== socket
.SO_ERROR
and
625 raise NotImplementedError("Only asyncore specific behaviour "
637 class file_dispatcher(dispatcher
):
639 def __init__(self
, fd
, map=None):
640 dispatcher
.__init
__(self
, None, map)
641 self
.connected
= True
644 except AttributeError:
647 # set it to non-blocking mode
648 flags
= fcntl
.fcntl(fd
, fcntl
.F_GETFL
, 0)
649 flags
= flags | os
.O_NONBLOCK
650 fcntl
.fcntl(fd
, fcntl
.F_SETFL
, flags
)
652 def set_file(self
, fd
):
653 self
.socket
= file_wrapper(fd
)
654 self
._fileno
= self
.socket
.fileno()