<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010, 2012 Aldebaran Robotics
*/

#include <iostream>
#include <vector>
#include <map>
#include <set>

#include <qimessaging/object.hpp>
#include <qimessaging/transport_server.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/service_directory.hpp>
#include <qimessaging/session.hpp>
#include <qimessaging/datastream.hpp>
#include <qimessaging/service_info.hpp>
#include "src/transport_server_p.hpp"
#include "src/server_functor_result_future_p.hpp"
#include "src/session_p.hpp"
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qimessaging/url.hpp>

namespace qi
{

  class ServiceDirectoryPrivate : public TransportServerInterface,
      public TransportSocketInterface,
      public Object
  {
  public:
    ServiceDirectoryPrivate();
    ~ServiceDirectoryPrivate();

    virtual void newConnection(TransportServer* server, TransportSocket *socket);
    virtual void onSocketReadyRead(TransportSocket *socket, int id);
    virtual void onSocketWriteDone(TransportSocket *client);
    virtual void onSocketConnected(TransportSocket *client);
    virtual void onSocketDisconnected(TransportSocket *client);

    std::vector<ServiceInfo> services();
    ServiceInfo              service(const std::string &name);
    unsigned int             registerService(const ServiceInfo &svcinfo);
    void                     unregisterService(const unsigned int &idx);
    TransportSocket         *socket() { return currentSocket; }
    void                     serviceReady(const unsigned int &idx);
  public:
    Session                                               *session;
    qi::TransportServer                                   *ts;
    std::map<unsigned int, ServiceInfo>                    pendingServices;
    std::map<unsigned int, ServiceInfo>                    connectedServices;
    std::map<std::string, unsigned int>                    nameToIdx;
    std::map<TransportSocket*, std::vector<unsigned int> > socketToIdx;
    unsigned int                                           servicesCount;
    TransportSocket                                       *currentSocket;
    std::set<TransportSocket*>                             _clients;
    boost::recursive_mutex                                 _clientsMutex;
  }; // !ServiceDirectoryPrivate

  ServiceDirectoryPrivate::ServiceDirectoryPrivate()
  :  session(new Session)
    , ts(0)
    , servicesCount(0)
    , currentSocket(0)
  {
    ServiceInfo si;
    si.setName("serviceDirectory");
    si.setServiceId(1);
    unsigned int regid = registerService(si);
    serviceReady(1);
    //serviceDirectory must have id '1'
    assert(regid == 1);
    // Make calls synchronous on net event loop so that the 'currentSocket' hack
    // works.
    moveToEventLoop(getDefaultNetworkEventLoop());
    /*
     * Order is important. See qi::Message::ServiceDirectoryFunctions.
     */
    advertiseMethod("service", this, &ServiceDirectoryPrivate::service);
    advertiseMethod("services", this, &ServiceDirectoryPrivate::services);
    advertiseMethod("registerService", this, &ServiceDirectoryPrivate::registerService);
    advertiseMethod("unregisterService", this, &ServiceDirectoryPrivate::unregisterService);
    advertiseMethod("serviceReady", this, &ServiceDirectoryPrivate::serviceReady);
  }

  ServiceDirectoryPrivate::~ServiceDirectoryPrivate()
  {
    {
      boost::recursive_mutex::scoped_lock sl(_clientsMutex);
      for (std::set<TransportSocket*>::iterator i = _clients.begin();
        i!= _clients.end(); ++i)
      {
        (*i)->removeCallbacks(this);
        delete *i;
      }
      _clients.clear();
    } // Lock must not be held while deleting session, or deadlock
    delete ts;
    delete session;
  }

  void ServiceDirectoryPrivate::newConnection(TransportServer* server, TransportSocket *socket)
  {
    boost::recursive_mutex::scoped_lock sl(_clientsMutex);
    if (!socket)
      return;
    socket->addCallbacks(this);
    _clients.insert(socket);
  }

  void ServiceDirectoryPrivate::onSocketReadyRead(TransportSocket *socket, int id)
  {
    currentSocket  = socket;

    qi::Message msg;
    socket->read(id, &msg);
    FunctorParameters din(msg.buffer());

    ServerFunctorResult fr(socket, msg);
    metaCall(msg.function(), din, fr);

    currentSocket  = 0;
  }

