2 # -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
5 # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
28 import cPickle as pickle #@UnusedImport
30 import pickle #@Reimport
32 __PORT_MIN_NUMBER = 2810
33 __PORT_MAX_NUMBER = 2910
37 logger = logging.getLogger(__name__)
38 #logger.setLevel(logging.DEBUG)
39 logger.setLevel(logging.INFO)
40 ch = logging.StreamHandler()
41 ch.setLevel(logging.DEBUG)
42 formatter = logging.Formatter("%(levelname)s:%(threadName)s:%(pathname)s[%(lineno)s]%(message)s")
43 ch.setFormatter(formatter)
47 logger = createLogger()
49 #------------------------------------
51 def __acquire_lock(lock):
52 logger.debug("ACQUIRE LOCK")
53 if sys.platform == "win32":
55 # lock 1 byte: file is supposed to be zero-byte long
56 msvcrt.locking(lock.fileno(), msvcrt.LK_LOCK, 1)
59 fcntl.flock(lock, fcntl.LOCK_EX)
60 logger.debug("LOCK ACQUIRED")
62 def __release_lock(lock):
63 logger.debug("RELEASE LOCK")
64 if sys.platform == "win32":
66 msvcrt.locking(lock.fileno(), msvcrt.LK_UNLCK, 1)
69 fcntl.flock(lock, fcntl.LOCK_UN)
70 logger.debug("LOCK RELEASED")
72 #------------------------------------
74 def _getConfigurationFilename():
75 omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
77 from salome_utils import generateFileName
78 portmanager_config = generateFileName(omniorbUserPath,
84 temp = tempfile.NamedTemporaryFile()
85 lock_file = os.path.join(os.path.dirname(temp.name), ".salome", ".PortManager.lock")
88 os.makedirs(os.path.dirname(lock_file))
95 return (portmanager_config, lock_file)
98 def __isPortUsed(port, config):
100 for ports in config.values():
102 return (port in busy_ports) or __isNetworkConnectionActiveOnPort(port)
105 def __isNetworkConnectionActiveOnPort(port):
106 # :NOTE: Under windows:
107 # netstat options -l and -t are unavailable
108 # grep command is unavailable
109 if sys.platform == "win32":
110 cmd = ['netstat','-a','-n','-p','tcp']
112 cmd = ['netstat','-ant']
117 from subprocess import Popen, PIPE, STDOUT
118 p = Popen(cmd, stdout=PIPE, stderr=STDOUT)
119 out, err = p.communicate()
121 print("Error when trying to access active network connections.")
123 print("... Presumably this package is not installed...Please install netstat if available for your distribution.")
124 print("... Trying socket based approach")
127 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
128 result = sock.connect_ex(("127.0.0.1", port))
130 print("Port %r: Closed" % (port))
138 traceback.print_exc()
141 from io import StringIO
142 buf = StringIO(out.decode('utf-8', 'ignore'))
143 ports = buf.readlines()
144 # search for TCP - LISTEN connections
146 regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE );
149 p = int(regObj.match(item).group(1))
150 if p == port: return True
156 def getPort(preferredPort=None):
157 logger.debug("GET PORT")
159 config_file, lock_file = _getConfigurationFilename()
160 oldmask = os.umask(0)
161 with open(lock_file, 'wb') as lock:
167 logger.debug("read configuration file")
169 with open(config_file, 'rb') as f:
170 config = pickle.load(f)
172 logger.debug("Problem loading PortManager file: %s"%config_file)
173 # In this case config dictionary is reset
175 logger.debug("load config: %s"%str(config))
176 appli_path = os.getenv("ABSOLUTE_APPLI_PATH", "unknown")
180 config[appli_path] = []
184 if not port or __isPortUsed(port, config):
185 port = __PORT_MIN_NUMBER
186 while __isPortUsed(port, config):
187 if port == __PORT_MAX_NUMBER:
189 msg += "Can't find a free port to launch omniNames\n"
190 msg += "Try to kill the running servers and then launch SALOME again.\n"
191 raise RuntimeError(msg)
192 logger.debug("Port %s seems to be busy"%str(port))
194 logger.debug("found free port: %s"%str(port))
195 config[appli_path].append(port)
198 logger.debug("write config: %s"%str(config))
200 with open(config_file, 'wb') as f:
201 pickle.dump(config, f, protocol=0)
210 logger.debug("get port: %s"%str(port))
214 def releasePort(port):
216 logger.debug("RELEASE PORT (%s)"%port)
218 config_file, lock_file = _getConfigurationFilename()
219 oldmask = os.umask(0)
220 with open(lock_file, 'wb') as lock:
226 logger.debug("read configuration file")
228 with open(config_file, 'rb') as f:
229 config = pickle.load(f)
230 except IOError: # empty file
233 logger.debug("load config: %s"%str(config))
234 appli_path = os.getenv("ABSOLUTE_APPLI_PATH", "unknown")
238 config[appli_path] = []
240 # remove port from list
241 ports_info = config[appli_path]
242 config[appli_path] = [x for x in ports_info if x != port]
245 logger.debug("write config: %s"%str(config))
247 with open(config_file, 'wb') as f:
248 pickle.dump(config, f, protocol=0)
255 logger.debug("released port port: %s"%str(port))
261 config_file, lock_file = _getConfigurationFilename()
262 oldmask = os.umask(0)
263 with open(lock_file, 'wb') as lock:
269 logger.debug("read configuration file")
271 with open(config_file, 'rb') as f:
272 config = pickle.load(f)
273 except IOError: # empty file
276 logger.debug("load config: %s"%str(config))
277 appli_path = os.getenv("ABSOLUTE_APPLI_PATH", "unknown")
281 config[appli_path] = []
283 # Scan all possible ports to determine which ones are owned by other applications
284 ports_info = { 'this': [], 'other': [] }
285 my_busy_ports = config[appli_path]
286 for port in range(__PORT_MIN_NUMBER, __PORT_MAX_NUMBER):
287 if __isPortUsed(port, config):
288 logger.debug("Port %s seems to be busy"%str(port))
289 if port in my_busy_ports:
290 ports_info["this"].append(port)
292 ports_info["other"].append(port)
294 logger.debug("all busy_ports: %s"%str(ports_info))
296 sorted_ports = { 'this': sorted(ports_info['this']),
297 'other': sorted(ports_info['other']) }