From 81e5f65737b6791b8a7ab992c8377ff286e21fac Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sun, 4 Dec 2011 16:40:18 +0000
Subject: [PATCH] remove mentions to old solver interface

---
 doc/texinfo/gmsh.texi                     | 72 ++++-------------------
 utils/solvers/c++/GmshSocket.h            | 45 ++++++++++----
 utils/solvers/{ => legacy}/c++/solver.cpp |  0
 utils/solvers/{ => legacy}/c++/solver.opt |  0
 4 files changed, 45 insertions(+), 72 deletions(-)
 rename utils/solvers/{ => legacy}/c++/solver.cpp (100%)
 rename utils/solvers/{ => legacy}/c++/solver.opt (100%)

diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index 370b677ad3..4881271a3d 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -201,7 +201,6 @@ Mesh commands
 Solver module
 
 * Solver options::              
-* Solver example::              
 
 Post-processing module
 
@@ -3034,28 +3033,27 @@ as well as the way meshes are displayed in the GUI, is given in
 @cindex Solver, module
 @cindex Module, Solver
 
-External solvers can be interfaced with Gmsh using a simple
-client-server model.
-
-To add a new solver in the solver module, you need to specify its name
-(@code{Solver.Name0}, @code{Solver.Name1}, etc.) and the path to the
-executable (@code{Solver.Executable0}, @code{Solver.Executable1}, etc.);
-see @ref{Solver options list}).
+External solvers can driven by Gmsh through the ONELAB
+@url{http://www.onelab.info} interface. To add a new solver in the
+solver module, you need to specify its name (@code{Solver.Name0},
+@code{Solver.Name1}, etc.) and the path to the executable
+(@code{Solver.Executable0}, @code{Solver.Executable1}, etc.); see
+@ref{Solver options list}).
 
 The client-server API for the solver interface is defined in the
