Package pysys :: Package utils :: Module allocport
[hide private]
[frames] | no frames]

Source Code for Module pysys.utils.allocport

  1  #!/usr/bin/env python 
  2  # PySys System Test Framework, Copyright (C) 2006-2016  M.B.Grieve 
  3   
  4  # This library is free software; you can redistribute it and/or 
  5  # modify it under the terms of the GNU Lesser General Public 
  6  # License as published by the Free Software Foundation; either 
  7  # version 2.1 of the License, or (at your option) any later version. 
  8   
  9  # This library is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 12  # Lesser General Public License for more details. 
 13   
 14  # You should have received a copy of the GNU Lesser General Public 
 15  # License along with this library; if not, write to the Free Software 
 16  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 
 17   
 18  # Contact: moraygrieve@users.sourceforge.net 
 19   
 20  import collections, random, socket, sys, subprocess 
 21  from pysys import process_lock 
 22  from pysys.constants import * 
 23   
 24  # LRU queue of server TCP ports for allocation to tests which need to 
 25  # start TCP servers. Initialized to None since it might not actually be used. 
 26  # Properly initialize only on demand. 
 27  tcpServerPortPool = None 
 28   
29 -def getEphemeralTCPPortRange():
30 """Returns the range of TCP ports the operating system uses to allocate 31 ephemeral ports from i.e. the ports allocated for the client side of a 32 client-server connection. Returned as a tuple, 33 (ephemeral_low, ephemeral_high) or raises exception on error. 34 """ 35 # Find the smallest and largest ephemeral port 36 if PLATFORM == 'linux': 37 f = open('/proc/sys/net/ipv4/ip_local_port_range') 38 s = f.readline().split() 39 ephemeral_low = int(s[0]) 40 ephemeral_high = int(s[1]) 41 del f 42 elif PLATFORM == 'sunos': 43 def runNdd(driver, parameter): 44 p = subprocess.Popen(['/usr/sbin/ndd', driver, parameter], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 45 return int(p.communicate()[0].strip())
46 ephemeral_low = runNdd('/dev/tcp', 'tcp_smallest_anon_port') 47 ephemeral_high = runNdd('/dev/tcp', 'tcp_largest_anon_port') 48 elif PLATFORM == 'darwin': 49 def runSysctl(parameter): 50 p = subprocess.Popen(['/usr/sbin/sysctl', '-n', parameter], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 51 return int(p.communicate()[0].strip()) 52 ephemeral_low = runSysctl('net.inet.ip.portrange.first') 53 ephemeral_high = runSysctl('net.inet.ip.portrange.last') 54 elif PLATFORM == 'win32': 55 ephemeral_low = 1025 56 ephemeral_high = 5000 # The default 57 import _winreg 58 h = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters') 59 try: 60 ephemeral_high = _winreg.QueryValueEx(h, 'MaxUserPort')[0] 61 except: 62 # Accept the default if there isn't a value in the registry 63 pass 64 finally: 65 _winreg.CloseKey(h) 66 del h 67 else: 68 raise SystemError("No way of determining ephemeral port range on platform %s" % sys.platform) 69 70 return (ephemeral_low, ephemeral_high) 71
72 -def initializePortPool():
73 """Initialize the pool of ports we can allocate TCP server ports from 74 i.e. ports to which processes can bind to without clashes with other 75 processes 76 """ 77 78 global tcpServerPortPool 79 80 ephemeral_low, ephemeral_high = getEphemeralTCPPortRange() 81 82 # Allocate server ports from all non-privileged, non-ephemeral ports 83 tcpServerPortPool = range(1024, ephemeral_low) + range(ephemeral_high,65536) 84 85 # Randomize the port set to reduce the chance of clashes between 86 # simultaneous runs on the same machine 87 random.shuffle(tcpServerPortPool) 88 89 # Convert to an LRU queue of ports 90 tcpServerPortPool = collections.deque(tcpServerPortPool)
91
92 -def portIsInUse(port):
93 # Try to bind to it to see if anyone else is using it 94 with process_lock: 95 s = None 96 try: 97 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 98 99 # Set SO_LINGER since we don't want any accidentally 100 # connecting clients to cause the socket to hang 101 # around 102 if OSFAMILY == 'windows': 103 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 0) 104 105 # Set non-blocking since we want to fail fast rather 106 # than block 107 s.setblocking(0) 108 109 # Bind to empty host i.e wildcard interface 110 try: 111 s.bind(("", port)) 112 except Exception: 113 # If we get any exception assume it is because 114 # the port is in use 115 s.close() 116 return True 117 118 # Listen may not be necessary, but on unix it seems to 119 # help do a more complete shutdown if listen is called 120 s.listen(1) 121 try: 122 s.shutdown(socket.SHUT_RDWR) 123 except Exception: 124 # Do nothing - on windows shutdown sometimes 125 # fails even after listen 126 pass 127 s.close() 128 return False 129 except Exception, e: 130 # Don't expect this but just in case 131 print 'Here', e 132 if s != None: 133 s.close() 134 return True
135
136 -def allocateTCPPort():
137 while True: 138 port = tcpServerPortPool.popleft() 139 if portIsInUse(port): 140 # Toss the port back at the end of the queue 141 tcpServerPortPool.append(port) 142 else: 143 return port
144
145 -class TCPPortOwner:
146 - def __init__(self):
147 self.port = allocateTCPPort()
148
149 - def cleanup(self):
150 tcpServerPortPool.append(self.port)
151 152 # Initialize the TCP port pool 153 initializePortPool() 154