diff --git a/utils/solvers/c++/onelab.h b/utils/solvers/c++/onelab.h
new file mode 100644
index 0000000000000000000000000000000000000000..32ed1533606dcb71cbd144f5a5a22a87849fcb4f
--- /dev/null
+++ b/utils/solvers/c++/onelab.h
@@ -0,0 +1,817 @@
+// OneLab - Copyright (C) 2011 ULg-UCL
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished
+// to do so, provided that the above copyright notice(s) and this
+// permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice
+// appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _ONELAB_H_
+#define _ONELAB_H_
+
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+#include <iostream>
+#include <sstream>
+#include "GmshSocket.h"
+
+namespace onelab{
+
+  // The base parameter class.
+  class parameter{
+  private:
+    // the name of the parameter, including its '/'-separated path in
+    // the parameter hierarchy. Parameters or subpaths can start with
+    // numbers to force their relative ordering (such numbers are
+    // automatically hidden in the interface).
+    std::string _name;
+    // help strings (if provided, the short help serves as a better
+    // way to display the parameter in the interface). Richer encoding
+    // (UTF? HTML?) might be used in the future.
+    std::string _shortHelp, _help;
+    // clients that use this parameter
+    std::set<std::string> _clients;
+    // flag to check if the parameter has been changed since the last
+    // run()
+    bool _changed;
+    // should the parameter be visible in the interface?
+    bool _visible;
+  protected:
+    // optional additional attributes
+    std::map<std::string, std::string> _attributes;
+  public:
+    parameter(const std::string &name="", const std::string &shortHelp="", 
+              const std::string &help="")
+      : _name(name), _shortHelp(shortHelp), _help(help), _changed(true),
+        _visible(true) {}
+    void setName(const std::string &name){ _name = name; }
+    void setShortHelp(const std::string &shortHelp){ _shortHelp = shortHelp; }
+    void setHelp(const std::string &help){ _help = help; }
+    void setChanged(bool changed){ _changed = changed; }
+    void setVisible(bool visible){ _visible = visible; }
+    void setAttribute(const std::string &key, const std::string &value)
+    {
+      _attributes[key] = value;
+    }
+    void setAttributes(const std::map<std::string, std::string> &attributes)
+    {
+      _attributes = attributes; 
+    }
+    void setClients(const std::set<std::string> &clients){ _clients = clients; }
+    void addClient(const std::string &client){ _clients.insert(client); }
+    void addClients(const std::set<std::string> &clients)
+    { 
+      _clients.insert(clients.begin(), clients.end()); 
+    }
+    bool hasClient(const std::string &client)
+    {
+      return (_clients.find(client) != _clients.end());
+    }
+    virtual std::string getType() const = 0;
+    const std::string &getName() const { return _name; }
+    const std::string &getShortHelp() const { return _shortHelp; }
+    const std::string &getHelp() const { return _help; }
+    bool getChanged() const { return _changed; }
+    bool getVisible() const { return _visible; }
+    std::string getAttribute(const std::string &key) const
+    {
+      std::map<std::string, std::string>::const_iterator it = _attributes.find(key);
+      if(it != _attributes.end()) return it->second;
+      return "";
+    }
+    const std::map<std::string, std::string> &getAttributes() const 
+    {
+      return _attributes; 
+    }
+    const std::set<std::string> &getClients() const { return _clients; }
+    static char charSep() { return '\0'; }
+    static double maxNumber() { return 1e200; }
+    static std::string version() { return "1.0"; }
+    static std::string getNextToken(const std::string &msg, 
+                                    std::string::size_type &first)
+    {
+      std::string::size_type last = msg.find_first_of(charSep(), first);
+      std::string next = msg.substr(first, last - first);
+      first = (last == std::string::npos) ? last : last + 1;
+      return next;
+    }
+    std::string sanitize(const std::string &in) const
+    {
+      std::string out(in);
+      for(unsigned int i = 0; i < in.size(); i++)
+        if(out[i] == charSep()) out[i] = ' ';
+      return out;
+    }
+    virtual std::string toChar() const
+    {
+      std::ostringstream sstream;
+      sstream << version() << charSep() << getType() << charSep() 
+              << sanitize(getName()) << charSep() 
+              << sanitize(getShortHelp()) << charSep() 
+              << sanitize(getHelp()) << charSep() 
+              << (getVisible() ? 1 : 0) << charSep()
+              << _attributes.size() << charSep();
+      for(std::map<std::string, std::string>::const_iterator it = _attributes.begin();
+          it != _attributes.end(); it++)
+        sstream << sanitize(it->first) << charSep() 
+                << sanitize(it->second) << charSep();
+      sstream << getClients().size() << charSep();
+      for(std::set<std::string>::const_iterator it = getClients().begin();
+          it != getClients().end(); it++)
+        sstream << sanitize(*it) << charSep();
+      return sstream.str();
+    }
+    virtual std::string::size_type fromChar(const std::string &msg)
+    {
+      std::string::size_type pos = 0;
+      if(getNextToken(msg, pos) != version()) return 0;
+      if(getNextToken(msg, pos) != getType()) return 0;
+      setName(getNextToken(msg, pos));
+      setShortHelp(getNextToken(msg, pos));
+      setHelp(getNextToken(msg, pos));
+      setVisible(atoi(getNextToken(msg, pos).c_str()));
+      int numAttributes = atoi(getNextToken(msg, pos).c_str());
+      for(int i = 0; i < numAttributes; i++){
+        std::string key(getNextToken(msg, pos));
+        setAttribute(key, getNextToken(msg, pos));
+      }
+      int numClients = atoi(getNextToken(msg, pos).c_str());
+      for(int i = 0; i < numClients; i++){
+        std::string client(getNextToken(msg, pos));
+        addClient(client);
+      }
+      return pos;
+    }
+    static void getInfoFromChar(const std::string &msg, std::string &version, 
+                                std::string &type, std::string &name)
+    {
+      std::string::size_type first = 0;
+      version = getNextToken(msg, first);
+      type = getNextToken(msg, first);
+      name = getNextToken(msg, first);
+    }
+  };
+  
+  class parameterLessThan{
+  public:
+    bool operator()(const parameter *p1, const parameter *p2) const
+    {
+      return p1->getName() < p2->getName();
+    }
+  };
+
+  // The number class. Numbers are stored internally as double
+  // precision real numbers. Currently all more complicated types
+  // (complex numbers, vectors, etc.) are supposed to be encapsulated
+  // in functions. We might add more base types in the future to make
+  // the interface more expressive.
+  class number : public parameter{
+  private:
+    double _value, _min, _max, _step;
+    std::vector<double> _choices;
+  public:
+    number(const std::string &name="", double value=0.,
+           const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(value), 
+        _min(-maxNumber()), _max(maxNumber()), _step(0.) {}
+    void setValue(double value){ _value = value; }
+    void setMin(double min){ _min = min; }
+    void setMax(double max){ _max = max; }
+    void setStep(double step){ _step = step; }
+    void setChoices(const std::vector<double> &choices){ _choices = choices; }
+    std::string getType() const { return "number"; }
+    double getValue() const { return _value; }
+    double getMin() const { return _min; }
+    double getMax() const { return _max; }
+    double getStep() const { return _step; }
+    const std::vector<double> &getChoices() const { return _choices; }
+    void update(const number &p)
+    {
+      addClients(p.getClients()); // complete the list
+      setShortHelp(p.getShortHelp());
+      setHelp(p.getHelp());
+      setAttributes(p.getAttributes());
+      if(p.getValue() != getValue()){
+        setValue(p.getValue());
+        setChanged(true);
+      }
+      setMin(p.getMin());
+      setMax(p.getMax());
+      setStep(p.getStep());
+      setChoices(p.getChoices());
+    }
+    std::string toChar() const
+    {
+      std::ostringstream sstream;
+      sstream << parameter::toChar() << _value << charSep() 
+              << _min << charSep() << _max << charSep() << _step << charSep()
+              << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << _choices[i] << charSep();
+      return sstream.str();
+    }
+    std::string::size_type fromChar(const std::string &msg)
+    {
+      std::string::size_type pos = parameter::fromChar(msg);
+      if(!pos) return 0;
+      setValue(atof(getNextToken(msg, pos).c_str()));
+      setMin(atof(getNextToken(msg, pos).c_str()));
+      setMax(atof(getNextToken(msg, pos).c_str()));
+      setStep(atof(getNextToken(msg, pos).c_str()));
+      _choices.resize(atoi(getNextToken(msg, pos).c_str()));
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        _choices[i] = atof(getNextToken(msg, pos).c_str());
+      return pos;
+    }
+  };
+
+  // The string class. A string has a mutable "kind": we do not derive
+  // specialized classes, because the kind should be changeable at
+  // runtime (e.g. from a client-dependent mathematical expression to
+  // a table of values). Possible kinds: generic, filename, hostname,
+  // client-dependent mathematical expression, comma-separated list of
+  // values, matlab matrix, onelab mathematical expression (through
+  // mathex?), ...
+  class string : public parameter{
+  private:
+    std::string _value, _kind;
+    std::vector<std::string> _choices;
+  public:
+    string(const std::string &name="", const std::string &value="", 
+           const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(value), _kind("generic") {}
+    void setValue(const std::string &value){ _value = value; }
+    void setKind(const std::string &kind){ _kind = kind; }
+    void setChoices(const std::vector<std::string> &choices){ _choices = choices; }
+    std::string getType() const { return "string"; }
+    const std::string &getValue() const { return _value; }
+    const std::string &getKind() const { return _kind; }
+    const std::vector<std::string> &getChoices() const { return _choices; }
+    void update(const string &p)
+    {
+      addClients(p.getClients());
+      setShortHelp(p.getShortHelp());
+      setHelp(p.getHelp());
+      setAttributes(p.getAttributes());
+      if(p.getValue() != getValue()){
+        setValue(p.getValue());
+        setChanged(true);
+      }
+      if(p.getKind() != getKind()){
+        setKind(p.getKind());
+        setChanged(true);
+      }
+      setChoices(p.getChoices());
+    }
+    std::string toChar() const
+    {
+      std::ostringstream sstream;
+      sstream << parameter::toChar() << sanitize(_value) << charSep()
+              << sanitize(_kind) << charSep()
+              << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << sanitize(_choices[i]) << charSep();
+      return sstream.str();
+    }
+    std::string::size_type fromChar(const std::string &msg)
+    {
+      std::string::size_type pos = parameter::fromChar(msg);
+      if(!pos) return 0;
+      setValue(getNextToken(msg, pos));
+      setKind(getNextToken(msg, pos));
+      _choices.resize(atoi(getNextToken(msg, pos).c_str()));
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        _choices[i] = getNextToken(msg, pos);
+      return pos;
+    }
+  };
+
+  // The region class. A region can be any kind of geometrical entity,
+  // represented as identifiers of physical regions. Operations on
+  // regions will include union, intersection, etc.
+  class region : public parameter{
+  private:
+    std::string _value; // TODO: change this into std::set<std::string>
+    std::vector<std::string> _choices;
+  public:
+    region(const std::string &name="", const std::string &value="",
+           const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(value) {}
+    void setValue(const std::string &value){ _value = value; }
+    std::string getType() const { return "region"; }
+    const std::string &getValue() const { return _value; }
+    void update(const region &p)
+    {
+      addClients(p.getClients());
+      setShortHelp(p.getShortHelp());
+      setHelp(p.getHelp());
+      setAttributes(p.getAttributes());
+      if(p.getValue() != getValue()){
+        setValue(p.getValue());
+        setChanged(true);
+      }
+    }
+    std::string toChar() const
+    {
+      std::ostringstream sstream;
+      sstream << parameter::toChar() << _value << charSep() 
+              << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << sanitize(_choices[i]) << charSep();
+      return sstream.str();
+    }
+  };
+
+  // The (possibly piece-wise defined on regions) function
+  // class. Functions are entirely client-dependent: they are just
+  // represented internally as onelab strings, defined on onelab
+  // regions.
+  class function : public parameter{
+  private:
+    std::string _value;
+    std::map<std::string, std::string> _pieceWiseValues;
+    std::vector<std::string> _choices;
+  public:
+    function(const std::string &name="", const std::string &value="",
+             const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(value) {}
+    void setValue(const std::string &value, const std::string &region="")
+    {
+      if(region.empty())
+        _value = value;
+      else
+        _pieceWiseValues[region] = value;
+    }
+    std::string getType() const { return "function"; }
+    const std::string getValue(const std::string &region="") const
+    {
+      if(region.size()){
+        std::map<std::string, std::string>::const_iterator it =
+          _pieceWiseValues.find(region);
+        if(it != _pieceWiseValues.end()) return it->second;
+        return "";
+      }
+      else return _value; 
+    }
+    const std::map<std::string, std::string> &getPieceWiseValues() const 
+    {
+      return _pieceWiseValues; 
+    }
+    void update(const function &p)
+    {
+      addClients(p.getClients());
+      setShortHelp(p.getShortHelp());
+      setHelp(p.getHelp());
+      setAttributes(p.getAttributes());
+      if(p.getValue() != getValue()){
+        setValue(p.getValue());
+        setChanged(true);
+      }
+    }
+    std::string toChar() const
+    {
+      std::ostringstream sstream;
+      sstream << parameter::toChar() << sanitize(_value) << charSep()
+              << _pieceWiseValues.size() << charSep();
+      for(std::map<std::string, std::string>::const_iterator it =
+            _pieceWiseValues.begin(); it != _pieceWiseValues.end(); it++)
+        sstream << sanitize(it->first) << charSep() 
+                << sanitize(it->second) << charSep();
+      sstream << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << sanitize(_choices[i]) << charSep();
+      return sstream.str();
+    }
+  };
+
+  // The parameter space, i.e., the set of parameters stored and
+  // handled by the onelab server.
+  class parameterSpace{
+  private:
+    std::set<number*, parameterLessThan> _numbers;
+    std::set<string*, parameterLessThan> _strings;
+    std::set<region*, parameterLessThan> _regions;
+    std::set<function*, parameterLessThan> _functions;
+    // set a parameter in the parameter space; if it already exists,
+    // update it (adding new clients if necessary). This needs to be
+    // locked to avoid race conditions when several clients try to set
+    // a parameter at the same time.
+    template <class T> bool _set(const T &p, const std::string &client,
+                                 std::set<T*, parameterLessThan> &ps)
+    {
+      typename std::set<T*, parameterLessThan>::iterator it = ps.find((T*)&p);
+      if(it != ps.end()){
+        (*it)->update(p);
+        if(client.size()) (*it)->addClient(client);
+      }
+      else{
+        T* newp = new T(p);
+        if(client.size()) newp->addClient(client);
+        ps.insert(newp);
+      }
+      return true;
+    }
+    // get the parameter matching the given name, or all the
+    // parameters in the category if no name is given. If we find a
+    // given parameter by name, we add the client requesting the
+    // parameter to the list of clients for this parameter. This also
+    // needs to be locked.
+    template <class T> bool _get(std::vector<T> &p, const std::string &name,
+                                 const std::string &client,
+                                 std::set<T*, parameterLessThan> &ps)
+    {
+      p.clear();
+      if(name.empty()){
+        for(typename std::set<T*, parameterLessThan>::iterator it = ps.begin();
+            it != ps.end(); it++)
+          p.push_back(**it);
+      }
+      else{
+        T tmp(name);
+        typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
+        if(it != ps.end()){
+          if(client.size()) (*it)->addClient(client);
+          p.push_back(**it);
+        }
+      }
+      return true;
+    }
+    void _getAllParameters(std::set<parameter*> &ps) const
+    {
+      ps.insert(_numbers.begin(), _numbers.end());
+      ps.insert(_strings.begin(), _strings.end());
+      ps.insert(_regions.begin(), _regions.end());
+      ps.insert(_functions.begin(), _functions.end());
+    }
+  public:
+    parameterSpace(){}
+    ~parameterSpace(){ clear(); }
+    void clear()
+    {
+      std::set<parameter*> ps;
+      _getAllParameters(ps);
+      for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++)
+        delete *it;
+      _numbers.clear();
+      _strings.clear();
+      _regions.clear();
+      _functions.clear();
+    }
+    bool set(const number &p,
+             const std::string &client=""){ return _set(p, client, _numbers); }
+    bool set(const string &p,
+             const std::string &client=""){ return _set(p, client, _strings); }
+    bool set(const region &p,
+             const std::string &client=""){ return _set(p, client, _regions); }
+    bool set(const function &p,
+             const std::string &client=""){ return _set(p, client, _functions); }
+    bool get(std::vector<number> &ps, const std::string &name="", 
+             const std::string &client=""){ return _get(ps, name, client, _numbers); }
+    bool get(std::vector<string> &ps, const std::string &name="",
+             const std::string &client=""){ return _get(ps, name, client, _strings); }
+    bool get(std::vector<region> &ps, const std::string &name="",
+             const std::string &client=""){ return _get(ps, name, client, _regions); }
+    bool get(std::vector<function> &ps, const std::string &name="",
+             const std::string &client=""){ return _get(ps, name, client, _functions); }
+    // check if at least one parameter depends on the given client
+    bool hasClient(const std::string &client) const
+    {
+      std::set<parameter*> ps;
+      _getAllParameters(ps);
+      for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++)
+        if((*it)->hasClient(client)) return true;
+      return false;
+    }
+    // check if some parameters have changed (optionnally only check
+    // the parameters that depend on a given client)
+    bool getChanged(const std::string &client="") const
+    {
+      std::set<parameter*> ps;
+      _getAllParameters(ps);
+      for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++){
+        if((client.empty() || (*it)->hasClient(client)) && (*it)->getChanged())
+          return true;
+      }
+      return false;
+    }
+    // set the changed flag for all parameters (optionnally only affect those
+    // parameters that depend on a given client)
+    bool setChanged(bool changed, const std::string &client="")
+    {
+      std::set<parameter*> ps;
+      _getAllParameters(ps);
+      for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++)
+        if(client.empty() || (*it)->hasClient(client))
+          (*it)->setChanged(changed);
+    }
+    // serialize the parameter space (optinally only serialize those
+    // parameters that depend on the given client)
+    std::string toChar(const std::string &client="") const
+    {
+      std::string s;
+      std::set<parameter*> ps;
+      _getAllParameters(ps);
+      for(std::set<parameter*>::const_iterator it = ps.begin(); it != ps.end(); it++)
+        if(client.empty() || (*it)->hasClient(client)) s += (*it)->toChar() + "\n";
+      return s;
+    }
+  };
+
+  // The onelab client: a class that communicates with the onelab
+  // server. Each client should be derived from this one. A client can
+  // be understood as "one simulation step in a complex computation".
+  class client{
+  protected:
+    // the name of the client
+    std::string _name;
+    // the id of the client, used to create a unique socket for this client
+    int _id;
+    // the index of the client in an external client list (if any)
+    int _index;
+  public:
+    client(const std::string &name) : _name(name), _id(0), _index(-1){}
+    virtual ~client(){}
+    std::string getName(){ return _name; }
+    void setId(int id){ _id = id; }
+    int getId(){ return _id; }
+    void setIndex(int index){ _index = index; }
+    int getIndex(){ return _index; }
+    virtual bool run(const std::string &what){ return false; }
+    virtual bool isNetworkClient(){ return false; }
+    virtual bool kill(){ return false; }
+    virtual void sendInfo(const std::string &msg){ std::cout << msg << std::endl; }
+    virtual void sendWarning(const std::string &msg){ std::cerr << msg << std::endl; }
+    virtual void sendError(const std::string &msg){ std::cerr << msg << std::endl; }
+    virtual void sendProgress(const std::string &msg){ std::cout << msg << std::endl; }
+    virtual void sendMergeFileRequest(const std::string &msg){}
+    virtual void sendParseStringRequest(const std::string &msg){}
+    virtual void sendVertexArray(const std::string &msg){}
+    virtual bool set(const number &p) = 0;
+    virtual bool set(const string &p) = 0;
+    virtual bool set(const region &p) = 0;
+    virtual bool set(const function &p) = 0;
+    virtual bool get(std::vector<number> &ps, const std::string &name="") = 0;
+    virtual bool get(std::vector<string> &ps, const std::string &name="") = 0;
+    virtual bool get(std::vector<region> &ps, const std::string &name="") = 0;
+    virtual bool get(std::vector<function> &ps, const std::string &name="") = 0;
+  };
+
+  // The onelab server: a singleton that stores the parameter space
+  // and interacts with onelab clients.
+  class server{
+  private:
+    // the unique server
+    static server *_server;
+    // the address of the server
+    std::string _address;
+    // the connected clients, indexed by name
+    std::map<std::string, client*> _clients;
+    // the parameter space
+    parameterSpace _parameterSpace;
+  public:
+    server(const std::string &address="") : _address(address) {}
+    ~server(){}
+    static server *instance(const std::string &address="")
+    {
+      if(!_server) _server = new server(address);
+      return _server;
+    }
+    void clear(){ _parameterSpace.clear(); }
+    template <class T> bool set(const T &p, const std::string &client="")
+    {
+      return _parameterSpace.set(p, client); 
+    }
+    template <class T> bool get(std::vector<T> &ps, const std::string &name="",
+                                const std::string &client="")
+    {
+      return _parameterSpace.get(ps, name, client); 
+    }
+    typedef std::map<std::string, client*>::iterator citer;
+    citer firstClient(){ return _clients.begin(); }
+    citer lastClient(){ return _clients.end(); }
+    citer findClient(const std::string &name){ return _clients.find(name); }
+    void registerClient(client *c)
+    {
+      _clients[c->getName()] = c;
+      c->setId(_clients.size());
+    }
+    void unregisterClient(client *c){ _clients.erase(c->getName()); }
+    void setChanged(bool changed, const std::string &client="")
+    {
+      _parameterSpace.setChanged(changed, client);
+    }
+    bool getChanged(const std::string &client="")
+    {
+      return _parameterSpace.getChanged(client);
+    }
+    std::string toChar(const std::string &client="")
+    {
+      return _parameterSpace.toChar(client); 
+    }
+  };
+    
+  class localClient : public client{
+  private:
+    template <class T> bool _set(const T &p)
+    {
+      server::instance()->set(p, _name);
+      return true;
+    }
+    template <class T> bool _get(std::vector<T> &ps,
+                                 const std::string &name="")
+    {
+      server::instance()->get(ps, name, _name);
+      return true;
+    }
+  public:
+    localClient(const std::string &name) : client(name)
+    {
+      server::instance()->registerClient(this);
+    }
+    virtual ~localClient(){}
+    virtual bool set(const number &p){ return _set(p); }
+    virtual bool set(const string &p){ return _set(p); }
+    virtual bool set(const function &p){ return _set(p); }
+    virtual bool set(const region &p){ return _set(p); }
+    virtual bool get(std::vector<number> &ps,
+                     const std::string &name=""){ return _get(ps, name); }
+    virtual bool get(std::vector<string> &ps,
+                     const std::string &name=""){ return _get(ps, name); }
+    virtual bool get(std::vector<function> &ps,
+                     const std::string &name=""){ return _get(ps, name); }
+    virtual bool get(std::vector<region> &ps,
+                     const std::string &name=""){ return _get(ps, name); }
+  };
+
+  class localNetworkClient : public localClient{
+  private:
+    // command line to launch the remote network client
+    std::string _commandLine;
+    // command line option to specify socket
+    std::string _socketSwitch;
+    // pid of the remote network client
+    int _pid;
+    // underlying GmshServer
+    GmshServer *_gmshServer;
+  public:
+    localNetworkClient(const std::string &name, const std::string &commandLine)
+      : localClient(name), _commandLine(commandLine), _socketSwitch("-onelab"),
+        _pid(-1), _gmshServer(0) {}
+    virtual ~localNetworkClient(){}
+    virtual bool isNetworkClient(){ return true; }
+    const std::string &getCommandLine(){ return _commandLine; }
+    void setCommandLine(const std::string &s){ _commandLine = s; }
+    const std::string &getSocketSwitch(){ return _socketSwitch; }
+    void setSocketSwitch(const std::string &s){ _socketSwitch = s; }
+    int getPid(){ return _pid; }
+    void setPid(int pid){ _pid = pid; }
+    GmshServer *getGmshServer(){ return _gmshServer; }
+    void setGmshServer(GmshServer *server){ _gmshServer = server; }
+    virtual bool run(const std::string &what);
+    virtual bool kill();
+  };
+
+  class remoteNetworkClient : public client{
+  private:
+    // address (inet:port or unix socket) of the server
+    std::string _serverAddress;
+    // underlying GmshClient
+    GmshClient *_gmshClient;
+    template <class T> bool _set(const T &p)
+    {
+      if(!_gmshClient) return false;
+      std::string msg = p.toChar();
+      _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER, msg.size(), &msg[0]);
+      return true;
+    }
+    template <class T> bool _get(std::vector<T> &ps, 
+                                 const std::string &name="")
+    {
+      ps.clear();
+      if(!_gmshClient) return false;
+      T p(name);
+      std::string msg = p.toChar();
+      _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY, msg.size(), &msg[0]);
+      while(1){
+        // stop if we have no communications for 10 secs
+        int ret = _gmshClient->Select(10, 0);
+        if(!ret){
+          _gmshClient->Info("Timout: aborting remote get");
+          return false;
+        }
+        else if(ret < 0){
+          _gmshClient->Error("Error on select: aborting remote get");
+          return false;
+        }
+        int type, length, swap;
+        if(!_gmshClient->ReceiveHeader(&type, &length, &swap)){
+          _gmshClient->Error("Did not receive message header: aborting remote get");
+          return false;
+        }
+        std::string msg(length, ' ');
+        if(!_gmshClient->ReceiveMessage(length, &msg[0])){
+          _gmshClient->Error("Did not receive message body: aborting remote get");
+          return false;
+        }
+        if(type == GmshSocket::GMSH_PARAMETER){
+          T p;
+          p.fromChar(msg);
+          ps.push_back(p);
+          return true;
+        }
+        else if(type == GmshSocket::GMSH_INFO){
+          // parameter not found
+          return true;
+        }
+        else{
+          _gmshClient->Error("Unknown message type: aborting remote get");
+          return false;
+        }
+      }
+      return true;
+    }
+  public:
+    remoteNetworkClient(const std::string &name, const std::string &serverAddress)
+      : client(name), _serverAddress(serverAddress)
+    {
+      _gmshClient = new GmshClient();
+      if(_gmshClient->Connect(_serverAddress.c_str()) < 0){
+        delete _gmshClient;
+        _gmshClient = 0;
+      }
+      else{
+        _gmshClient->Start();
+      }
+    }
+    virtual ~remoteNetworkClient()
+    {
+      if(_gmshClient){
+        _gmshClient->Stop();
+        _gmshClient->Disconnect();
+        delete _gmshClient;
+        _gmshClient = 0;
+      }
+    }
+    GmshClient *getGmshClient(){ return _gmshClient; }
+    virtual bool isNetworkClient(){ return true; }
+    virtual bool set(const number &p){ return _set(p); }
+    virtual bool set(const string &p){ return _set(p); }
+    virtual bool set(const function &p){ return _set(p); }
+    virtual bool set(const region &p){ return _set(p); }
+    virtual bool get(std::vector<number> &ps, 
+                     const std::string &name=""){ return _get(ps, name); }
+    virtual bool get(std::vector<string> &ps,
+                     const std::string &name=""){ return _get(ps, name); }
+    virtual bool get(std::vector<function> &ps, 
+                     const std::string &name=""){ return _get(ps, name); }
+    virtual bool get(std::vector<region> &ps,
+                     const std::string &name=""){ return _get(ps, name); }
+    void sendInfo(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->Info(msg.c_str()); 
+    }
+    void sendWarning(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->Warning(msg.c_str()); 
+    }
+    void sendError(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->Error(msg.c_str()); 
+    }
+    void sendProgress(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->Progress(msg.c_str()); 
+    }
+    void sendMergeFileRequest(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->MergeFile(msg.c_str()); 
+    }
+    void sendParseStringRequest(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->ParseString(msg.c_str()); 
+    }
+  };
+
+}
+
+#endif
diff --git a/utils/solvers/c++/solver.cpp b/utils/solvers/c++/solver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dec6b3d8ffe2afbf6c32ee50fd3d93d780be8bec
--- /dev/null
+++ b/utils/solvers/c++/solver.cpp
@@ -0,0 +1,36 @@
+#include <iostream>
+#include <vector>
+#include <string>
+#include "onelab.h"
+
+int main(int argc, char **argv) 
+{
+  onelab::remoteNetworkClient *client = 0;
+
+  for(int i = 0; i < argc; i++){
+    if(std::string(argv[i]) == "-onelab" && i < argc - 1)
+      client = new onelab::remoteNetworkClient("My solver", argv[i + 1]);
+  }
+
+  if(!client){
+    printf("usage: %s -onelab socket\n", argv[0]);
+    exit(1);
+  }
+
+  std::vector<onelab::string> strings;
+
+  // try to get the string variable "My solver/My string" from the server
+  client->get(strings, "My solver/My string");
+  if(strings.size()){
+    std::cout << "Got string from server: '" << strings[0].getValue() << "'\n";
+  }
+  else{
+    // send a value to the server
+    onelab::string s("My solver/My string", "Hello!");
+    client->set(s);
+  }
+
+  delete client;
+
+  return 0;
+}