Salome HOME
Updated copyright comment
[modules/kernel.git] / src / Launcher / SALOME_ExternalServerLauncher.cxx
1 // Copyright (C) 2019-2024  CEA, EDF, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony GEAY (EDF R&D)
20
21 #include "SALOME_ExternalServerLauncher.hxx"
22 #include "SALOME_ExternalServerHandler.hxx"
23 #include "SALOME_NamingService.hxx"
24 #include "SALOME_LauncherException.hxx"
25 #include "SALOME_ContainerManager.hxx"
26 #include "SALOME_CPythonHelper.hxx"
27
28 #include CORBA_CLIENT_HEADER(SALOME_ExternalServerLauncher)
29
30 #ifndef WIN32
31 #include <unistd.h>
32 #else
33 #include <windows.h>
34 #include <Basics_Utils.hxx>
35 #endif
36
37 #include <sstream>
38 #include <fstream>
39 #include <algorithm>
40 #include <memory>
41 #include <functional>
42
43 const char SALOME_ExternalServerLauncher::NAME_IN_NS[]="/ExternalServers";
44
45 unsigned SALOME_ExternalServerLauncher::CNT = 0;
46
47 SALOME_ExternalServerLauncher::SALOME_ExternalServerLauncher(const SALOME_CPythonHelper *pyHelper, CORBA::ORB_ptr orb, PortableServer::POA_var poa,SALOME_NamingService_Abstract *ns):_pyHelper(pyHelper),_poa(poa)
48 {
49   _NS = ns == nullptr ? new SALOME_NamingService(orb) : ns;
50   PortableServer::ObjectId_var id(_poa->activate_object(this));
51   CORBA::Object_var obj(_poa->id_to_reference(id));
52   SALOME::ExternalServerLauncher_var refPtr(SALOME::ExternalServerLauncher::_narrow(obj));
53   _NS->Register(refPtr,NAME_IN_NS);
54 }
55
56 SALOME_ExternalServerLauncher::~SALOME_ExternalServerLauncher()
57 {
58   delete _NS;
59 }
60
61 class ChdirRAII
62 {
63 public:
64 #ifndef WIN32
65   ChdirRAII(const std::string& wd):_wd(wd) { if(_wd.empty()) return ; char *pwd(get_current_dir_name()); _od = pwd; free(pwd); chdir(_wd.c_str()); }
66   ~ChdirRAII() { if(_od.empty()) return ; chdir(_od.c_str()); }
67 #else
68         ChdirRAII(const std::string& wd) : _wd(wd) { 
69                 if (_wd.empty()) 
70                         return;
71                 TCHAR pwd[MAX_PATH];
72                 GetCurrentDirectory(sizeof(pwd), pwd);
73                 _od = Kernel_Utils::utf8_encode_s(pwd);
74                 SetCurrentDirectory(Kernel_Utils::utf8_decode_s(_wd).c_str());
75         }
76         ~ChdirRAII() { 
77                 if (_od.empty()) return; 
78                 SetCurrentDirectory(Kernel_Utils::utf8_decode_s(_od).c_str());
79         }
80 #endif  
81 private:
82   std::string _wd;
83   std::string _od;
84 };
85
86 SALOME::ExternalServerHandler_ptr SALOME_ExternalServerLauncher::launchServer(const char *server_name, const char *working_dir, const SALOME::CmdList& command_list )
87 {
88   std::vector<std::string> servers(ListOfExternalServersCpp(_NS));
89   if(std::find(servers.begin(),servers.end(),server_name)!=servers.end())
90     {
91       std::ostringstream oss2; oss2 << "SALOME_ExternalServerLauncher::launchServer : Server \""<< server_name << "\" already exists !";
92       throw SALOME_LauncherException(oss2.str());
93     }
94   std::vector<std::string> cmd(command_list.length());
95   for(size_t i=0;i<command_list.length();i++)
96     cmd[i] = command_list[i];
97   long pid(0);
98   try
99     {
100       ChdirRAII cr(working_dir);
101       pid = SALOME_ContainerManager::SystemWithPIDThreadSafe(cmd) ;
102     }
103   catch(SALOME_Exception& e)
104     {
105       std::ostringstream oss2; oss2 << "SALOME_ExternalServerLauncher::launchServer : Fail to launch subprocess ! Reason is : " << e.what() << " !";
106       throw SALOME_LauncherException(oss2.str());
107     }
108   SALOME_ExternalServerHandler *retServ(new SALOME_ExternalServerHandler(this,server_name,_NS,pid));
109   retServ->registerToKill(_pyHelper);
110   PortableServer::ObjectId_var id(_poa->activate_object(retServ));
111   CORBA::Object_var obj(_poa->id_to_reference(id));
112   std::string fullServerName(CreateAbsNameInNSFromServerName(server_name));
113   SALOME::ExternalServerHandler_ptr ret(SALOME::ExternalServerHandler::_narrow(obj));
114   _NS->Register(ret,fullServerName.c_str());
115   return ret;
116 }
117
118 void SALOME_ExternalServerLauncher::registerToKill(const char *server_name, CORBA::Long PID)
119 {
120   std::ostringstream oss;
121   oss << "Custom_"<< server_name << "_" << CNT++;
122   _pyHelper->registerToSalomePiDict(oss.str(),PID);
123   _list_of_pids_to_kill.push_back(PID);
124 }
125
126 void SALOME_ExternalServerLauncher::cleanServersInNS()
127 {
128   std::vector<std::string> servers(ListOfExternalServersCpp(_NS));
129   for(std::vector<std::string>::const_iterator it=servers.begin();it!=servers.end();it++)
130     {
131       if(!IsAliveAndKicking(_NS,(*it).c_str()))
132         {
133           std::string fullServerName(CreateAbsNameInNSFromServerName(*it));
134           _NS->Destroy_Name(fullServerName.c_str());
135         }
136     }
137 }
138
139 void SALOME_ExternalServerLauncher::shutdownServers()
140 {
141   for(auto pid : this->_list_of_pids_to_kill)
142     {
143       SALOME_ExternalServerHandler::KillPID(pid);
144     }
145   //
146   std::vector<std::string> lioes(ListOfExternalServersCpp(_NS));
147   for(auto servName : lioes)
148     {
149       SALOME::ExternalServerHandler_var proc(GetServerHandlerGivenName(_NS,servName));
150       PortableServer::ServantBase *procServ(_poa->reference_to_servant(proc));
151       SALOME_ExternalServerHandler *procServC(dynamic_cast<SALOME_ExternalServerHandler *>(procServ));
152       try
153         {
154           procServC->killMe();
155         }
156       catch(...)
157         { }
158     }
159   cleanServersInNS();
160 }
161
162 SALOME::StringVec *SALOME_ExternalServerLauncher::listServersInNS()
163 {
164   SALOME::StringVec *ret(new SALOME::StringVec);
165   std::vector<std::string> loes(ListOfExternalServersCpp(_NS));
166   std::size_t sz(loes.size());
167   ret->length(sz);
168   for(size_t i=0; i<sz; i++)
169     {
170       (*ret)[i]=CORBA::string_dup(loes[i].c_str());
171     }
172   return ret;
173 }
174
175 SALOME::ExternalServerHandler_ptr SALOME_ExternalServerLauncher::retrieveServerRefGivenNSEntry( const char *ns_entry )
176 {
177   SALOME::ExternalServerHandler_var ret(GetServerHandlerGivenName(_NS,ns_entry));
178   return ret._retn();
179 }
180
181 char *SALOME_ExternalServerLauncher::gethostname()
182 {
183   std::string ret(_pyHelper->evalS("socket.gethostname()"));
184   return CORBA::string_dup(ret.c_str());
185 }
186
187 SALOME::ByteVec *SALOME_ExternalServerLauncher::fetchContentOfFileAndRm(const char *file_name)
188 {
189   std::ifstream t(file_name);
190   if(!t.good())
191     {
192       std::ostringstream oss; oss << "SALOME_ExternalServerLauncher::fetchContentOfFileAndRm : Error when trying to open \"" <<  file_name << "\" file !";
193       throw SALOME_LauncherException(oss.str());
194     }
195   t.seekg(0, std::ios::end);
196   size_t size(t.tellg());
197   std::unique_ptr<char,std::function<void(char *)> > buffer(new char[size],[](char *pt) { delete [] pt; });
198   t.seekg(0);
199   t.read(buffer.get(),size);
200   //
201   std::unique_ptr<SALOME::ByteVec> ret(new SALOME::ByteVec);
202   ret->length(size);
203   for(size_t i=0;i<size;++i)
204     (*ret)[i] = buffer.get()[i];
205   //
206   if( unlink(file_name)!=0 )
207     {
208       std::cerr << "Error when trying to remove \"" << file_name << "\" !";
209     }
210   //
211   return ret.release();
212 }
213
214 std::vector<std::string> SALOME_ExternalServerLauncher::ListOfExternalServersCpp(SALOME_NamingService_Abstract *ns)
215 {
216   ns->Change_Directory(NAME_IN_NS);
217   std::vector<std::string> ret(ns->list_directory());
218   return ret;
219 }
220
221 std::string SALOME_ExternalServerLauncher::CreateAbsNameInNSFromServerName(const std::string& scopeName)
222 {
223   std::ostringstream oss; oss << NAME_IN_NS << "/" << scopeName;
224   return oss.str();
225 }
226
227 bool SALOME_ExternalServerLauncher::IsAliveAndKicking(SALOME::ExternalServerHandler_ptr server)
228 {
229   bool ret(true);
230   try
231     {
232       server->ping();
233     }
234   catch(...)
235     { ret=false; }
236   return ret;
237 }
238
239 bool SALOME_ExternalServerLauncher::IsAliveAndKicking(SALOME_NamingService_Abstract *ns, const std::string& serverName)
240 {
241   SALOME::ExternalServerHandler_var pt(GetServerHandlerGivenName(ns, serverName));
242   if( CORBA::is_nil(pt) )
243     return false;
244   return IsAliveAndKicking(pt);
245 }
246
247 SALOME::ExternalServerHandler_var SALOME_ExternalServerLauncher::GetServerHandlerGivenName(SALOME_NamingService_Abstract *ns, const std::string& serverName)
248 {
249   std::vector<std::string> serverNames(ListOfExternalServersCpp(ns));
250   if(std::find(serverNames.begin(),serverNames.end(),serverName)==serverNames.end())
251     {
252       std::ostringstream oss; oss << "SALOME_ExternalServerLauncher::GetServerHandlerGivenName : scope name \"" << serverName << "\" does not exist !";
253       throw SALOME_LauncherException(oss.str());
254     }
255   std::string fullServerName(CreateAbsNameInNSFromServerName(serverName));
256   CORBA::Object_var obj(ns->Resolve(fullServerName.c_str()));
257   SALOME::ExternalServerHandler_var ret(SALOME::ExternalServerHandler::_narrow(obj));
258   return ret;
259 }