Salome HOME
0021746: EDF 2135 GEOM: Unification of Python documentations
[modules/kernel.git] / bin / PortManager.py
1 #!/usr/bin/env python
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
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.
12 #
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.
17 #
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
21 #
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24 import os
25 import sys
26
27 try:
28   import cPickle as pickle
29 except:
30   import pickle
31
32 import logging
33 def createLogger():
34   logger = logging.getLogger(__name__)
35 #  logger.setLevel(logging.DEBUG)
36   ch = logging.StreamHandler()
37   ch.setLevel(logging.DEBUG)
38   formatter = logging.Formatter("%(levelname)s:%(threadName)s:%(message)s")
39   ch.setFormatter(formatter)
40   logger.addHandler(ch)
41   return logger
42 #
43 logger = createLogger()
44
45 #------------------------------------
46 # A file locker (Linux only)
47 import fcntl
48 class PortManagerLock:
49   def __init__(self, filename, readonly=False, blocking=True):
50     # This will create it if it does not exist already
51     logger.debug("Create lock on %s"%filename)
52     self.__readonly = readonly
53     self.__blocking = blocking
54     self.__filename = filename
55     flag = 'w'
56     if self.__readonly:
57       flag = 'r'
58     self.handle = open(self.__filename, 'a+')
59
60   def acquire(self):
61     mode = fcntl.LOCK_EX
62     if not self.__blocking: # Raise an IOError exception if file has already been locked
63       mode = mode | fcntl.LOCK_NB
64     fcntl.flock(self.handle, mode)
65     logger.debug("lock acquired %s"%self.__blocking)
66
67   def release(self):
68     fcntl.flock(self.handle, fcntl.LOCK_UN)
69     logger.debug("lock released")
70
71   def __del__(self):
72     logger.debug("Close lock file")
73     self.handle.close()
74     os.remove(self.__filename)
75 #
76
77 def _getConfigurationFilename():
78   omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
79
80   from salome_utils import generateFileName
81   portmanager_config = generateFileName(omniorbUserPath,
82                                         prefix="omniORB",
83                                         suffix="PortManager",
84                                         extension="cfg",
85                                         hidden=True)
86   lock_file = portmanager_config + "-lock"
87   return (portmanager_config, lock_file)
88 #
89
90 def __isPortUsed(port, busy_ports):
91   return (port in busy_ports) or __isNetworkConnectionActiveOnPort(port)
92 #
93
94 def __isNetworkConnectionActiveOnPort(port):
95   # :NOTE: Under windows:
96   #        netstat options -l and -t are unavailable
97   #        grep command is unavailable
98   from subprocess import Popen, PIPE
99   (stdout, stderr) = Popen(['netstat','-an'], stdout=PIPE).communicate()
100   import StringIO
101   buf = StringIO.StringIO(stdout)
102   ports = buf.readlines()
103   # search for TCP - LISTEN connections
104   import re
105   regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE );
106   for item in ports:
107     try:
108       p = int(regObj.match(item).group(1))
109       if p == port: return True
110     except:
111       pass
112 #
113
114 def getPort(preferedPort=None):
115   logger.debug("GET PORT")
116
117   config_file, lock_file = _getConfigurationFilename()
118   with open(lock_file, 'w') as lock:
119     # acquire lock
120     fcntl.flock(lock, fcntl.LOCK_EX)
121
122     # read config
123     config = {'busy_ports':[]}
124     logger.debug("read configuration file")
125     try:
126       with open(config_file, 'r') as f:
127         config = pickle.load(f)
128     except IOError: # empty file
129       pass
130
131     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
132
133     # append port
134     busy_ports = config["busy_ports"]
135     port = preferedPort
136     if not port or __isPortUsed(port, busy_ports):
137       port = 2810
138       while __isPortUsed(port, busy_ports):
139         if port == 2810+100:
140           msg  = "\n"
141           msg += "Can't find a free port to launch omniNames\n"
142           msg += "Try to kill the running servers and then launch SALOME again.\n"
143           raise RuntimeError, msg
144         port = port + 1
145     logger.debug("found free port: %s"%str(port))
146     config["busy_ports"].append(port)
147
148     # write config
149     logger.debug("write busy_ports: %s"%str(config["busy_ports"]))
150     try:
151       with open(config_file, 'w') as f:
152         pickle.dump(config, f)
153     except IOError:
154       pass
155
156     # release lock
157     fcntl.flock(lock, fcntl.LOCK_UN)
158
159     logger.debug("get port: %s"%str(port))
160     return port
161 #
162
163 def releasePort(port):
164   port = int(port)
165   logger.debug("RELEASE PORT (%s)"%port)
166
167   config_file, lock_file = _getConfigurationFilename()
168   with open(lock_file, 'w') as lock:
169     # acquire lock
170     fcntl.flock(lock, fcntl.LOCK_EX)
171
172     # read config
173     config = {'busy_ports':[]}
174     logger.debug("read configuration file")
175     try:
176       with open(config_file, 'r') as f:
177         config = pickle.load(f)
178     except IOError: # empty file
179       pass
180
181     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
182
183     # remove port from list
184     busy_ports = config["busy_ports"]
185
186     if port in busy_ports:
187       busy_ports.remove(port)
188       config["busy_ports"] = busy_ports
189
190     # write config
191     logger.debug("write busy_ports: %s"%str(config["busy_ports"]))
192     try:
193       with open(config_file, 'w') as f:
194         pickle.dump(config, f)
195     except IOError:
196       pass
197
198     # release lock
199     fcntl.flock(lock, fcntl.LOCK_UN)
200
201     logger.debug("released port port: %s"%str(port))
202 #
203
204 def getBusyPorts():
205   config_file, lock_file = _getConfigurationFilename()
206   with open(lock_file, 'w') as lock:
207     # acquire lock
208     fcntl.flock(lock, fcntl.LOCK_EX)
209
210     # read config
211     config = {'busy_ports':[]}
212     logger.debug("read configuration file")
213     try:
214       with open(config_file, 'r') as f:
215         config = pickle.load(f)
216     except IOError: # empty file
217       pass
218
219     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
220
221     busy_ports = config["busy_ports"]
222     # release lock
223     fcntl.flock(lock, fcntl.LOCK_UN)
224
225     return busy_ports
226 #