Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(80)

Side by Side Diff: Lib/asyncore.py

Issue 744: [issue1736190] asyncore/asynchat patches (Closed) SVN Base: http://svn.python.org/view/*checkout*/python/trunk/
Patch Set: Created 1 year, 7 months ago , Downloaded from: http://bugs.python.org/file10196/full_async_patch.patch
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 # -*- Mode: Python -*- 1 # -*- Mode: Python -*-
2 # Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp 2 # Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp
3 # Author: Sam Rushing <rushing@nightmare.com> 3 # Author: Sam Rushing <rushing@nightmare.com>
4 4
5 # ====================================================================== 5 # ======================================================================
6 # Copyright 1996 by Sam Rushing 6 # Copyright 1996 by Sam Rushing
7 # 7 #
8 # All Rights Reserved 8 # All Rights Reserved
9 # 9 #
10 # Permission to use, copy, modify, and distribute this software and 10 # Permission to use, copy, modify, and distribute this software and
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 sophisticated high-performance network servers and clients a snap. 46 sophisticated high-performance network servers and clients a snap.
47 """ 47 """
48 48
49 import select 49 import select
50 import socket 50 import socket
51 import sys 51 import sys
52 import time 52 import time
53 53
54 import os 54 import os
55 from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \ 55 from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
56 ENOTCONN, ESHUTDOWN, EINTR, EISCONN, errorcode 56 ENOTCONN, ESHUTDOWN, EINTR, EISCONN, EBADF, ECONNABORTED, errorcode
57 57
58 try: 58 try:
59 socket_map 59 socket_map
60 except NameError: 60 except NameError:
61 socket_map = {} 61 socket_map = {}
62
63 def _strerror(err):
64 res = os.strerror(err)
65 if res == 'Unknown error':
66 res = errorcode[err]
67 return res
62 68
63 class ExitNow(Exception): 69 class ExitNow(Exception):
64 pass 70 pass
65 71
66 def read(obj): 72 def read(obj):
67 try: 73 try:
68 obj.handle_read_event() 74 obj.handle_read_event()
69 except ExitNow: 75 except (ExitNow, KeyboardInterrupt, SystemExit):
70 raise 76 raise
71 except: 77 except:
72 obj.handle_error() 78 obj.handle_error()
73 79
74 def write(obj): 80 def write(obj):
75 try: 81 try:
76 obj.handle_write_event() 82 obj.handle_write_event()
77 except ExitNow: 83 except (ExitNow, KeyboardInterrupt, SystemExit):
78 raise 84 raise
79 except: 85 except:
80 obj.handle_error() 86 obj.handle_error()
81 87
82 def _exception (obj): 88 def _exception(obj):
83 try: 89 try:
84 obj.handle_expt_event() 90 obj.handle_expt_event()
85 except ExitNow: 91 except (ExitNow, KeyboardInterrupt, SystemExit):
86 raise 92 raise
87 except: 93 except:
88 obj.handle_error() 94 obj.handle_error()
89 95
90 def readwrite(obj, flags): 96 def readwrite(obj, flags):
91 try: 97 try:
92 if flags & (select.POLLIN | select.POLLPRI): 98 if flags & (select.POLLIN | select.POLLPRI):
93 obj.handle_read_event() 99 obj.handle_read_event()
94 if flags & select.POLLOUT: 100 if flags & select.POLLOUT:
95 obj.handle_write_event() 101 obj.handle_write_event()
96 if flags & (select.POLLERR | select.POLLHUP | select.POLLNVAL): 102 if flags & (select.POLLERR | select.POLLHUP | select.POLLNVAL):
97 obj.handle_expt_event() 103 obj.handle_expt_event()
98 except ExitNow: 104 except (ExitNow, KeyboardInterrupt, SystemExit):
99 raise 105 raise
100 except: 106 except:
101 obj.handle_error() 107 obj.handle_error()
102 108
103 def poll(timeout=0.0, map=None): 109 def poll(timeout=0.0, map=None):
104 if map is None: 110 if map is None:
105 map = socket_map 111 map = socket_map
106 if map: 112 if map:
107 r = []; w = []; e = [] 113 r = []; w = []; e = []
108 for fd, obj in map.items(): 114 for fd, obj in map.items():
109 is_r = obj.readable() 115 is_r = obj.readable()
110 is_w = obj.writable() 116 is_w = obj.writable()
111 if is_r: 117 if is_r:
112 r.append(fd) 118 r.append(fd)
113 if is_w: 119 if is_w:
114 w.append(fd) 120 w.append(fd)
115 if is_r or is_w: 121 if is_r or is_w:
116 e.append(fd) 122 e.append(fd)
117 if [] == r == w == e: 123 if [] == r == w == e:
118 time.sleep(timeout) 124 time.sleep(timeout)
119 else: 125 return
120 try: 126
121 r, w, e = select.select(r, w, e, timeout) 127 try:
122 except select.error, err: 128 r, w, e = select.select(r, w, e, timeout)
123 if err[0] != EINTR: 129 except select.error, err:
124 raise 130 if err[0] != EINTR:
125 else: 131 raise
126 return 132 else:
133 return
127 134
128 for fd in r: 135 for fd in r:
129 obj = map.get(fd) 136 obj = map.get(fd)
130 if obj is None: 137 if obj is None:
131 continue 138 continue
132 read(obj) 139 read(obj)
133 140
134 for fd in w: 141 for fd in w:
135 obj = map.get(fd) 142 obj = map.get(fd)
136 if obj is None: 143 if obj is None:
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 connected = False 208 connected = False
202 accepting = False 209 accepting = False
203 closing = False 210 closing = False
204 addr = None 211 addr = None
205 212
206 def __init__(self, sock=None, map=None): 213 def __init__(self, sock=None, map=None):
207 if map is None: 214 if map is None:
208 self._map = socket_map 215 self._map = socket_map
209 else: 216 else:
210 self._map = map 217 self._map = map
211 218
219 self._fileno = None
220
212 if sock: 221 if sock:
222 # Set to nonblocking just to make sure for cases where we
223 # get a socket from a blocking source.
224 sock.setblocking(0)
213 self.set_socket(sock, map) 225 self.set_socket(sock, map)
214 # I think it should inherit this anyway
215 self.socket.setblocking(0)
216 self.connected = True 226 self.connected = True
217 # XXX Does the constructor require that the socket passed 227 # The constructor no longer requires that the socket
218 # be connected? 228 # passed be connected.
219 try: 229 try:
220 self.addr = sock.getpeername() 230 self.addr = sock.getpeername()
221 except socket.error: 231 except socket.error:
222 # The addr isn't crucial 232 if err[0] == ENOTCONN:
223 pass 233 # To handle the case where we got an unconnected
234 # socket.
235 self.connected = False
236 else:
237 # The socket is broken in some unknown way, alert
238 # the user and remove it from the map (to prevent
239 # polling of broken sockets).
240 self.del_channel(map)
241 raise
224 else: 242 else:
225 self.socket = None 243 self.socket = None
226 244
227 def __repr__(self): 245 def __repr__(self):
228 status = [self.__class__.__module__+"."+self.__class__.__name__] 246 status = [self.__class__.__module__+"."+self.__class__.__name__]
229 if self.accepting and self.addr: 247 if self.accepting and self.addr:
230 status.append('listening') 248 status.append('listening')
231 elif self.connected: 249 elif self.connected:
232 status.append('connected') 250 status.append('connected')
233 if self.addr is not None: 251 if self.addr is not None:
(...skipping 13 matching lines...) Expand all
247 fd = self._fileno 265 fd = self._fileno
248 if map is None: 266 if map is None:
249 map = self._map 267 map = self._map
250 if map.has_key(fd): 268 if map.has_key(fd):
251 #self.log_info('closing channel %d:%s' % (fd, self)) 269 #self.log_info('closing channel %d:%s' % (fd, self))
252 del map[fd] 270 del map[fd]
253 self._fileno = None 271 self._fileno = None
254 272
255 def create_socket(self, family, type): 273 def create_socket(self, family, type):
256 self.family_and_type = family, type 274 self.family_and_type = family, type
257 self.socket = socket.socket(family, type) 275 sock = socket.socket(family, type)
258 self.socket.setblocking(0) 276 sock.setblocking(0)
259 self._fileno = self.socket.fileno() 277 self.set_socket(sock)
260 self.add_channel()
261 278
262 def set_socket(self, sock, map=None): 279 def set_socket(self, sock, map=None):
263 self.socket = sock 280 self.socket = sock
264 ## self.__dict__['socket'] = sock 281 ## self.__dict__['socket'] = sock
265 self._fileno = sock.fileno() 282 self._fileno = sock.fileno()
266 self.add_channel(map) 283 self.add_channel(map)
267 284
268 def set_reuse_addr(self): 285 def set_reuse_addr(self):
269 # try to re-use a server port if possible 286 # try to re-use a server port if possible
270 try: 287 try:
(...skipping 17 matching lines...) Expand all
288 def writable(self): 305 def writable(self):
289 return True 306 return True
290 307
291 # ================================================== 308 # ==================================================
292 # socket object methods. 309 # socket object methods.
293 # ================================================== 310 # ==================================================
294 311
295 def listen(self, num): 312 def listen(self, num):
296 self.accepting = True 313 self.accepting = True
297 if os.name == 'nt' and num > 5: 314 if os.name == 'nt' and num > 5:
298 num = 1 315 num = 5
299 return self.socket.listen(num) 316 return self.socket.listen(num)
300 317
301 def bind(self, addr): 318 def bind(self, addr):
302 self.addr = addr 319 self.addr = addr
303 return self.socket.bind(addr) 320 return self.socket.bind(addr)
304 321
305 def connect(self, address): 322 def connect(self, address):
306 self.connected = False 323 self.connected = False
307 err = self.socket.connect_ex(address) 324 err = self.socket.connect_ex(address)
308 # XXX Should interpret Winsock return values 325 # XXX Should interpret Winsock return values
309 if err in (EINPROGRESS, EALREADY, EWOULDBLOCK): 326 if err in (EINPROGRESS, EALREADY, EWOULDBLOCK):
310 return 327 return
311 if err in (0, EISCONN): 328 if err in (0, EISCONN):
312 self.addr = address 329 self.addr = address
313 self.connected = True 330 self.handle_connect_event()
314 self.handle_connect()
315 else: 331 else:
316 raise socket.error, (err, errorcode[err]) 332 raise socket.error(err, errorcode[err])
317 333
318 def accept(self): 334 def accept(self):
319 # XXX can return either an address pair or None 335 # XXX can return either an address pair or None
320 try: 336 try:
321 conn, addr = self.socket.accept() 337 conn, addr = self.socket.accept()
322 return conn, addr 338 return conn, addr
323 except socket.error, why: 339 except socket.error, why:
324 if why[0] == EWOULDBLOCK: 340 if why[0] == EWOULDBLOCK:
325 pass 341 pass
326 else: 342 else:
327 raise 343 raise
328 344
329 def send(self, data): 345 def send(self, data):
330 try: 346 try:
331 result = self.socket.send(data) 347 result = self.socket.send(data)
332 return result 348 return result
333 except socket.error, why: 349 except socket.error, why:
334 if why[0] == EWOULDBLOCK: 350 if why[0] == EWOULDBLOCK:
335 return 0 351 return 0
352 elif why[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED):
353 self.handle_close()
354 return 0
336 else: 355 else:
337 raise 356 raise
338 return 0
339 357
340 def recv(self, buffer_size): 358 def recv(self, buffer_size):
341 try: 359 try:
342 data = self.socket.recv(buffer_size) 360 data = self.socket.recv(buffer_size)
343 if not data: 361 if not data:
344 # a closed connection is indicated by signaling 362 # a closed connection is indicated by signaling
345 # a read condition, and having recv() return 0. 363 # a read condition, and having recv() return 0.
346 self.handle_close() 364 self.handle_close()
347 return '' 365 return ''
348 else: 366 else:
349 return data 367 return data
350 except socket.error, why: 368 except socket.error, why:
351 # winsock sometimes throws ENOTCONN 369 # winsock sometimes throws ENOTCONN
352 if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]: 370 if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED]:
353 self.handle_close() 371 self.handle_close()
354 return '' 372 return ''
355 else: 373 else:
356 raise 374 raise
357 375
358 def close(self): 376 def close(self):
377 self.connected = False
378 self.accepting = False
359 self.del_channel() 379 self.del_channel()
360 self.socket.close() 380 try:
381 self.socket.close()
382 except socket.error, why:
383 if why[0] not in (ENOTCONN, EBADF):
384 raise
361 385
362 # cheap inheritance, used to pass all other attribute 386 # cheap inheritance, used to pass all other attribute
363 # references to the underlying socket object. 387 # references to the underlying socket object.
364 def __getattr__(self, attr): 388 def __getattr__(self, attr):
365 return getattr(self.socket, attr) 389 return getattr(self.socket, attr)
366 390
367 # log and log_info may be overridden to provide more sophisticated 391 # log and log_info may be overridden to provide more sophisticated
368 # logging and warning methods. In general, log is for 'hit' logging 392 # logging and warning methods. In general, log is for 'hit' logging
369 # and 'log_info' is for informational, warning and error logging. 393 # and 'log_info' is for informational, warning and error logging.
370 394
371 def log(self, message): 395 def log(self, message):
372 sys.stderr.write('log: %s\n' % str(message)) 396 sys.stderr.write('log: %s\n' % str(message))
373 397
374 def log_info(self, message, type='info'): 398 def log_info(self, message, type='info'):
375 if __debug__ or type != 'info': 399 if __debug__ or type != 'info':
376 print '%s: %s' % (type, message) 400 print '%s: %s' % (type, message)
377 401
378 def handle_read_event(self): 402 def handle_read_event(self):
379 if self.accepting: 403 if self.accepting:
380 # for an accepting socket, getting a read implies 404 # accepting sockets are never connected, they "spawn" new
381 # that we are connected 405 # sockets that are connected
382 if not self.connected:
383 self.connected = True
384 self.handle_accept() 406 self.handle_accept()
385 elif not self.connected: 407 elif not self.connected:
386 self.handle_connect() 408 self.handle_connect_event()
387 self.connected = True
388 self.handle_read() 409 self.handle_read()
389 else: 410 else:
390 self.handle_read() 411 self.handle_read()
391 412
413 def handle_connect_event(self):
414 self.connected = True
415 self.handle_connect()
416
392 def handle_write_event(self): 417 def handle_write_event(self):
393 # getting a write implies that we are connected 418 if self.accepting:
419 # Accepting sockets shouldn't get a write event.
420 # We will pretend it didn't happen.
421 return
422
394 if not self.connected: 423 if not self.connected:
395 self.handle_connect() 424 #check for errors
396 self.connected = True 425 err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
426 if err != 0:
427 raise socket.error(err, strerror(err))
428
429 self.handle_connect_event()
397 self.handle_write() 430 self.handle_write()
398 431
399 def handle_expt_event(self): 432 def handle_expt_event(self):
400 self.handle_expt() 433 # if the handle_expt is the same default worthless method,
434 # we'll not even bother calling it, we'll instead generate
435 # a useful error
436 x = True
437 try:
438 y1 = self.__class__.handle_expt.im_func
439 y2 = dispatcher.handle_expt.im_func
440 x = y1 is y2
441 except AttributeError:
442 pass
443
444 if x:
445 err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
446 msg = _strerror(err)
447
448 raise socket.error(err, msg)
449 else:
450 self.handle_expt()
401 451
402 def handle_error(self): 452 def handle_error(self):
403 nil, t, v, tbinfo = compact_traceback() 453 nil, t, v, tbinfo = compact_traceback()
404 454
405 # sometimes a user repr method will crash. 455 # sometimes a user repr method will crash.
406 try: 456 try:
407 self_repr = repr(self) 457 self_repr = repr(self)
408 except: 458 except:
409 self_repr = '<__repr__(self) failed for object at %0x>' % id(self) 459 self_repr = '<__repr__(self) failed for object at %0x>' % id(self)
410 460
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 self.out_buffer = self.out_buffer + data 516 self.out_buffer = self.out_buffer + data
467 self.initiate_send() 517 self.initiate_send()
468 518
469 # --------------------------------------------------------------------------- 519 # ---------------------------------------------------------------------------
470 # used for debugging. 520 # used for debugging.
471 # --------------------------------------------------------------------------- 521 # ---------------------------------------------------------------------------
472 522
473 def compact_traceback(): 523 def compact_traceback():
474 t, v, tb = sys.exc_info() 524 t, v, tb = sys.exc_info()
475 tbinfo = [] 525 tbinfo = []
476 assert tb # Must have a traceback 526 if not tb: # Must have a traceback
527 raise AssertionError("traceback does not exist")
477 while tb: 528 while tb:
478 tbinfo.append(( 529 tbinfo.append((
479 tb.tb_frame.f_code.co_filename, 530 tb.tb_frame.f_code.co_filename,
480 tb.tb_frame.f_code.co_name, 531 tb.tb_frame.f_code.co_name,
481 str(tb.tb_lineno) 532 str(tb.tb_lineno)
482 )) 533 ))
483 tb = tb.tb_next 534 tb = tb.tb_next
484 535
485 # just to be safe 536 # just to be safe
486 del tb 537 del tb
487 538
488 file, function, line = tbinfo[-1] 539 file, function, line = tbinfo[-1]
489 info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo]) 540 info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo])
490 return (file, function, line), t, v, info 541 return (file, function, line), t, v, info
491 542
492 def close_all(map=None): 543 def close_all(map=None, ignore_all=False):
493 if map is None: 544 if map is None:
494 map = socket_map 545 map = socket_map
495 for x in map.values(): 546 for x in map.values():
496 x.socket.close() 547 try:
548 x.close()
549 except OSError, x:
550 if x[0] == EBADF:
551 pass
552 elif not ignore_all:
553 raise
554 except (ExitNow, KeyboardInterrupt, SystemExit):
555 raise
556 except:
557 if not ignore_all:
558 raise
497 map.clear() 559 map.clear()
498 560
499 # Asynchronous File I/O: 561 # Asynchronous File I/O:
500 # 562 #
501 # After a little research (reading man pages on various unixen, and 563 # After a little research (reading man pages on various unixen, and
502 # digging through the linux kernel), I've determined that select() 564 # digging through the linux kernel), I've determined that select()
503 # isn't meant for doing asynchronous file i/o. 565 # isn't meant for doing asynchronous file i/o.
504 # Heartening, though - reading linux/mm/filemap.c shows that linux 566 # Heartening, though - reading linux/mm/filemap.c shows that linux
505 # supports asynchronous read-ahead. So _MOST_ of the time, the data 567 # supports asynchronous read-ahead. So _MOST_ of the time, the data
506 # will be sitting in memory for us already when we go to read it. 568 # will be sitting in memory for us already when we go to read it.
507 # 569 #
508 # What other OS's (besides NT) support async file i/o? [VMS?] 570 # What other OS's (besides NT) support async file i/o? [VMS?]
509 # 571 #
510 # Regardless, this is useful for pipes, and stdin/stdout... 572 # Regardless, this is useful for pipes, and stdin/stdout...
511 573
512 if os.name == 'posix': 574 if os.name == 'posix':
513 import fcntl 575 import fcntl
514 576
515 class file_wrapper: 577 class file_wrapper:
516 # here we override just enough to make a file 578 # Here we override just enough to make a file
517 # look like a socket for the purposes of asyncore. 579 # look like a socket for the purposes of asyncore.
580 # The passed fd is automatically os.dup()'d
518 581
519 def __init__(self, fd): 582 def __init__(self, fd):
520 self.fd = fd 583 self.fd = os.dup(fd)
521 584
522 def recv(self, *args): 585 def recv(self, *args):
523 return os.read(self.fd, *args) 586 return os.read(self.fd, *args)
524 587
525 def send(self, *args): 588 def send(self, *args):
526 return os.write(self.fd, *args) 589 return os.write(self.fd, *args)
527 590
528 read = recv 591 read = recv
529 write = send 592 write = send
530 593
531 def close(self): 594 def close(self):
532 os.close(self.fd) 595 os.close(self.fd)
533 596
534 def fileno(self): 597 def fileno(self):
535 return self.fd 598 return self.fd
536 599
537 class file_dispatcher(dispatcher): 600 class file_dispatcher(dispatcher):
538 601
539 def __init__(self, fd, map=None): 602 def __init__(self, fd, map=None):
540 dispatcher.__init__(self, None, map) 603 dispatcher.__init__(self, None, map)
541 self.connected = True 604 self.connected = True
605 try:
606 fd = fd.fileno()
607 except AttributeError:
608 pass
542 self.set_file(fd) 609 self.set_file(fd)
543 # set it to non-blocking mode 610 # set it to non-blocking mode
544 flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0) 611 flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
545 flags = flags | os.O_NONBLOCK 612 flags = flags | os.O_NONBLOCK
546 fcntl.fcntl(fd, fcntl.F_SETFL, flags) 613 fcntl.fcntl(fd, fcntl.F_SETFL, flags)
547 614
548 def set_file(self, fd): 615 def set_file(self, fd):
549 self._fileno = fd 616 self._fileno = fd
550 self.socket = file_wrapper(fd) 617 self.socket = file_wrapper(fd)
551 self.add_channel() 618 self.add_channel()
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld r497