From e05baa81ea35b45a4cabb393c8803a2774e6f9bf Mon Sep 17 00:00:00 2001 From: aguerre Date: Fri, 6 Sep 2013 14:31:59 +0000 Subject: [PATCH] Add port manager to ensure concurrent sessions have a unique port each. --- bin/CMakeLists.txt | 2 + bin/PortManager.py | 200 ++++++++++++++++++ bin/Singleton.py | 44 ++++ bin/appliskel/tests/CMakeLists.txt | 1 + .../tests/concurrentSession/CMakeLists.txt | 44 ++++ .../TestConcurrentSession.py | 71 +++++++ .../concurrentSession/TestMinimalExample.py | 56 +++++ bin/appliskel/tests/launcher/CMakeLists.txt | 11 +- .../tests/launcher/TestLauncherSessionArgs.py | 30 ++- bin/launchConfigureParser.py | 2 + bin/parseConfigFile.py | 4 +- bin/runSalome.py | 3 + bin/salome_session.py | 2 + bin/searchFreePort.py | 141 +++++------- 14 files changed, 508 insertions(+), 103 deletions(-) create mode 100644 bin/PortManager.py create mode 100644 bin/Singleton.py create mode 100644 bin/appliskel/tests/concurrentSession/CMakeLists.txt create mode 100644 bin/appliskel/tests/concurrentSession/TestConcurrentSession.py create mode 100644 bin/appliskel/tests/concurrentSession/TestMinimalExample.py diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index a562f96f8..07ef256a4 100755 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -43,6 +43,7 @@ SET(SCRIPTS orbmodule.py ORBConfigFile.py parseConfigFile.py + PortManager.py runSalome runSalome.py runSession.py @@ -57,6 +58,7 @@ SET(SCRIPTS setenv.py showNS.py shutdownSalome.py + Singleton.py virtual_salome.py waitContainers.py waitNS.py diff --git a/bin/PortManager.py b/bin/PortManager.py new file mode 100644 index 000000000..6c4ecb596 --- /dev/null +++ b/bin/PortManager.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE +# +# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +from Singleton import Singleton + +from multiprocessing.managers import SyncManager +import multiprocessing +import time +import socket +import Queue +import sys +import os + +""" +This class handles port distribution for SALOME sessions. +In case of concurent sessions, each will have its own port number. +""" +class PortManager(object): # :TODO: must manage lock owner + __metaclass__ = Singleton + # + def __init__(self, startNumber = 2810, limit = 100, timeout=60): + super(PortManager, self).__init__() + self.__startNumber = startNumber + self.__limit = startNumber + limit + self.__lockedPorts = [] + self.__lock = multiprocessing.Lock() + self.__timeout = timeout + self.__lastChangeTime = time.time() + # + def getPort(self): + with self.__lock: + port = self.__startNumber + while self.isPortUsed(port): + if port == self.__limit: + msg = "\n" + msg += "Can't find a free port to launch omniNames\n" + msg += "Try to kill the running servers and then launch SALOME again.\n" + raise RuntimeError, msg + port = port + 1 + + self.__lockedPorts.append(port) + self.__lastChangeTime = time.time() + return port + # + def releasePort(self, port): + with self.__lock: + if port in self.__lockedPorts: + self.__lockedPorts.remove(port) + self.__lastChangeTime = time.time() + # + def isBusy(self): + return len(self.__lockedPorts) + # + def isPortUsed(self, port): + return (port in self.__lockedPorts) or self.__isNetworkConnectionActiveOnPort(port) + # + def __isNetworkConnectionActiveOnPort(self, port): + # :NOTE: Under windows: + # netstat options -l and -t are unavailable + # grep command is unavailable + from subprocess import Popen, PIPE + (stdout, stderr) = Popen(['netstat','-an'], stdout=PIPE).communicate() + import StringIO + buf = StringIO.StringIO(stdout) + ports = buf.readlines() + # search for TCP - LISTEN connections + import re + regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE ); + for item in ports: + try: + p = int(regObj.match(item).group(1)) + if p == port: return True + except: + pass + # + def timeout(self): + return (time.time() - self.__lastChangeTime > self.__timeout) + # + def __str__(self): + with self.__lock: + return "PortManager: list of locked ports:" + str(self.__lockedPorts) + # +# + +def __build_server(ip, port, authkey): + message_queue = multiprocessing.Queue() + + class MyManager(SyncManager): + pass + + MyManager.register("PortManager", PortManager, exposed=['getPort', 'releasePort', 'isBusy', 'isPortUsed', 'timeout', '__str__']) + MyManager.register("get_message_queue", callable=lambda: message_queue) + + manager = MyManager(address=(ip, port), authkey=authkey) + + try: + manager.get_server() + manager.start() + except (EOFError, socket.error): + print 'Server already started on %s:%s'%(ip,port) + sys.exit(1) + + return manager +# + +def __build_client(ip, port, authkey): + class MyManager(SyncManager): + pass + + MyManager.register("PortManager") + MyManager.register("get_message_queue") + + manager = MyManager(address=(ip, port), authkey=authkey) + try: + manager.connect() + except socket.error: + raise Exception("Unable to connect to server on %s:%s"%(ip, port)) + return manager +# + +def __run_server(ip, port, authkey, timeout): + theserver = __build_server(ip, port, authkey) + shared_mesq = theserver.get_message_queue() + print 'PortManager server started on %s:%s'%(ip,port) + portManager = theserver.PortManager(timeout=timeout) + + while portManager.isBusy() or not portManager.timeout(): + try: + message = shared_mesq.get(block=False) + print message + except Queue.Empty: + pass + + print "PortManager server is shuting down..." + time.sleep(2) + theserver.shutdown() +# + +# +semaphore = None +# +def __run_client(manager, execute_func): + with semaphore: + name = multiprocessing.current_process().name + processId = os.getpid() + + # do the job + if execute_func: + execute_func(manager, name, processId) +# + +# +local_ip = '127.0.0.1' +port = 5000 +authkey = 'salome_port_manager_access' +# +lock = multiprocessing.Lock() +def start_server(nbSimultaneous=10, timeout=10): + with lock: + procServer = multiprocessing.Process(target=__run_server, args=(local_ip,port,authkey,timeout,)) + procServer.start() + global semaphore + semaphore = multiprocessing.Semaphore(nbSimultaneous) + time.sleep(2) +# + +def start_client(ip=local_ip, execute_func=None, name="anonymous"): + manager = __build_client(ip, port, authkey) + p = multiprocessing.Process(target=__run_client, name=name, args=(manager,execute_func,)) + p.start() + return manager +# + +client_id = 0 +def start_clients(nbClients, ip, execute_func, name_prefix="Client"): + global client_id + for i in range(nbClients): + start_client(ip, execute_func, name=name_prefix+"_"+str(client_id)) + client_id = client_id + 1 +# diff --git a/bin/Singleton.py b/bin/Singleton.py new file mode 100644 index 000000000..0f0f53f5e --- /dev/null +++ b/bin/Singleton.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE +# +# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +""" +The Singleton metaclass is used by each class which must have a unique instance. +Example: +class SingleInstanceClass(object): + __metaclass__ = Singleton + ... +""" +class Singleton(type): + # + def __init(self): + super(Singleton, self).__init__() + # + def __call__(self, *args, **kwargs): + try: + return self.__instance + except AttributeError: + self.__instance = super(Singleton, self).__call__(*args, **kwargs) + return self.__instance + # +# diff --git a/bin/appliskel/tests/CMakeLists.txt b/bin/appliskel/tests/CMakeLists.txt index e051906ee..41af658e2 100644 --- a/bin/appliskel/tests/CMakeLists.txt +++ b/bin/appliskel/tests/CMakeLists.txt @@ -17,4 +17,5 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # +ADD_SUBDIRECTORY(concurrentSession) ADD_SUBDIRECTORY(launcher) diff --git a/bin/appliskel/tests/concurrentSession/CMakeLists.txt b/bin/appliskel/tests/concurrentSession/CMakeLists.txt new file mode 100644 index 000000000..59df15a29 --- /dev/null +++ b/bin/appliskel/tests/concurrentSession/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 2013 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +include(CTest) +ENABLE_TESTING() + +# define environment for running tests +SET(PYTHON_VERSION ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}) + +SET(KERNEL_ROOT_DIR $ENV{KERNEL_ROOT_DIR} CACHE PATH "Path to the Salome KERNEL") +IF(NOT EXISTS ${KERNEL_ROOT_DIR}) + MESSAGE(FATAL_ERROR "KERNEL_ROOT_DIR undefined") +ENDIF(NOT EXISTS ${KERNEL_ROOT_DIR}) + +SET(THIS_PYTHONPATH $ENV{KERNEL_ROOT_DIR}/bin/salome:$ENV{KERNEL_ROOT_DIR}/lib/python$ENV{PYTHON_VERSION}/site-packages/salome:$ENV{KERNEL_ROOT_DIR}/lib64/python$ENV{PYTHON_VERSION}/site-packages/salome:$ENV{PYTHONPATH}) +SET(THIS_LD_LIBRARY_PATH $ENV{KERNEL_ROOT_DIR}/lib/salome:$ENV{LD_LIBRARY_PATH}) + +# add tests (use make test to run) +FILE(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/Test*.py") +FOREACH(file ${tests}) + GET_FILENAME_COMPONENT(testname ${file} NAME_WE) + ADD_TEST(${testname} ${PYTHON_EXECUTABLE} "${file}") + SET_PROPERTY(TEST ${testname} APPEND PROPERTY ENVIRONMENT PYTHONPATH=${THIS_PYTHONPATH} LD_LIBRARY_PATH=${THIS_LD_LIBRARY_PATH}) +ENDFOREACH() + +# install Python scripts +FILE(GLOB scripts "${CMAKE_CURRENT_SOURCE_DIR}/*.py") +SALOME_INSTALL_SCRIPTS("${scripts}" ${SALOME_INSTALL_SCRIPT_SCRIPTS}/appliskel/tests/concurrentSession) diff --git a/bin/appliskel/tests/concurrentSession/TestConcurrentSession.py b/bin/appliskel/tests/concurrentSession/TestConcurrentSession.py new file mode 100644 index 000000000..190226363 --- /dev/null +++ b/bin/appliskel/tests/concurrentSession/TestConcurrentSession.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# Copyright (C) 2013 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +import os +import sys +import unittest +import multiprocessing + +class SalomeSession(object): + def __init__(self, script, killAtEnd=True): + self.__killAtEnd = killAtEnd + import runSalome + sys.argv = ["runSalome.py"] + sys.argv += ["--terminal"] + sys.argv += ["%s" % script] + clt, d = runSalome.main() + # + def __del__(self): + if self.__killAtEnd: + port = os.getenv('NSPORT') + import killSalomeWithPort + killSalomeWithPort.killMyPort(port) + return + # +# + +def run_session(): + SalomeSession("") +# +class TestConcurrentLaunch(unittest.TestCase): + def testSingleSession(self): + print "** Testing single session **" + SalomeSession("") + # + def testMultiSession(self): + print "** Testing multi sessions **" + + jobs = [] + for i in range(3): + p = multiprocessing.Process(target=run_session) + jobs.append(p) + p.start() + + for j in jobs: + j.join() + # + @classmethod + def tearDownClass(cls): + import killSalome + killSalome.killAllPorts() + # +# + +unittest.main() diff --git a/bin/appliskel/tests/concurrentSession/TestMinimalExample.py b/bin/appliskel/tests/concurrentSession/TestMinimalExample.py new file mode 100644 index 000000000..7022585db --- /dev/null +++ b/bin/appliskel/tests/concurrentSession/TestMinimalExample.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# Copyright (C) 2013 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from PortManager import start_server, start_clients +import time +import datetime +import random +import sys +import unittest + +def hello(manager, name, processId): + seconds = random.randrange(3, 10) + startTime = datetime.datetime.now().time() + + portManager = manager.PortManager() + message_queue = manager.get_message_queue() + port = portManager.getPort() + message_queue.put("+ Process %s (%d) says: Hello! at %s on port %d and waits for %d seconds"%(name, processId, startTime, port, seconds)) + time.sleep(seconds) + endTime = datetime.datetime.now().time() + portManager.releasePort(port) + message_queue.put("- Process %s (%d) finished at %s --> port %d is free"%(name, processId, endTime, port)) +# + +class TestMinimalExample(unittest.TestCase): + def testConcurrent(self): + nbProcesses = 10 + nbSimultaneous = 4 + ip = '127.0.0.1' + + # start server + start_server(nbSimultaneous=nbSimultaneous, timeout=5) + + # start several clients + start_clients(nbProcesses, ip, hello) + # +# + +unittest.main() diff --git a/bin/appliskel/tests/launcher/CMakeLists.txt b/bin/appliskel/tests/launcher/CMakeLists.txt index 8158f4f4f..6f63234e0 100644 --- a/bin/appliskel/tests/launcher/CMakeLists.txt +++ b/bin/appliskel/tests/launcher/CMakeLists.txt @@ -17,12 +17,5 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -SET(SCRIPTS - add.py - getLogger.py - hello.py - lines.py - TestLauncherSessionArgs.py -) - -SALOME_INSTALL_SCRIPTS("${SCRIPTS}" ${SALOME_INSTALL_SCRIPT_SCRIPTS}/appliskel/tests/launcher) +FILE(GLOB scripts "${CMAKE_CURRENT_SOURCE_DIR}/*.py") +SALOME_INSTALL_SCRIPTS("${scripts}" ${SALOME_INSTALL_SCRIPT_SCRIPTS}/appliskel/tests/launcher) diff --git a/bin/appliskel/tests/launcher/TestLauncherSessionArgs.py b/bin/appliskel/tests/launcher/TestLauncherSessionArgs.py index d10008603..07a19b8b2 100644 --- a/bin/appliskel/tests/launcher/TestLauncherSessionArgs.py +++ b/bin/appliskel/tests/launcher/TestLauncherSessionArgs.py @@ -1,3 +1,22 @@ +# Copyright (C) 2013 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + import unittest import os @@ -15,10 +34,6 @@ class TestSessionArgs(unittest.TestCase): def setUpClass(cls): # Initialize path to SALOME application path_to_launcher = os.getenv("SALOME_LAUNCHER") - if not path_to_launcher: - msg = "Error: please set SALOME_LAUNCHER variable to the salome command of your application folder." - self.fail(msg) - # appli_dir = os.path.dirname(path_to_launcher) envd_dir = os.path.join(appli_dir, "env.d") @@ -46,7 +61,6 @@ class TestSessionArgs(unittest.TestCase): cls.lines2Msg = "hello.py is 16 lines longadd.py is 18 lines long" cls.linesUnreadable = ["lines.py", "args:hello.py,add.py,1,2,outfile="+cls.logFile] cls.linesUnreadableMsg = "hello.py is 16 lines longadd.py is 18 lines longFile '1' cannot be readFile '2' cannot be read" - # @classmethod def tearDownClass(cls): @@ -135,4 +149,10 @@ class TestSessionArgs(unittest.TestCase): if __name__ == "__main__": + path_to_launcher = os.getenv("SALOME_LAUNCHER") + if not path_to_launcher: + msg = "Error: please set SALOME_LAUNCHER variable to the salome command of your application folder." + raise Exception(msg) + unittest.main() +# diff --git a/bin/launchConfigureParser.py b/bin/launchConfigureParser.py index d89e2d1df..7043c5154 100755 --- a/bin/launchConfigureParser.py +++ b/bin/launchConfigureParser.py @@ -878,6 +878,8 @@ def get_env(theAdditionalOptions=[], appname=salomeappname, cfgname=salomecfgnam # Process --print-port option if cmd_opts.print_port: + import PortManager + PortManager.start_server(nbSimultaneous=25, timeout=10) from searchFreePort import searchFreePort searchFreePort({}) print "port:%s"%(os.environ['NSPORT']) diff --git a/bin/parseConfigFile.py b/bin/parseConfigFile.py index 0388c6c57..3511bbe97 100644 --- a/bin/parseConfigFile.py +++ b/bin/parseConfigFile.py @@ -209,6 +209,7 @@ class EnvFileConverter(object): self.allParsedVariableNames=[] # exclude line that begin with: self.exclude = [ 'if', 'then', 'else', 'fi', '#', 'echo' ] + self.exclude.append('$gconfTool') # QUICK FIX :TODO: provide method to extend this variable # discard the following keywords if at the beginning of line: self.discard = [ 'export' ] # the following keywords imply a special processing if at the beginning of line: @@ -250,6 +251,7 @@ class EnvFileConverter(object): value = self._purgeValue(value, k) line = ADD_TO_PREFIX + k + ": " + value # Update list of variable names + # :TODO: define excludeBlock variable (similar to exclude) and provide method to extend it if "cleandup()" in line: print "WARNING: parseConfigFile.py: skip cleandup and look for '# PRODUCT environment'" while True: @@ -264,7 +266,7 @@ class EnvFileConverter(object): variable, value = line.split('=') except: #avoid error for complicated sh line xx=`...=...`, but warning print "WARNING: parseConfigFile.py: line with multiples '=' character are hazardous: '"+line+"'" - variable, value = line.split('=',1) + variable, value = line.split('=',1) self.allParsedVariableNames.append(variable) # Self-extending variables that are not in reserved keywords # Example: FOO=something:${FOO} diff --git a/bin/runSalome.py b/bin/runSalome.py index be66e3f3e..acb9c981f 100755 --- a/bin/runSalome.py +++ b/bin/runSalome.py @@ -34,6 +34,7 @@ from server import process_id, Server import json from salomeLauncherUtils import formatScriptsAndArgs import subprocess +import PortManager # ----------------------------------------------------------------------------- @@ -769,6 +770,7 @@ def no_main(): args, modules_list, modules_root_dir = pickle.load(fenv) fenv.close() kill_salome(args) + PortManager.start_server(nbSimultaneous=25, timeout=10) from searchFreePort import searchFreePort searchFreePort(args, 0) clt = useSalome(args, modules_list, modules_root_dir) @@ -804,6 +806,7 @@ def main(): test = False pass if test: + PortManager.start_server(nbSimultaneous=25, timeout=10) from searchFreePort import searchFreePort searchFreePort(args, save_config, args.get('useport')) pass diff --git a/bin/salome_session.py b/bin/salome_session.py index d3d6c4fe3..1f2f2d7af 100644 --- a/bin/salome_session.py +++ b/bin/salome_session.py @@ -30,12 +30,14 @@ import os import sys import string import socket +import PortManager _session = None def startSession(modules=[]): global _session if _session: return + PortManager.start_server(nbSimultaneous=25, timeout=10) from searchFreePort import searchFreePort searchFreePort() _session = SalomeSession(modules) diff --git a/bin/searchFreePort.py b/bin/searchFreePort.py index 07540095d..a384db635 100644 --- a/bin/searchFreePort.py +++ b/bin/searchFreePort.py @@ -22,106 +22,71 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -def searchFreePort(args={}, save_config=1, use_port=None): - """ - Search free port for SALOME session. - Returns first found free port number. - """ - import sys, os, re, shutil - - # :NOTE: Under windows: - # netstat options -l and -t are unavailable - # grep command is unavailable - - from subprocess import Popen, PIPE - (stdout, stderr) = Popen(['netstat','-an'], stdout=PIPE).communicate() - import StringIO - buf = StringIO.StringIO(stdout) - ports = buf.readlines() +import os +import sys +def __setup_config(nsport, args, save_config): # - def portIsUsed(port, data): - regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE ); - for item in data: - try: - p = int(regObj.match(item).group(1)) - if p == port: return True - pass - except: + from salome_utils import generateFileName, getHostName + hostname = getHostName() + # + omniorbUserPath = os.getenv("OMNIORB_USER_PATH") + kwargs={} + if omniorbUserPath is not None: + kwargs["with_username"]=True + # + from ORBConfigFile import writeORBConfigFile + omniorb_config, giopsize = writeORBConfigFile(omniorbUserPath, hostname, nsport, kwargs) + args['port'] = os.environ['NSPORT'] + # + if save_config: + last_running_config = generateFileName(omniorbUserPath, prefix="omniORB", + suffix="last", + extension="cfg", + hidden=True, + **kwargs) + #os.environ['LAST_RUNNING_CONFIG'] = last_running_config + try: + if sys.platform == "win32": + import shutil + shutil.copyfile(omniorb_config, last_running_config) + else: + try: + if os.access(last_running_config, os.F_OK): + os.remove(last_running_config) + except OSError: + pass + os.symlink(omniorb_config, last_running_config) pass pass - return False + except: + pass # +# - def setup_config(nsport): - # - from salome_utils import generateFileName, getHostName - hostname = getHostName() - # - omniorbUserPath = os.getenv("OMNIORB_USER_PATH") - kwargs={} - if omniorbUserPath is not None: - kwargs["with_username"]=True - # - from ORBConfigFile import writeORBConfigFile - omniorb_config, giopsize = writeORBConfigFile(omniorbUserPath, hostname, nsport, kwargs) - args['port'] = os.environ['NSPORT'] - # - if save_config: - last_running_config = generateFileName(omniorbUserPath, prefix="omniORB", - suffix="last", - extension="cfg", - hidden=True, - **kwargs) - os.environ['LAST_RUNNING_CONFIG'] = last_running_config - try: - if sys.platform == "win32": - import shutil - shutil.copyfile(omniorb_config, last_running_config) - else: - try: - if os.access(last_running_config, os.F_OK): - os.remove(last_running_config) - except OSError: - pass - os.symlink(omniorb_config, last_running_config) - pass - pass - except: - pass - # +def searchFreePort(args={}, save_config=1, use_port=None): + """ + Search free port for SALOME session. + Returns first found free port number. + """ + + import PortManager + client = PortManager.start_client() # :NOTE: might specify a (remote) IP + portManager = client.PortManager() if use_port: print "Check if port can be used: %d" % use_port, - if not portIsUsed(use_port, ports): + if not portManager.isPortUsed(use_port): print "- OK" - setup_config(use_port) + __setup_config(use_port, args, save_config) return else: print "- KO: port is busy" - pass + pass # - print "Searching for a free port for naming service:", - # - - NSPORT=2810 - limit=NSPORT+100 - # - - while 1: - if not portIsUsed(NSPORT, ports): - print "%s - OK"%(NSPORT) - setup_config(NSPORT) - break - print "%s"%(NSPORT), - if NSPORT == limit: - msg = "\n" - msg += "Can't find a free port to launch omniNames\n" - msg += "Try to kill the running servers and then launch SALOME again.\n" - raise RuntimeError, msg - NSPORT=NSPORT+1 - pass - # - - return + port = portManager.getPort() + print "%s - OK"%(port) + __setup_config(port, args, save_config) + port = portManager.releasePort(port) +# -- 2.39.2