Salome HOME
do not read .sh environment files anymore
[modules/kernel.git] / bin / PortManager.py
index 71143075f1f895e6557d6fa78e855445ca7a1b7a..53ebacea9a7c9e86b59bd0958ee0b1234407c87c 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #  -*- coding: iso-8859-1 -*-
-# Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2016  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
@@ -8,7 +8,7 @@
 # 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.
+# version 2.1 of the License, or (at your option) any later version.
 #
 # This library is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 #
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
-import multiprocessing
-import time
-import socket
-
 import os
 import sys
-import threading
-import SocketServer
 
 try:
-  import cPickle as pickle
+  import cPickle as pickle #@UnusedImport
 except:
-  import pickle
-
-import struct
-import ctypes
+  import pickle #@Reimport
 
 import logging
 def createLogger():
   logger = logging.getLogger(__name__)
 #  logger.setLevel(logging.DEBUG)
+  logger.setLevel(logging.INFO)
   ch = logging.StreamHandler()
   ch.setLevel(logging.DEBUG)
   formatter = logging.Formatter("%(levelname)s:%(threadName)s:%(message)s")
@@ -51,43 +43,26 @@ def createLogger():
 #
 logger = createLogger()
 
-
-if sys.platform == 'win32':
-  import multiprocessing.reduction    # make sockets pickable/inheritable
-
-multiprocessing.freeze_support() # Add support for when a program which uses multiprocessing has been frozen to produce a Windows executable.
-
 #------------------------------------
-# A file locker (Linux only)
-import fcntl
-class PortManagerLock:
-  def __init__(self, filename, readonly=False, blocking=True):
-    # This will create it if it does not exist already
-    logger.debug("Create lock on %s"%filename)
-    self.__readonly = readonly
-    self.__blocking = blocking
-    self.__filename = filename
-    flag = 'w'
-    if self.__readonly:
-      flag = 'r'
-    self.handle = open(self.__filename, 'a+')
-
-  def acquire(self):
-    mode = fcntl.LOCK_EX
-    if not self.__blocking: # Raise an IOError exception if file has already been locked
-      mode = mode | fcntl.LOCK_NB
-    fcntl.flock(self.handle, mode)
-    logger.debug("lock acquired %s"%self.__blocking)
-
-  def release(self):
-    fcntl.flock(self.handle, fcntl.LOCK_UN)
-    logger.debug("lock released")
-
-  def __del__(self):
-    logger.debug("Close lock file")
-    self.handle.close()
-    os.remove(self.__filename)
+# A file locker
+def __acquire_lock(lock):
+  if sys.platform == "win32":
+    import msvcrt
+    # lock 1 byte: file is supposed to be zero-byte long
+    msvcrt.locking(lock.fileno(), msvcrt.LK_LOCK, 1)
+  else:
+    import fcntl
+    fcntl.flock(lock, fcntl.LOCK_EX)
 #
+def __release_lock(lock):
+  if sys.platform == "win32":
+    import msvcrt
+    msvcrt.locking(lock.fileno(), msvcrt.LK_UNLCK, 1)
+  else:
+    import fcntl
+    fcntl.flock(lock, fcntl.LOCK_UN)
+#
+#------------------------------------
 
 def _getConfigurationFilename():
   omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
@@ -98,7 +73,11 @@ def _getConfigurationFilename():
                                         suffix="PortManager",
                                         extension="cfg",
                                         hidden=True)
-  lock_file = portmanager_config + "-lock"
+  import tempfile
+  temp = tempfile.NamedTemporaryFile()
+  lock_file = os.path.join(os.path.dirname(temp.name), ".omniORB_PortManager.lock")
+  temp.close()
+
   return (portmanager_config, lock_file)
 #
 
@@ -110,10 +89,26 @@ def __isNetworkConnectionActiveOnPort(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()
+  if sys.platform == "win32":
+    cmd = ['netstat','-a','-n','-p tcp']
+  else:
+    cmd = ['netstat','-ant']
+    pass
+
+  err = None
+  try:
+    from subprocess import Popen, PIPE, STDOUT
+    p = Popen(cmd, stdout=PIPE, stderr=STDOUT)
+    out, err = p.communicate()
+  except:
+    print "Error when trying to access active network connections."
+    if err: print err
+    import traceback
+    traceback.print_exc()
+    return False
+
   import StringIO
-  buf = StringIO.StringIO(stdout)
+  buf = StringIO.StringIO(out)
   ports = buf.readlines()
   # search for TCP - LISTEN connections
   import re
@@ -124,15 +119,17 @@ def __isNetworkConnectionActiveOnPort(port):
       if p == port: return True
     except:
       pass
+  return False
 #
 
 def getPort(preferedPort=None):
   logger.debug("GET PORT")
 
   config_file, lock_file = _getConfigurationFilename()
+  oldmask = os.umask(0)
   with open(lock_file, 'w') as lock:
     # acquire lock
-    fcntl.flock(lock, fcntl.LOCK_EX)
+    __acquire_lock(lock)
 
     # read config
     config = {'busy_ports':[]}
@@ -140,8 +137,9 @@ def getPort(preferedPort=None):
     try:
       with open(config_file, 'r') as f:
         config = pickle.load(f)
-    except IOError: # empty file
-      pass
+    except:
+      logger.info("Problem loading PortManager file: %s"%config_file)
+      # In this case config dictionary is reset
 
     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
 
@@ -156,6 +154,9 @@ def getPort(preferedPort=None):
           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
+        logger.debug("Port %s seems to be busy"%str(port))
+        if not port in config["busy_ports"]:
+          config["busy_ports"].append(port)
         port = port + 1
     logger.debug("found free port: %s"%str(port))
     config["busy_ports"].append(port)
@@ -169,10 +170,12 @@ def getPort(preferedPort=None):
       pass
 
     # release lock
-    fcntl.flock(lock, fcntl.LOCK_UN)
+    __release_lock(lock)
+  #
 
-    logger.debug("get port: %s"%str(port))
-    return port
+  os.umask(oldmask)
+  logger.debug("get port: %s"%str(port))
+  return port
 #
 
 def releasePort(port):
@@ -180,9 +183,10 @@ def releasePort(port):
   logger.debug("RELEASE PORT (%s)"%port)
 
   config_file, lock_file = _getConfigurationFilename()
+  oldmask = os.umask(0)
   with open(lock_file, 'w') as lock:
     # acquire lock
-    fcntl.flock(lock, fcntl.LOCK_EX)
+    __acquire_lock(lock)
 
     # read config
     config = {'busy_ports':[]}
@@ -211,16 +215,20 @@ def releasePort(port):
       pass
 
     # release lock
-    fcntl.flock(lock, fcntl.LOCK_UN)
+    __release_lock(lock)
 
     logger.debug("released port port: %s"%str(port))
+
+  os.umask(oldmask)
 #
 
 def getBusyPorts():
+  busy_ports = []
   config_file, lock_file = _getConfigurationFilename()
+  oldmask = os.umask(0)
   with open(lock_file, 'w') as lock:
     # acquire lock
-    fcntl.flock(lock, fcntl.LOCK_EX)
+    __acquire_lock(lock)
 
     # read config
     config = {'busy_ports':[]}
@@ -235,7 +243,8 @@ def getBusyPorts():
 
     busy_ports = config["busy_ports"]
     # release lock
-    fcntl.flock(lock, fcntl.LOCK_UN)
+    __release_lock(lock)
 
-    return busy_ports
+  os.umask(oldmask)
+  return busy_ports
 #