  void ServiceDirectoryPrivate::onSocketWriteDone(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketConnected(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketDisconnected(TransportSocket *socket)
  {
    boost::recursive_mutex::scoped_lock sl(_clientsMutex);
    _clients.erase(socket);
    currentSocket = socket;

    // if services were connected behind the socket
    std::map<TransportSocket*, std::vector<unsigned int> >::iterator it;
    if ((it = socketToIdx.find(socket)) == socketToIdx.end())
    {
      return;
    }
    // Copy the vector, iterators will be invalidated.
    std::vector<unsigned int> ids = it->second;
    // Always start at the beginning since we erase elements on unregisterService
    // and mess up the iterator
    for (std::vector<unsigned int>::iterator it2 = ids.begin();
         it2 != ids.end();
         ++it2)
    {
      qiLogInfo("qimessaging.ServiceDirectory") << "service "
                                                << connectedServices[*it2].name()
                                                << " (#" << *it2 << ") disconnected"
                                                << std::endl;
      unregisterService(*it2);
    }
    socketToIdx.erase(it);
    currentSocket = 0;
    delete socket;
  }

  std::vector<ServiceInfo> ServiceDirectoryPrivate::services()
  {
    std::vector<ServiceInfo> result;
    std::map<unsigned int, ServiceInfo>::const_iterator it;

    for (it = connectedServices.begin(); it != connectedServices.end(); ++it)
      result.push_back(it->second);

    return result;
  }

  ServiceInfo ServiceDirectoryPrivate::service(const std::string &name)
  {
    std::map<unsigned int, ServiceInfo>::const_iterator servicesIt;
    std::map<std::string, unsigned int>::const_iterator it;

    it = nameToIdx.find(name);
    if (it == nameToIdx.end())
      return ServiceInfo();

    unsigned int idx = it->second;

    servicesIt = connectedServices.find(idx);
    if (servicesIt == connectedServices.end())
      return ServiceInfo();

    return servicesIt->second;
  }

  unsigned int ServiceDirectoryPrivate::registerService(const ServiceInfo &svcinfo)
  {
    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(svcinfo.name());
    if (it != nameToIdx.end())
    {
      qiLogWarning("qimessaging.ServiceDirectory")  << "service " << svcinfo.name()
                                                    << " is already registered (#" << it->second << ")" << std::endl;
      return 0;
    }

    unsigned int idx = ++servicesCount;
    nameToIdx[svcinfo.name()] = idx;
    // Do not add serviceDirectory on the map (socket() == null)
    if (idx != qi::Message::Service_ServiceDirectory)
    {
      socketToIdx[socket()].push_back(idx);
    }
    pendingServices[idx] = svcinfo;
    pendingServices[idx].setServiceId(idx);

    qiLogInfo("qimessaging.ServiceDirectory")  << "service " << svcinfo.name() << " registered (#" << idx << ")" << std::endl;
    for (std::vector<std::string>::const_iterator it = svcinfo.endpoints().begin();
         it != svcinfo.endpoints().end();
         ++it)
    {
      qiLogDebug("qimessaging.ServiceDirectory") << svcinfo.name() << " is now on " << *it << std::endl;
    }

    return idx;
  }

  void ServiceDirectoryPrivate::unregisterService(const unsigned int &idx)
  {
    // search the id before accessing it
    // otherwise operator[] create a empty entry
    std::map<unsigned int, ServiceInfo>::iterator it2;
    it2 = connectedServices.find(idx);
    if (it2 == connectedServices.end())
    {
      qiLogError("qimessaging.ServiceDirectory") << "Can't find service #" << idx;
      return;
    }

    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(connectedServices[idx].name());
    if (it == nameToIdx.end())
    {
      qiLogError("Mapping error, service not in nameToIdx");
      return;
    }
    std::string serviceName = it2->second.name();
    qiLogInfo("qimessaging.ServiceDirectory") << "service "
      << serviceName
      << " (#" << idx << ") unregistered"
      << std::endl;
    nameToIdx.erase(it);
    connectedServices.erase(it2);

    // Find and remove serviceId into socketToIdx map
    std::map<TransportSocket *, std::vector<unsigned int> >::iterator socketIt;
    for (socketIt = socketToIdx.begin(); socketIt != socketToIdx.end(); ++socketIt)
    {
      // notify every session that the service is unregistered
      qi::Message msg;
      msg.setType(qi::Message::Type_Event);
      msg.setService(idx);
      msg.setObject(qi::Message::Object_Main);
      msg.setFunction(qi::Message::ServiceDirectoryFunction_UnregisterService);

      qi::Buffer     buf;
      qi::ODataStream d(buf);
      d << serviceName;

      if (d.status() == qi::ODataStream::Status_Ok)
      {
        msg.setBuffer(buf);
        if (!socketIt->first->send(msg))
        {
          qiLogError("qimessaging.Session") << "Error while unregister service, cannot send event.";
        }
      }

      std::vector<unsigned int>::iterator serviceIdxIt;
      for (serviceIdxIt = socketIt->second.begin();
        serviceIdxIt != socketIt->second.end();
        ++serviceIdxIt)
      {
        if (*serviceIdxIt == idx)
        {
          socketIt->second.erase(serviceIdxIt);
          break;
        }
      }
    }
  }

  void ServiceDirectoryPrivate::serviceReady(const unsigned int &idx)
  {
    // search the id before accessing it
    // otherwise operator[] create a empty entry
    std::map<unsigned int, ServiceInfo>::iterator itService;
    itService = pendingServices.find(idx);
    if (itService == pendingServices.end())
    {
      qiLogError("qimessaging.ServiceDirectory") << "Can't find pending service #" << idx;
      return;
    }

    std::string serviceName = itService->second.name();
    connectedServices[idx] = itService->second;
    pendingServices.erase(itService);

    std::map<TransportSocket*, std::vector<unsigned int> >::iterator socketIt;
    for (socketIt = socketToIdx.begin(); socketIt != socketToIdx.end(); ++socketIt)
    {
      qi::Message msg;
      msg.setType(qi::Message::Type_Event);
      msg.setService(idx);
      msg.setObject(qi::Message::Object_Main);
      msg.setFunction(qi::Message::ServiceDirectoryFunction_RegisterService);

      qi::Buffer     buf;
      qi::ODataStream d(buf);
      d << serviceName;

      if (d.status() == qi::ODataStream::Status_Ok)
      {
        msg.setBuffer(buf);
        if (!socketIt->first->send(msg))
        {
          qiLogError("qimessaging.Session") << "Error while register service, cannot send event.";
        }
      }
    }
  }

ServiceDirectory::ServiceDirectory()
  : _p(new ServiceDirectoryPrivate())
{
}

ServiceDirectory::~ServiceDirectory()
{
  delete _p;
}

bool ServiceDirectory::listen(const qi::Url &address)
{
  std::vector<std::string> eps;
  ServiceInfo             &si = _p->connectedServices[1];

  eps.push_back(address.str());
  si.setEndpoints(eps);
  _p->ts = new qi::TransportServer(address);
  _p->ts->addCallbacks(_p);

  if (_p->ts->listen())
  {
    qiLogVerbose("qimessaging.ServiceDirectory") << "Started ServiceDirectory at " << _p->ts->listenUrl().str();

    return true;
  }
  else
  {
    qiLogError("qimessaging.ServiceDirectory") << "Could not listen on "
                                               << address.str() << std::endl;
    return false;
  }
}

void ServiceDirectory::close() {
  _p->ts->close();
}

qi::Url ServiceDirectory::listenUrl() const {
  return _p->ts->listenUrl();
}

}; // !qi
<commit_msg>servicedirectory: close the sd in dtor<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010, 2012 Aldebaran Robotics
*/

#include <iostream>
#include <vector>
#include <map>
#include <set>

#include <qimessaging/object.hpp>
#include <qimessaging/transport_server.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/service_directory.hpp>
#include <qimessaging/session.hpp>
#include <qimessaging/datastream.hpp>
#include <qimessaging/service_info.hpp>
#include "src/transport_server_p.hpp"
#include "src/server_functor_result_future_p.hpp"
#include "src/session_p.hpp"
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qimessaging/url.hpp>

namespace qi
{

  class ServiceDirectoryPrivate : public TransportServerInterface,
      public TransportSocketInterface,
      public Object
  {
  public:
    ServiceDirectoryPrivate();
    ~ServiceDirectoryPrivate();

    virtual void newConnection(TransportServer* server, TransportSocket *socket);
    virtual void onSocketReadyRead(TransportSocket *socket, int id);
    virtual void onSocketWriteDone(TransportSocket *client);
    virtual void onSocketConnected(TransportSocket *client);
    virtual void onSocketDisconnected(TransportSocket *client);

    std::vector<ServiceInfo> services();
    ServiceInfo              service(const std::string &name);
    unsigned int             registerService(const ServiceInfo &svcinfo);
    void                     unregisterService(const unsigned int &idx);
    TransportSocket         *socket() { return currentSocket; }
    void                     serviceReady(const unsigned int &idx);
  public:
    Session                                               *session;
    qi::TransportServer                                   *ts;
    std::map<unsigned int, ServiceInfo>                    pendingServices;
    std::map<unsigned int, ServiceInfo>                    connectedServices;
    std::map<std::string, unsigned int>                    nameToIdx;
    std::map<TransportSocket*, std::vector<unsigned int> > socketToIdx;
    unsigned int                                           servicesCount;
    TransportSocket                                       *currentSocket;
    std::set<TransportSocket*>                             _clients;
    boost::recursive_mutex                                 _clientsMutex;
  }; // !ServiceDirectoryPrivate

  ServiceDirectoryPrivate::ServiceDirectoryPrivate()
  :  session(new Session)
    , ts(0)
    , servicesCount(0)
    , currentSocket(0)
  {
    ServiceInfo si;
    si.setName("serviceDirectory");
    si.setServiceId(1);
    unsigned int regid = registerService(si);
    serviceReady(1);
    //serviceDirectory must have id '1'
    assert(regid == 1);
    // Make calls synchronous on net event loop so that the 'currentSocket' hack
    // works.
    moveToEventLoop(getDefaultNetworkEventLoop());
    /*
     * Order is important. See qi::Message::ServiceDirectoryFunctions.
     */
    advertiseMethod("service", this, &ServiceDirectoryPrivate::service);
    advertiseMethod("services", this, &ServiceDirectoryPrivate::services);
    advertiseMethod("registerService", this, &ServiceDirectoryPrivate::registerService);
    advertiseMethod("unregisterService", this, &ServiceDirectoryPrivate::unregisterService);
    advertiseMethod("serviceReady", this, &ServiceDirectoryPrivate::serviceReady);
  }

  ServiceDirectoryPrivate::~ServiceDirectoryPrivate()
  {
    {
      boost::recursive_mutex::scoped_lock sl(_clientsMutex);
      for (std::set<TransportSocket*>::iterator i = _clients.begin();
        i!= _clients.end(); ++i)
      {
        (*i)->removeCallbacks(this);
        delete *i;
      }
      _clients.clear();
    } // Lock must not be held while deleting session, or deadlock
    delete ts;
    delete session;
  }

  void ServiceDirectoryPrivate::newConnection(TransportServer* server, TransportSocket *socket)
  {
    boost::recursive_mutex::scoped_lock sl(_clientsMutex);
    if (!socket)
      return;
    socket->addCallbacks(this);
    _clients.insert(socket);
  }

  void ServiceDirectoryPrivate::onSocketReadyRead(TransportSocket *socket, int id)
  {
    currentSocket  = socket;

    qi::Message msg;
    socket->read(id, &msg);
    FunctorParameters din(msg.buffer());

    ServerFunctorResult fr(socket, msg);
    metaCall(msg.function(), din, fr);

    currentSocket  = 0;
  }

  void ServiceDirectoryPrivate::onSocketWriteDone(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketConnected(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketDisconnected(TransportSocket *socket)
  {
    boost::recursive_mutex::scoped_lock sl(_clientsMutex);
    _clients.erase(socket);
    currentSocket = socket;

    // if services were connected behind the socket
    std::map<TransportSocket*, std::vector<unsigned int> >::iterator it;
    if ((it = socketToIdx.find(socket)) == socketToIdx.end())
    {
      return;
    }
    // Copy the vector, iterators will be invalidated.
    std::vector<unsigned int> ids = it->second;
    // Always start at the beginning since we erase elements on unregisterService
    // and mess up the iterator
    for (std::vector<unsigned int>::iterator it2 = ids.begin();
         it2 != ids.end();
         ++it2)
    {
      qiLogInfo("qimessaging.ServiceDirectory") << "service "
                                                << connectedServices[*it2].name()
                                                << " (#" << *it2 << ") disconnected"
                                                << std::endl;
      unregisterService(*it2);
    }
    socketToIdx.erase(it);
    currentSocket = 0;
    delete socket;
  }

  std::vector<ServiceInfo> ServiceDirectoryPrivate::services()
  {
    std::vector<ServiceInfo> result;
    std::map<unsigned int, ServiceInfo>::const_iterator it;

    for (it = connectedServices.begin(); it != connectedServices.end(); ++it)
      result.push_back(it->second);

    return result;
  }

  ServiceInfo ServiceDirectoryPrivate::service(const std::string &name)
  {
    std::map<unsigned int, ServiceInfo>::const_iterator servicesIt;
    std::map<std::string, unsigned int>::const_iterator it;

    it = nameToIdx.find(name);
    if (it == nameToIdx.end())
      return ServiceInfo();

    unsigned int idx = it->second;

    servicesIt = connectedServices.find(idx);
    if (servicesIt == connectedServices.end())
      return ServiceInfo();

    return servicesIt->second;
  }

  unsigned int ServiceDirectoryPrivate::registerService(const ServiceInfo &svcinfo)
  {
    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(svcinfo.name());
    if (it != nameToIdx.end())
    {
      qiLogWarning("qimessaging.ServiceDirectory")  << "service " << svcinfo.name()
                                                    << " is already registered (#" << it->second << ")" << std::endl;
      return 0;
    }

    unsigned int idx = ++servicesCount;
    nameToIdx[svcinfo.name()] = idx;
    // Do not add serviceDirectory on the map (socket() == null)
    if (idx != qi::Message::Service_ServiceDirectory)
    {
      socketToIdx[socket()].push_back(idx);
    }
    pendingServices[idx] = svcinfo;
    pendingServices[idx].setServiceId(idx);

    qiLogInfo("qimessaging.ServiceDirectory")  << "service " << svcinfo.name() << " registered (#" << idx << ")" << std::endl;
    for (std::vector<std::string>::const_iterator it = svcinfo.endpoints().begin();
         it != svcinfo.endpoints().end();
         ++it)
    {
      qiLogDebug("qimessaging.ServiceDirectory") << svcinfo.name() << " is now on " << *it << std::endl;
    }

    return idx;
  }

  void ServiceDirectoryPrivate::unregisterService(const unsigned int &idx)
  {
    // search the id before accessing it
    // otherwise operator[] create a empty entry
    std::map<unsigned int, ServiceInfo>::iterator it2;
    it2 = connectedServices.find(idx);
    if (it2 == connectedServices.end())
    {
      qiLogError("qimessaging.ServiceDirectory") << "Can't find service #" << idx;
      return;
    }

    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(connectedServices[idx].name());
    if (it == nameToIdx.end())
    {
      qiLogError("Mapping error, service not in nameToIdx");
      return;
    }
    std::string serviceName = it2->second.name();
    qiLogInfo("qimessaging.ServiceDirectory") << "service "
      << serviceName
      << " (#" << idx << ") unregistered"
      << std::endl;
    nameToIdx.erase(it);
    connectedServices.erase(it2);

    // Find and remove serviceId into socketToIdx map
    std::map<TransportSocket *, std::vector<unsigned int> >::iterator socketIt;
    for (socketIt = socketToIdx.begin(); socketIt != socketToIdx.end(); ++socketIt)
    {
      // notify every session that the service is unregistered
      qi::Message msg;
      msg.setType(qi::Message::Type_Event);
      msg.setService(idx);
      msg.setObject(qi::Message::Object_Main);
      msg.setFunction(qi::Message::ServiceDirectoryFunction_UnregisterService);

      qi::Buffer     buf;
      qi::ODataStream d(buf);
      d << serviceName;

      if (d.status() == qi::ODataStream::Status_Ok)
      {
        msg.setBuffer(buf);
        if (!socketIt->first->send(msg))
        {
          qiLogError("qimessaging.Session") << "Error while unregister service, cannot send event.";
        }
      }

      std::vector<unsigned int>::iterator serviceIdxIt;
      for (serviceIdxIt = socketIt->second.begin();
        serviceIdxIt != socketIt->second.end();
        ++serviceIdxIt)
      {
        if (*serviceIdxIt == idx)
        {
          socketIt->second.erase(serviceIdxIt);
          break;
        }
      }
    }
  }

  void ServiceDirectoryPrivate::serviceReady(const unsigned int &idx)
  {
    // search the id before accessing it
    // otherwise operator[] create a empty entry
    std::map<unsigned int, ServiceInfo>::iterator itService;
    itService = pendingServices.find(idx);
    if (itService == pendingServices.end())
    {
      qiLogError("qimessaging.ServiceDirectory") << "Can't find pending service #" << idx;
      return;
    }

    std::string serviceName = itService->second.name();
    connectedServices[idx] = itService->second;
    pendingServices.erase(itService);

    std::map<TransportSocket*, std::vector<unsigned int> >::iterator socketIt;
    for (socketIt = socketToIdx.begin(); socketIt != socketToIdx.end(); ++socketIt)
    {
      qi::Message msg;
      msg.setType(qi::Message::Type_Event);
      msg.setService(idx);
      msg.setObject(qi::Message::Object_Main);
      msg.setFunction(qi::Message::ServiceDirectoryFunction_RegisterService);

      qi::Buffer     buf;
      qi::ODataStream d(buf);
      d << serviceName;

      if (d.status() == qi::ODataStream::Status_Ok)
      {
        msg.setBuffer(buf);
        if (!socketIt->first->send(msg))
        {
          qiLogError("qimessaging.Session") << "Error while register service, cannot send event.";
        }
      }
    }
  }

ServiceDirectory::ServiceDirectory()
  : _p(new ServiceDirectoryPrivate())
{
}

ServiceDirectory::~ServiceDirectory()
{
  close();
  delete _p;
}

bool ServiceDirectory::listen(const qi::Url &address)
{
  std::vector<std::string> eps;
  ServiceInfo             &si = _p->connectedServices[1];

  eps.push_back(address.str());
  si.setEndpoints(eps);
  _p->ts = new qi::TransportServer(address);
  _p->ts->addCallbacks(_p);

  if (_p->ts->listen())
  {
    qiLogVerbose("qimessaging.ServiceDirectory") << "Started ServiceDirectory at " << _p->ts->listenUrl().str();

    return true;
  }
  else
  {
    qiLogError("qimessaging.ServiceDirectory") << "Could not listen on "
                                               << address.str() << std::endl;
    return false;
  }
}

void ServiceDirectory::close() {
  _p->ts->close();
}

qi::Url ServiceDirectory::listenUrl() const {
  return _p->ts->listenUrl();
}

}; // !qi
<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010, 2012 Aldebaran Robotics
*/

#include <iostream>
#include <vector>
#include <map>

#include <qimessaging/object.hpp>
#include <qimessaging/transport_server.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/service_directory.hpp>
#include <qimessaging/session.hpp>
#include <qimessaging/datastream.hpp>
#include <qimessaging/service_info.hpp>
#include "src/network_thread.hpp"
#include "src/transport_server_p.hpp"
#include "src/server_functor_result_future_p.hpp"
#include <qi/os.hpp>
#include <qi/log.hpp>

namespace qi
{

  class ServiceDirectoryPrivate : public TransportServerInterface,
      public TransportSocketInterface,
      public Object
  {
  public:
    ServiceDirectoryPrivate();
    ~ServiceDirectoryPrivate();

    virtual void newConnection();
    virtual void onSocketReadyRead(TransportSocket *socket, int id);
    virtual void onSocketWriteDone(TransportSocket *client);
    virtual void onSocketConnected(TransportSocket *client);
    virtual void onSocketDisconnected(TransportSocket *client);

    std::vector<ServiceInfo> services();
    ServiceInfo              service(const std::string &name);
    unsigned int             registerService(const ServiceInfo &svcinfo);
    void                     unregisterService(const unsigned int &idx);
    TransportSocket         *socket() { return currentSocket; }

  public:
    qi::NetworkThread                                     *nthd;
    qi::TransportServer                                   *ts;
    std::map<unsigned int, ServiceInfo>                    connectedServices;
    std::map<std::string, unsigned int>                    nameToIdx;
    std::map<TransportSocket*, std::vector<unsigned int> > socketToIdx;
    unsigned int                                           servicesCount;
    TransportSocket                                       *currentSocket;
  }; // !ServiceDirectoryPrivate

  ServiceDirectoryPrivate::ServiceDirectoryPrivate()
    : nthd(new qi::NetworkThread())
    , ts(new qi::TransportServer())
    , servicesCount(0)
    , currentSocket(0)
  {
    ts->setCallbacks(this);

    ServiceInfo si;
    si.setName("serviceDirectory");
    si.setServiceId(1);
    unsigned int regid = registerService(si);
    //serviceDirectory must have id '1'
    assert(regid == 1);

    /*
     * Order is important. See qi::Message::ServiceDirectoryFunctions.
     */
    advertiseMethod("service", this, &ServiceDirectoryPrivate::service);
    advertiseMethod("services", this, &ServiceDirectoryPrivate::services);
    advertiseMethod("registerService", this, &ServiceDirectoryPrivate::registerService);
    advertiseMethod("unregisterService", this, &ServiceDirectoryPrivate::unregisterService);
  }

  ServiceDirectoryPrivate::~ServiceDirectoryPrivate()
  {
    delete ts;
    delete nthd;
  }

  void ServiceDirectoryPrivate::newConnection()
  {
    TransportSocket *socket = ts->nextPendingConnection();
    if (!socket)
      return;
    socket->setCallbacks(this);
  }

  void ServiceDirectoryPrivate::onSocketReadyRead(TransportSocket *socket, int id)
  {
    currentSocket  = socket;

    qi::Message msg;
    socket->read(id, &msg);
    FunctorParameters din(msg.buffer());

    ServerFunctorResult fr(socket, msg);
    metaCall(msg.function(), din, fr);

    currentSocket  = 0;
  }

  void ServiceDirectoryPrivate::onSocketWriteDone(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketConnected(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketDisconnected(TransportSocket *socket)
  {
    currentSocket = socket;

    // if services were connected behind the socket
    std::map<TransportSocket*, std::vector<unsigned int> >::iterator it;
    if ((it = socketToIdx.find(socket)) == socketToIdx.end())
    {
      return;
    }

    for (std::vector<unsigned int>::iterator it2 = it->second.begin();
         it2 != it->second.end();
         it2++)
    {
      qiLogInfo("qimessaging.ServiceDirectory") << "service "
                                                << connectedServices[*it2].name()
                                                << " (#" << *it2 << ") disconnected"
                                                << std::endl;
      unregisterService(*it2);
    }
    socketToIdx.erase(it);
    currentSocket = 0;
  }

  std::vector<ServiceInfo> ServiceDirectoryPrivate::services()
  {
    std::vector<ServiceInfo> result;
    std::map<unsigned int, ServiceInfo>::const_iterator it;

    for (it = connectedServices.begin(); it != connectedServices.end(); ++it)
      result.push_back(it->second);

    return result;
  }

  ServiceInfo ServiceDirectoryPrivate::service(const std::string &name)
  {
    std::map<unsigned int, ServiceInfo>::const_iterator servicesIt;
    std::map<std::string, unsigned int>::const_iterator it;

    it = nameToIdx.find(name);
    if (it == nameToIdx.end())
      return ServiceInfo();

    unsigned int idx = it->second;

    servicesIt = connectedServices.find(idx);
    if (servicesIt == connectedServices.end())
      return ServiceInfo();

    return servicesIt->second;
  }

  unsigned int ServiceDirectoryPrivate::registerService(const ServiceInfo &svcinfo)
  {
    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(svcinfo.name());
    if (it != nameToIdx.end())
    {
      qiLogWarning("qimessaging.ServiceDirectory")  << "service " << svcinfo.name()
                                                    << " is already registered (#" << it->second << ")" << std::endl;
      return 0;
    }

    unsigned int idx = ++servicesCount;
    nameToIdx[svcinfo.name()] = idx;
    socketToIdx[socket()].push_back(idx);
    connectedServices[idx] = svcinfo;
    connectedServices[idx].setServiceId(idx);
    qiLogInfo("qimessaging.ServiceDirectory")  << "service " << svcinfo.name() << " registered (#" << idx << ")" << std::endl;
    return idx;
  }

  void ServiceDirectoryPrivate::unregisterService(const unsigned int &idx)
  {
    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(connectedServices[idx].name());
    if (it != nameToIdx.end())
    {
      qiLogInfo("qimessaging.ServiceDirectory") << "service "
                                                << connectedServices[idx].name()
                                                << " (#" << idx << ") unregistered"
                                                << std::endl;
      nameToIdx.erase(it);

      std::map<unsigned int, ServiceInfo>::iterator it2;
      it2 = connectedServices.find(idx);
      if (it2 == connectedServices.end())
        qiLogError("qimessaging.ServiceDirectory") << "Can't find service #" << idx;
      else
        connectedServices.erase(it2);
    }
  }

ServiceDirectory::ServiceDirectory()
  : _p(new ServiceDirectoryPrivate())
{
}

ServiceDirectory::~ServiceDirectory()
{
  delete _p;
}

bool ServiceDirectory::listen(const qi::Url &address)
{
  std::vector<std::string> eps;
  ServiceInfo             &si = _p->connectedServices[1];

  eps.push_back(address.str());
  si.setEndpoints(eps);

  if (_p->ts->_p->start(_p->nthd->getEventBase(), address))
  {
    return true;
  }
  else
  {
    qiLogError("qimessaging.ServiceDirectory") << "Could not listen on "
                                               << address.str() << std::endl;
    return false;
  }
}

void ServiceDirectory::join()
{
  _p->nthd->join();
}

}; // !qi
<commit_msg>Add fixme.<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2010, 2012 Aldebaran Robotics
*/

#include <iostream>
#include <vector>
#include <map>

#include <qimessaging/object.hpp>
#include <qimessaging/transport_server.hpp>
#include <qimessaging/transport_socket.hpp>
#include <qimessaging/service_directory.hpp>
#include <qimessaging/session.hpp>
#include <qimessaging/datastream.hpp>
#include <qimessaging/service_info.hpp>
#include "src/network_thread.hpp"
#include "src/transport_server_p.hpp"
#include "src/server_functor_result_future_p.hpp"
#include <qi/os.hpp>
#include <qi/log.hpp>

namespace qi
{

  class ServiceDirectoryPrivate : public TransportServerInterface,
      public TransportSocketInterface,
      public Object
  {
  public:
    ServiceDirectoryPrivate();
    ~ServiceDirectoryPrivate();

    virtual void newConnection();
    virtual void onSocketReadyRead(TransportSocket *socket, int id);
    virtual void onSocketWriteDone(TransportSocket *client);
    virtual void onSocketConnected(TransportSocket *client);
    virtual void onSocketDisconnected(TransportSocket *client);

    std::vector<ServiceInfo> services();
    ServiceInfo              service(const std::string &name);
    unsigned int             registerService(const ServiceInfo &svcinfo);
    void                     unregisterService(const unsigned int &idx);
    TransportSocket         *socket() { return currentSocket; }

  public:
    qi::NetworkThread                                     *nthd;
    qi::TransportServer                                   *ts;
    std::map<unsigned int, ServiceInfo>                    connectedServices;
    std::map<std::string, unsigned int>                    nameToIdx;
    std::map<TransportSocket*, std::vector<unsigned int> > socketToIdx;
    unsigned int                                           servicesCount;
    TransportSocket                                       *currentSocket;
  }; // !ServiceDirectoryPrivate

  ServiceDirectoryPrivate::ServiceDirectoryPrivate()
    : nthd(new qi::NetworkThread())
    , ts(new qi::TransportServer())
    , servicesCount(0)
    , currentSocket(0)
  {
    ts->setCallbacks(this);

    ServiceInfo si;
    si.setName("serviceDirectory");
    si.setServiceId(1);
    unsigned int regid = registerService(si);
    //serviceDirectory must have id '1'
    assert(regid == 1);

    /*
     * Order is important. See qi::Message::ServiceDirectoryFunctions.
     */
    advertiseMethod("service", this, &ServiceDirectoryPrivate::service);
    advertiseMethod("services", this, &ServiceDirectoryPrivate::services);
    advertiseMethod("registerService", this, &ServiceDirectoryPrivate::registerService);
    advertiseMethod("unregisterService", this, &ServiceDirectoryPrivate::unregisterService);
  }

  ServiceDirectoryPrivate::~ServiceDirectoryPrivate()
  {
    delete ts;
    delete nthd;
  }

  void ServiceDirectoryPrivate::newConnection()
  {
    TransportSocket *socket = ts->nextPendingConnection();
    if (!socket)
      return;
    socket->setCallbacks(this);
  }

  void ServiceDirectoryPrivate::onSocketReadyRead(TransportSocket *socket, int id)
  {
    currentSocket  = socket;

    qi::Message msg;
    socket->read(id, &msg);
    FunctorParameters din(msg.buffer());

    ServerFunctorResult fr(socket, msg);
    metaCall(msg.function(), din, fr);

    currentSocket  = 0;
  }

  void ServiceDirectoryPrivate::onSocketWriteDone(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketConnected(TransportSocket *socket)
  {
    currentSocket = socket;

    currentSocket = 0;
  }

  void ServiceDirectoryPrivate::onSocketDisconnected(TransportSocket *socket)
  {
    currentSocket = socket;

    // if services were connected behind the socket
    std::map<TransportSocket*, std::vector<unsigned int> >::iterator it;
    if ((it = socketToIdx.find(socket)) == socketToIdx.end())
    {
      return;
    }

    for (std::vector<unsigned int>::iterator it2 = it->second.begin();
         it2 != it->second.end();
         it2++)
    {
      qiLogInfo("qimessaging.ServiceDirectory") << "service "
                                                << connectedServices[*it2].name()
                                                << " (#" << *it2 << ") disconnected"
                                                << std::endl;
      unregisterService(*it2);
    }
    socketToIdx.erase(it);
    currentSocket = 0;
  }

  std::vector<ServiceInfo> ServiceDirectoryPrivate::services()
  {
    std::vector<ServiceInfo> result;
    std::map<unsigned int, ServiceInfo>::const_iterator it;

    for (it = connectedServices.begin(); it != connectedServices.end(); ++it)
      result.push_back(it->second);

    return result;
  }

  ServiceInfo ServiceDirectoryPrivate::service(const std::string &name)
  {
    std::map<unsigned int, ServiceInfo>::const_iterator servicesIt;
    std::map<std::string, unsigned int>::const_iterator it;

    it = nameToIdx.find(name);
    if (it == nameToIdx.end())
      return ServiceInfo();

    unsigned int idx = it->second;

    servicesIt = connectedServices.find(idx);
    if (servicesIt == connectedServices.end())
      return ServiceInfo();

    return servicesIt->second;
  }

  unsigned int ServiceDirectoryPrivate::registerService(const ServiceInfo &svcinfo)
  {
    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(svcinfo.name());
    if (it != nameToIdx.end())
    {
      qiLogWarning("qimessaging.ServiceDirectory")  << "service " << svcinfo.name()
                                                    << " is already registered (#" << it->second << ")" << std::endl;
      return 0;
    }

    unsigned int idx = ++servicesCount;
    nameToIdx[svcinfo.name()] = idx;
    socketToIdx[socket()].push_back(idx);
    connectedServices[idx] = svcinfo;
    connectedServices[idx].setServiceId(idx);
    qiLogInfo("qimessaging.ServiceDirectory")  << "service " << svcinfo.name() << " registered (#" << idx << ")" << std::endl;
    return idx;
  }

  void ServiceDirectoryPrivate::unregisterService(const unsigned int &idx)
  {
    std::map<std::string, unsigned int>::iterator it;
    it = nameToIdx.find(connectedServices[idx].name());
    if (it != nameToIdx.end())
    {
      qiLogInfo("qimessaging.ServiceDirectory") << "service "
                                                << connectedServices[idx].name()
                                                << " (#" << idx << ") unregistered"
                                                << std::endl;
      nameToIdx.erase(it);

      std::map<unsigned int, ServiceInfo>::iterator it2;
      it2 = connectedServices.find(idx);
      if (it2 == connectedServices.end())
        qiLogError("qimessaging.ServiceDirectory") << "Can't find service #" << idx;
      else
        connectedServices.erase(it2);

      // FIXME: should update socketToIdx...
    }
  }

ServiceDirectory::ServiceDirectory()
  : _p(new ServiceDirectoryPrivate())
{
}

ServiceDirectory::~ServiceDirectory()
{
  delete _p;
}

bool ServiceDirectory::listen(const qi::Url &address)
{
  std::vector<std::string> eps;
  ServiceInfo             &si = _p->connectedServices[1];

  eps.push_back(address.str());
  si.setEndpoints(eps);

  if (_p->ts->_p->start(_p->nthd->getEventBase(), address))
  {
    return true;
  }
  else
  {
    qiLogError("qimessaging.ServiceDirectory") << "Could not listen on "
                                               << address.str() << std::endl;
    return false;
  }
}

void ServiceDirectory::join()
{
  _p->nthd->join();
}

}; // !qi
<|endoftext|>


<commit_before>/*
  WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible
                   with Arduino WiFi shield library

  Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
  This file is part of the esp8266 core for Arduino environment.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define LWIP_INTERNAL

extern "C"
{
    #include "include/wl_definitions.h"
    #include "osapi.h"
    #include "ets_sys.h"
}

#include "debug.h"
#include "ESP8266WiFi.h"
#include "WiFiClient.h"
#include "WiFiServer.h"
#include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include <include/ClientContext.h>
#include "c_types.h"

uint16_t WiFiClient::_localPort = 0;

static bool defaultNoDelay = false; // false == Nagle enabled by default
static bool defaultSync = false;

bool getDefaultPrivateGlobalSyncValue ()
{
    return defaultSync;
}

void WiFiClient::setDefaultNoDelay (bool noDelay)
{
    defaultNoDelay = noDelay;
}

void WiFiClient::setDefaultSync (bool sync)
{
    defaultSync = sync;
}

bool WiFiClient::getDefaultNoDelay ()
{
    return defaultNoDelay;
}

bool WiFiClient::getDefaultSync ()
{
    return defaultSync;
}

template<>
WiFiClient* SList<WiFiClient>::_s_first = 0;

WiFiClient::WiFiClient()
: _client(0)
{
    _timeout = 5000;
    WiFiClient::_add(this);
}

WiFiClient::WiFiClient(ClientContext* client)
: _client(client)
{
    _timeout = 5000;
    _client->ref();
    WiFiClient::_add(this);

    setSync(defaultSync);
    setNoDelay(defaultNoDelay);
}

WiFiClient::~WiFiClient()
{
    WiFiClient::_remove(this);
    if (_client)
        _client->unref();
}

WiFiClient::WiFiClient(const WiFiClient& other)
{
    _client = other._client;
    _timeout = other._timeout;
    _localPort = other._localPort;
    if (_client)
        _client->ref();
    WiFiClient::_add(this);
}

WiFiClient& WiFiClient::operator=(const WiFiClient& other)
{
   if (_client)
        _client->unref();
    _client = other._client;
    _timeout = other._timeout;
    _localPort = other._localPort;
    if (_client)
        _client->ref();
    return *this;
}

int WiFiClient::connect(const char* host, uint16_t port)
{
    IPAddress remote_addr;
    if (WiFi.hostByName(host, remote_addr, _timeout))
    {
        return connect(remote_addr, port);
    }
    return 0;
}

int WiFiClient::connect(const String& host, uint16_t port)
{
    return connect(host.c_str(), port);
}

int WiFiClient::connect(CONST IPAddress& ip, uint16_t port)
{
    if (_client) {
        stop();
        _client->unref();
        _client = nullptr;
    }

#if LWIP_VERSION_MAJOR == 1
    // if the default interface is down, tcp_connect exits early without
    // ever calling tcp_err
    // http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html
    netif* interface = ip_route(ip);
    if (!interface) {
        DEBUGV("no route to host\r\n");
        return 0;
    }
#endif

    tcp_pcb* pcb = tcp_new();
    if (!pcb)
        return 0;

    if (_localPort > 0) {
        pcb->local_port = _localPort++;
    }

    _client = new ClientContext(pcb, nullptr, nullptr);
    _client->ref();
    _client->setTimeout(_timeout);
    int res = _client->connect(ip, port);
    if (res == 0) {
        _client->unref();
        _client = nullptr;
        return 0;
    }

    setSync(defaultSync);
    setNoDelay(defaultNoDelay);

    return 1;
}

void WiFiClient::setNoDelay(bool nodelay) {
    if (!_client)
        return;
    _client->setNoDelay(nodelay);
}

bool WiFiClient::getNoDelay() const {
    if (!_client)
        return false;
    return _client->getNoDelay();
}

void WiFiClient::setSync(bool sync)
{
    if (!_client)
        return;
    _client->setSync(sync);
}

bool WiFiClient::getSync() const
{
    if (!_client)
        return false;
    return _client->getSync();
}

size_t WiFiClient::availableForWrite ()
{
    return _client? _client->availableForWrite(): 0;
}

size_t WiFiClient::write(uint8_t b)
{
    return write(&b, 1);
}

size_t WiFiClient::write(const uint8_t *buf, size_t size)
{
    if (!_client || !size)
    {
        return 0;
    }
    _client->setTimeout(_timeout);
    return _client->write(buf, size);
}

size_t WiFiClient::write(Stream& stream, size_t unused)
{
    (void) unused;
    return WiFiClient::write(stream);
}

size_t WiFiClient::write(Stream& stream)
{
    if (!_client || !stream.available())
    {
        return 0;
    }
    _client->setTimeout(_timeout);
    return _client->write(stream);
}

size_t WiFiClient::write_P(PGM_P buf, size_t size)
{
    if (!_client || !size)
    {
        return 0;
    }
    _client->setTimeout(_timeout);
    return _client->write_P(buf, size);
}

int WiFiClient::available()
{
    if (!_client)
        return false;

    int result = _client->getSize();

    if (!result) {
        optimistic_yield(100);
    }
    return result;
}

int WiFiClient::read()
{
    if (!available())
        return -1;

    return _client->read();
}

int WiFiClient::read(uint8_t* buf, size_t size)
{
    return (int) _client->read(reinterpret_cast<char*>(buf), size);
}

int WiFiClient::peek()
{
    if (!available())
        return -1;

    return _client->peek();
}

size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
    size_t count = 0;

    if(!_client) {
        return 0;
    }

    _startMillis = millis();
    while((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
        yield();
    }

    if(available() < (int) length) {
        count = available();
    } else {
        count = length;
    }

    return _client->peekBytes((char *)buffer, count);
}

bool WiFiClient::flush(unsigned int maxWaitMs)
{
    if (!_client)
        return true;

    if (maxWaitMs == 0)
        maxWaitMs = WIFICLIENT_MAX_FLUSH_WAIT_MS;
    return _client->wait_until_sent(maxWaitMs);
}

bool WiFiClient::stop(unsigned int maxWaitMs)
{
    if (!_client)
        return true;

    bool ret = flush(maxWaitMs); // virtual, may be ssl's
    if (_client->close() != ERR_OK)
        ret = false;
    return ret;
}

uint8_t WiFiClient::connected()
{
    if (!_client || _client->state() == CLOSED)
        return 0;

    return _client->state() == ESTABLISHED || available();
}

uint8_t WiFiClient::status()
{
    if (!_client)
        return CLOSED;
    return _client->state();
}

WiFiClient::operator bool()
{
    return connected();
}

IPAddress WiFiClient::remoteIP()
{
    if (!_client)
        return IPAddress(0U);

    return IPAddress(_client->getRemoteAddress());
}

uint16_t WiFiClient::remotePort()
{
    if (!_client)
        return 0;

    return _client->getRemotePort();
}

IPAddress WiFiClient::localIP()
{
    if (!_client)
        return IPAddress(0U);

    return IPAddress(_client->getLocalAddress());
}

uint16_t WiFiClient::localPort()
{
    if (!_client)
        return 0;

    return _client->getLocalPort();
}

void WiFiClient::stopAll()
{
    for (WiFiClient* it = _s_first; it; it = it->_next) {
        it->stop();
    }
}

void WiFiClient::stopAllExcept(WiFiClient* except)
{
    for (WiFiClient* it = _s_first; it; it = it->_next) {
        if (it != except) {
            it->stop();
        }
    }
}

void WiFiClient::keepAlive (uint16_t idle_sec, uint16_t intv_sec, uint8_t count)
{
    _client->keepAlive(idle_sec, intv_sec, count);
}

bool WiFiClient::isKeepAliveEnabled () const
{
    return _client->isKeepAliveEnabled();
}

uint16_t WiFiClient::getKeepAliveIdle () const
{
    return _client->getKeepAliveIdle();
}

uint16_t WiFiClient::getKeepAliveInterval () const
{
    return _client->getKeepAliveInterval();
}

uint8_t WiFiClient::getKeepAliveCount () const
{
    return _client->getKeepAliveCount();
}
<commit_msg>WiFiClient::remoteIP: fix nullptr crash (#5634)<commit_after>/*
  WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible
                   with Arduino WiFi shield library

  Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
  This file is part of the esp8266 core for Arduino environment.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define LWIP_INTERNAL

extern "C"
{
    #include "include/wl_definitions.h"
    #include "osapi.h"
    #include "ets_sys.h"
}

#include "debug.h"
#include "ESP8266WiFi.h"
#include "WiFiClient.h"
#include "WiFiServer.h"
#include "lwip/opt.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#include <include/ClientContext.h>
#include "c_types.h"

uint16_t WiFiClient::_localPort = 0;

static bool defaultNoDelay = false; // false == Nagle enabled by default
static bool defaultSync = false;

bool getDefaultPrivateGlobalSyncValue ()
{
    return defaultSync;
}

void WiFiClient::setDefaultNoDelay (bool noDelay)
{
    defaultNoDelay = noDelay;
}

void WiFiClient::setDefaultSync (bool sync)
{
    defaultSync = sync;
}

bool WiFiClient::getDefaultNoDelay ()
{
    return defaultNoDelay;
}

bool WiFiClient::getDefaultSync ()
{
    return defaultSync;
}

template<>
WiFiClient* SList<WiFiClient>::_s_first = 0;

WiFiClient::WiFiClient()
: _client(0)
{
    _timeout = 5000;
    WiFiClient::_add(this);
}

WiFiClient::WiFiClient(ClientContext* client)
: _client(client)
{
    _timeout = 5000;
    _client->ref();
    WiFiClient::_add(this);

    setSync(defaultSync);
    setNoDelay(defaultNoDelay);
}

WiFiClient::~WiFiClient()
{
    WiFiClient::_remove(this);
    if (_client)
        _client->unref();
}

WiFiClient::WiFiClient(const WiFiClient& other)
{
    _client = other._client;
    _timeout = other._timeout;
    _localPort = other._localPort;
    if (_client)
        _client->ref();
    WiFiClient::_add(this);
}

WiFiClient& WiFiClient::operator=(const WiFiClient& other)
{
   if (_client)
        _client->unref();
    _client = other._client;
    _timeout = other._timeout;
    _localPort = other._localPort;
    if (_client)
        _client->ref();
    return *this;
}

int WiFiClient::connect(const char* host, uint16_t port)
{
    IPAddress remote_addr;
    if (WiFi.hostByName(host, remote_addr, _timeout))
    {
        return connect(remote_addr, port);
    }
    return 0;
}

int WiFiClient::connect(const String& host, uint16_t port)
{
    return connect(host.c_str(), port);
}

int WiFiClient::connect(CONST IPAddress& ip, uint16_t port)
{
    if (_client) {
        stop();
        _client->unref();
        _client = nullptr;
    }

#if LWIP_VERSION_MAJOR == 1
    // if the default interface is down, tcp_connect exits early without
    // ever calling tcp_err
    // http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html
    netif* interface = ip_route(ip);
    if (!interface) {
        DEBUGV("no route to host\r\n");
        return 0;
    }
#endif

    tcp_pcb* pcb = tcp_new();
    if (!pcb)
        return 0;

    if (_localPort > 0) {
        pcb->local_port = _localPort++;
    }

    _client = new ClientContext(pcb, nullptr, nullptr);
    _client->ref();
    _client->setTimeout(_timeout);
    int res = _client->connect(ip, port);
    if (res == 0) {
        _client->unref();
        _client = nullptr;
        return 0;
    }

    setSync(defaultSync);
    setNoDelay(defaultNoDelay);

    return 1;
}

void WiFiClient::setNoDelay(bool nodelay) {
    if (!_client)
        return;
    _client->setNoDelay(nodelay);
}

bool WiFiClient::getNoDelay() const {
    if (!_client)
        return false;
    return _client->getNoDelay();
}

void WiFiClient::setSync(bool sync)
{
    if (!_client)
        return;
    _client->setSync(sync);
}

bool WiFiClient::getSync() const
{
    if (!_client)
        return false;
    return _client->getSync();
}

size_t WiFiClient::availableForWrite ()
{
    return _client? _client->availableForWrite(): 0;
}

size_t WiFiClient::write(uint8_t b)
{
    return write(&b, 1);
}

size_t WiFiClient::write(const uint8_t *buf, size_t size)
{
    if (!_client || !size)
    {
        return 0;
    }
    _client->setTimeout(_timeout);
    return _client->write(buf, size);
}

size_t WiFiClient::write(Stream& stream, size_t unused)
{
    (void) unused;
    return WiFiClient::write(stream);
}

size_t WiFiClient::write(Stream& stream)
{
    if (!_client || !stream.available())
    {
        return 0;
    }
    _client->setTimeout(_timeout);
    return _client->write(stream);
}

size_t WiFiClient::write_P(PGM_P buf, size_t size)
{
    if (!_client || !size)
    {
        return 0;
    }
    _client->setTimeout(_timeout);
    return _client->write_P(buf, size);
}

int WiFiClient::available()
{
    if (!_client)
        return false;

    int result = _client->getSize();

    if (!result) {
        optimistic_yield(100);
    }
    return result;
}

int WiFiClient::read()
{
    if (!available())
        return -1;

    return _client->read();
}

int WiFiClient::read(uint8_t* buf, size_t size)
{
    return (int) _client->read(reinterpret_cast<char*>(buf), size);
}

int WiFiClient::peek()
{
    if (!available())
        return -1;

    return _client->peek();
}

size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
    size_t count = 0;

    if(!_client) {
        return 0;
    }

    _startMillis = millis();
    while((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
        yield();
    }

    if(available() < (int) length) {
        count = available();
    } else {
        count = length;
    }

    return _client->peekBytes((char *)buffer, count);
}

bool WiFiClient::flush(unsigned int maxWaitMs)
{
    if (!_client)
        return true;

    if (maxWaitMs == 0)
        maxWaitMs = WIFICLIENT_MAX_FLUSH_WAIT_MS;
    return _client->wait_until_sent(maxWaitMs);
}

bool WiFiClient::stop(unsigned int maxWaitMs)
{
    if (!_client)
        return true;

    bool ret = flush(maxWaitMs); // virtual, may be ssl's
    if (_client->close() != ERR_OK)
        ret = false;
    return ret;
}

uint8_t WiFiClient::connected()
{
    if (!_client || _client->state() == CLOSED)
        return 0;

    return _client->state() == ESTABLISHED || available();
}

uint8_t WiFiClient::status()
{
    if (!_client)
        return CLOSED;
    return _client->state();
}

WiFiClient::operator bool()
{
    return connected();
}

IPAddress WiFiClient::remoteIP()
{
    if (!_client || !_client->getRemoteAddress())
        return IPAddress(0U);

    return _client->getRemoteAddress();
}

uint16_t WiFiClient::remotePort()
{
    if (!_client)
        return 0;

    return _client->getRemotePort();
}

IPAddress WiFiClient::localIP()
{
    if (!_client)
        return IPAddress(0U);

    return IPAddress(_client->getLocalAddress());
}

uint16_t WiFiClient::localPort()
{
    if (!_client)
        return 0;

    return _client->getLocalPort();
}

void WiFiClient::stopAll()
{
    for (WiFiClient* it = _s_first; it; it = it->_next) {
        it->stop();
    }
}

void WiFiClient::stopAllExcept(WiFiClient* except)
{
    for (WiFiClient* it = _s_first; it; it = it->_next) {
        if (it != except) {
            it->stop();
        }
    }
}

void WiFiClient::keepAlive (uint16_t idle_sec, uint16_t intv_sec, uint8_t count)
{
    _client->keepAlive(idle_sec, intv_sec, count);
}

bool WiFiClient::isKeepAliveEnabled () const
{
    return _client->isKeepAliveEnabled();
}

uint16_t WiFiClient::getKeepAliveIdle () const
{
    return _client->getKeepAliveIdle();
}

uint16_t WiFiClient::getKeepAliveInterval () const
{
    return _client->getKeepAliveInterval();
}

uint8_t WiFiClient::getKeepAliveCount () const
{
    return _client->getKeepAliveCount();
}
<|endoftext|>


<commit_before>#include <eosio/chain/transaction_metadata.hpp>
#include <eosio/chain/thread_utils.hpp>
#include <boost/asio/thread_pool.hpp>

namespace eosio { namespace chain {

recovery_keys_type transaction_metadata::recover_keys( const chain_id_type& chain_id ) const {
   // Unlikely for more than one chain_id to be used in one nodeos instance
   std::unique_lock<std::mutex> g( _signing_keys_future_mtx );
   if( _signing_keys_future.valid() ) {
      const signing_keys_future_value_type& sig_keys = _signing_keys_future.get();
      if( std::get<0>( sig_keys ) == chain_id ) {
         return std::make_pair( std::get<1>( sig_keys ), std::get<2>( sig_keys ) );
      }
   }

   g.unlock();
   // shared_keys_future not created or different chain_id
   auto recovered_pub_keys = std::make_shared<flat_set<public_key_type>>();
   const signed_transaction& trn = _packed_trx->get_signed_transaction();
   fc::microseconds cpu_usage = trn.get_signature_keys( chain_id, fc::time_point::maximum(), *recovered_pub_keys );

   g.lock();
   std::promise<signing_keys_future_value_type> p;
   p.set_value( std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys ) ) );
   _signing_keys_future = p.get_future().share();

   const signing_keys_future_value_type& sig_keys = _signing_keys_future.get();
   return std::make_pair( std::get<1>( sig_keys ), std::get<2>( sig_keys ) );
}

void transaction_metadata::start_recover_keys( const transaction_metadata_ptr& mtrx,
                                               boost::asio::io_context& thread_pool,
                                               const chain_id_type& chain_id,
                                               fc::microseconds time_limit,
                                               std::function<void()> next )
{
   std::unique_lock<std::mutex> g( mtrx->_signing_keys_future_mtx );
   if( mtrx->_signing_keys_future.valid() && std::get<0>( mtrx->_signing_keys_future.get() ) == chain_id ) { // already created
      g.unlock();
      if( next ) next();
   }

   mtrx->_signing_keys_future = async_thread_pool( thread_pool, [time_limit, chain_id, mtrx, next{std::move(next)}]() {
      fc::time_point deadline = time_limit == fc::microseconds::maximum() ?
                                fc::time_point::maximum() : fc::time_point::now() + time_limit;

      auto recovered_pub_keys = std::make_shared<flat_set<public_key_type>>();
      const signed_transaction& trn = mtrx->_packed_trx->get_signed_transaction();
      fc::microseconds cpu_usage = trn.get_signature_keys( chain_id, deadline, *recovered_pub_keys );
      if( next ) next();
      return std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys ));
   } );

}

} } // eosio::chain
<commit_msg>Make sure next is called if get_signature_keys throws an exception<commit_after>#include <eosio/chain/transaction_metadata.hpp>
#include <eosio/chain/thread_utils.hpp>
#include <boost/asio/thread_pool.hpp>

namespace eosio { namespace chain {

recovery_keys_type transaction_metadata::recover_keys( const chain_id_type& chain_id ) const {
   // Unlikely for more than one chain_id to be used in one nodeos instance
   std::unique_lock<std::mutex> g( _signing_keys_future_mtx );
   if( _signing_keys_future.valid() ) {
      const signing_keys_future_value_type& sig_keys = _signing_keys_future.get();
      if( std::get<0>( sig_keys ) == chain_id ) {
         return std::make_pair( std::get<1>( sig_keys ), std::get<2>( sig_keys ) );
      }
   }

   g.unlock();
   // shared_keys_future not created or different chain_id
   wlog( "recovering keys in recover_keys" );
   auto recovered_pub_keys = std::make_shared<flat_set<public_key_type>>();
   const signed_transaction& trn = _packed_trx->get_signed_transaction();
   fc::microseconds cpu_usage = trn.get_signature_keys( chain_id, fc::time_point::maximum(), *recovered_pub_keys );

   g.lock();
   std::promise<signing_keys_future_value_type> p;
   p.set_value( std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys ) ) );
   _signing_keys_future = p.get_future().share();

   const signing_keys_future_value_type& sig_keys = _signing_keys_future.get();
   return std::make_pair( std::get<1>( sig_keys ), std::get<2>( sig_keys ) );
}

void transaction_metadata::start_recover_keys( const transaction_metadata_ptr& mtrx,
                                               boost::asio::io_context& thread_pool,
                                               const chain_id_type& chain_id,
                                               fc::microseconds time_limit,
                                               std::function<void()> next )
{
   std::unique_lock<std::mutex> g( mtrx->_signing_keys_future_mtx );
   if( mtrx->_signing_keys_future.valid() && std::get<0>( mtrx->_signing_keys_future.get() ) == chain_id ) { // already created
      g.unlock();
      if( next ) next();
      return;
   }

   mtrx->_signing_keys_future = async_thread_pool( thread_pool, [time_limit, chain_id, mtrx, next{std::move(next)}]() {
      auto recovered_pub_keys = std::make_shared<flat_set<public_key_type>>();
      fc::microseconds cpu_usage;
      try {
         fc::time_point deadline = time_limit == fc::microseconds::maximum() ?
                                   fc::time_point::maximum() : fc::time_point::now() + time_limit;

         const signed_transaction& trn = mtrx->_packed_trx->get_signed_transaction();
         cpu_usage = trn.get_signature_keys( chain_id, deadline, *recovered_pub_keys );
      } catch( ... ) {
         if( next ) next();
         throw;
      }
      if( next ) next();
      return std::make_tuple( chain_id, cpu_usage, std::move( recovered_pub_keys ));
   } );

}

} } // eosio::chain
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>

#include <LocalRegions/LocalRegions.hpp>
#include <LocalRegions/QuadExp.h>
#include <LocalRegions/TriExp.h>

using namespace Nektar;
using namespace StdRegions;
using namespace LocalRegions;
using namespace SpatialDomains;
using namespace std;

#include <SpatialDomains/QuadGeom.h>
#include <SpatialDomains/TriGeom.h>
#include <SpatialDomains/MeshComponents.h>

static double quadsol(double x1,double x2,int order1, int order2,
		      BasisType btype1, BasisType btype2);

static double trisol(double x1,double x2,int order1, int order2);

// compile using Builds/Demos/StdRegions -> make DEBUG=1 Project2D

// This routine projects a polynomial or trigonmetric functions which
// has energy in all mdoes of the expansions and reports and error

int main(int argc, char *argv[])
{

  int           i,j,k,l;
  const         double *z1,*z2,*w;
  int           order1,order2, nq1,nq2;
  PointsType    Qtype1,Qtype2;
  BasisType     btype1,btype2;
  ShapeType     regionshape;
  StdExpansion2D *E;
  double        *sol, coords[8];
  EdgeOrientation edgeDir = eForwards;

  if((argc != 16)&&(argc != 14))
  {
    fprintf(stderr,"Usage: Project2D RegionShape Type1 Type2 order1 "
	    "order2  nq1 nq2 x1, y1, x2, y2,.... \n");

    fprintf(stderr,"Where RegionShape is an integer value which "
	    "dictates the region shape:\n");
    fprintf(stderr,"\t Triangle      = 2\n");
    fprintf(stderr,"\t Quadrilateral = 3\n");

    fprintf(stderr,"Where type is an integer value which "
	    "dictates the basis as:\n");

    fprintf(stderr,"\t Ortho_A    = 0\n");
    fprintf(stderr,"\t Ortho_B    = 1\n");
    fprintf(stderr,"\t Modified_A = 3\n");
    fprintf(stderr,"\t Modified_B = 4\n");
    fprintf(stderr,"\t Fourier    = 6\n");
    fprintf(stderr,"\t Lagrange   = 7\n");
    fprintf(stderr,"\t Legendre   = 8\n");
    fprintf(stderr,"\t Chebyshev  = 9\n");

    fprintf(stderr,"Note type = 2,5 are for three-dimensional basis\n");

    fprintf(stderr,"The last series of values are the coordinates\n");
    exit(1);
  }

  regionshape = (ShapeType) atoi(argv[1]);

  // Check to see if 2D region
  if((regionshape != eTriangle)&&(regionshape != eQuadrilateral))
  {
    ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		     "This shape is not a 2D region");
  }

  btype1 = (BasisType) atoi(argv[2]);
  btype2 = (BasisType) atoi(argv[3]);

  // Check to see that correct Expansions are used
  switch(regionshape)
  {
  case eTriangle:
    if((btype1 == eOrtho_B)||(btype1 == eModified_B))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		       "Basis 1 cannot be of type Ortho_B or Modified_B");
    }

    if((btype2 != eOrtho_B)&&(btype2 != eModified_B))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		       "Basis 2 must be of type Ortho_B or Modified_B");
    }
    break;
  case eQuadrilateral:

    if((btype1 == eOrtho_B)||(btype1 == eOrtho_B)||
       (btype1 == eModified_B)||(btype1 == eModified_C))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		     "Basis 1 is for 2 or 3D expansions");
    }

    if((btype2 == eOrtho_B)||(btype2 == eOrtho_B)||
       (btype2 == eModified_B)||(btype2 == eModified_C))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		       "Basis 2 is for 2 or 3D expansions");
    }
    break;
  }

  order1 =   atoi(argv[4]);
  order2 =   atoi(argv[5]);
  nq1    =   atoi(argv[6]);
  nq2    =   atoi(argv[7]);

  sol    = new double [nq1*nq2];

  if(btype1 != eFourier)
  {
    Qtype1 = eLobatto;
  }
  else
  {
    Qtype1 = eFourierEvenSp;
  }

  if(btype2 != eFourier)
  {
    Qtype2 = eLobatto;
  }
  else
  {
    Qtype2 = eFourierEvenSp;
  }

  //-----------------------------------------------
  // Define a segment expansion based on basis definition

  switch(regionshape)
  {
  case eTriangle:
  {
    coords[0]    =   atof(argv[8]);
    coords[1]    =   atof(argv[9]);
    coords[2]    =   atof(argv[10]);
    coords[3]    =   atof(argv[11]);
    coords[4]    =   atof(argv[12]);
    coords[5]    =   atof(argv[13]);

    // Set up coordinates
    VertexComponentSharedPtr verts[3];
    verts[0] = SharedVertexPtr(new VertexComponent(2,0,coords[0],coords[1],0));
    verts[1] = SharedVertexPtr(new VertexComponent(2,1,coords[2],coords[3],0));
    verts[2] = SharedVertexPtr(new VertexComponent(2,2,coords[4],coords[5],0));

    // Set up Edges
    EdgeComponentSharedPtr edges[3];
    edges[0] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[1] = EdgeComponentSharedPtr(new EdgeComponent(1,2));
    edges[2] = EdgeComponentSharedPtr(new EdgeComponent(2,2));

    EdgeOrientation eorient[3];

    eorient[0] = edgeDir;
    eorient[1] = edgeDir;
    eorient[2] = edgeDir;

    TriGeom *geom = new TriGeom(verts,edges,eorient);
    geom->SetOwnData();

    const BasisKey b1(btype1,order1,Qtype1,nq1,0,0);
    const BasisKey b2(btype2,order2,Qtype2,nq2,1,0);

    E = new TriExp(b1,b2,geom);
    E->SetGeoFac(E->GenGeoFac());

    E->GetZW(0,z1,w);
    E->GetZW(1,z2,w);

    //----------------------------------------------
    // Define solution to be projected

    double *xc[2];
    xc[0] = new double [2*nq1*nq2];
    xc[1] = xc[0] + nq1*nq2;
    E->GetCoords(xc);

    for(i = 0; i < nq1; ++i)
    {
      for(j = 0; j < nq2; ++j)
      {
	sol[i+nq1*j] = trisol(xc[0][j*nq1+i],xc[1][j*nq1+i],
			       order1,order2);
      }
    }
    delete[] xc[0];
    //----------------------------------------------
  }
  break;
  case eQuadrilateral:
  {
    // Gather coordinates
    coords[0]    =   atof(argv[8]);
    coords[1]    =   atof(argv[9]);
    coords[2]    =   atof(argv[10]);
    coords[3]    =   atof(argv[11]);
    coords[4]    =   atof(argv[12]);
    coords[5]    =   atof(argv[13]);
    coords[6]    =   atof(argv[14]);
    coords[7]    =   atof(argv[15]);

    // Set up coordinates
    VertexComponentSharedPtr verts[4];
    verts[0] = SharedVertexPtr(new VertexComponent(2,0,coords[0],coords[1],0));
    verts[1] = SharedVertexPtr(new VertexComponent(2,1,coords[2],coords[3],0));
    verts[2] = SharedVertexPtr(new VertexComponent(2,2,coords[4],coords[5],0));
    verts[3] = SharedVertexPtr(new VertexComponent(2,3,coords[6],coords[7],0));

    // Set up Edges
    EdgeComponentSharedPtr edges[4];
    edges[0] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[1] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[2] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[3] = EdgeComponentSharedPtr(new EdgeComponent(0,2));

    EdgeOrientation eorient[4];

    eorient[0] = edgeDir;
    eorient[1] = edgeDir;
    eorient[2] = edgeDir;
    eorient[3] = edgeDir;

    QuadGeom *geom = new QuadGeom(verts,edges,eorient);
    geom->SetOwnData();

    // Define basis
    const BasisKey b1(btype1,order1,Qtype1,nq1,0,0);
    const BasisKey b2(btype2,order2,Qtype2,nq2,0,0);

    E = new QuadExp(b1,b2,geom);
    E->SetGeoFac(E->GenGeoFac());

    //----------------------------------------------
    // Define solution to be projected

    E->GetZW(0,z1,w);
    E->GetZW(1,z2,w);

    double *xc[2];
    xc[0] = new double [2*nq1*nq2];
    xc[1] = xc[0] + nq1*nq2;
    E->GetCoords(xc);

    for(i = 0; i < nq1; ++i)
    {
      for(j = 0; j < nq2; ++j)
      {
	sol[i+nq1*j] = quadsol(xc[0][j*nq1+i],xc[1][j*nq1+i],
			       order1,order2,btype1,btype2);
      }
    }

    delete[] xc[0];
    //---------------------------------------------
  }

  break;
  }

  //---------------------------------------------
  // Project onto Expansion
  E->FwdTrans(sol);
  //---------------------------------------------

  //-------------------------------------------
  // Backward Transform Solution to get projected values
  E->BwdTrans(E->GetPhys());
  //-------------------------------------------

  //--------------------------------------------
  // Write solution
  FILE *outfile = fopen("ProjectFile2D.dat","w");
  E->WriteToFile(outfile);
  fclose(outfile);
  //-------------------------------------------

  //--------------------------------------------
  // Calculate L_inf error
  cout << "L infinity error: " << E->Linf(sol) << endl;
  cout << "L 2 error:        " << E->L2  (sol) << endl;
  //--------------------------------------------

  //-------------------------------------------
  // Evaulate solution at x = y =0  and print error

  double x[2];
  x[0] = (coords[0] + coords[2])*0.5;
  x[1] = (coords[1] + coords[5])*0.5;
  double nsol = E->Evaluate(x);

  if(regionshape == eTriangle)
  {
    sol[0] = trisol(x[0],x[1],order1,order2);
  }
  else
  {
    sol[0] = quadsol(x[0],x[1],order1,order2,btype1,btype2);
  }

  cout << "error at (x,y) = " << x[0] << "," << x[1] << " : "
       << nsol - sol[0] << endl;

  //-------------------------------------------

  delete[] sol;
  return 0;
}

static double quadsol(double x1,double x2,int order1, int order2,
		      BasisType btype1, BasisType btype2)
{
  int k,l;
  double sol = 0.0;

  if(btype1 != eFourier)
  {
    if(btype2 != eFourier)
    {
      for(k = 0; k < order1; ++k)
      {
	for(l = 0; l < order2; ++l)
	{
	  sol += pow(x1,k)*pow(x2,l);
	}
      }
    }
    else
    {
      for(k = 0; k < order1; ++k)
      {
	for(l = 0; l < order2/2; ++l)
	{
	  sol += pow(x1,k)*sin(M_PI*l*x2)
		  + pow(x1,k)*cos(M_PI*l*x2);
	}
      }
    }
  }
  else
  {
    if(btype2 != eFourier)
    {
      for(k = 0; k < order1/2; ++k)
      {
	for(l = 0; l < order2; ++l)
	{
	  sol += sin(M_PI*k*x1)*pow(x2,l)
	    + cos(M_PI*k*x1)*pow(x2,l);
	}
      }
    }
    else
    {
      for(k = 0; k < order1/2; ++k)
      {
	for(l = 0; l < order2/2; ++l)
	{
	  sol += sin(M_PI*k*x1)*sin(M_PI*l*x2)
	    + sin(M_PI*k*x1)*cos(M_PI*l*x2)
	    + cos(M_PI*k*x1)*sin(M_PI*l*x2)
	    + cos(M_PI*k*x1)*cos(M_PI*l*x2);
	}
      }
    }
  }

  return sol;

}

static double trisol(double x1,double x2,int order1, int order2)
{
  int k,l;
  double sol = 0.0;

  // activate all modes
  for(k = 0; k < order1; ++k)
  {
    for(l = 0; l < order2-k; ++l)
    {
      sol += pow(x1,k)*pow(x2,l);
    }
  }

  return sol;
}
<commit_msg>Updated VertexSharedPtr to VertexComponentSharedPtr<commit_after>#include <cstdio>
#include <cstdlib>

#include <LocalRegions/LocalRegions.hpp>
#include <LocalRegions/QuadExp.h>
#include <LocalRegions/TriExp.h>

using namespace Nektar;
using namespace StdRegions;
using namespace LocalRegions;
using namespace SpatialDomains;
using namespace std;

#include <SpatialDomains/QuadGeom.h>
#include <SpatialDomains/TriGeom.h>
#include <SpatialDomains/MeshComponents.h>

static double quadsol(double x1,double x2,int order1, int order2,
		      BasisType btype1, BasisType btype2);

static double trisol(double x1,double x2,int order1, int order2);

// compile using Builds/Demos/StdRegions -> make DEBUG=1 Project2D

// This routine projects a polynomial or trigonmetric functions which
// has energy in all mdoes of the expansions and reports and error

int main(int argc, char *argv[])
{

  int           i,j,k,l;
  const         double *z1,*z2,*w;
  int           order1,order2, nq1,nq2;
  PointsType    Qtype1,Qtype2;
  BasisType     btype1,btype2;
  ShapeType     regionshape;
  StdExpansion2D *E;
  double        *sol, coords[8];
  EdgeOrientation edgeDir = eForwards;

  if((argc != 16)&&(argc != 14))
  {
    fprintf(stderr,"Usage: Project2D RegionShape Type1 Type2 order1 "
	    "order2  nq1 nq2 x1, y1, x2, y2,.... \n");

    fprintf(stderr,"Where RegionShape is an integer value which "
	    "dictates the region shape:\n");
    fprintf(stderr,"\t Triangle      = 2\n");
    fprintf(stderr,"\t Quadrilateral = 3\n");

    fprintf(stderr,"Where type is an integer value which "
	    "dictates the basis as:\n");

    fprintf(stderr,"\t Ortho_A    = 0\n");
    fprintf(stderr,"\t Ortho_B    = 1\n");
    fprintf(stderr,"\t Modified_A = 3\n");
    fprintf(stderr,"\t Modified_B = 4\n");
    fprintf(stderr,"\t Fourier    = 6\n");
    fprintf(stderr,"\t Lagrange   = 7\n");
    fprintf(stderr,"\t Legendre   = 8\n");
    fprintf(stderr,"\t Chebyshev  = 9\n");

    fprintf(stderr,"Note type = 2,5 are for three-dimensional basis\n");

    fprintf(stderr,"The last series of values are the coordinates\n");
    exit(1);
  }

  regionshape = (ShapeType) atoi(argv[1]);

  // Check to see if 2D region
  if((regionshape != eTriangle)&&(regionshape != eQuadrilateral))
  {
    ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		     "This shape is not a 2D region");
  }

  btype1 = (BasisType) atoi(argv[2]);
  btype2 = (BasisType) atoi(argv[3]);

  // Check to see that correct Expansions are used
  switch(regionshape)
  {
  case eTriangle:
    if((btype1 == eOrtho_B)||(btype1 == eModified_B))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		       "Basis 1 cannot be of type Ortho_B or Modified_B");
    }

    if((btype2 != eOrtho_B)&&(btype2 != eModified_B))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		       "Basis 2 must be of type Ortho_B or Modified_B");
    }
    break;
  case eQuadrilateral:

    if((btype1 == eOrtho_B)||(btype1 == eOrtho_B)||
       (btype1 == eModified_B)||(btype1 == eModified_C))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		     "Basis 1 is for 2 or 3D expansions");
    }

    if((btype2 == eOrtho_B)||(btype2 == eOrtho_B)||
       (btype2 == eModified_B)||(btype2 == eModified_C))
    {
      ErrorUtil::Error(ErrorUtil::efatal,__FILE__,__LINE__,
		       "Basis 2 is for 2 or 3D expansions");
    }
    break;
  }

  order1 =   atoi(argv[4]);
  order2 =   atoi(argv[5]);
  nq1    =   atoi(argv[6]);
  nq2    =   atoi(argv[7]);

  sol    = new double [nq1*nq2];

  if(btype1 != eFourier)
  {
    Qtype1 = eLobatto;
  }
  else
  {
    Qtype1 = eFourierEvenSp;
  }

  if(btype2 != eFourier)
  {
    Qtype2 = eLobatto;
  }
  else
  {
    Qtype2 = eFourierEvenSp;
  }

  //-----------------------------------------------
  // Define a segment expansion based on basis definition

  switch(regionshape)
  {
  case eTriangle:
  {
    coords[0]    =   atof(argv[8]);
    coords[1]    =   atof(argv[9]);
    coords[2]    =   atof(argv[10]);
    coords[3]    =   atof(argv[11]);
    coords[4]    =   atof(argv[12]);
    coords[5]    =   atof(argv[13]);

    // Set up coordinates
    VertexComponentSharedPtr verts[3];
    verts[0] = VertexComponentSharedPtr(new VertexComponent(2,0,coords[0],coords[1],0));
    verts[1] = VertexComponentSharedPtr(new VertexComponent(2,1,coords[2],coords[3],0));
    verts[2] = VertexComponentSharedPtr(new VertexComponent(2,2,coords[4],coords[5],0));

    // Set up Edges
    EdgeComponentSharedPtr edges[3];
    edges[0] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[1] = EdgeComponentSharedPtr(new EdgeComponent(1,2));
    edges[2] = EdgeComponentSharedPtr(new EdgeComponent(2,2));

    EdgeOrientation eorient[3];

    eorient[0] = edgeDir;
    eorient[1] = edgeDir;
    eorient[2] = edgeDir;

    TriGeom *geom = new TriGeom(verts,edges,eorient);
    geom->SetOwnData();

    const BasisKey b1(btype1,order1,Qtype1,nq1,0,0);
    const BasisKey b2(btype2,order2,Qtype2,nq2,1,0);

    E = new TriExp(b1,b2,geom);
    E->SetGeoFac(E->GenGeoFac());

    E->GetZW(0,z1,w);
    E->GetZW(1,z2,w);

    //----------------------------------------------
    // Define solution to be projected

    double *xc[2];
    xc[0] = new double [2*nq1*nq2];
    xc[1] = xc[0] + nq1*nq2;
    E->GetCoords(xc);

    for(i = 0; i < nq1; ++i)
    {
      for(j = 0; j < nq2; ++j)
      {
	sol[i+nq1*j] = trisol(xc[0][j*nq1+i],xc[1][j*nq1+i],
			       order1,order2);
      }
    }
    delete[] xc[0];
    //----------------------------------------------
  }
  break;
  case eQuadrilateral:
  {
    // Gather coordinates
    coords[0]    =   atof(argv[8]);
    coords[1]    =   atof(argv[9]);
    coords[2]    =   atof(argv[10]);
    coords[3]    =   atof(argv[11]);
    coords[4]    =   atof(argv[12]);
    coords[5]    =   atof(argv[13]);
    coords[6]    =   atof(argv[14]);
    coords[7]    =   atof(argv[15]);

    // Set up coordinates
    VertexComponentSharedPtr verts[4];
    verts[0] = VertexComponentSharedPtr(new VertexComponent(2,0,coords[0],coords[1],0));
    verts[1] = VertexComponentSharedPtr(new VertexComponent(2,1,coords[2],coords[3],0));
    verts[2] = VertexComponentSharedPtr(new VertexComponent(2,2,coords[4],coords[5],0));
    verts[3] = VertexComponentSharedPtr(new VertexComponent(2,3,coords[6],coords[7],0));

    // Set up Edges
    EdgeComponentSharedPtr edges[4];
    edges[0] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[1] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[2] = EdgeComponentSharedPtr(new EdgeComponent(0,2));
    edges[3] = EdgeComponentSharedPtr(new EdgeComponent(0,2));

    EdgeOrientation eorient[4];

    eorient[0] = edgeDir;
    eorient[1] = edgeDir;
    eorient[2] = edgeDir;
    eorient[3] = edgeDir;

    QuadGeom *geom = new QuadGeom(verts,edges,eorient);
    geom->SetOwnData();

    // Define basis
    const BasisKey b1(btype1,order1,Qtype1,nq1,0,0);
    const BasisKey b2(btype2,order2,Qtype2,nq2,0,0);

    E = new QuadExp(b1,b2,geom);
    E->SetGeoFac(E->GenGeoFac());

    //----------------------------------------------
    // Define solution to be projected

    E->GetZW(0,z1,w);
    E->GetZW(1,z2,w);

    double *xc[2];
    xc[0] = new double [2*nq1*nq2];
    xc[1] = xc[0] + nq1*nq2;
    E->GetCoords(xc);

    for(i = 0; i < nq1; ++i)
    {
      for(j = 0; j < nq2; ++j)
      {
	sol[i+nq1*j] = quadsol(xc[0][j*nq1+i],xc[1][j*nq1+i],
			       order1,order2,btype1,btype2);
      }
    }

    delete[] xc[0];
    //---------------------------------------------
  }

  break;
  }

  //---------------------------------------------
  // Project onto Expansion
  E->FwdTrans(sol);
  //---------------------------------------------

  //-------------------------------------------
  // Backward Transform Solution to get projected values
  E->BwdTrans(E->GetPhys());
  //-------------------------------------------

  //--------------------------------------------
  // Write solution
  FILE *outfile = fopen("ProjectFile2D.dat","w");
  E->WriteToFile(outfile);
  fclose(outfile);
  //-------------------------------------------

  //--------------------------------------------
  // Calculate L_inf error
  cout << "L infinity error: " << E->Linf(sol) << endl;
  cout << "L 2 error:        " << E->L2  (sol) << endl;
  //--------------------------------------------

  //-------------------------------------------
  // Evaulate solution at x = y =0  and print error

  double x[2];
  x[0] = (coords[0] + coords[2])*0.5;
  x[1] = (coords[1] + coords[5])*0.5;
  double nsol = E->Evaluate(x);

  if(regionshape == eTriangle)
  {
    sol[0] = trisol(x[0],x[1],order1,order2);
  }
  else
  {
    sol[0] = quadsol(x[0],x[1],order1,order2,btype1,btype2);
  }

  cout << "error at (x,y) = " << x[0] << "," << x[1] << " : "
       << nsol - sol[0] << endl;

  //-------------------------------------------

  delete[] sol;
  return 0;
}

static double quadsol(double x1,double x2,int order1, int order2,
		      BasisType btype1, BasisType btype2)
{
  int k,l;
  double sol = 0.0;

  if(btype1 != eFourier)
  {
    if(btype2 != eFourier)
    {
      for(k = 0; k < order1; ++k)
      {
	for(l = 0; l < order2; ++l)
	{
	  sol += pow(x1,k)*pow(x2,l);
	}
      }
    }
    else
    {
      for(k = 0; k < order1; ++k)
      {
	for(l = 0; l < order2/2; ++l)
	{
	  sol += pow(x1,k)*sin(M_PI*l*x2)
		  + pow(x1,k)*cos(M_PI*l*x2);
	}
      }
    }
  }
  else
  {
    if(btype2 != eFourier)
    {
      for(k = 0; k < order1/2; ++k)
      {
	for(l = 0; l < order2; ++l)
	{
	  sol += sin(M_PI*k*x1)*pow(x2,l)
	    + cos(M_PI*k*x1)*pow(x2,l);
	}
      }
    }
    else
    {
      for(k = 0; k < order1/2; ++k)
      {
	for(l = 0; l < order2/2; ++l)
	{
	  sol += sin(M_PI*k*x1)*sin(M_PI*l*x2)
	    + sin(M_PI*k*x1)*cos(M_PI*l*x2)
	    + cos(M_PI*k*x1)*sin(M_PI*l*x2)
	    + cos(M_PI*k*x1)*cos(M_PI*l*x2);
	}
      }
    }
  }

  return sol;

}

static double trisol(double x1,double x2,int order1, int order2)
{
  int k,l;
  double sol = 0.0;

  // activate all modes
  for(k = 0; k < order1; ++k)
  {
    for(l = 0; l < order2-k; ++l)
    {
      sol += pow(x1,k)*pow(x2,l);
    }
  }

  return sol;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Gustaf Räntilä
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <q/pp.hpp>
#include <q/abi.hpp>

#ifdef LIBQ_ON_ANDROID

#include "stacktrace.hpp"

#include <unwind.h>
#include <dlfcn.h>

namespace q { namespace detail {

stacktrace default_stacktrace( ) noexcept
{
	static const std::size_t buflen = 128;
	struct stack {
		std::size_t size = 0;
		void* addresses[ buflen ];
	};
	stack s;

	_Unwind_Backtrace( [ ]( struct _Unwind_Context* context, void* arg)
	{
		uintptr_t pc = _Unwind_GetIP( context );
		stack* s = static_cast< stack* >( arg );
		if ( pc )
		{
			if ( s->size == buflen )
				return _URC_END_OF_STACK;
			s->addresses[ s->size++ ] =
				reinterpret_cast< void* >( pc );
		}
		return _URC_NO_REASON;
	}, &s );

	std::vector< stacktrace::frame > frames;
	frames.reserve( s.size );

	for ( std::size_t i = 0; i < s.size; ++i )
	{
		stacktrace::frame frame;
		Dl_info info;
		if ( dladdr( s.addresses[ i ], &info ) && info.dli_sname )
			frame.symbol = info.dli_sname;
		frame.addr =
			reinterpret_cast< std::uint64_t >( s.addresses[ i ] );
		frame.frameno = i;
		frames.push_back( frame );
	}

	return stacktrace( std::move( frames ) );
}

} } // namespace detail, namespace q

#endif // LIBQ_ON_ANDROID
<commit_msg>stacktrace: demangling of function names for android<commit_after>/*
 * Copyright 2013 Gustaf Räntilä
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <q/pp.hpp>
#include <q/abi.hpp>

#ifdef LIBQ_ON_ANDROID

#include "stacktrace.hpp"

#include <unwind.h>
#include <dlfcn.h>

namespace q { namespace detail {

stacktrace default_stacktrace( ) noexcept
{
	static const std::size_t buflen = 128;
	struct stack {
		std::size_t size = 0;
		void* addresses[ buflen ];
	};
	stack s;

	_Unwind_Backtrace( [ ]( struct _Unwind_Context* context, void* arg)
	{
		uintptr_t pc = _Unwind_GetIP( context );
		stack* s = static_cast< stack* >( arg );
		if ( pc )
		{
			if ( s->size == buflen )
				return _URC_END_OF_STACK;
			s->addresses[ s->size++ ] =
				reinterpret_cast< void* >( pc );
		}
		return _URC_NO_REASON;
	}, &s );

	std::vector< stacktrace::frame > frames;
	frames.reserve( s.size );

	for ( std::size_t i = 0; i < s.size; ++i )
	{
		stacktrace::frame frame;
		Dl_info info;
		if ( dladdr( s.addresses[ i ], &info ) && info.dli_sname )
			frame.symbol = info.dli_sname;
		auto demanged = demangle_cxx( frame.symbol.c_str( ) );
		if ( !demanged.empty( ) )
			frame.symbol = demanged;
		frame.addr =
			reinterpret_cast< std::uint64_t >( s.addresses[ i ] );
		frame.frameno = i;
		frames.push_back( frame );
	}

	return stacktrace( std::move( frames ) );
}

} } // namespace detail, namespace q

#endif // LIBQ_ON_ANDROID
<|endoftext|>