mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Fixes Issue #14635: telnetlib will use poll() rather than select() when possible
to avoid failing due to the select() file descriptor limit.
This commit is contained in:
		
							parent
							
								
									4774946c3b
								
							
						
					
					
						commit
						dad5711677
					
				
					 4 changed files with 223 additions and 7 deletions
				
			
		
							
								
								
									
										130
									
								
								Lib/telnetlib.py
									
										
									
									
									
								
							
							
						
						
									
										130
									
								
								Lib/telnetlib.py
									
										
									
									
									
								
							|  | @ -34,6 +34,7 @@ | |||
| 
 | ||||
| 
 | ||||
| # Imported modules | ||||
| import errno | ||||
| import sys | ||||
| import socket | ||||
| import select | ||||
|  | @ -205,6 +206,7 @@ def __init__(self, host=None, port=0, | |||
|         self.sb = 0 # flag for SB and SE sequence. | ||||
|         self.sbdataq = b'' | ||||
|         self.option_callback = None | ||||
|         self._has_poll = hasattr(select, 'poll') | ||||
|         if host is not None: | ||||
|             self.open(host, port, timeout) | ||||
| 
 | ||||
|  | @ -286,6 +288,61 @@ def read_until(self, match, timeout=None): | |||
|         possibly the empty string.  Raise EOFError if the connection | ||||
|         is closed and no cooked data is available. | ||||
| 
 | ||||
|         """ | ||||
|         if self._has_poll: | ||||
|             return self._read_until_with_poll(match, timeout) | ||||
|         else: | ||||
|             return self._read_until_with_select(match, timeout) | ||||
| 
 | ||||
|     def _read_until_with_poll(self, match, timeout): | ||||
|         """Read until a given string is encountered or until timeout. | ||||
| 
 | ||||
|         This method uses select.poll() to implement the timeout. | ||||
|         """ | ||||
|         n = len(match) | ||||
|         call_timeout = timeout | ||||
|         if timeout is not None: | ||||
|             from time import time | ||||
|             time_start = time() | ||||
|         self.process_rawq() | ||||
|         i = self.cookedq.find(match) | ||||
|         if i < 0: | ||||
|             poller = select.poll() | ||||
|             poll_in_or_priority_flags = select.POLLIN | select.POLLPRI | ||||
|             poller.register(self, poll_in_or_priority_flags) | ||||
|             while i < 0 and not self.eof: | ||||
|                 try: | ||||
|                     ready = poller.poll(call_timeout) | ||||
|                 except select.error as e: | ||||
|                     if e.errno == errno.EINTR: | ||||
|                         if timeout is not None: | ||||
|                             elapsed = time() - time_start | ||||
|                             call_timeout = timeout-elapsed | ||||
|                         continue | ||||
|                     raise | ||||
|                 for fd, mode in ready: | ||||
|                     if mode & poll_in_or_priority_flags: | ||||
|                         i = max(0, len(self.cookedq)-n) | ||||
|                         self.fill_rawq() | ||||
|                         self.process_rawq() | ||||
|                         i = self.cookedq.find(match, i) | ||||
|                 if timeout is not None: | ||||
|                     elapsed = time() - time_start | ||||
|                     if elapsed >= timeout: | ||||
|                         break | ||||
|                     call_timeout = timeout-elapsed | ||||
|             poller.unregister(self) | ||||
|         if i >= 0: | ||||
|             i = i + n | ||||
|             buf = self.cookedq[:i] | ||||
|             self.cookedq = self.cookedq[i:] | ||||
|             return buf | ||||
|         return self.read_very_lazy() | ||||
| 
 | ||||
|     def _read_until_with_select(self, match, timeout=None): | ||||
|         """Read until a given string is encountered or until timeout. | ||||
| 
 | ||||
|         The timeout is implemented using select.select(). | ||||
|         """ | ||||
|         n = len(match) | ||||
|         self.process_rawq() | ||||
|  | @ -588,6 +645,79 @@ def expect(self, list, timeout=None): | |||
|         or if more than one expression can match the same input, the | ||||
|         results are undeterministic, and may depend on the I/O timing. | ||||
| 
 | ||||
|         """ | ||||
|         if self._has_poll: | ||||
|             return self._expect_with_poll(list, timeout) | ||||
|         else: | ||||
|             return self._expect_with_select(list, timeout) | ||||
| 
 | ||||
|     def _expect_with_poll(self, expect_list, timeout=None): | ||||
|         """Read until one from a list of a regular expressions matches. | ||||
| 
 | ||||
|         This method uses select.poll() to implement the timeout. | ||||
|         """ | ||||
|         re = None | ||||
|         expect_list = expect_list[:] | ||||
|         indices = range(len(expect_list)) | ||||
|         for i in indices: | ||||
|             if not hasattr(expect_list[i], "search"): | ||||
|                 if not re: import re | ||||
|                 expect_list[i] = re.compile(expect_list[i]) | ||||
|         call_timeout = timeout | ||||
|         if timeout is not None: | ||||
|             from time import time | ||||
|             time_start = time() | ||||
|         self.process_rawq() | ||||
|         m = None | ||||
|         for i in indices: | ||||
|             m = expect_list[i].search(self.cookedq) | ||||
|             if m: | ||||
|                 e = m.end() | ||||
|                 text = self.cookedq[:e] | ||||
|                 self.cookedq = self.cookedq[e:] | ||||
|                 break | ||||
|         if not m: | ||||
|             poller = select.poll() | ||||
|             poll_in_or_priority_flags = select.POLLIN | select.POLLPRI | ||||
|             poller.register(self, poll_in_or_priority_flags) | ||||
|             while not m and not self.eof: | ||||
|                 try: | ||||
|                     ready = poller.poll(call_timeout) | ||||
|                 except select.error as e: | ||||
|                     if e.errno == errno.EINTR: | ||||
|                         if timeout is not None: | ||||
|                             elapsed = time() - time_start | ||||
|                             call_timeout = timeout-elapsed | ||||
|                         continue | ||||
|                     raise | ||||
|                 for fd, mode in ready: | ||||
|                     if mode & poll_in_or_priority_flags: | ||||
|                         self.fill_rawq() | ||||
|                         self.process_rawq() | ||||
|                         for i in indices: | ||||
|                             m = expect_list[i].search(self.cookedq) | ||||
|                             if m: | ||||
|                                 e = m.end() | ||||
|                                 text = self.cookedq[:e] | ||||
|                                 self.cookedq = self.cookedq[e:] | ||||
|                                 break | ||||
|                 if timeout is not None: | ||||
|                     elapsed = time() - time_start | ||||
|                     if elapsed >= timeout: | ||||
|                         break | ||||
|                     call_timeout = timeout-elapsed | ||||
|             poller.unregister(self) | ||||
|         if m: | ||||
|             return (i, m, text) | ||||
|         text = self.read_very_lazy() | ||||
|         if not text and self.eof: | ||||
|             raise EOFError | ||||
|         return (-1, None, text) | ||||
| 
 | ||||
|     def _expect_with_select(self, list, timeout=None): | ||||
|         """Read until one from a list of a regular expressions matches. | ||||
| 
 | ||||
|         The timeout is implemented using select.select(). | ||||
|         """ | ||||
|         re = None | ||||
|         list = list[:] | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gregory P. Smith
						Gregory P. Smith