]> SALOME platform Git repositories - modules/kernel.git/commitdiff
Salome HOME
Add port manager to ensure concurrent sessions have a unique port each.
authoraguerre <aguerre>
Fri, 6 Sep 2013 14:31:59 +0000 (14:31 +0000)
committeraguerre <aguerre>
Fri, 6 Sep 2013 14:31:59 +0000 (14:31 +0000)
14 files changed:
bin/CMakeLists.txt
bin/PortManager.py [new file with mode: 0644]
bin/Singleton.py [new file with mode: 0644]
bin/appliskel/tests/CMakeLists.txt
bin/appliskel/tests/concurrentSession/CMakeLists.txt [new file with mode: 0644]
bin/appliskel/tests/concurrentSession/TestConcurrentSession.py [new file with mode: 0644]
bin/appliskel/tests/concurrentSession/TestMinimalExample.py [new file with mode: 0644]
bin/appliskel/tests/launcher/CMakeLists.txt
bin/appliskel/tests/launcher/TestLauncherSessionArgs.py
bin/launchConfigureParser.py
bin/parseConfigFile.py
bin/runSalome.py
bin/salome_session.py
bin/searchFreePort.py

index a562f96f8fe3032c9568e09478c6ea9af8d00f58..07ef256a4123270d0ff4525fc8b0d8a5ba700086 100755 (executable)
@@ -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 (file)
index 0000000..6c4ecb5
--- /dev/null
@@ -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 (file)
index 0000000..0f0f53f
--- /dev/null
@@ -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
+  #
+#
index e051906ee1ee0e5cbbd04b58e5e61857fc482b57..41af658e259e108d301ceb462ad5a53e83de5764 100644 (file)
@@ -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 (file)
index 0000000..59df15a
--- /dev/null
@@ -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 (file)
index 0000000..1902263
--- /dev/null
@@ -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 (file)
index 0000000..7022585
--- /dev/null
@@ -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()
index 8158f4f4ff924c7d7fa1981fc552dd0fff7cc400..6f63234e0cb2ea7bf278689ce17095aea5f95e28 100644 (file)
 # 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)
index d10008603a56d1f813926830215dbf576166b531..07a19b8b28120c1349148024f76b0d2fe4457d24 100644 (file)
@@ -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()
+#
index d89e2d1df708716bdb69e7845adc234b567e0eac..7043c515484523de493a47c420c1c17f7e25a4b5 100755 (executable)
@@ -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'])
index 0388c6c5776cbc662ccb573d6e58237bdff4d5cb..3511bbe97e4ecb2047ad07971c9120f830d5898d 100644 (file)
@@ -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}
index be66e3f3ee8e10ce808d9f58f96a7978c690a7d8..acb9c981f4f89a3d45727e952c4485a6e5af1507 100755 (executable)
@@ -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
index d3d6c4fe383f19bf4bcbb79401b6dd90b585a27f..1f2f2d7afc05edd3425204d4fc83d964a5eb5a82 100644 (file)
@@ -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)
index 07540095d5289eda6b396edc0a7e87ae36ff661c..a384db635ad8eabf14156379453960761441b33d 100644 (file)
 # 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)
+#