Salome HOME
412fb0b5d9dbf0dafddb85db66891b83a1926eab
[modules/smesh.git] / src / SMESHUtils / SMESH_MGLicenseKeyGen.cxx
1 // Copyright (C) 2007-2022  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 // File      : SMESHUtils_MGLicenseKeyGen.cxx
20 // Created   : Sat Jul 31 18:54:16 2021
21 // Author    : Edward AGAPOV (OCC)
22
23 #include "SMESH_MGLicenseKeyGen.hxx"
24
25 #include "SMESH_Comment.hxx"
26 #include "SMESH_File.hxx"
27 #include "SMESH_TryCatch.hxx"
28
29 #include <Basics_DirUtils.hxx>
30 #include <Basics_Utils.hxx>
31
32 #include <cstdlib> // getenv, system
33
34 #include <boost/filesystem.hpp>
35 #include <boost/regex.hpp>
36 namespace boofs = boost::filesystem;
37
38 #ifdef WIN32
39
40 #  include <windows.h>
41 #  include <process.h>
42
43 #  define LibHandle HMODULE
44 #  define LoadLib( name ) LoadLibrary( name )
45 #  define GetProc GetProcAddress
46 #  define UnLoadLib( handle ) FreeLibrary( handle );
47
48 #else // WIN32
49
50 #  include <dlfcn.h>
51
52 #  define LibHandle void*
53 #  define LoadLib( name ) dlopen( name, RTLD_LAZY | RTLD_LOCAL )
54 #  define GetProc dlsym
55 #  define UnLoadLib( handle ) dlclose( handle );
56
57 #endif // WIN32
58
59 // to retrieve description of exception caught by SMESH_TRY
60 #undef SMESH_CAUGHT
61 #define SMESH_CAUGHT error =
62
63 constexpr char MESHGEMS_OLD_STYLE[] = "MESHGEMS_OLD_STYLE";
64 constexpr char SPATIAL_LICENSE[] = "SPATIAL_LICENSE";
65
66
67 namespace
68 {
69   static LibHandle theLibraryHandle = nullptr; //!< handle of a loaded library
70
71   const char* theEnvVar = "SALOME_MG_KEYGEN_LIB_PATH"; /* var specifies either full file name
72                                                           of libSalomeMeshGemsKeyGenerator or
73                                                           URL to download the library from */
74
75   const char* theTmpEnvVar = "SALOME_TMP_DIR"; // directory to download the library to
76
77   //-----------------------------------------------------------------------------------
78   /*!
79    * \brief Remove library file at destruction in case if it was downloaded from server
80    */
81   //-----------------------------------------------------------------------------------
82
83   struct LibraryFile
84   {
85     std::string _name; // full file name
86     bool        _isURL;
87
88     LibraryFile(): _isURL( false ) {}
89
90     ~LibraryFile()
91     {
92       if ( _isURL )
93       {
94         if ( theLibraryHandle )
95         {
96           UnLoadLib( theLibraryHandle );
97           theLibraryHandle = nullptr;
98         }
99
100         std::string tmpDir; // tmp dir that should not be removed
101         if ( const char* libPath = getenv( theTmpEnvVar ))
102         {
103           tmpDir = libPath;
104           while (( !tmpDir.empty() ) &&
105                  ( tmpDir.back() == '/' || tmpDir.back() == '\\' ))
106             tmpDir.pop_back();
107         }
108
109         while ( SMESH_File( _name ).remove() )
110         {
111           size_t length = _name.size();
112           _name = boofs::path( _name ).parent_path().string(); // goto parent directory
113           if ( _name.size() == length )
114             break; // no more parents
115
116           if ( _name == tmpDir )
117             break; // don't remove tmp dir
118
119           if ( !Kernel_Utils::IsEmptyDir( _name ))
120             break;
121         }
122       }
123     }
124   };
125
126
127   //================================================================================
128   /*!
129    * \brief Retrieve description of the last error
130    *  \param [out] error - return the description
131    *  \return bool - true if the description found
132    */
133   //================================================================================
134
135   bool getLastError( std::string& error )
136   {
137 #ifndef WIN32
138
139     if ( const char* text = dlerror() )
140     {
141       error = text;
142       return true;
143     }
144     return false;
145
146 #else
147
148     DWORD dw = GetLastError();
149     void* cstr;
150     DWORD msgLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
151                                  NULL,
152                                  dw,
153                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
154                                  (LPTSTR) &cstr,
155                                  0,
156                                  NULL
157                                  );
158     if ( msgLen > 0 ) {
159 #  if defined( UNICODE )
160       error = Kernel_Utils::encode_s((wchar_t*)cstr);
161 #  else
162       error = (char*)cstr;
163 #  endif
164       LocalFree(cstr);
165     }
166
167     return (bool)msgLen;
168
169 #endif
170   }
171
172   //================================================================================
173   /*!
174    * \brief Adjust file extension according to the platform
175    */
176   //================================================================================
177
178   bool setExtension( std::string& fileName, std::string& error )
179   {
180     if ( fileName.empty() )
181     {
182       error = "Library file name is empty";
183       return false;
184     }
185 #if defined(WIN32)
186     std::string ext = ".dll";
187 #elif defined(__APPLE__)
188     std::string ext = ".dylib";
189 #else
190     std::string ext = ".so";
191 #endif
192
193     fileName = fileName.substr( 0, fileName.find_last_of('.')) + ext;
194     return true;
195   }
196
197   //================================================================================
198   /*!
199    * \brief Check if library file name looks like an URL
200    *  \param [in,out] libraryFile - holds file name and returns result in _isURL member field
201    *  \return bool - true if the file name looks like an URL
202    */
203   //================================================================================
204
205   bool isURL( LibraryFile & libraryFile )
206   {
207     {// round1
208       enum { SCHEME = 2, AUTHORITY = 4, PATH = 5 }; // sub-strings
209       boost::regex urlRegex ( R"(^(([^:\/?#]+):)?(//([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?)",
210                               boost::regex::extended );
211       boost::smatch matchResult;
212
213       libraryFile._isURL = false;
214       if ( boost::regex_match( libraryFile._name, matchResult, urlRegex ))
215         libraryFile._isURL = ( !matchResult.str( SCHEME    ).empty() &&
216                               !matchResult.str( AUTHORITY ).empty() &&
217                               !matchResult.str( PATH      ).empty() );
218     }
219     if(libraryFile._isURL)
220       return true;
221     {// round2
222       enum { HOST = 2, PORT = 3, PATH = 4 }; // sub-strings
223       boost::regex urlRegex ( R"(^(([^:\/?#]+):)?([^/]+)?(/[^#]*))",
224                               boost::regex::extended );
225       boost::smatch matchResult;
226
227       libraryFile._isURL = false;
228       if ( boost::regex_match( libraryFile._name, matchResult, urlRegex ))
229         libraryFile._isURL = ( !matchResult.str( HOST ).empty() &&
230                               !matchResult.str( PORT ).empty() &&
231                               !matchResult.str( PATH ).empty() );
232     }
233     return libraryFile._isURL;
234   }
235
236   //================================================================================
237   /*!
238    * \brief Download libraryFile._name URL to SALOME_TMP_DIR
239    *  \param [in,out] libraryFile - holds the URL and returns name of a downloaded file
240    *  \param [out] error - return error description
241    *  \return bool - is a success
242    */
243   //================================================================================
244
245   bool downloadLib( LibraryFile& libraryFile, std::string & error )
246   {
247     // check if can write into SALOME_TMP_DIR
248
249     std::string tmpDir = Kernel_Utils::GetTmpDirByEnv( theTmpEnvVar );
250     if ( tmpDir.empty() ||
251          !Kernel_Utils::IsExists( tmpDir ))
252     {
253       error = "Can't download " + libraryFile._name + " as SALOME_TMP_DIR is not correctly set";
254       return false;
255     }
256     if ( !Kernel_Utils::IsWritable( tmpDir ))
257     {
258       error = "Can't download " + libraryFile._name + " as '" + tmpDir + "' is not writable. "
259         "Check SALOME_TMP_DIR environment variable";
260       return false;
261     }
262
263     // Download
264
265     std::string url = libraryFile._name;
266
267 #ifdef WIN32
268
269     std::string outFile = tmpDir + "MeshGemsKeyGenerator.dll";
270
271     // use wget (== Invoke-WebRequest) PowerShell command available since Windows 7
272     std::string psCmd = "wget -Uri " + url + " -OutFile " + outFile;
273     std::string   cmd = "powershell.exe " + psCmd;
274
275 #else
276
277     std::string outFile = tmpDir + "libMeshGemsKeyGenerator.so";
278
279     std::string cmd = "smesh_wget.py " + url + " -O " + outFile;
280
281 #endif
282
283     if ( Kernel_Utils::IsExists( outFile )) // remove existing file
284     {
285       SMESH_File lib( outFile, /*open=*/false );
286       if ( !lib.remove() )
287       {
288         error = lib.error();
289         return false;
290       }
291     }
292
293 #ifndef WIN32
294     //[EDF25906]
295     std::string redirect = tmpDir + "redirect.out";
296     std::ostringstream oss;
297     oss << cmd << " " << redirect;
298     cmd = oss.str();
299 #endif
300
301     system( cmd.c_str() ); // download
302
303 #ifndef WIN32
304     {//[EDF25906]
305       std::ifstream infile(redirect);
306       infile.seekg(0, std::ios::end);
307       size_t length = infile.tellg();
308       infile.seekg(0, std::ios::beg);
309       std::unique_ptr<char []> buffer(new char[length+1]);
310       buffer[length] = '\0';
311       infile.read(const_cast<char *>( buffer.get() ),length);
312
313       MESSAGE( buffer.get() );
314     }
315     {
316       SMESH_File redirectFile( redirect, /*open=*/false );
317       redirectFile.remove();
318     }
319 #endif
320
321     SMESH_File resultFile( outFile, /*open=*/false );
322     bool ok = ( resultFile.exists() && resultFile.size() > 0 );
323
324     if ( ok )
325       libraryFile._name = outFile;
326     else
327       error = "Can't download file " + url;
328
329     return ok;
330   }
331
332   //================================================================================
333   /*!
334    * \brief Load libMeshGemsKeyGenerator.so
335    *  \param [out] error - return error description
336    *  \param [out] libraryFile - return library file name and _isURL flag
337    *  \return bool - is a success
338    */
339   //================================================================================
340
341   bool loadLibrary( std::string& error, LibraryFile& libraryFile )
342   {
343     if ( theLibraryHandle )
344       return true;
345
346     const char* libPath = getenv( theEnvVar );
347     if ( !libPath )
348     {
349       error = SMESH_Comment( "Environment variable ") <<  theEnvVar << " is not set";
350       return false;
351     }
352
353     libraryFile._name = libPath;
354     // if ( !setExtension( libraryFile._name, error )) // is it necessary?
355     //   return false;
356
357     if ( isURL( libraryFile ))
358     {
359       if ( !downloadLib( libraryFile, error ))
360       {
361         // try to fix extension
362         std::string url = libraryFile._name;
363         if ( !setExtension( libraryFile._name, error ))
364           return false;
365         if ( url == libraryFile._name )
366           return false; // extension not changed
367
368         if ( !downloadLib( libraryFile, error ))
369           return false;
370       }
371     }
372
373 #if defined( WIN32 ) && defined( UNICODE )
374     std::wstring encodePath = Kernel_Utils::utf8_decode_s( libraryFile._name );
375     const wchar_t*     path = encodePath.c_str();
376 #else
377     const char*        path = libraryFile._name.c_str();
378 #endif
379
380     theLibraryHandle = LoadLib( path );
381     if ( !theLibraryHandle )
382     {
383       if ( ! getLastError( error ))
384         error = "Can't load library '" + libraryFile._name + "'";
385     }
386
387     return theLibraryHandle;
388   }
389
390 } // anonymous namespace
391
392
393 namespace SMESHUtils_MGLicenseKeyGen // API implementation
394 {
395   //================================================================================
396   /*!
397    * \brief Sign a CAD
398    *  \param [in] meshgems_cad - pointer to a MG CAD object (meshgems_cad_t)
399    *  \param [out] error - return error description
400    *  \return bool - is a success
401    */
402   //================================================================================
403
404   bool SignCAD_After( void* meshgems_cad, std::string& error )
405   {
406     LibraryFile libraryFile;
407     if ( !loadLibrary( error, libraryFile ))
408       return false;
409
410     bool ok = false;
411     typedef bool (*SignFun)(void* );
412     SignFun signFun = (SignFun) GetProc( theLibraryHandle, "SignCAD" );
413     if ( !signFun )
414     {
415       if ( ! getLastError( error ))
416         error = SMESH_Comment( "Can't find symbol 'SignCAD' in '") << getenv( theEnvVar ) << "'";
417     }
418     else
419     {
420       SMESH_TRY;
421
422       ok = signFun( meshgems_cad );
423
424       SMESH_CATCH( SMESH::returnError );
425
426       if ( !error.empty() )
427         ok = false;
428       else if ( !ok )
429         error = "SignCAD() failed (located in '" + libraryFile._name + "')";
430     }
431     return ok;
432   }
433
434   //================================================================================
435   /*!
436    * \brief Unlock a specific MeshGems product (for products called as a library)
437    *  \param [in] product - product of MeshGems to unlock
438    *  \param [out] error - return error description
439    *  \return bool - is a success
440    */
441   //================================================================================
442   bool UnlockProduct( const std::string& product, std::string& error )
443   {
444     MESSAGE("SMESH UnlockProduct: " << product);
445     LibraryFile libraryFile;
446     if ( !loadLibrary( error, libraryFile ))
447       return false;
448
449     bool ok = false;
450     // get the key from KeyGen
451     std::string key = SMESHUtils_MGLicenseKeyGen::GetKey(error);
452     typedef int (*SignFun)(const char* );
453
454     // specific function to unlock each product
455     std::string function = "meshgems_" + product + "_unlock_product";
456
457     SignFun signFun = (SignFun) GetProc( theLibraryHandle, function.c_str() );
458     if ( !signFun )
459     {
460       if ( ! getLastError( error ))
461         error = SMESH_Comment( "Can't find symbol '") << function << "' in '" << getenv( theEnvVar ) << "'";
462     }
463     else
464     {
465       SMESH_TRY;
466
467       int status = signFun( key.c_str() );
468       // MeshGems status: 0: OK, 1: warning, -1: error
469       ok = status >= 0;
470
471       SMESH_CATCH( SMESH::returnError );
472
473       if ( !error.empty() )
474         {
475           ok = false;
476         }
477       else if ( !ok )
478         error = "UnlockProduct() failed (located in '" + libraryFile._name + "')";
479     }
480     return ok;
481   }
482   
483   //================================================================================
484   /*!
485    * \brief Sign a CAD (or don't do it if env MESHGEMS_OLD_STYLE is set)
486    *  \param [in] meshgems_cad - pointer to a MG CAD object (meshgems_cad_t)
487    *  \param [out] error - return error description
488    *  \return bool - is a success
489    */
490   //================================================================================
491   bool SignCAD( void* meshgems_cad, std::string& error )
492   {
493     const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
494     if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 )
495       {
496         if (NeedsMGSpatialEnvLicense(error))
497           // SignCAD is only called by cadsurf. Other components call SignMesh
498           return UnlockProduct("cadsurf", error);
499         else
500           return SignCAD_After(meshgems_cad, error);
501       }
502     else
503       return true;
504   }
505
506   //================================================================================
507   /*!
508    * \brief Sign a mesh
509    *  \param [in] meshgems_mesh - pointer to a MG mesh (meshgems_mesh_t)
510    *  \param [out] error - return error description
511    *  \return bool - is a success
512    */
513   //================================================================================
514
515   bool SignMesh_After( void* meshgems_mesh, std::string& error )
516   {
517     LibraryFile libraryFile;
518     if ( !loadLibrary( error, libraryFile ))
519       return false;
520
521     bool ok = false;
522     typedef bool (*SignFun)(void* );
523     SignFun signFun = (SignFun) GetProc( theLibraryHandle, "SignMesh" );
524     if ( !signFun )
525     {
526       if ( ! getLastError( error ))
527         error = SMESH_Comment( "Can't find symbol 'SignMesh' in '") << getenv( theEnvVar ) << "'";
528     }
529     else
530     {
531       SMESH_TRY;
532
533       ok = signFun( meshgems_mesh );
534
535       SMESH_CATCH( SMESH::returnError );
536
537       if ( !error.empty() )
538         ok = false;
539       else if ( !ok )
540         error = "SignMesh() failed (located in '" + libraryFile._name + "')";
541     }
542     return ok;
543   }
544   
545   //================================================================================
546   /*!
547    * \brief Sign a mesh (or don't do it if env MESHGEMS_OLD_STYLE is set)
548    *  \param [in] meshgems_mesh - pointer to a MG mesh (meshgems_mesh_t)
549    *  \param [in] product - product of MeshGems to unlock
550    *  \param [out] error - return error description
551    *  \return bool - is a success
552    */
553   //================================================================================
554   bool SignMesh( void* meshgems_mesh, const std::string& product, std::string& error )
555   {
556     const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
557     if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 )
558       {
559         if (NeedsMGSpatialEnvLicense(error))
560           // unlock product (MG 2.15)
561           return UnlockProduct(product, error);
562         else
563           // sign the mesh (MG 2.13 and 2.14)
564           return SignMesh_After(meshgems_mesh, error);
565       }
566     else
567       // use DLIM8 server (nothing to do here)
568       return true;
569   }
570
571   //================================================================================
572   /*!
573    * \brief Return a license key to pass as argument to a MG mesher executable
574    *  \param [in] gmfFile - path to an input mesh file
575    *  \param [in] nb* - nb of entities in the input mesh
576    *  \param [out] error - return error description
577    *  \return std::string - the key
578    */
579   //================================================================================
580
581   std::string GetKey_After(const std::string& gmfFile,
582                             int                nbVertex,
583                             int                nbEdge,
584                             int                nbFace,
585                             int                nbVol,
586                             std::string&       error)
587   {
588     std::string key;
589     LibraryFile libraryFile;
590     if ( !loadLibrary( error, libraryFile ))
591       return key;
592
593     typedef std::string (*GetKeyFun)(std::string const &, int, int, int, int );
594     GetKeyFun keyFun = (GetKeyFun) GetProc( theLibraryHandle, "GetKey" );
595     if ( !keyFun )
596     {
597       if ( ! getLastError( error ))
598         error = SMESH_Comment( "Can't find symbol 'GetKey' in '") << getenv( theEnvVar ) << "'";
599     }
600     else
601     {
602       key = keyFun( gmfFile, nbVertex, nbEdge, nbFace, nbVol );
603     }
604     if ( key.empty() )
605       error = "GetKey() failed (located in '" + libraryFile._name + "')";
606
607     return key;
608   }
609
610   //================================================================================
611   /*!
612    * \brief Return a license key to pass as argument to a MG mesher executable (>2.15)
613    *  \param [out] error - return error description
614    *  \return std::string - the key
615    */
616   //================================================================================
617
618   std::string GetKey_After(std::string&       error)
619   {
620     std::string key;
621     LibraryFile libraryFile;
622     if ( !loadLibrary( error, libraryFile ))
623       return key;
624
625     typedef std::string (*GetKeyFun)();
626     GetKeyFun keyFun = (GetKeyFun) GetProc( theLibraryHandle, "GetKey" );
627     if ( !keyFun )
628     {
629       if ( ! getLastError( error ))
630         error = SMESH_Comment( "Can't find symbol 'GetKey' in '") << getenv( theEnvVar ) << "'";
631     }
632     else
633     {
634       key = keyFun( );
635     }
636     if ( key.empty() )
637       error = "GetKey() failed (located in '" + libraryFile._name + "')";
638
639     return key;
640   }
641
642
643   //================================================================================
644   /*!
645    * \brief Get MeshGems version from the keygen library and meshgems built-in functions
646    *  \param [out] error - return error description
647    *  \return int - the version
648    */
649   //================================================================================
650   int GetMGVersionHex(std::string&       error)
651   {
652     // get minor version
653     int v_min = -1;
654     LibraryFile libraryFile;
655     if ( !loadLibrary( error, libraryFile ))
656       return v_min;
657
658     typedef int (*GetKeyFun)();
659     GetKeyFun keyFun = (GetKeyFun) GetProc( theLibraryHandle, "meshgems_core_get_version_minor" );
660     if ( !keyFun )
661     {
662       if ( ! getLastError( error ))
663         error = SMESH_Comment( "Can't find symbol 'meshgems_core_get_version_minor' in '") << getenv( theEnvVar ) << "'";
664     }
665     else
666     {
667         v_min = keyFun( );
668     }
669     if ( v_min==-1 )
670       error = "meshgems_core_get_version_minor() failed (located in '" + libraryFile._name + "')";
671
672     MESSAGE("meshgems_core_get_version_minor: " << v_min);
673
674     // get major version
675     int v_maj = -1;
676
677     typedef int (*GetKeyFun)();
678     keyFun = (GetKeyFun) GetProc( theLibraryHandle, "meshgems_core_get_version_major" );
679     if ( !keyFun )
680     {
681       if ( ! getLastError( error ))
682         error = SMESH_Comment( "Can't find symbol 'meshgems_core_get_version_major' in '") << getenv( theEnvVar ) << "'";
683     }
684     else
685     {
686         v_maj = keyFun( );
687     }
688     if ( v_maj==-1 )
689       error = "meshgems_core_get_version_major() failed (located in '" + libraryFile._name + "')";
690
691     MESSAGE("meshgems_core_get_version_major: " << v_maj);
692
693     // get patch version
694     int v_patch = -1;
695
696     typedef int (*GetKeyFun)();
697     keyFun = (GetKeyFun) GetProc( theLibraryHandle, "meshgems_core_get_version_patch" );
698     if ( !keyFun )
699     {
700       if ( ! getLastError( error ))
701         error = SMESH_Comment( "Can't find symbol 'meshgems_core_get_version_patch' in '") << getenv( theEnvVar ) << "'";
702     }
703     else
704     {
705         v_patch = keyFun( );
706     }
707     if ( v_patch==-1 )
708       error = "meshgems_core_get_version_patch() failed (located in '" + libraryFile._name + "')";
709
710     MESSAGE("meshgems_core_get_version_patch: " << v_patch );
711
712     int v_hex = (v_maj << 16 | v_min << 8 | v_patch);
713
714     MESSAGE("v_hex: " << v_hex);
715
716     return v_hex;
717   }
718
719   //================================================================================
720   /*!
721    * \brief Guess if the Spatial license is needed (if MeshGems is > 2.15.0)
722    *  \param [out] error - return error description
723    *  \return bool - true if MeshGems is > 2.15.0
724    */
725   //================================================================================
726   bool NeedsMGSpatialEnvLicense(std::string& error)
727   {
728     // if MeshGems version is > 2.15.0, need to set SPATIAL_LICENSE
729     int v_hex = GetMGVersionHex(error);
730     bool ok = (v_hex > MESHGEMS_215);
731     if (ok)
732       MESSAGE("MeshGems version is > 2.15.0, need to set SPATIAL_LICENSE");
733     return ok;
734   }
735
736   //================================================================================
737   /*!
738    * \brief Set the SPATIAL_LICENSE environment variable
739    *  \param [out] error - return error description
740    *  \return bool - true in case of success
741    */
742   //================================================================================
743   bool SetMGSpatialEnvLicense(std::string& error)
744   {
745     int ok;
746     std::string key = GetKey(error);
747 #ifndef WIN32
748     ok = setenv(SPATIAL_LICENSE, key.c_str(), 0); // 0 means do not overwrite
749 #else
750     ok = Kernel_Utils::setenv(SPATIAL_LICENSE, key.c_str(), 0 );
751 #endif
752     MESSAGE("Set SPATIAL_LICENSE");
753     return (ok==0);
754   }
755
756   //================================================================================
757   /*!
758    * \brief Get the license key from libMeshGemsKeyGenerator.so or $SPATIAL_LICENSE
759    * Called by plugins calling MG products as executables.
760    * If MESHGEMS_OLD_STYLE is set, return "0", to use old DLIM8 server license
761    * instead of the key.
762    *  \param [in] gmfFile - path to an input mesh file
763    *  \param [in] nb* - nb of entities in the input mesh
764    *  \param [out] error - return error description
765    *  \return std::string - the key
766    */
767   //================================================================================
768   std::string GetKey(const std::string& gmfFile,
769                     int                nbVertex,
770                     int                nbEdge,
771                     int                nbFace,
772                     int                nbVol,
773                     std::string&       error)
774   {
775     // default key if MESHGEMS_OLD_STYLE or SPATIAL_LICENSE is set
776     std::string key("0");
777     const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
778     if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 )
779       {
780         const char *spatialLicenseEnvVar( getenv( SPATIAL_LICENSE ) );
781         if ( !spatialLicenseEnvVar || strlen(spatialLicenseEnvVar) == 0 )
782           {
783             if (NeedsMGSpatialEnvLicense(error))
784               {
785                 // if MG version > 2.15, set environment license, don't return it as a key
786                 // otherwise it will be printed in the command line
787                 MESSAGE("SPATIAL_LICENSE not in env => we add it from MGKeygen .so");
788                 SetMGSpatialEnvLicense(error);
789               }
790             else
791               {
792                 // generate the key from the mesh info (MG 2.13 and 2.14)
793                 MESSAGE("MG < 2.15 => get the key from MGKeygen .so and this mesh info");
794                 key = GetKey_After(gmfFile,nbVertex,nbEdge,nbFace,nbVol,error);
795               }
796           }
797         else
798           MESSAGE("SPATIAL_LICENSE already in env => we use it");
799       }
800     if (! error.empty())
801       std::cerr << error;
802     return key;
803   }
804
805   //================================================================================
806   /*!
807    * \brief Get the license key from libMeshGemsKeyGenerator.so or $SPATIAL_LICENSE
808    * Called for MG 2.15 by CADSurf and MG plugins calling MG products as library,
809    * i.e. compiled as library with -DSALOME_USE_MG_LIBS=ON
810    *  \param [out] error - return error description
811    *  \return std::string - the key
812    */
813   //================================================================================
814   std::string GetKey(std::string&       error)
815   {
816     // default key if not found in .so or in SPATIAL_LICENSE
817     std::string key("0");
818     const char *meshGemsOldStyleEnvVar( getenv( MESHGEMS_OLD_STYLE ) );
819     if ( !meshGemsOldStyleEnvVar || strlen(meshGemsOldStyleEnvVar) == 0 ){
820       const char *spatialLicenseEnvVar( getenv( SPATIAL_LICENSE ) );
821       if ( !spatialLicenseEnvVar || strlen(spatialLicenseEnvVar) == 0 )
822         {
823           MESSAGE("SPATIAL_LICENSE not in env => we add it from MGKeygen .so");
824           // use new style, i.e. key in a library
825           key = GetKey_After(error);
826         }
827       else
828         {
829           MESSAGE("SPATIAL_LICENSE already in env => we use it");
830           key = std::string(spatialLicenseEnvVar);
831         }
832     }
833     if (! error.empty())
834       std::cerr << error;
835     return key;
836   }
837
838   //================================================================================
839   /*!
840    * \brief Return false if libMeshGemsKeyGenerator.so is not functional
841    *  \param [out] error - return error description
842    *  \return bool - is a success
843    */
844   //================================================================================
845
846   bool CheckKeyGenLibrary( std::string& error )
847   {
848     return !GetKey("",4,0,2,0,error ).empty();
849   }
850
851   //================================================================================
852   /*!
853    * \brief Return KeyGenerator library name
854    */
855   //================================================================================
856
857   std::string GetLibraryName()
858   {
859     std::string libName, error;
860     if ( const char* libPath = getenv( theEnvVar ))
861     {
862       libName = Kernel_Utils::GetBaseName( libPath );
863     }
864     else
865     {
866       libName = "libSalomeMeshGemsKeyGenerator";
867     }
868     setExtension( libName, error );
869     return libName;
870   }
871 }