Salome HOME
16345298c60071e73d064ac7d0b8fd05dd8be627
[modules/kernel.git] / bin / PortManager.py
1 #!/usr/bin/env python
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2015  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 #@UnusedImport
29 except:
30   import pickle #@Reimport
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 def __acquire_lock(lock):
48   if sys.platform == "win32":
49     import msvcrt
50     # lock 1 byte: file is supposed to be zero-byte long
51     msvcrt.locking(lock.fileno(), msvcrt.LK_LOCK, 1)
52   else:
53     import fcntl
54     fcntl.flock(lock, fcntl.LOCK_EX)
55 #
56 def __release_lock(lock):
57   if sys.platform == "win32":
58     import msvcrt
59     msvcrt.locking(lock.fileno(), msvcrt.LK_UNLCK, 1)
60   else:
61     import fcntl
62     fcntl.flock(lock, fcntl.LOCK_UN)
63 #
64
65 def _getConfigurationFilename():
66   omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
67
68   from salome_utils import generateFileName
69   portmanager_config = generateFileName(omniorbUserPath,
70                                         prefix="omniORB",
71                                         suffix="PortManager",
72                                         extension="cfg",
73                                         hidden=True)
74   import tempfile
75   temp = tempfile.NamedTemporaryFile()
76   lock_file = os.path.join(os.path.dirname(temp.name), ".omniORB_PortManager.lock")
77   temp.close()
78
79   return (portmanager_config, lock_file)
80 #
81
82 def __isPortUsed(port, busy_ports):
83   return (port in busy_ports) or __isNetworkConnectionActiveOnPort(port)
84 #
85
86 def __isNetworkConnectionActiveOnPort(port):
87   # :NOTE: Under windows:
88   #        netstat options -l and -t are unavailable
89   #        grep command is unavailable
90   from subprocess import Popen, PIPE
91   stdout, _ = Popen(['netstat','-an'], stdout=PIPE).communicate()
92   import StringIO
93   buf = StringIO.StringIO(stdout)
94   ports = buf.readlines()
95   # search for TCP - LISTEN connections
96   import re
97   regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE );
98   for item in ports:
99     try:
100       p = int(regObj.match(item).group(1))
101       if p == port: return True
102     except:
103       pass
104 #
105
106 def getPort(preferedPort=None):
107   logger.debug("GET PORT")
108
109   config_file, lock_file = _getConfigurationFilename()
110   oldmask = os.umask(0)
111   with open(lock_file, 'w') as lock:
112     # acquire lock
113     __acquire_lock(lock)
114
115     # read config
116     config = {'busy_ports':[]}
117     logger.debug("read configuration file")
118     try:
119       with open(config_file, 'r') as f:
120         config = pickle.load(f)
121     except:
122       print "Problem loading PortManager file: %s"%config_file
123       # In this case config dictionary is reset
124
125     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
126
127     # append port
128     busy_ports = config["busy_ports"]
129     port = preferedPort
130     if not port or __isPortUsed(port, busy_ports):
131       port = 2810
132       while __isPortUsed(port, busy_ports):
133         if port == 2810+100:
134           msg  = "\n"
135           msg += "Can't find a free port to launch omniNames\n"
136           msg += "Try to kill the running servers and then launch SALOME again.\n"
137           raise RuntimeError, msg
138         port = port + 1
139     logger.debug("found free port: %s"%str(port))
140     config["busy_ports"].append(port)
141
142     # write config
143     logger.debug("write busy_ports: %s"%str(config["busy_ports"]))
144     try:
145       with open(config_file, 'w') as f:
146         pickle.dump(config, f)
147     except IOError:
148       pass
149
150     # release lock
151     __release_lock(lock)
152   #
153
154   os.umask(oldmask)
155   logger.debug("get port: %s"%str(port))
156   return port
157 #
158
159 def releasePort(port):
160   port = int(port)
161   logger.debug("RELEASE PORT (%s)"%port)
162
163   config_file, lock_file = _getConfigurationFilename()
164   with open(lock_file, 'w') as lock:
165     # acquire lock
166     __acquire_lock(lock)
167
168     # read config
169     config = {'busy_ports':[]}
170     logger.debug("read configuration file")
171     try:
172       with open(config_file, 'r') as f:
173         config = pickle.load(f)
174     except IOError: # empty file
175       pass
176
177     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
178
179     # remove port from list
180     busy_ports = config["busy_ports"]
181
182     if port in busy_ports:
183       busy_ports.remove(port)
184       config["busy_ports"] = busy_ports
185
186     # write config
187     logger.debug("write busy_ports: %s"%str(config["busy_ports"]))
188     try:
189       with open(config_file, 'w') as f:
190         pickle.dump(config, f)
191     except IOError:
192       pass
193
194     # release lock
195     __release_lock(lock)
196
197     logger.debug("released port port: %s"%str(port))
198 #
199
200 def getBusyPorts():
201   config_file, lock_file = _getConfigurationFilename()
202   with open(lock_file, 'w') as lock:
203     # acquire lock
204     __acquire_lock(lock)
205
206     # read config
207     config = {'busy_ports':[]}
208     logger.debug("read configuration file")
209     try:
210       with open(config_file, 'r') as f:
211         config = pickle.load(f)
212     except IOError: # empty file
213       pass
214
215     logger.debug("load busy_ports: %s"%str(config["busy_ports"]))
216
217     busy_ports = config["busy_ports"]
218     # release lock
219     __release_lock(lock)
220
221     return busy_ports
222 #