Salome HOME
Compilation on Windows.
[modules/kernel.git] / src / Launcher / SALOME_ExternalServerLauncher.cxx
1 // Copyright (C) 2019  CEA/DEN, EDF R&D, 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 constexpr char 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):_pyHelper(pyHelper),_poa(poa)
48 {
49   _NS = new SALOME_NamingService(orb);
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   const char *toto(command_list[0]);
96   for(auto i=0;i<command_list.length();i++)
97     cmd[i] = command_list[i];
98   long pid(0);
99   try
100     {
101       ChdirRAII cr(working_dir);
102       pid = SALOME_ContainerManager::SystemWithPIDThreadSafe(cmd) ;
103     }
104   catch(SALOME_Exception& e)
105     {
106       std::ostringstream oss2; oss2 << "SALOME_ExternalServerLauncher::launchServer : Fail to launch subprocess ! Reason is : " << e.what() << " !";
107       throw SALOME_LauncherException(oss2.str());
108     }
109   SALOME_ExternalServerHandler *retServ(new SALOME_ExternalServerHandler(this,server_name,_NS,pid));
110   retServ->registerToKill(_pyHelper);
111   PortableServer::ObjectId_var id(_poa->activate_object(retServ));
112   CORBA::Object_var obj(_poa->id_to_reference(id));
113   std::string fullServerName(CreateAbsNameInNSFromServerName(server_name));
114   SALOME::ExternalServerHandler_ptr ret(SALOME::ExternalServerHandler::_narrow(obj));
115   _NS->Register(ret,fullServerName.c_str());
116   return ret;
117 }
118
119 void SALOME_ExternalServerLauncher::registerToKill(const char *server_name, CORBA::Long PID)
120 {
121   std::ostringstream oss;
122   oss << "Custom_"<< server_name << "_" << CNT++;
123   _pyHelper->registerToSalomePiDict(oss.str(),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   std::vector<std::string> lioes(ListOfExternalServersCpp(_NS));
142   for(auto servName : lioes)
143     {
144       SALOME::ExternalServerHandler_var proc(GetServerHandlerGivenName(_NS,servName));
145       PortableServer::ServantBase *procServ(_poa->reference_to_servant(proc));
146       SALOME_ExternalServerHandler *procServC(dynamic_cast<SALOME_ExternalServerHandler *>(procServ));
147       try
148         {
149           procServC->killMe();
150         }
151       catch(...)
152         { }
153     }
154   cleanServersInNS();
155 }
156
157 SALOME::StringVec *SALOME_ExternalServerLauncher::listServersInNS()
158 {
159   SALOME::StringVec *ret(new SALOME::StringVec);
160   std::vector<std::string> loes(ListOfExternalServersCpp(_NS));
161   std::size_t sz(loes.size());
162   ret->length(sz);
163   for(auto i = 0; i<sz ; i++)
164     {
165       (*ret)[i]=CORBA::string_dup(loes[i].c_str());
166     }
167   return ret;
168 }
169
170 SALOME::ExternalServerHandler_ptr SALOME_ExternalServerLauncher::retrieveServerRefGivenNSEntry( const char *ns_entry )
171 {
172   SALOME::ExternalServerHandler_var ret(GetServerHandlerGivenName(_NS,ns_entry));
173   return ret._retn();
174 }
175
176 char *SALOME_ExternalServerLauncher::gethostname()
177 {
178   std::string ret(_pyHelper->evalS("socket.gethostname()"));
179   return CORBA::string_dup(ret.c_str());
180 }
181
182 SALOME::ByteVec *SALOME_ExternalServerLauncher::fetchContentOfFileAndRm(const char *file_name)
183 {
184   std::ifstream t(file_name);
185   if(!t.good())
186     {
187       std::ostringstream oss; oss << "SALOME_ExternalServerLauncher::fetchContentOfFileAndRm : Error when trying to open \"" <<  file_name << "\" file !";
188       throw SALOME_LauncherException(oss.str());
189     }
190   t.seekg(0, std::ios::end);
191   size_t size(t.tellg());
192   std::unique_ptr<char,std::function<void(char *)> > buffer(new char[size],[](char *pt) { delete [] pt; });
193   t.seekg(0);
194   t.read(buffer.get(),size);
195   //
196   std::unique_ptr<SALOME::ByteVec> ret(new SALOME::ByteVec);
197   ret->length(size);
198   for(std::size_t i=0;i<size;++i)
199     (*ret)[i] = buffer.get()[i];
200   //
201   if( unlink(file_name)!=0 )
202     {
203       std::cerr << "Error when trying to remove \"" << file_name << "\" !";
204     }
205   //
206   return ret.release();
207 }
208
209 std::vector<std::string> SALOME_ExternalServerLauncher::ListOfExternalServersCpp(SALOME_NamingService *ns)
210 {
211   ns->Change_Directory(NAME_IN_NS);
212   std::vector<std::string> ret(ns->list_directory());
213   return ret;
214 }
215
216 std::string SALOME_ExternalServerLauncher::CreateAbsNameInNSFromServerName(const std::string& scopeName)
217 {
218   std::ostringstream oss; oss << NAME_IN_NS << "/" << scopeName;
219   return oss.str();
220 }
221
222 bool SALOME_ExternalServerLauncher::IsAliveAndKicking(SALOME::ExternalServerHandler_ptr server)
223 {
224   bool ret(true);
225   try
226     {
227       server->ping();
228     }
229   catch(...)
230     { ret=false; }
231   return ret;
232 }
233
234 bool SALOME_ExternalServerLauncher::IsAliveAndKicking(SALOME_NamingService *ns, const std::string& serverName)
235 {
236   SALOME::ExternalServerHandler_var pt(GetServerHandlerGivenName(ns, serverName));
237   if( CORBA::is_nil(pt) )
238     return false;
239   return IsAliveAndKicking(pt);
240 }
241
242 SALOME::ExternalServerHandler_var SALOME_ExternalServerLauncher::GetServerHandlerGivenName(SALOME_NamingService *ns, const std::string& serverName)
243 {
244   std::vector<std::string> serverNames(ListOfExternalServersCpp(ns));
245   if(std::find(serverNames.begin(),serverNames.end(),serverName)==serverNames.end())
246     {
247       std::ostringstream oss; oss << "SALOME_ExternalServerLauncher::GetServerHandlerGivenName : scope name \"" << serverName << "\" does not exist !";
248       throw SALOME_LauncherException(oss.str());
249     }
250   std::string fullServerName(CreateAbsNameInNSFromServerName(serverName));
251   CORBA::Object_var obj(ns->Resolve(fullServerName.c_str()));
252   SALOME::ExternalServerHandler_var ret(SALOME::ExternalServerHandler::_narrow(obj));
253   return ret;
254 }