-@file{onelab.h} header: see @ref{Solver example}, for an example of how
-to interface a C++ solver.
+@file{onelab.h} header. See the sources of GetDP
+(@url{http://geuz.org/getdp}, for an example on how to use the ONELAB
+programming interface.
 
 @menu
 * Solver options::              
-* Solver example::              
 @end menu
 
 @c -------------------------------------------------------------------------
 @c Solver options
 @c -------------------------------------------------------------------------
 
-@node Solver options, Solver example, Solver module, Solver module
+@node Solver options,  , Solver module, Solver module
 @section Solver options
 
 @cindex Solver commands
@@ -3063,35 +3061,6 @@ to interface a C++ solver.
 
 The list of all the solver options is given in @ref{Solver options list}.
 
-@c -------------------------------------------------------------------------
-@c Solver example
-@c -------------------------------------------------------------------------
-
-@node Solver example,  , Solver options, Solver module
-@section Solver example
-
-@cindex Solver example
-@cindex Example, solver
-
-Here is a small example of how to interface a C++ solver with Gmsh. The
-following listing reproduces the @file{utils/solvers/c++/solver.cpp} file
-from the Gmsh source distribution.
-
-@sp 1
-
-@verbatiminclude ../../utils/solvers/c++/solver.cpp
-
-@sp 1
-
-To define the above solver as the second external solver in Gmsh, you then
-need to define the following options (either merge them in your Gmsh option
-file, or use the @code{-option} command-line option---see @ref{Command-line
-options}):
-
-@sp 1
-
-@verbatiminclude ../../utils/solvers/c++/solver.opt
-
 @c =========================================================================
 @c Post-processing module
 @c =========================================================================
@@ -5357,24 +5326,9 @@ output file just load the mesh file back using `File->Open'.
 @enumerate
 @item How do I integrate my own solver with Gmsh?
 
-If you want to simply launch a program from within Gmsh, just edit the
-options to define your solver commands (e.g. Solver.Name0,
-Solver.Executable0, etc.), and set the ClientServer option to zero
-(e.g. Solver.ClientServer0 = 0).
-
-If you want your solver to interact with Gmsh (for error messages,
-option definitions, post-processing, etc.), you will need to link your
-solver with the GmshClient routines and add the appropriate function
-calls inside your program. You will of course also need to define your
-solver commands in an option file, but this time you should set the
-ClientServer variable to 1 (e.g. Solver.ClientServer = 1). C, C++,
-Perl and Python solver examples are available in the source
-distribution in the @file{utils/solvers} directory.
-
-@item On Windows, Gmsh does not seem to find the solver executable. What's wrong?
-
-The solver executable (for example, `getdp.exe') has to be in your
-path. If it is not specify its location in the `Command' field.
+Gmsh uses the ONELAB interface (@url{http://www.onelab.info}) to
+interact with external solvers. Have a look at the GetDP finite element
+solver (@url{http://geuz.org/getdp}) to see how this is done.
 
 @item Can I launch Gmsh from my solver (instead of launching my solver from Gmsh) in order to monitor a solution?
 
diff --git a/utils/solvers/c++/GmshSocket.h b/utils/solvers/c++/GmshSocket.h
index fbabdb473c..462933f4a8 100644
--- a/utils/solvers/c++/GmshSocket.h
+++ b/utils/solvers/c++/GmshSocket.h
@@ -28,6 +28,7 @@
 #define _GMSH_SOCKET_H_
 
 //#include "GmshConfig.h"
+#include <string>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -82,7 +83,7 @@ class GmshSocket{
   // the socket descriptor
   int _sock;
   // the socket name
-  const char *_sockname;
+  std::string _sockname;
   // send some data over the socket
   void _SendData(const void *buffer, int bytes)
   {
@@ -132,7 +133,7 @@ class GmshSocket{
 #endif
   }
  public:
-  GmshSocket() : _sock(0), _sockname(0)
+  GmshSocket() : _sock(0)
   {
 #if defined(WIN32) && !defined(__CYGWIN__)
     WSADATA wsaData;
@@ -245,7 +246,6 @@ class GmshClient : public GmshSocket {
     // slight delay to make sure that the socket is bound by the
     // server before we attempt to connect to it
     _Sleep(100);
-
     if(strstr(sockname, "/") || strstr(sockname, "\\") || !strstr(sockname, ":")){
 #if !defined(WIN32) || defined(__CYGWIN__)
       // UNIX socket (testing ":" is not enough with Windows paths)
@@ -288,8 +288,9 @@ class GmshClient : public GmshSocket {
       memcpy((char *)&addr_in.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
       addr_in.sin_port = htons(portno);
       for(int tries = 0; tries < 5; tries++) {
-        if(connect(_sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0)
+        if(connect(_sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0){
           return _sock;
+	}
         _Sleep(100);
       }
     }
@@ -323,33 +324,36 @@ class GmshServer : public GmshSocket{
     if(!sockname) throw "Invalid (null) socket name";
     _sockname = sockname;
     int tmpsock;
-    if(strstr(_sockname, "/") || strstr(_sockname, "\\") || !strstr(_sockname, ":")){
+    if(strstr(_sockname.c_str(), "/") || strstr(_sockname.c_str(), "\\") ||
+       !strstr(_sockname.c_str(), ":")){
       // UNIX socket (testing ":" is not enough with Windows paths)
       _portno = -1;
 #if !defined(WIN32) || defined(__CYGWIN__)
       // delete the file if it already exists
-      unlink(_sockname);
+      unlink(_sockname.c_str());
       // create a socket
       tmpsock = socket(PF_UNIX, SOCK_STREAM, 0);
       if(tmpsock < 0) throw "Couldn't create socket";
       // bind the socket to its name
       struct sockaddr_un addr_un;
       memset((char *) &addr_un, 0, sizeof(addr_un));
-      strcpy(addr_un.sun_path, _sockname);
+      strcpy(addr_un.sun_path, _sockname.c_str());
       addr_un.sun_family = AF_UNIX;
       if(bind(tmpsock, (struct sockaddr *)&addr_un, sizeof(addr_un)) < 0){
         CloseSocket(tmpsock);
         throw "Couldn't bind socket to name";
       }
       // change permissions on the socket name in case it has to be rm'd later
-      chmod(_sockname, 0666);
+      chmod(_sockname.c_str(), 0666);
 #else
       throw "Unix sockets not available on Windows";
 #endif
     }
     else{
-      // TCP/IP socket
-      const char *port = strstr(_sockname, ":");
+      // TCP/IP socket: valid names are either explicit ("hostname:12345")
+      // or implicit ("hostname:", "hostname: ", "hostname:0") in which case
+      // the system attributes at random an available port
+      const char *port = strstr(_sockname.c_str(), ":");
       _portno = atoi(port + 1);
       // create a socket
       tmpsock = socket(AF_INET, SOCK_STREAM, 0);
@@ -364,15 +368,30 @@ class GmshServer : public GmshSocket{
       memset((char *) &addr_in, 0, sizeof(addr_in));
       addr_in.sin_family = AF_INET;
       addr_in.sin_addr.s_addr = INADDR_ANY;
-      addr_in.sin_port = htons(_portno);
+      addr_in.sin_port = htons(_portno); // random assign if _portno == 0
       if(bind(tmpsock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0){
         CloseSocket(tmpsock);
         throw "Couldn't bind socket to name";
       }
+      if(!_portno){ // retrieve name if randomly assigned port
+        socklen_t addrlen = sizeof(addr_in);
+        int rc = getsockname(tmpsock, (struct sockaddr *)&addr_in, &addrlen);
+        _portno = ntohs(addr_in.sin_port);
+	int pos = _sockname.find(':'); // remove trailing ' ' or '0'
+        char tmp[256];
+	sprintf(tmp, "%s:%d", _sockname.substr(0, pos).c_str(), _portno);
+        _sockname.assign(tmp);
+      }
     }
 
     if(command && strlen(command)){
-      SystemCall(command); // start the solver
+      // we assume that the command line always ends with the socket name
+      std::string cmd(command);
+      cmd += " " + _sockname;
+#if !defined(WIN32)
+      cmd += " &";
+#endif
+      SystemCall(cmd.c_str()); // start the solver
     }
     else{
       timeout = 0.; // no command launched: don't set a timeout
@@ -420,7 +439,7 @@ class GmshServer : public GmshSocket{
   {
 #if !defined(WIN32) || defined(__CYGWIN__)
     if(_portno < 0)
-      unlink(_sockname);
+      unlink(_sockname.c_str());
 #endif
     ShutdownSocket(_sock);
     CloseSocket(_sock);
diff --git a/utils/solvers/c++/solver.cpp b/utils/solvers/legacy/c++/solver.cpp
similarity index 100%
rename from utils/solvers/c++/solver.cpp
rename to utils/solvers/legacy/c++/solver.cpp
diff --git a/utils/solvers/c++/solver.opt b/utils/solvers/legacy/c++/solver.opt
similarity index 100%
rename from utils/solvers/c++/solver.opt
rename to utils/solvers/legacy/c++/solver.opt
-- 
GitLab