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-2013  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 == 'win32': 49 ephemeral_low = 1025 50 ephemeral_high = 5000 # The default 51 import _winreg 52 h = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters') 53 try: 54 ephemeral_high = _winreg.QueryValueEx(h, 'MaxUserPort')[0] 55 except: 56 # Accept the default if there isn't a value in the registry 57 pass 58 finally: 59 _winreg.CloseKey(h) 60 del h 61 else: 62 raise SystemError("No way of determining ephemeral port range on platform %s" % sys.platform) 63 64 return (ephemeral_low, ephemeral_high) 65
66 -def initializePortPool():
67 """Initialize the pool of ports we can allocate TCP server ports from 68 i.e. ports to which processes can bind to without clashes with other 69 processes 70 """ 71 72 global tcpServerPortPool 73 74 ephemeral_low, ephemeral_high = getEphemeralTCPPortRange() 75 76 # Allocate server ports from all non-privileged, non-ephemeral ports 77 tcpServerPortPool = range(1024, ephemeral_low) + range(ephemeral_high,65536) 78 79 # Randomize the port set to reduce the chance of clashes between 80 # simultaneous runs on the same machine 81 random.shuffle(tcpServerPortPool) 82 83 # Convert to an LRU queue of ports 84 tcpServerPortPool = collections.deque(tcpServerPortPool)
85
86 -def portIsInUse(port):
87 # Try to bind to it to see if anyone else is using it 88 with process_lock: 89 s = None 90 try: 91 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 92 93 # Set SO_LINGER since we don't want any accidentally 94 # connecting clients to cause the socket to hang 95 # around 96 if OSFAMILY == 'windows': 97 s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 0) 98 99 # Set non-blocking since we want to fail fast rather 100 # than block 101 s.setblocking(0) 102 103 # Bind to empty host i.e wildcard interface 104 try: 105 s.bind(("", port)) 106 except Exception: 107 # If we get any exception assume it is because 108 # the port is in use 109 s.close() 110 return True 111 112 # Listen may not be necessary, but on unix it seems to 113 # help do a more complete shutdown if listen is called 114 s.listen(1) 115 try: 116 s.shutdown(socket.SHUT_RDWR) 117 except Exception: 118 # Do nothing - on windows shutdown sometimes 119 # fails even after listen 120 pass 121 s.close() 122 return False 123 except Exception, e: 124 # Don't expect this but just in case 125 print 'Here', e 126 if s != None: 127 s.close() 128 return True
129
130 -def allocateTCPPort():
131 while True: 132 port = tcpServerPortPool.popleft() 133 if portIsInUse(port): 134 # Toss the port back at the end of the queue 135 tcpServerPortPool.append(port) 136 else: 137 return port
138
139 -class TCPPortOwner:
140 - def __init__(self):
141 self.port = allocateTCPPort()
142
143 - def __del__(self):
144 tcpServerPortPool.append(self.port)
145 146 # Initialize the TCP port pool 147 initializePortPool() 148