<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/openni_camera/openni_driver.h>
#include <pcl/filters/approximate_voxel_grid.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/console/parse.h>
#include <pcl/common/time.h>

#define FPS_CALC(_WHAT_) \
do \
{ \
    static unsigned count = 0;\
    static double last = pcl::getTime ();\
    double now = pcl::getTime (); \
    ++count; \
    if (now - last >= 1.0) \
    { \
      std::cout << "Average framerate("<< _WHAT_ << "): " << double(count)/double(now - last) << " Hz" <<  std::endl; \
      count = 0; \
      last = now; \
    } \
}while(false)

template <typename PointType>
class OpenNIVoxelGrid
{
  public:
    typedef pcl::PointCloud<PointType> Cloud;
    typedef typename Cloud::Ptr CloudPtr;
    typedef typename Cloud::ConstPtr CloudConstPtr;

    OpenNIVoxelGrid (const std::string& device_id = "",
                     const std::string& field_name = "z", float min_v = 0, float max_v = 5.0,
                     float leaf_size_x = 0.01, float leaf_size_y = 0.01, float leaf_size_z = 0.01)
    : viewer ("PCL OpenNI VoxelGrid Viewer")
    , device_id_(device_id)
    {
      grid_.setLeafSize (leaf_size_x, leaf_size_y, leaf_size_z);
      grid_.setFilterFieldName (field_name);
      grid_.setFilterLimits (min_v, max_v);
    }

    void
    cloud_cb_ (const CloudConstPtr& cloud)
    {
      set (cloud);
    }

    void
    set (const CloudConstPtr& cloud)
    {
      //lock while we set our cloud;
      boost::mutex::scoped_lock lock (mtx_);
      cloud_  = cloud;
    }

    CloudPtr
    get ()
    {
      //lock while we swap our cloud and reset it.
      boost::mutex::scoped_lock lock (mtx_);
      CloudPtr temp_cloud (new Cloud);

      grid_.setInputCloud (cloud_);
      grid_.filter (*temp_cloud);

      return (temp_cloud);
    }

    void
    run ()
    {
      pcl::Grabber* interface = new pcl::OpenNIGrabber (device_id_);

      boost::function<void (const CloudConstPtr&)> f = boost::bind (&OpenNIVoxelGrid::cloud_cb_, this, _1);
      boost::signals2::connection c = interface->registerCallback (f);

      interface->start ();

      while (!viewer.wasStopped ())
      {
        if (cloud_)
        {
          FPS_CALC ("drawing");
          //the call to get() sets the cloud_ to null;
          viewer.showCloud (get ());
        }
      }

      interface->stop ();
    }

    pcl::ApproximateVoxelGrid<PointType> grid_;
    pcl::visualization::CloudViewer viewer;
    std::string device_id_;
    boost::mutex mtx_;
    CloudConstPtr cloud_;
};

void
usage (char ** argv)
{
  std::cout << "usage: " << argv[0] << " <device_id> <options>\n\n"
            << "where options are:\n         -minmax min-max  :: set the ApproximateVoxelGrid min-max cutting values (default: 0-5.0)\n"
            <<                     "         -field  X        :: use field/dimension 'X' to filter data on (default: 'z')\n"

            << "                             -leaf x, y, z  :: set the ApproximateVoxelGrid leaf size (default: 0.01)\n";

  openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
  if (driver.getNumberDevices () > 0)
  {
    for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
    {
      cout << "Device: " << deviceIdx + 1 << ", vendor: " << driver.getVendorName (deviceIdx) << ", product: " << driver.getProductName (deviceIdx)
              << ", connected: " << (int)driver.getBus (deviceIdx) << " @ " << (int)driver.getAddress (deviceIdx) << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'" << endl;
      cout << "device_id may be #1, #2, ... for the first second etc device in the list or" << endl
           << "                 bus@address for the device connected to a specific usb-bus / address combination (works only in Linux) or" << endl
           << "                 <serial-number> (only in Linux and for devices which provide serial numbers)"  << endl;
    }
  }
  else
    cout << "No devices connected." << endl;
}

int
main (int argc, char ** argv)
{
  if (pcl::console::find_argument (argc, argv, "-h") != -1)
    usage (argv);

  double min_v = 0, max_v = 5.0;
  pcl::console::parse_2x_arguments (argc, argv, "-minmax", min_v, max_v, false);
  std::string field_name ("z");
  pcl::console::parse_argument (argc, argv, "-field", field_name);
  PCL_INFO ("Filtering data on %s between %f -> %f.\n", field_name.c_str (), min_v, max_v);
  double leaf_x = 0.01, leaf_y = 0.01, leaf_z = 0.01;
  pcl::console::parse_3x_arguments (argc, argv, "-leaf", leaf_x, leaf_y, leaf_z, false);
  PCL_INFO ("Using %f, %f, %f as a leaf size for VoxelGrid.\n", leaf_x, leaf_y, leaf_z);

  pcl::OpenNIGrabber grabber ("");
  if (grabber.providesCallback<pcl::OpenNIGrabber::sig_cb_openni_point_cloud_rgb> ())
  {
    OpenNIVoxelGrid<pcl::PointXYZRGB> v ("", field_name, min_v, max_v, leaf_x, leaf_y, leaf_z);
    v.run ();
  }
  else
  {
    OpenNIVoxelGrid<pcl::PointXYZ> v ("", field_name, min_v, max_v, leaf_x, leaf_y, leaf_z);
    v.run ();
  }

  return (0);
}
<commit_msg>fixed a compiler error<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/openni_camera/openni_driver.h>
#include <pcl/filters/approximate_voxel_grid.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/console/parse.h>
#include <pcl/common/time.h>

#define FPS_CALC(_WHAT_) \
do \
{ \
    static unsigned count = 0;\
    static double last = pcl::getTime ();\
    double now = pcl::getTime (); \
    ++count; \
    if (now - last >= 1.0) \
    { \
      std::cout << "Average framerate("<< _WHAT_ << "): " << double(count)/double(now - last) << " Hz" <<  std::endl; \
      count = 0; \
      last = now; \
    } \
}while(false)

template <typename PointType>
class OpenNIVoxelGrid
{
  public:
    typedef pcl::PointCloud<PointType> Cloud;
    typedef typename Cloud::Ptr CloudPtr;
    typedef typename Cloud::ConstPtr CloudConstPtr;

    OpenNIVoxelGrid (const std::string& device_id = "",
                     const std::string& field_name = "z", float min_v = 0, float max_v = 5.0,
                     float leaf_size_x = 0.01, float leaf_size_y = 0.01, float leaf_size_z = 0.01)
    : viewer ("PCL OpenNI VoxelGrid Viewer")
    , device_id_(device_id)
    {
      grid_.setLeafSize (leaf_size_x, leaf_size_y, leaf_size_z);
      //grid_.setFilterFieldName (field_name);
      //grid_.setFilterLimits (min_v, max_v);
    }

    void
    cloud_cb_ (const CloudConstPtr& cloud)
    {
      set (cloud);
    }

    void
    set (const CloudConstPtr& cloud)
    {
      //lock while we set our cloud;
      boost::mutex::scoped_lock lock (mtx_);
      cloud_  = cloud;
    }

    CloudPtr
    get ()
    {
      //lock while we swap our cloud and reset it.
      boost::mutex::scoped_lock lock (mtx_);
      CloudPtr temp_cloud (new Cloud);

      grid_.setInputCloud (cloud_);
      grid_.filter (*temp_cloud);

      return (temp_cloud);
    }

    void
    run ()
    {
      pcl::Grabber* interface = new pcl::OpenNIGrabber (device_id_);

      boost::function<void (const CloudConstPtr&)> f = boost::bind (&OpenNIVoxelGrid::cloud_cb_, this, _1);
      boost::signals2::connection c = interface->registerCallback (f);

      interface->start ();

      while (!viewer.wasStopped ())
      {
        if (cloud_)
        {
          FPS_CALC ("drawing");
          //the call to get() sets the cloud_ to null;
          viewer.showCloud (get ());
        }
      }

      interface->stop ();
    }

    pcl::ApproximateVoxelGrid<PointType> grid_;
    pcl::visualization::CloudViewer viewer;
    std::string device_id_;
    boost::mutex mtx_;
    CloudConstPtr cloud_;
};

void
usage (char ** argv)
{
  std::cout << "usage: " << argv[0] << " <device_id> <options>\n\n"
            << "where options are:\n         -minmax min-max  :: set the ApproximateVoxelGrid min-max cutting values (default: 0-5.0)\n"
            <<                     "         -field  X        :: use field/dimension 'X' to filter data on (default: 'z')\n"

            << "                             -leaf x, y, z  :: set the ApproximateVoxelGrid leaf size (default: 0.01)\n";

  openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
  if (driver.getNumberDevices () > 0)
  {
    for (unsigned deviceIdx = 0; deviceIdx < driver.getNumberDevices (); ++deviceIdx)
    {
      cout << "Device: " << deviceIdx + 1 << ", vendor: " << driver.getVendorName (deviceIdx) << ", product: " << driver.getProductName (deviceIdx)
              << ", connected: " << (int)driver.getBus (deviceIdx) << " @ " << (int)driver.getAddress (deviceIdx) << ", serial number: \'" << driver.getSerialNumber (deviceIdx) << "\'" << endl;
      cout << "device_id may be #1, #2, ... for the first second etc device in the list or" << endl
           << "                 bus@address for the device connected to a specific usb-bus / address combination (works only in Linux) or" << endl
           << "                 <serial-number> (only in Linux and for devices which provide serial numbers)"  << endl;
    }
  }
  else
    cout << "No devices connected." << endl;
}

int
main (int argc, char ** argv)
{
  if (pcl::console::find_argument (argc, argv, "-h") != -1)
    usage (argv);

  double min_v = 0, max_v = 5.0;
  pcl::console::parse_2x_arguments (argc, argv, "-minmax", min_v, max_v, false);
  std::string field_name ("z");
  pcl::console::parse_argument (argc, argv, "-field", field_name);
  PCL_INFO ("Filtering data on %s between %f -> %f.\n", field_name.c_str (), min_v, max_v);
  double leaf_x = 0.01, leaf_y = 0.01, leaf_z = 0.01;
  pcl::console::parse_3x_arguments (argc, argv, "-leaf", leaf_x, leaf_y, leaf_z, false);
  PCL_INFO ("Using %f, %f, %f as a leaf size for VoxelGrid.\n", leaf_x, leaf_y, leaf_z);

  pcl::OpenNIGrabber grabber ("");
  if (grabber.providesCallback<pcl::OpenNIGrabber::sig_cb_openni_point_cloud_rgb> ())
  {
    OpenNIVoxelGrid<pcl::PointXYZRGB> v ("", field_name, min_v, max_v, leaf_x, leaf_y, leaf_z);
    v.run ();
  }
  else
  {
    OpenNIVoxelGrid<pcl::PointXYZ> v ("", field_name, min_v, max_v, leaf_x, leaf_y, leaf_z);
    v.run ();
  }

  return (0);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: durationhdl.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2008-03-12 10:51:02 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _XMLOFF_PROPERTYHANDLER_DURATIONS_HXX
#include "durationhdl.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _COM_SUN_STAR_UTIL_DATETIME_HPP_
#include <com/sun/star/util/DateTime.hpp>
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

#ifndef _XMLOFF_XMLUCONV_HXX
#include <xmloff/xmluconv.hxx>
#endif

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;

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

sal_Bool XMLDurationMS16PropHdl_Impl::importXML(
        const OUString& rStrImpValue,
           Any& rValue,
        const SvXMLUnitConverter& ) const
{
    DateTime aTime;
    if( !SvXMLUnitConverter::convertTime( aTime,  rStrImpValue ) )
        return false;

    const sal_Int16 nMS = ( ( aTime.Hours * 60 + aTime.Minutes ) * 60 + aTime.Seconds ) * 100 + aTime.HundredthSeconds;
    rValue <<= nMS;

    return sal_True;
}

sal_Bool XMLDurationMS16PropHdl_Impl::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& ) const
{
    sal_Int16 nMS = sal_Int16();

    if(rValue >>= nMS)
    {
        OUStringBuffer aOut;
        DateTime aTime( nMS, 0, 0, 0, 0, 0, 0 );
        SvXMLUnitConverter::convertTime( aOut, aTime );
        rStrExpValue = aOut.makeStringAndClear();
        return sal_True;
    }

    return sal_False;
}

XMLDurationMS16PropHdl_Impl::~XMLDurationMS16PropHdl_Impl()
{
}
<commit_msg>INTEGRATION: CWS changefileheader (1.7.18); FILE MERGED 2008/04/01 16:09:55 thb 1.7.18.3: #i85898# Stripping all external header guards 2008/04/01 13:05:02 thb 1.7.18.2: #i85898# Stripping all external header guards 2008/03/31 16:28:22 rt 1.7.18.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: durationhdl.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"
#include "durationhdl.hxx"
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/util/DateTime.hpp>
#include <rtl/ustrbuf.hxx>
#include <xmloff/xmluconv.hxx>

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;

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

sal_Bool XMLDurationMS16PropHdl_Impl::importXML(
        const OUString& rStrImpValue,
           Any& rValue,
        const SvXMLUnitConverter& ) const
{
    DateTime aTime;
    if( !SvXMLUnitConverter::convertTime( aTime,  rStrImpValue ) )
        return false;

    const sal_Int16 nMS = ( ( aTime.Hours * 60 + aTime.Minutes ) * 60 + aTime.Seconds ) * 100 + aTime.HundredthSeconds;
    rValue <<= nMS;

    return sal_True;
}

sal_Bool XMLDurationMS16PropHdl_Impl::exportXML(
        OUString& rStrExpValue,
        const Any& rValue,
        const SvXMLUnitConverter& ) const
{
    sal_Int16 nMS = sal_Int16();

    if(rValue >>= nMS)
    {
        OUStringBuffer aOut;
        DateTime aTime( nMS, 0, 0, 0, 0, 0, 0 );
        SvXMLUnitConverter::convertTime( aOut, aTime );
        rStrExpValue = aOut.makeStringAndClear();
        return sal_True;
    }

    return sal_False;
}

XMLDurationMS16PropHdl_Impl::~XMLDurationMS16PropHdl_Impl()
{
}
<|endoftext|>


<commit_before>#include "sipfieldparsing.h"

#include "sipconversions.h"

#include <QRegularExpression>
#include <QDebug>

// TODO: Support SIPS uri scheme. Needed for TLS
bool parseURI(QString values, SIP_URI& uri);
bool parseParameterNameToValue(std::shared_ptr<QList<SIPParameter>> parameters,
                               QString name, QString& value);
bool parseUint(QString values, uint& number);

bool parseURI(QString values, SIP_URI& uri)
{
  // RFC3261_TODO: Try to understand other than sip: addresses such as "tel:" and give error?

  // TLS TODO: Support sips
  QRegularExpression re_field("(\\w+ )?<sip:(\\w+)@([\\w\.:]+)>");
  QRegularExpressionMatch field_match = re_field.match(values);

  if(field_match.hasMatch() && (field_match.lastCapturedIndex() == 4
          || field_match.lastCapturedIndex() == 3))
  {
    uri.realname = field_match.captured(1);
    uri.username = field_match.captured(2);
    uri.host = field_match.captured(3);
    return true;
  }

  return false;
}

bool parseParameterNameToValue(std::shared_ptr<QList<SIPParameter>> parameters,
                               QString name, QString& value)
{
  if(parameters != nullptr)
  {
    for(SIPParameter parameter : *parameters)
    {
      if(parameter.name == name)
      {
        value = parameter.value;
        return true;
      }
    }
  }
  return false;
}

bool parseUint(QString values, uint& number)
{
  QRegularExpression re_field("(\\d+)");
  QRegularExpressionMatch field_match = re_field.match(values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 1)
  {
    number = values.toUInt();
    return true;
  }
  return false;
}

bool parseToField(SIPField& field,
                  std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  Q_ASSERT(message->dialog);

  if(!parseURI(field.values, message->to))
  {
    return false;
  }

  parseParameterNameToValue(field.parameters, "tag", message->dialog->toTag);
  return true;
}

bool parseFromField(SIPField& field,
                    std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  Q_ASSERT(message->dialog);

  if(!parseURI(field.values, message->from))
  {
    return false;
  }
  parseParameterNameToValue(field.parameters, "tag", message->dialog->fromTag);
  return true;
}

bool parseCSeqField(SIPField& field,
                  std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  QRegularExpression re_field("(\\d+) (\\w+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 2)
  {
    message->cSeq = field_match.captured(1).toUInt();
    message->transactionRequest = stringToRequest(field_match.captured(2));
    return true;
  }
  return false;
}

bool parseCallIDField(SIPField& field,
                      std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  Q_ASSERT(message->dialog);

  QRegularExpression re_field("(\\S+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 1)
  {
    message->dialog->callID = field.values;
    return true;
  }

  return false;
}

bool parseViaField(SIPField& field,
                   std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  QRegularExpression re_field("SIP\/(\\d\.\\d)\/(\\w+) ([\\w\.:]+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(!field_match.hasMatch() || field_match.lastCapturedIndex() < 3)
  {
    return false;
  }
  else if(field_match.lastCapturedIndex() == 3)
  {
    ViaInfo via = {stringToConnection(field_match.captured(2)),
                   field_match.captured(1),
                   field_match.captured(3), ""};

    parseParameterNameToValue(field.parameters, "branch", via.branch);
    message->senderReplyAddress.push_back(via);
  }
  else
  {
    return false;
  }
  return true;
}

bool parseMaxForwardsField(SIPField& field,
                           std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  return parseUint(field.values, message->maxForwards);
}

bool parseContactField(SIPField& field,
                       std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  return parseURI(field.values, message->contact);
}

bool parseContentTypeField(SIPField& field,
                           std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  QRegularExpression re_field("(\\w+/\\w+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 1)
  {
    message->content.type = stringToContentType(field_match.captured(1));
    return true;
  }
  return false;
}

bool parseContentLengthField(SIPField& field,
                             std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  return parseUint(field.values, message->content.length);
}

bool parseServerField(SIPField& field,
                  std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  message->server = field.values;

  return true;
}

bool isLinePresent(QString name, QList<SIPField>& fields)
{
  for(SIPField field : fields)
  {
    if(field.name == name)
    {
      return true;
    }
  }
  qDebug() << "Did not find header:" << name;
  return false;
}

bool parseParameter(QString text, SIPParameter& parameter)
{
  QRegularExpression re_parameter("([^=]+)=([^;]+)");
  QRegularExpressionMatch parameter_match = re_parameter.match(text);
  if(parameter_match.hasMatch() && parameter_match.lastCapturedIndex() == 2)
  {
    parameter.name = parameter_match.captured(1);
    parameter.value = parameter_match.captured(2);
    return true;
  }

  return false;
}
<commit_msg>feature(Transport): Parse connection type from URI.<commit_after>#include "sipfieldparsing.h"

#include "sipconversions.h"

#include <QRegularExpression>
#include <QDebug>

// TODO: Support SIPS uri scheme. Needed for TLS
bool parseURI(QString values, SIP_URI& uri);
ConnectionType parseUritype(QString type);
bool parseParameterNameToValue(std::shared_ptr<QList<SIPParameter>> parameters,
                               QString name, QString& value);
bool parseUint(QString values, uint& number);

bool parseURI(QString values, SIP_URI& uri)
{
  // TODO: parse quotation marks in real name

  QRegularExpression re_field("(\\w+ )?<(\\w+):(\\w+)@([\\w\.:]+)>");
  QRegularExpressionMatch field_match = re_field.match(values);

  // number of matches depends whether real name was given
  if (field_match.hasMatch())
  {
    if (field_match.lastCapturedIndex() == 4)
    {
      uri.realname = field_match.captured(1);
      uri.connection = parseUritype(field_match.captured(2));
      uri.username = field_match.captured(3);
      uri.host = field_match.captured(4);
    }
    else if(field_match.lastCapturedIndex() == 3)
    {
      uri.connection = parseUritype(field_match.captured(1));
      uri.username = field_match.captured(2);
      uri.host = field_match.captured(3);
    }
    return uri.connection != ANY;
  }

  return false;
}

ConnectionType parseUritype(QString type)
{
  if (type == "sip")
  {
    return TCP;
  }
  else if (type == "sips")
  {
    return TLS;
  }
  else if (type == "tel")
  {
    return TEL;
  }
  else
  {
    qDebug() << "ERROR:  Could not identify connection type:" << type;
  }

  return ANY;
}

bool parseParameterNameToValue(std::shared_ptr<QList<SIPParameter>> parameters,
                               QString name, QString& value)
{
  if(parameters != nullptr)
  {
    for(SIPParameter parameter : *parameters)
    {
      if(parameter.name == name)
      {
        value = parameter.value;
        return true;
      }
    }
  }
  return false;
}

bool parseUint(QString values, uint& number)
{
  QRegularExpression re_field("(\\d+)");
  QRegularExpressionMatch field_match = re_field.match(values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 1)
  {
    number = values.toUInt();
    return true;
  }
  return false;
}

bool parseToField(SIPField& field,
                  std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  Q_ASSERT(message->dialog);

  if(!parseURI(field.values, message->to))
  {
    return false;
  }

  parseParameterNameToValue(field.parameters, "tag", message->dialog->toTag);
  return true;
}

bool parseFromField(SIPField& field,
                    std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  Q_ASSERT(message->dialog);

  if(!parseURI(field.values, message->from))
  {
    return false;
  }
  parseParameterNameToValue(field.parameters, "tag", message->dialog->fromTag);
  return true;
}

bool parseCSeqField(SIPField& field,
                  std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  QRegularExpression re_field("(\\d+) (\\w+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 2)
  {
    message->cSeq = field_match.captured(1).toUInt();
    message->transactionRequest = stringToRequest(field_match.captured(2));
    return true;
  }
  return false;
}

bool parseCallIDField(SIPField& field,
                      std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  Q_ASSERT(message->dialog);

  QRegularExpression re_field("(\\S+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 1)
  {
    message->dialog->callID = field.values;
    return true;
  }

  return false;
}

bool parseViaField(SIPField& field,
                   std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  QRegularExpression re_field("SIP\/(\\d\.\\d)\/(\\w+) ([\\w\.:]+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(!field_match.hasMatch() || field_match.lastCapturedIndex() < 3)
  {
    return false;
  }
  else if(field_match.lastCapturedIndex() == 3)
  {
    ViaInfo via = {stringToConnection(field_match.captured(2)),
                   field_match.captured(1),
                   field_match.captured(3), ""};

    parseParameterNameToValue(field.parameters, "branch", via.branch);
    message->senderReplyAddress.push_back(via);
  }
  else
  {
    return false;
  }
  return true;
}

bool parseMaxForwardsField(SIPField& field,
                           std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  return parseUint(field.values, message->maxForwards);
}

bool parseContactField(SIPField& field,
                       std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  return parseURI(field.values, message->contact);
}

bool parseContentTypeField(SIPField& field,
                           std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);

  QRegularExpression re_field("(\\w+/\\w+)");
  QRegularExpressionMatch field_match = re_field.match(field.values);

  if(field_match.hasMatch() && field_match.lastCapturedIndex() == 1)
  {
    message->content.type = stringToContentType(field_match.captured(1));
    return true;
  }
  return false;
}

bool parseContentLengthField(SIPField& field,
                             std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  return parseUint(field.values, message->content.length);
}

bool parseServerField(SIPField& field,
                  std::shared_ptr<SIPMessageInfo> message)
{
  Q_ASSERT(message);
  message->server = field.values;

  return true;
}

bool isLinePresent(QString name, QList<SIPField>& fields)
{
  for(SIPField field : fields)
  {
    if(field.name == name)
    {
      return true;
    }
  }
  qDebug() << "Did not find header:" << name;
  return false;
}

bool parseParameter(QString text, SIPParameter& parameter)
{
  QRegularExpression re_parameter("([^=]+)=([^;]+)");
  QRegularExpressionMatch parameter_match = re_parameter.match(text);
  if(parameter_match.hasMatch() && parameter_match.lastCapturedIndex() == 2)
  {
    parameter.name = parameter_match.captured(1);
    parameter.value = parameter_match.captured(2);
    return true;
  }

  return false;
}
<|endoftext|>


<commit_before>#include "iteration/group/group_solve_iteration.h"

namespace bart {

namespace iteration {

namespace group {

template <int dim>
GroupSolveIteration<dim>::GroupSolveIteration(
    std::unique_ptr<GroupSolver> group_solver_ptr,
    std::unique_ptr<ConvergenceChecker> convergence_checker_ptr,
    std::unique_ptr<MomentCalculator> moment_calculator_ptr,
    const std::shared_ptr<GroupSolution> &group_solution_ptr,
    const std::shared_ptr<SourceUpdater> &source_updater_ptr,
    const std::shared_ptr<Reporter> &reporter_ptr)
    : group_solver_ptr_(std::move(group_solver_ptr)),
      convergence_checker_ptr_(std::move(convergence_checker_ptr)),
      moment_calculator_ptr_(std::move(moment_calculator_ptr)),
      group_solution_ptr_(group_solution_ptr),
      source_updater_ptr_(source_updater_ptr),
      reporter_ptr_(reporter_ptr)
{}
template<int dim>
void GroupSolveIteration<dim>::Iterate(system::System &system) {

  const int total_groups = system.current_moments->total_groups();
  const int total_angles = group_solution_ptr_->total_angles();
  system::moments::MomentVector current_scalar_flux, previous_scalar_flux;

  if (reporter_ptr_ != nullptr)
    reporter_ptr_->Report("..Inner iterations");

  for (int group = 0; group < total_groups; ++group) {
    if (reporter_ptr_ != nullptr) {
      std::string report{"....Group: "};
      report += std::to_string(group);
      reporter_ptr_->Report(report);
    }

    convergence::Status convergence_status;
    convergence_checker_ptr_->Reset();
    do {
      previous_scalar_flux = current_scalar_flux;

      SolveGroup(group, system);

      current_scalar_flux = GetScalarFlux(group, system);

      if (convergence_status.iteration_number == 0) {
        previous_scalar_flux = current_scalar_flux;
        previous_scalar_flux = 0;
      }

      convergence_status = CheckConvergence(current_scalar_flux,
                                            previous_scalar_flux);

      if (reporter_ptr_ != nullptr)
        reporter_ptr_->Report(convergence_status);

      if (!convergence_status.is_complete) {
        for (int angle = 0; angle < total_angles; ++angle)
          UpdateSystem(system, group, angle);
      }
    } while (!convergence_status.is_complete);
    UpdateCurrentMoments(system, group);
  }
}

template <int dim>
void GroupSolveIteration<dim>::SolveGroup(int group, system::System &system) {
  group_solver_ptr_->SolveGroup(group, system, *group_solution_ptr_);
}

template <int dim>
system::moments::MomentVector GroupSolveIteration<dim>::GetScalarFlux(
    const int group, system::System &) {
  return moment_calculator_ptr_->CalculateMoment(group_solution_ptr_.get(),
                                                 group, 0, 0);
}

template <int dim>
convergence::Status GroupSolveIteration<dim>::CheckConvergence(
    system::moments::MomentVector &current_iteration,
    system::moments::MomentVector &previous_iteration) {
  return convergence_checker_ptr_->CheckFinalConvergence(current_iteration,
                                                         previous_iteration);
}

template <int dim>
void GroupSolveIteration<dim>::UpdateCurrentMoments(system::System &system,
                                                    const int group) {
  auto& current_moments = *system.current_moments;
  const int max_harmonic_l = current_moments.max_harmonic_l();

  for (int l = 0; l <= max_harmonic_l; ++l) {
    for (int m = -l; m <= l; ++m) {
      current_moments[{group, l, m}] = moment_calculator_ptr_->CalculateMoment(
          group_solution_ptr_.get(), group, l, m);
    }
  }
}

template class GroupSolveIteration<1>;
template class GroupSolveIteration<2>;
template class GroupSolveIteration<3>;

} // namespace group

} // namespace iteration

} // namespace bart
<commit_msg>edited reported text by GroupSolveIteration<commit_after>#include "iteration/group/group_solve_iteration.h"

namespace bart {

namespace iteration {

namespace group {

template <int dim>
GroupSolveIteration<dim>::GroupSolveIteration(
    std::unique_ptr<GroupSolver> group_solver_ptr,
    std::unique_ptr<ConvergenceChecker> convergence_checker_ptr,
    std::unique_ptr<MomentCalculator> moment_calculator_ptr,
    const std::shared_ptr<GroupSolution> &group_solution_ptr,
    const std::shared_ptr<SourceUpdater> &source_updater_ptr,
    const std::shared_ptr<Reporter> &reporter_ptr)
    : group_solver_ptr_(std::move(group_solver_ptr)),
      convergence_checker_ptr_(std::move(convergence_checker_ptr)),
      moment_calculator_ptr_(std::move(moment_calculator_ptr)),
      group_solution_ptr_(group_solution_ptr),
      source_updater_ptr_(source_updater_ptr),
      reporter_ptr_(reporter_ptr)
{}
template<int dim>
void GroupSolveIteration<dim>::Iterate(system::System &system) {

  const int total_groups = system.current_moments->total_groups();
  const int total_angles = group_solution_ptr_->total_angles();
  system::moments::MomentVector current_scalar_flux, previous_scalar_flux;

  if (reporter_ptr_ != nullptr)
    reporter_ptr_->Report("..Inner group iteration\n");

  for (int group = 0; group < total_groups; ++group) {
    if (reporter_ptr_ != nullptr) {
      std::string report{"....Group: "};
      report += std::to_string(group);
      report += "\n";
      reporter_ptr_->Report(report);
    }

    convergence::Status convergence_status;
    convergence_checker_ptr_->Reset();
    do {
      previous_scalar_flux = current_scalar_flux;

      SolveGroup(group, system);

      current_scalar_flux = GetScalarFlux(group, system);

      if (convergence_status.iteration_number == 0) {
        previous_scalar_flux = current_scalar_flux;
        previous_scalar_flux = 0;
      }

      convergence_status = CheckConvergence(current_scalar_flux,
                                            previous_scalar_flux);

      if (reporter_ptr_ != nullptr)
        reporter_ptr_->Report(convergence_status);

      if (!convergence_status.is_complete) {
        for (int angle = 0; angle < total_angles; ++angle)
          UpdateSystem(system, group, angle);
      }
    } while (!convergence_status.is_complete);
    UpdateCurrentMoments(system, group);
  }
}

template <int dim>
void GroupSolveIteration<dim>::SolveGroup(int group, system::System &system) {
  group_solver_ptr_->SolveGroup(group, system, *group_solution_ptr_);
}

template <int dim>
system::moments::MomentVector GroupSolveIteration<dim>::GetScalarFlux(
    const int group, system::System &) {
  return moment_calculator_ptr_->CalculateMoment(group_solution_ptr_.get(),
                                                 group, 0, 0);
}

template <int dim>
convergence::Status GroupSolveIteration<dim>::CheckConvergence(
    system::moments::MomentVector &current_iteration,
    system::moments::MomentVector &previous_iteration) {
  return convergence_checker_ptr_->CheckFinalConvergence(current_iteration,
                                                         previous_iteration);
}

template <int dim>
void GroupSolveIteration<dim>::UpdateCurrentMoments(system::System &system,
                                                    const int group) {
  auto& current_moments = *system.current_moments;
  const int max_harmonic_l = current_moments.max_harmonic_l();

  for (int l = 0; l <= max_harmonic_l; ++l) {
    for (int m = -l; m <= l; ++m) {
      current_moments[{group, l, m}] = moment_calculator_ptr_->CalculateMoment(
          group_solution_ptr_.get(), group, l, m);
    }
  }
}

template class GroupSolveIteration<1>;
template class GroupSolveIteration<2>;
template class GroupSolveIteration<3>;

} // namespace group

} // namespace iteration

} // namespace bart
<|endoftext|>


<commit_before>/* Copyright (c) 2017-2019 Hans-Kristian Arntzen
 *
 * 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, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * 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.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "audio_oboe.hpp"
#include "dsp/dsp.hpp"
#include "util.hpp"
#include <cmath>
#include <vector>
#include <algorithm>
#include <oboe/Oboe.h>

namespace Granite
{
namespace Audio
{
void set_oboe_low_latency_parameters(unsigned sample_rate, unsigned block_frames)
{
	// For OpenSL ES fallback path.
	oboe::DefaultStreamValues::SampleRate = sample_rate;
	oboe::DefaultStreamValues::FramesPerBurst = block_frames;
}

struct OboeBackend : Backend, oboe::AudioStreamCallback
{
	OboeBackend(BackendCallback &callback)
			: Backend(callback)
	{
	}

	~OboeBackend();
	bool init(float target_sample_rate, unsigned channels);

	const char *get_backend_name() override
	{
		return "Oboe";
	}

	float get_sample_rate() override
	{
		return sample_rate;
	}

	unsigned get_num_channels() override
	{
		return num_channels;
	}

	bool start() override;
	bool stop() override;
	void heartbeat() override;

	oboe::AudioStream *stream = nullptr;
	std::vector<float> mix_buffers[Backend::MaxAudioChannels];
	float *mix_buffers_ptr[Backend::MaxAudioChannels] = {};

	oboe::AudioFormat format = oboe::AudioFormat::Unspecified;
	float sample_rate = 0.0f;
	double inv_sample_rate = 0.0;
	unsigned num_channels = 0;
	int64_t frame_count = 0;
	int32_t frames_per_callback = 0;
	int32_t old_underrun_count = 0;
	bool is_active = false;

	double last_latency = 0.0;

	oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboe_stream,
	                                      void *audio_data,
	                                      int32_t num_frames) override;
};

OboeBackend::~OboeBackend()
{
	stop();
	if (stream)
		stream->close();
	stream = nullptr;
}

bool OboeBackend::init(float, unsigned channels)
{
	oboe::AudioStreamBuilder builder;
	builder.setDirection(oboe::Direction::Output);
	builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
	builder.setCallback(this);
	builder.setAudioApi(oboe::AudioApi::OpenSLES);
	builder.setChannelCount(channels);
	builder.setContentType(oboe::ContentType::Music);
	builder.setSharingMode(oboe::SharingMode::Shared);
	builder.setUsage(oboe::Usage::Game);
	if (builder.openStream(&stream) != oboe::Result::OK)
	{
		LOGE("Failed to create Oboe stream!\n");
		return false;
	}

	sample_rate = stream->getSampleRate();
	inv_sample_rate = 1.0 / sample_rate;
	num_channels = unsigned(stream->getChannelCount());
	format = stream->getFormat();
	frames_per_callback = stream->getFramesPerCallback();

	if (frames_per_callback == oboe::kUnspecified)
		frames_per_callback = stream->getFramesPerBurst();

	// Allocate mix-buffers.
	// If we have to generate more than this in a callback, iterate multiple times ...
	for (unsigned c = 0; c < num_channels; c++)
	{
		mix_buffers[c].resize(frames_per_callback);
		mix_buffers_ptr[c] = mix_buffers[c].data();
	}

	callback.set_backend_parameters(sample_rate, num_channels, size_t(frames_per_callback));
	// Set initial latency estimate.
	last_latency = double(stream->getBufferSizeInFrames()) * inv_sample_rate;
	callback.set_latency_usec(uint32_t(last_latency * 1e6));
	return true;
}

oboe::DataCallbackResult OboeBackend::onAudioReady(
		oboe::AudioStream *oboe_stream,
		void *audio_data,
		int32_t num_frames)
{
	auto xrun_count = oboe_stream->getXRunCount();
	if (xrun_count.error() == oboe::Result::OK)
	{
		int32_t underrun_count = xrun_count.value();
		if (underrun_count > old_underrun_count)
		{
			LOGW("Oboe: observed %d new underruns.", underrun_count - old_underrun_count);
			old_underrun_count = underrun_count;
		}
	}

	// Update measured latency.
	// Can fail spuriously, don't update latency estimate in that case.
	int64_t frame_position, time_ns;
	if (oboe_stream->getTimestamp(CLOCK_MONOTONIC, &frame_position, &time_ns) == oboe::Result::OK)
	{
		timespec ts;
		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
		{
			int64_t current_ns = ts.tv_sec * 1000000000 + ts.tv_nsec;

			// Extrapolate play counter based on timestamp.
			double playing_time = double(frame_position) * inv_sample_rate;
			playing_time += 1e-9 * double(current_ns - time_ns);
			double pushed_time = double(frame_count) * inv_sample_rate;
			double latency = pushed_time - playing_time;
			if (latency < 0.0)
				latency = 0.0;

			// Interpolate latency over time for a smoother result.
			last_latency = 0.95 * last_latency + 0.05 * latency;
			callback.set_latency_usec(uint32_t(last_latency * 1e6));

			//LOGI("Measured latency: %.3f ms\n", last_latency * 1000.0);
		}
	}

	frame_count += num_frames;

	union
	{
		int16_t *i16;
		float *f32;
		void *data;
	} u;
	u.data = audio_data;

	// Ideally we'll only run this once, but you never know ...
	while (num_frames)
	{
		auto to_render = std::min(num_frames, frames_per_callback);

		callback.mix_samples(mix_buffers_ptr, size_t(to_render));

		// Deal with whatever format AAudio wants.
		// Convert from deinterleaved F32 to whatever.
		if (format == oboe::AudioFormat::Float && num_channels == 2)
		{
			DSP::interleave_stereo_f32(u.f32, mix_buffers_ptr[0], mix_buffers_ptr[1], size_t(to_render));
			u.f32 += to_render * 2;
		}
		else if (format == oboe::AudioFormat::Float)
		{
			for (int f = 0; f < to_render; f++)
				for (unsigned c = 0; c < num_channels; c++)
					*u.f32++ = mix_buffers[c][f];
		}
		else if (format == oboe::AudioFormat::I16 && num_channels == 2)
		{
			DSP::interleave_stereo_f32_i16(u.i16, mix_buffers_ptr[0], mix_buffers_ptr[1], size_t(to_render));
			u.i16 += to_render * 2;
		}
		else
		{
			for (int f = 0; f < to_render; f++)
				for (unsigned c = 0; c < num_channels; c++)
					*u.i16++ = DSP::f32_to_i16(mix_buffers[c][f]);
		}

		num_frames -= to_render;
	}

	return oboe::DataCallbackResult::Continue;
}

// Called periodically from the main loop, just in case we need to recover from a device lost.
void OboeBackend::heartbeat()
{
}

bool OboeBackend::start()
{
	if (is_active)
		return false;

	if (!stream)
		return false;

	callback.on_backend_start();
	frame_count = 0;
	old_underrun_count = 0;

	// Starts async, and will pull from callback.
	oboe::Result res;
	if ((res = stream->requestStart()) != oboe::Result::OK)
	{
		LOGE("Oboe: Failed to start stream (%s).\n", oboe::convertToText(res));
		return false;
	}

	is_active = true;
	return true;
}

bool OboeBackend::stop()
{
	if (!is_active)
		return false;

	if (!stream)
		return false;

	oboe::Result res;
	if ((res = stream->stop(1000000)) != oboe::Result::OK)
	{
		LOGE("Oboe: Failed to stop stream (%s).\n", oboe::convertToText(res));
		return false;
	}

	callback.on_backend_stop();
	is_active = false;
	return true;
}

Backend *create_oboe_backend(BackendCallback &callback, float sample_rate, unsigned channels)
{
	auto *oboe = new OboeBackend(callback);
	if (!oboe->init(sample_rate, channels))
	{
		delete oboe;
		return nullptr;
	}
	return oboe;
}
}
}
<commit_msg>Oboe: Deal with DeviceDisconnected events.<commit_after>/* Copyright (c) 2017-2019 Hans-Kristian Arntzen
 *
 * 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, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * 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.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "audio_oboe.hpp"
#include "dsp/dsp.hpp"
#include "util.hpp"
#include <cmath>
#include <vector>
#include <algorithm>
#include <oboe/Oboe.h>

namespace Granite
{
namespace Audio
{
void set_oboe_low_latency_parameters(unsigned sample_rate, unsigned block_frames)
{
	// For OpenSL ES fallback path.
	oboe::DefaultStreamValues::SampleRate = sample_rate;
	oboe::DefaultStreamValues::FramesPerBurst = block_frames;
}

struct OboeBackend : Backend, oboe::AudioStreamCallback
{
	OboeBackend(BackendCallback &callback)
			: Backend(callback)
	{
		device_alive.test_and_set();
	}

	~OboeBackend();
	bool init(float target_sample_rate, unsigned channels);

	const char *get_backend_name() override
	{
		return "Oboe";
	}

	float get_sample_rate() override
	{
		return sample_rate;
	}

	unsigned get_num_channels() override
	{
		return num_channels;
	}

	bool start() override;
	bool stop() override;
	void heartbeat() override;

	oboe::AudioStream *stream = nullptr;
	std::vector<float> mix_buffers[Backend::MaxAudioChannels];
	float *mix_buffers_ptr[Backend::MaxAudioChannels] = {};

	oboe::AudioFormat format = oboe::AudioFormat::Unspecified;
	float sample_rate = 0.0f;
	double inv_sample_rate = 0.0;
	unsigned num_channels = 0;
	int64_t frame_count = 0;
	int32_t frames_per_callback = 0;
	int32_t old_underrun_count = 0;
	bool is_active = false;

	double last_latency = 0.0;

	oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboe_stream,
	                                      void *audio_data,
	                                      int32_t num_frames) override;

	void onErrorBeforeClose(oboe::AudioStream *oboe_stream, oboe::Result error) override;
	void onErrorAfterClose(oboe::AudioStream *oboe_stream, oboe::Result error) override;

	void setup_stream_builder(oboe::AudioStreamBuilder &builder);
	bool reinit();
	std::atomic_flag device_alive;
};

OboeBackend::~OboeBackend()
{
	stop();
	if (stream)
		stream->close();
	stream = nullptr;
}

bool OboeBackend::reinit()
{
	// Apparently the error callbacks can be called multiple times
	// from reading some Oboe samples.
	bool ret = init(0.0f, num_channels);
	if (!ret)
		return false;

	if (is_active)
	{
		is_active = false;
		if (!start())
			return false;

		LOGI("Oboe: Recovered from disconnect!\n");
	}

	return true;
}

void OboeBackend::setup_stream_builder(oboe::AudioStreamBuilder &builder)
{
	builder.setDirection(oboe::Direction::Output);
	builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
	builder.setCallback(this);
	//builder.setAudioApi(oboe::AudioApi::OpenSLES);
	builder.setChannelCount(num_channels);
	builder.setContentType(oboe::ContentType::Music);
	builder.setSharingMode(oboe::SharingMode::Shared);
	builder.setUsage(oboe::Usage::Game);

	// If we have already committed to a sample rate, keep using it.
	if (sample_rate != 0.0f)
		builder.setSampleRate(int32_t(sample_rate));
}

bool OboeBackend::init(float, unsigned channels)
{
	num_channels = channels;
	oboe::AudioStreamBuilder builder;
	setup_stream_builder(builder);

	if (builder.openStream(&stream) != oboe::Result::OK)
	{
		LOGE("Failed to create Oboe stream!\n");
		return false;
	}

	sample_rate = stream->getSampleRate();
	inv_sample_rate = 1.0 / sample_rate;
	num_channels = unsigned(stream->getChannelCount());
	format = stream->getFormat();

	if (!frames_per_callback)
	{
		frames_per_callback = stream->getFramesPerCallback();
		if (frames_per_callback == oboe::kUnspecified)
			frames_per_callback = stream->getFramesPerBurst();

		// Allocate mix-buffers.
		// If we have to generate more than this in a callback, iterate multiple times ...
		for (unsigned c = 0; c < num_channels; c++)
		{
			mix_buffers[c].resize(frames_per_callback);
			mix_buffers_ptr[c] = mix_buffers[c].data();
		}

		callback.set_backend_parameters(sample_rate, num_channels, size_t(frames_per_callback));
	}

	// Set initial latency estimate.
	last_latency = double(stream->getBufferSizeInFrames()) * inv_sample_rate;
	callback.set_latency_usec(uint32_t(last_latency * 1e6));

	return true;
}

void OboeBackend::onErrorBeforeClose(oboe::AudioStream *, oboe::Result error)
{
	LOGW("Oboe: Error before close: %s.\n", oboe::convertToText(error));
}

void OboeBackend::onErrorAfterClose(oboe::AudioStream *, oboe::Result error)
{
	LOGW("Oboe: Error after close: %s.\n", oboe::convertToText(error));
	if (error == oboe::Result::ErrorDisconnected)
		device_alive.clear(std::memory_order_release);
}

oboe::DataCallbackResult OboeBackend::onAudioReady(
		oboe::AudioStream *oboe_stream,
		void *audio_data,
		int32_t num_frames)
{
	auto xrun_count = oboe_stream->getXRunCount();
	if (xrun_count.error() == oboe::Result::OK)
	{
		int32_t underrun_count = xrun_count.value();
		if (underrun_count > old_underrun_count)
		{
			LOGW("Oboe: observed %d new underruns.", underrun_count - old_underrun_count);
			old_underrun_count = underrun_count;
		}
	}

	// Update measured latency.
	// Can fail spuriously, don't update latency estimate in that case.
	int64_t frame_position, time_ns;
	if (oboe_stream->getTimestamp(CLOCK_MONOTONIC, &frame_position, &time_ns) == oboe::Result::OK)
	{
		timespec ts;
		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
		{
			int64_t current_ns = ts.tv_sec * 1000000000 + ts.tv_nsec;

			// Extrapolate play counter based on timestamp.
			double playing_time = double(frame_position) * inv_sample_rate;
			playing_time += 1e-9 * double(current_ns - time_ns);
			double pushed_time = double(frame_count) * inv_sample_rate;
			double latency = pushed_time - playing_time;
			if (latency < 0.0)
				latency = 0.0;

			// Interpolate latency over time for a smoother result.
			last_latency = 0.95 * last_latency + 0.05 * latency;
			callback.set_latency_usec(uint32_t(last_latency * 1e6));

			//LOGI("Measured latency: %.3f ms\n", last_latency * 1000.0);
		}
	}

	frame_count += num_frames;

	union
	{
		int16_t *i16;
		float *f32;
		void *data;
	} u;
	u.data = audio_data;

	// Ideally we'll only run this loop once, but you never know ...
	while (num_frames)
	{
		auto to_render = std::min(num_frames, frames_per_callback);

		callback.mix_samples(mix_buffers_ptr, size_t(to_render));

		// Deal with whatever format AAudio wants.
		// Convert from deinterleaved F32 to whatever.
		if (format == oboe::AudioFormat::Float && num_channels == 2)
		{
			DSP::interleave_stereo_f32(u.f32, mix_buffers_ptr[0], mix_buffers_ptr[1], size_t(to_render));
			u.f32 += to_render * 2;
		}
		else if (format == oboe::AudioFormat::Float)
		{
			for (int f = 0; f < to_render; f++)
				for (unsigned c = 0; c < num_channels; c++)
					*u.f32++ = mix_buffers[c][f];
		}
		else if (format == oboe::AudioFormat::I16 && num_channels == 2)
		{
			DSP::interleave_stereo_f32_i16(u.i16, mix_buffers_ptr[0], mix_buffers_ptr[1], size_t(to_render));
			u.i16 += to_render * 2;
		}
		else
		{
			for (int f = 0; f < to_render; f++)
				for (unsigned c = 0; c < num_channels; c++)
					*u.i16++ = DSP::f32_to_i16(mix_buffers[c][f]);
		}

		num_frames -= to_render;
	}

	return oboe::DataCallbackResult::Continue;
}

// Called periodically from the main loop, just in case we need to recover from a device lost.
void OboeBackend::heartbeat()
{
	if (!device_alive.test_and_set(std::memory_order_acquire))
	{
		stream = nullptr;
		if (!reinit())
			LOGE("Oboe: Failed to reinit stream.\n");
	}
}

bool OboeBackend::start()
{
	if (is_active)
		return false;

	if (!stream)
		return false;

	callback.on_backend_start();
	frame_count = 0;
	old_underrun_count = 0;

	// Starts async, and will pull from callback.
	oboe::Result res;
	if ((res = stream->requestStart()) != oboe::Result::OK)
	{
		LOGE("Oboe: Failed to start stream (%s).\n", oboe::convertToText(res));
		return false;
	}

	is_active = true;
	return true;
}

bool OboeBackend::stop()
{
	if (!is_active)
		return false;

	if (!stream)
		return false;

	oboe::Result res;
	if ((res = stream->stop(1000000)) != oboe::Result::OK)
	{
		LOGE("Oboe: Failed to stop stream (%s).\n", oboe::convertToText(res));
		return false;
	}

	callback.on_backend_stop();
	is_active = false;
	return true;
}

Backend *create_oboe_backend(BackendCallback &callback, float sample_rate, unsigned channels)
{
	auto *oboe = new OboeBackend(callback);
	if (!oboe->init(sample_rate, channels))
	{
		delete oboe;
		return nullptr;
	}
	return oboe;
}
}
}
<|endoftext|>


<commit_before>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2022 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "callback_engine.hpp"
#include "callback_object.hpp"
#include "input_parameters_and_any_value_to_any_value_callback_with_universe.hpp"
#include "code/ylikuutio/data/any_value.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include standard headers
#include <cstddef>  // std::size_t
#include <iostream> // std::cout, std::cin, std::cerr
#include <optional> // std::optional

namespace yli::ontology
{
    class Universe;
}

namespace yli::callback
{
    void CallbackEngine::bind_callback_object(yli::callback::CallbackObject* const callback_object)
    {
        yli::hierarchy::bind_child_to_parent<yli::callback::CallbackObject*>(
                callback_object,
                this->callback_object_pointer_vector,
                this->free_callback_objectID_queue,
                this->number_of_callback_objects);
    }

    CallbackEngine::CallbackEngine(yli::ontology::Universe& universe)
        : universe { universe }
    {
        // constructor.
    }

    CallbackEngine::~CallbackEngine()
    {
        // destructor.
        std::cout << "This callback engine will be destroyed.\n";

        // destroy all callback objects of this callback engine.
        std::cout << "All callback objects of this callback engine will be destroyed.\n";
        yli::hierarchy::delete_children<yli::callback::CallbackObject*>(this->callback_object_pointer_vector, this->number_of_callback_objects);
    }

    yli::callback::CallbackObject* CallbackEngine::create_callback_object()
    {
        return new yli::callback::CallbackObject(this);
    }

    yli::callback::CallbackObject* CallbackEngine::create_callback_object(const InputParametersAndAnyValueToAnyValueCallbackWithUniverse callback)
    {
        return new yli::callback::CallbackObject(callback, this);
    }

    void CallbackEngine::set_callback_object_pointer(const std::size_t childID, yli::callback::CallbackObject* const child_pointer)
    {
        yli::hierarchy::set_child_pointer(childID, child_pointer, this->callback_object_pointer_vector, this->free_callback_objectID_queue, this->number_of_callback_objects);
    }

    std::optional<yli::data::AnyValue> CallbackEngine::execute(const yli::data::AnyValue& any_value)
    {
        std::optional<yli::data::AnyValue> return_any_value;
        bool is_any_callback_object_executed { false };

        // execute all callbacks.
        for (std::size_t child_i = 0; child_i < this->callback_object_pointer_vector.size(); child_i++)
        {
            yli::callback::CallbackObject* callback_object_pointer = static_cast<yli::callback::CallbackObject*>(this->callback_object_pointer_vector[child_i]);

            if (callback_object_pointer != nullptr)
            {
                return_any_value = callback_object_pointer->execute(any_value);
                is_any_callback_object_executed = true;
                this->return_values.emplace_back(return_any_value);
            }
            else
            {
                this->return_values.emplace_back(std::nullopt);
            }
        }

        this->return_values.clear();

        if (is_any_callback_object_executed)
        {
            return return_any_value;
        }

        return std::nullopt;
    }

    std::size_t CallbackEngine::get_n_of_return_values() const
    {
        return this->return_values.size();
    }

    std::optional<yli::data::AnyValue> CallbackEngine::get_nth_return_value(std::size_t n) const
    {
        // note: indexing of `n` begins from 0.

        std::size_t n_of_return_values = this->get_n_of_return_values();

        if (n_of_return_values <= n)
        {
            return std::nullopt;
        }

        return this->return_values.at(n_of_return_values - 1);
    }

    std::optional<yli::data::AnyValue> CallbackEngine::get_previous_return_value() const
    {
        std::size_t n_of_return_values = this->get_n_of_return_values();

        if (n_of_return_values == 0)
        {
            return std::nullopt;
        }

        return this->return_values.back();
    }

    yli::ontology::Universe& CallbackEngine::get_universe() const
    {
        return this->universe;
    }
}
<commit_msg>`CallbackEngine`: remove unnecessary `std::cout` output.<commit_after>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2022 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include "callback_engine.hpp"
#include "callback_object.hpp"
#include "input_parameters_and_any_value_to_any_value_callback_with_universe.hpp"
#include "code/ylikuutio/data/any_value.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include standard headers
#include <cstddef>  // std::size_t
#include <optional> // std::optional

namespace yli::ontology
{
    class Universe;
}

namespace yli::callback
{
    void CallbackEngine::bind_callback_object(yli::callback::CallbackObject* const callback_object)
    {
        yli::hierarchy::bind_child_to_parent<yli::callback::CallbackObject*>(
                callback_object,
                this->callback_object_pointer_vector,
                this->free_callback_objectID_queue,
                this->number_of_callback_objects);
    }

    CallbackEngine::CallbackEngine(yli::ontology::Universe& universe)
        : universe { universe }
    {
        // constructor.
    }

    CallbackEngine::~CallbackEngine()
    {
        // destroy all callback objects of this callback engine.
        yli::hierarchy::delete_children<yli::callback::CallbackObject*>(this->callback_object_pointer_vector, this->number_of_callback_objects);
    }

    yli::callback::CallbackObject* CallbackEngine::create_callback_object()
    {
        return new yli::callback::CallbackObject(this);
    }

    yli::callback::CallbackObject* CallbackEngine::create_callback_object(const InputParametersAndAnyValueToAnyValueCallbackWithUniverse callback)
    {
        return new yli::callback::CallbackObject(callback, this);
    }

    void CallbackEngine::set_callback_object_pointer(const std::size_t childID, yli::callback::CallbackObject* const child_pointer)
    {
        yli::hierarchy::set_child_pointer(childID, child_pointer, this->callback_object_pointer_vector, this->free_callback_objectID_queue, this->number_of_callback_objects);
    }

    std::optional<yli::data::AnyValue> CallbackEngine::execute(const yli::data::AnyValue& any_value)
    {
        std::optional<yli::data::AnyValue> return_any_value;
        bool is_any_callback_object_executed { false };

        // execute all callbacks.
        for (std::size_t child_i = 0; child_i < this->callback_object_pointer_vector.size(); child_i++)
        {
            yli::callback::CallbackObject* callback_object_pointer = static_cast<yli::callback::CallbackObject*>(this->callback_object_pointer_vector[child_i]);

            if (callback_object_pointer != nullptr)
            {
                return_any_value = callback_object_pointer->execute(any_value);
                is_any_callback_object_executed = true;
                this->return_values.emplace_back(return_any_value);
            }
            else
            {
                this->return_values.emplace_back(std::nullopt);
            }
        }

        this->return_values.clear();

        if (is_any_callback_object_executed)
        {
            return return_any_value;
        }

        return std::nullopt;
    }

    std::size_t CallbackEngine::get_n_of_return_values() const
    {
        return this->return_values.size();
    }

    std::optional<yli::data::AnyValue> CallbackEngine::get_nth_return_value(std::size_t n) const
    {
        // note: indexing of `n` begins from 0.

        std::size_t n_of_return_values = this->get_n_of_return_values();

        if (n_of_return_values <= n)
        {
            return std::nullopt;
        }

        return this->return_values.at(n_of_return_values - 1);
    }

    std::optional<yli::data::AnyValue> CallbackEngine::get_previous_return_value() const
    {
        std::size_t n_of_return_values = this->get_n_of_return_values();

        if (n_of_return_values == 0)
        {
            return std::nullopt;
        }

        return this->return_values.back();
    }

    yli::ontology::Universe& CallbackEngine::get_universe() const
    {
        return this->universe;
    }
}
<|endoftext|>


<commit_before>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <map>
#include <cstdlib>

#include "booksim.hpp"
#include "traffic.hpp"
#include "network.hpp"
#include "random_utils.hpp"
#include "misc_utils.hpp"

map<string, tTrafficFunction> gTrafficFunctionMap;

int gResetTraffic = 0;
int gStepTraffic  = 0;

void src_dest_bin( int source, int dest, int lg )
{
  int b, t;

  cout << "from: ";
  t = source;
  for ( b = 0; b < lg; ++b ) {
    cout << ( ( t >> ( lg - b - 1 ) ) & 0x1 );
  }

  cout << " to ";
  t = dest;
  for ( b = 0; b < lg; ++b ) {
    cout << ( ( t >> ( lg - b - 1 ) ) & 0x1 );
  }
  cout << endl;
}

/* Add Traffic functions here */

//=============================================================

int uniform( int source, int total_nodes )
{
  return RandomInt( total_nodes - 1 );
}

//=============================================================

int bitcomp( int source, int total_nodes )
{
  int lg   = log_two( total_nodes );
  int mask = total_nodes - 1;
  int dest;

  if ( ( 1 << lg ) != total_nodes ) {
    cout << "Error: The 'bitcomp' traffic pattern requires the number of"
	 << " nodes to be a power of two!" << endl;
    exit(-1);
  }

  dest = ( ~source ) & mask;

  return dest;
}

//=============================================================

int transpose( int source, int total_nodes )
{
  int lg      = log_two( total_nodes );
  int mask_lo = (1 << (lg/2)) - 1;
  int mask_hi = mask_lo << (lg/2);
  int dest;

  if ( ( ( 1 << lg ) != total_nodes ) || ( lg & 0x1 ) ) {
    cout << "Error: The 'transpose' traffic pattern requires the number of"
	 << " nodes to be an even power of two!" << endl;
    exit(-1);
  }

  dest = ( ( source >> (lg/2) ) & mask_lo ) |
    ( ( source << (lg/2) ) & mask_hi );

  return dest;
}

//=============================================================

int bitrev( int source, int total_nodes )
{
  int lg = log_two( total_nodes );
  int dest;

  if ( ( 1 << lg ) != total_nodes  ) {
    cout << "Error: The 'bitrev' traffic pattern requires the number of"
	 << " nodes to be a power of two!" << endl;
    exit(-1);
  }

  // If you were fancy you could do this in O(log log total_nodes)
  // instructions, but I'm not

  dest = 0;
  for ( int b = 0; b < lg; ++b  ) {
    dest |= ( ( source >> b ) & 0x1 ) << ( lg - b - 1 );
  }

  return dest;
}

//=============================================================

int shuffle( int source, int total_nodes )
{
  int lg = log_two( total_nodes );
  int dest;

  if ( ( 1 << lg ) != total_nodes  ) {
    cout << "Error: The 'shuffle' traffic pattern requires the number of"
	 << " nodes to be a power of two!" << endl;
    exit(-1);
  }

  dest = ( ( source << 1 ) & ( total_nodes - 1 ) ) |
    ( ( source >> ( lg - 1 ) ) & 0x1 );

  return dest;
}

//=============================================================

int tornado( int source, int total_nodes )
{
  int offset = 1;
  int dest = 0;

  for ( int n = 0; n < realgn; ++n ) {
    dest += offset *
      ( ( ( source / offset ) % realgk + ( realgk/2 - 1 ) ) % realgk );
    offset *= realgk;
  }
  //cout<<source<<" "<<dest<<endl;
  return dest;
}

//=============================================================

int neighbor( int source, int total_nodes )
{
  int offset = 1;
  int dest = 0;

  for ( int n = 0; n < realgn; ++n ) {
    dest += offset *
      ( ( ( source / offset ) % realgk + 1 ) % realgk );
    offset *= realgk;
  }

  //cout<<"Source "<<source<<" destination "<<dest<<endl;
  return dest;
}

//=============================================================

int *gPerm = 0;
int gPermSeed;

void GenerateRandomPerm( int total_nodes )
{
  int ind;
  int i,j;
  int cnt;
  unsigned long prev_rand;

  prev_rand = RandomIntLong( );
  RandomSeed( gPermSeed );

  if ( !gPerm ) {
    gPerm = new int [total_nodes];
  }

  for ( i = 0; i < total_nodes; ++i ) {
    gPerm[i] = -1;
  }

  for ( i = 0; i < total_nodes; ++i ) {
    ind = RandomInt( total_nodes - 1 - i );

    j   = 0;
    cnt = 0;
    while( ( cnt < ind ) ||
	   ( gPerm[j] != -1 ) ) {
      if ( gPerm[j] == -1 ) { ++cnt; }
      ++j;

      if ( j >= total_nodes ) {
	cout << "ERROR: GenerateRandomPerm( ) internal error" << endl;
	exit(-1);
      }
    }

    gPerm[j] = i;
  }

  RandomSeed( prev_rand );
}

int randperm( int source, int total_nodes )
{
  if ( gResetTraffic || !gPerm ) {
    GenerateRandomPerm( total_nodes );
    gResetTraffic = 0;
  }

  return gPerm[source];
}

//=============================================================

int diagonal( int source, int total_nodes )
{
  int t = RandomInt( 2 );
  int d;

  // 2/3 of traffic goes from source->source
  // 1/3 of traffic goes from source->(source+1)%total_nodes

  if ( t == 0 ) {
    d = ( source + 1 ) % total_nodes;
  } else {
    d = source;
  }

  return d;
}

//=============================================================

int asymmetric( int source, int total_nodes )
{
  int d;
  int half = total_nodes / 2;

  d = ( source % half ) + RandomInt( 1 ) * half;

  return d;
}

//=============================================================

int taper64( int source, int total_nodes )
{
  int d;

  if ( total_nodes != 64 ) {
    cout << "Error: The 'taper64' traffic pattern requires the number of"
	 << " nodes to be 64!" << endl;
    exit(-1);
  }

  if (RandomInt(1)) {
    d = (64 + source + 8*(RandomInt(2) - 1) + (RandomInt(2) - 1)) % 64;

  } else {
    d = RandomInt( total_nodes - 1 );
  }

  return d;
}

//=============================================================

int badperm_dfly( int source, int total_nodes )
{
  int grp_size_routers = powi(realgk, realgn - 1);
  int grp_size_nodes = grp_size_routers * realgk;

  int temp;
  int dest;

  temp = (int) (source / grp_size_nodes);
  dest =  (RandomInt(grp_size_nodes - 1) + (temp+1)*grp_size_nodes ) %  total_nodes;

  return dest;
}

int badperm_dflynew( int source, int total_nodes )
{
  int grp_size_routers = 2*realgk;
  int grp_size_nodes = grp_size_routers * realgk;

  int temp;
  int dest;

  temp = (int) (source / grp_size_nodes);
  dest =  (RandomInt(grp_size_nodes - 1) + (temp+1)*grp_size_nodes ) %  total_nodes;

  return dest;
}

void InitializeTrafficMap( )
{

  /* Register Traffic functions here */

  gTrafficFunctionMap["uniform"]  = &uniform;

  // "Bit" patterns

  gTrafficFunctionMap["bitcomp"]   = &bitcomp;
  gTrafficFunctionMap["bitrev"]    = &bitrev;
  gTrafficFunctionMap["transpose"] = &transpose;
  gTrafficFunctionMap["shuffle"]   = &shuffle;

  // "Digit" patterns

  gTrafficFunctionMap["tornado"]   = &tornado;
  gTrafficFunctionMap["neighbor"]  = &neighbor;

  // Other patterns

  gTrafficFunctionMap["randperm"]   = &randperm;

  gTrafficFunctionMap["diagonal"]   = &diagonal;
  gTrafficFunctionMap["asymmetric"] = &asymmetric;
  gTrafficFunctionMap["taper64"]    = &taper64;

  gTrafficFunctionMap["bad_dragon"]    = &badperm_dflynew;

}

void ResetTrafficFunction( )
{
  gResetTraffic++;
}

void StepTrafficFunction( )
{
  gStepTraffic++;
}

tTrafficFunction GetTrafficFunction( const Configuration& config )
{

  if(config.GetInt( "c" )!=1){
    int temp =  config.GetInt("xr");
    realgk = temp*gK;
    realgn = gN;
  } else {
    realgk = gK;
    realgn = gN;
  }

  string topo;
  config.GetStr( "topology", topo );

  map<string, tTrafficFunction>::const_iterator match;
  tTrafficFunction tf;

  string fn;

  config.GetStr( "traffic", fn, "none" );
  match = gTrafficFunctionMap.find( fn );

  if ( match != gTrafficFunctionMap.end( ) ) {
    tf = match->second;
  } else {
    cout << "Error: Undefined traffic pattern '" << fn << "'." << endl;
    exit(-1);
  }

  gPermSeed = config.GetInt( "perm_seed" );

  //seed the network
  RandomSeed(config.GetInt("seed"));
  return tf;
}

<commit_msg>add Ted's adversarial traffic pattern for dragonfly networks<commit_after>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <map>
#include <cstdlib>

#include "booksim.hpp"
#include "traffic.hpp"
#include "network.hpp"
#include "random_utils.hpp"
#include "misc_utils.hpp"

map<string, tTrafficFunction> gTrafficFunctionMap;

int gResetTraffic = 0;
int gStepTraffic  = 0;

void src_dest_bin( int source, int dest, int lg )
{
  int b, t;

  cout << "from: ";
  t = source;
  for ( b = 0; b < lg; ++b ) {
    cout << ( ( t >> ( lg - b - 1 ) ) & 0x1 );
  }

  cout << " to ";
  t = dest;
  for ( b = 0; b < lg; ++b ) {
    cout << ( ( t >> ( lg - b - 1 ) ) & 0x1 );
  }
  cout << endl;
}

/* Add Traffic functions here */

//=============================================================

int uniform( int source, int total_nodes )
{
  return RandomInt( total_nodes - 1 );
}

//=============================================================

int bitcomp( int source, int total_nodes )
{
  int lg   = log_two( total_nodes );
  int mask = total_nodes - 1;
  int dest;

  if ( ( 1 << lg ) != total_nodes ) {
    cout << "Error: The 'bitcomp' traffic pattern requires the number of"
	 << " nodes to be a power of two!" << endl;
    exit(-1);
  }

  dest = ( ~source ) & mask;

  return dest;
}

//=============================================================

int transpose( int source, int total_nodes )
{
  int lg      = log_two( total_nodes );
  int mask_lo = (1 << (lg/2)) - 1;
  int mask_hi = mask_lo << (lg/2);
  int dest;

  if ( ( ( 1 << lg ) != total_nodes ) || ( lg & 0x1 ) ) {
    cout << "Error: The 'transpose' traffic pattern requires the number of"
	 << " nodes to be an even power of two!" << endl;
    exit(-1);
  }

  dest = ( ( source >> (lg/2) ) & mask_lo ) |
    ( ( source << (lg/2) ) & mask_hi );

  return dest;
}

//=============================================================

int bitrev( int source, int total_nodes )
{
  int lg = log_two( total_nodes );
  int dest;

  if ( ( 1 << lg ) != total_nodes  ) {
    cout << "Error: The 'bitrev' traffic pattern requires the number of"
	 << " nodes to be a power of two!" << endl;
    exit(-1);
  }

  // If you were fancy you could do this in O(log log total_nodes)
  // instructions, but I'm not

  dest = 0;
  for ( int b = 0; b < lg; ++b  ) {
    dest |= ( ( source >> b ) & 0x1 ) << ( lg - b - 1 );
  }

  return dest;
}

//=============================================================

int shuffle( int source, int total_nodes )
{
  int lg = log_two( total_nodes );
  int dest;

  if ( ( 1 << lg ) != total_nodes  ) {
    cout << "Error: The 'shuffle' traffic pattern requires the number of"
	 << " nodes to be a power of two!" << endl;
    exit(-1);
  }

  dest = ( ( source << 1 ) & ( total_nodes - 1 ) ) |
    ( ( source >> ( lg - 1 ) ) & 0x1 );

  return dest;
}

//=============================================================

int tornado( int source, int total_nodes )
{
  int offset = 1;
  int dest = 0;

  for ( int n = 0; n < realgn; ++n ) {
    dest += offset *
      ( ( ( source / offset ) % realgk + ( realgk/2 - 1 ) ) % realgk );
    offset *= realgk;
  }
  //cout<<source<<" "<<dest<<endl;
  return dest;
}

//=============================================================

int neighbor( int source, int total_nodes )
{
  int offset = 1;
  int dest = 0;

  for ( int n = 0; n < realgn; ++n ) {
    dest += offset *
      ( ( ( source / offset ) % realgk + 1 ) % realgk );
    offset *= realgk;
  }

  //cout<<"Source "<<source<<" destination "<<dest<<endl;
  return dest;
}

//=============================================================

int *gPerm = 0;
int gPermSeed;

void GenerateRandomPerm( int total_nodes )
{
  int ind;
  int i,j;
  int cnt;
  unsigned long prev_rand;

  prev_rand = RandomIntLong( );
  RandomSeed( gPermSeed );

  if ( !gPerm ) {
    gPerm = new int [total_nodes];
  }

  for ( i = 0; i < total_nodes; ++i ) {
    gPerm[i] = -1;
  }

  for ( i = 0; i < total_nodes; ++i ) {
    ind = RandomInt( total_nodes - 1 - i );

    j   = 0;
    cnt = 0;
    while( ( cnt < ind ) ||
	   ( gPerm[j] != -1 ) ) {
      if ( gPerm[j] == -1 ) { ++cnt; }
      ++j;

      if ( j >= total_nodes ) {
	cout << "ERROR: GenerateRandomPerm( ) internal error" << endl;
	exit(-1);
      }
    }

    gPerm[j] = i;
  }

  RandomSeed( prev_rand );
}

int randperm( int source, int total_nodes )
{
  if ( gResetTraffic || !gPerm ) {
    GenerateRandomPerm( total_nodes );
    gResetTraffic = 0;
  }

  return gPerm[source];
}

//=============================================================

int diagonal( int source, int total_nodes )
{
  int t = RandomInt( 2 );
  int d;

  // 2/3 of traffic goes from source->source
  // 1/3 of traffic goes from source->(source+1)%total_nodes

  if ( t == 0 ) {
    d = ( source + 1 ) % total_nodes;
  } else {
    d = source;
  }

  return d;
}

//=============================================================

int asymmetric( int source, int total_nodes )
{
  int d;
  int half = total_nodes / 2;

  d = ( source % half ) + RandomInt( 1 ) * half;

  return d;
}

//=============================================================

int taper64( int source, int total_nodes )
{
  int d;

  if ( total_nodes != 64 ) {
    cout << "Error: The 'taper64' traffic pattern requires the number of"
	 << " nodes to be 64!" << endl;
    exit(-1);
  }

  if (RandomInt(1)) {
    d = (64 + source + 8*(RandomInt(2) - 1) + (RandomInt(2) - 1)) % 64;

  } else {
    d = RandomInt( total_nodes - 1 );
  }

  return d;
}

//=============================================================

int badperm_dfly( int source, int total_nodes )
{
  int grp_size_routers = powi(realgk, realgn - 1);
  int grp_size_nodes = grp_size_routers * realgk;

  int temp;
  int dest;

  temp = (int) (source / grp_size_nodes);
  dest =  (RandomInt(grp_size_nodes - 1) + (temp+1)*grp_size_nodes ) %  total_nodes;

  return dest;
}

int badperm_dflynew( int source, int total_nodes )
{
  int grp_size_routers = 2*realgk;
  int grp_size_nodes = grp_size_routers * realgk;

  int temp;
  int dest;

  temp = (int) (source / grp_size_nodes);
  dest =  (RandomInt(grp_size_nodes - 1) + (temp+1)*grp_size_nodes ) %  total_nodes;

  return dest;
}

int badperm_yarc(int source, int total_nodes){
  int row = (int)(source/realgk);
  int col = (int)(source%realgk);

  return RandomInt(realgk-1)*realgk+row;
}

void InitializeTrafficMap( )
{

  /* Register Traffic functions here */

  gTrafficFunctionMap["uniform"]  = &uniform;

  // "Bit" patterns

  gTrafficFunctionMap["bitcomp"]   = &bitcomp;
  gTrafficFunctionMap["bitrev"]    = &bitrev;
  gTrafficFunctionMap["transpose"] = &transpose;
  gTrafficFunctionMap["shuffle"]   = &shuffle;

  // "Digit" patterns

  gTrafficFunctionMap["tornado"]   = &tornado;
  gTrafficFunctionMap["neighbor"]  = &neighbor;

  // Other patterns

  gTrafficFunctionMap["randperm"]   = &randperm;

  gTrafficFunctionMap["diagonal"]   = &diagonal;
  gTrafficFunctionMap["asymmetric"] = &asymmetric;
  gTrafficFunctionMap["taper64"]    = &taper64;

  gTrafficFunctionMap["bad_dragon"]    = &badperm_dflynew;
  gTrafficFunctionMap["badperm_yarc"] = &badperm_yarc;
}

void ResetTrafficFunction( )
{
  gResetTraffic++;
}

void StepTrafficFunction( )
{
  gStepTraffic++;
}

tTrafficFunction GetTrafficFunction( const Configuration& config )
{

  if(config.GetInt( "c" )!=1){
    int temp =  config.GetInt("xr");
    realgk = temp*gK;
    realgn = gN;
  } else {
    realgk = gK;
    realgn = gN;
  }

  string topo;
  config.GetStr( "topology", topo );

  map<string, tTrafficFunction>::const_iterator match;
  tTrafficFunction tf;

  string fn;

  config.GetStr( "traffic", fn, "none" );
  match = gTrafficFunctionMap.find( fn );

  if ( match != gTrafficFunctionMap.end( ) ) {
    tf = match->second;
  } else {
    cout << "Error: Undefined traffic pattern '" << fn << "'." << endl;
    exit(-1);
  }

  gPermSeed = config.GetInt( "perm_seed" );

  //seed the network
  RandomSeed(config.GetInt("seed"));
  return tf;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "de_web_plugin_private.h"
#ifdef Q_OS_UNIX
  #include <unistd.h>
#endif

#ifdef Q_OS_UNIX
    static const char *pwsalt = "$1$8282jdkmskwiu29291"; // $1$ for MD5
#endif

ApiAuth::ApiAuth() :
    needSaveDatabase(false),
    state(StateNormal)
{

}

/*! Init authentification and security.
 */
void DeRestPluginPrivate::initAuthentification()
{
    bool ok = false;

    if (gwConfig.contains("gwusername") && gwConfig.contains("gwpassword"))
    {
        gwAdminUserName = gwConfig["gwusername"].toString();
        gwAdminPasswordHash = gwConfig["gwpassword"].toString();

        if (!gwAdminUserName.isEmpty() && !gwAdminPasswordHash.isEmpty())
        {
            ok = true;
        }
    }

    if (!ok)
    {
        // generate default username and password
        gwAdminUserName = "delight";
        gwAdminPasswordHash = "delight";

        DBG_Printf(DBG_INFO, "create default username and password\n");

        // combine username:password
        QString comb = QString("%1:%2").arg(gwAdminUserName).arg(gwAdminPasswordHash);
        // create base64 encoded version as used in HTTP basic authentification
        QString hash = comb.toLocal8Bit().toBase64();

        gwAdminPasswordHash = encryptString(hash);

        queSaveDb(DB_CONFIG, DB_SHORT_SAVE_DELAY);
    }

}

/*! Use HTTP basic authentification to check if the request
    has valid credentials to create API key.
 */
bool DeRestPluginPrivate::allowedToCreateApikey(const ApiRequest &req)
{
    if (req.hdr.hasKey("Authorization"))
    {
        QStringList ls = req.hdr.value("Authorization").split(' ');
        if ((ls.size() > 1) && ls[0] == "Basic")
        {
            QString enc = encryptString(ls[1]);

            if (enc == gwAdminPasswordHash)
            {
                return true;
            }

            DBG_Printf(DBG_INFO, "Invalid admin password hash: %s\n", qPrintable(enc));
        }
    }

    return false;
}

/*! Checks if the request is authenticated to access the API.
    \retval true if authenticated
    \retval false if not authenticated and the rsp http status is set to 403 Forbidden and JSON error is appended
 */
bool DeRestPluginPrivate::checkApikeyAuthentification(const ApiRequest &req, ApiResponse &rsp)
{
    QString apikey = req.apikey();

    if (apikey.isEmpty())
    {
        return false;
    }

    std::vector<ApiAuth>::iterator i = apiAuths.begin();
    std::vector<ApiAuth>::iterator end = apiAuths.end();

    for (; i != end; ++i)
    {
        if (apikey == i->apikey)
        {
            i->lastUseDate = QDateTime::currentDateTimeUtc();

            // fill in useragent string if not already exist
            if (i->useragent.isEmpty())
            {
                if (req.hdr.hasKey("User-Agent"))
                {
                    i->useragent = req.hdr.value("User-Agent");
                    DBG_Printf(DBG_HTTP, "set useragent '%s' for apikey '%s'\n", qPrintable(i->useragent), qPrintable(i->apikey));
                }
            }

            i->needSaveDatabase = true;
            if (!apiAuthSaveDatabaseTime.isValid() || apiAuthSaveDatabaseTime.elapsed() > (1000 * 60 * 30))
            {
                apiAuthSaveDatabaseTime.start();
                queSaveDb(DB_AUTH, DB_LONG_SAVE_DELAY);
            }
            return true;
        }
    }

#if 0
    // allow non registered devices to use the api if the link button is pressed
    if (gwLinkButton)
    {
        ApiAuth auth;
        auth.needSaveDatabase = true;
        auth.apikey = apikey;
        auth.devicetype = "unknown";
        auth.createDate = QDateTime::currentDateTimeUtc();
        auth.lastUseDate = QDateTime::currentDateTimeUtc();
        apiAuths.push_back(auth);
        queSaveDb(DB_AUTH, DB_SHORT_SAVE_DELAY);
        return true;
    }
#endif

    rsp.httpStatus = HttpStatusForbidden;
    rsp.list.append(errorToMap(ERR_UNAUTHORIZED_USER, req.path.join("/"), "unauthorized user"));

    return false;
}

/*! Encrypts a string with using crypt() MD5 + salt. (unix only)
    \param str the input string
    \return the encrypted string on success or the unchanged input string on fail
 */
QString DeRestPluginPrivate::encryptString(const QString &str)
{
#ifdef Q_OS_UNIX
        // further encrypt and salt the hash
        const char *enc = crypt(str.toLocal8Bit().constData(), pwsalt);

        if (enc)
        {
            return QString(enc);
        }
        else
        {
            DBG_Printf(DBG_ERROR, "crypt(): %s failed\n", qPrintable(str));
            // fall through and return str
        }

#endif // Q_OS_UNIX
        return str;
}
<commit_msg>Fix authentification via deleted apikeys<commit_after>/*
 * Copyright (c) 2016 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "de_web_plugin_private.h"
#ifdef Q_OS_UNIX
  #include <unistd.h>
#endif

#ifdef Q_OS_UNIX
    static const char *pwsalt = "$1$8282jdkmskwiu29291"; // $1$ for MD5
#endif

ApiAuth::ApiAuth() :
    needSaveDatabase(false),
    state(StateNormal)
{

}

/*! Init authentification and security.
 */
void DeRestPluginPrivate::initAuthentification()
{
    bool ok = false;

    if (gwConfig.contains("gwusername") && gwConfig.contains("gwpassword"))
    {
        gwAdminUserName = gwConfig["gwusername"].toString();
        gwAdminPasswordHash = gwConfig["gwpassword"].toString();

        if (!gwAdminUserName.isEmpty() && !gwAdminPasswordHash.isEmpty())
        {
            ok = true;
        }
    }

    if (!ok)
    {
        // generate default username and password
        gwAdminUserName = "delight";
        gwAdminPasswordHash = "delight";

        DBG_Printf(DBG_INFO, "create default username and password\n");

        // combine username:password
        QString comb = QString("%1:%2").arg(gwAdminUserName).arg(gwAdminPasswordHash);
        // create base64 encoded version as used in HTTP basic authentification
        QString hash = comb.toLocal8Bit().toBase64();

        gwAdminPasswordHash = encryptString(hash);

        queSaveDb(DB_CONFIG, DB_SHORT_SAVE_DELAY);
    }

}

/*! Use HTTP basic authentification to check if the request
    has valid credentials to create API key.
 */
bool DeRestPluginPrivate::allowedToCreateApikey(const ApiRequest &req)
{
    if (req.hdr.hasKey("Authorization"))
    {
        QStringList ls = req.hdr.value("Authorization").split(' ');
        if ((ls.size() > 1) && ls[0] == "Basic")
        {
            QString enc = encryptString(ls[1]);

            if (enc == gwAdminPasswordHash)
            {
                return true;
            }

            DBG_Printf(DBG_INFO, "Invalid admin password hash: %s\n", qPrintable(enc));
        }
    }

    return false;
}

/*! Checks if the request is authenticated to access the API.
    \retval true if authenticated
    \retval false if not authenticated and the rsp http status is set to 403 Forbidden and JSON error is appended
 */
bool DeRestPluginPrivate::checkApikeyAuthentification(const ApiRequest &req, ApiResponse &rsp)
{
    QString apikey = req.apikey();

    if (apikey.isEmpty())
    {
        return false;
    }

    std::vector<ApiAuth>::iterator i = apiAuths.begin();
    std::vector<ApiAuth>::iterator end = apiAuths.end();

    for (; i != end; ++i)
    {
        if (apikey == i->apikey && i->state == ApiAuth::StateNormal)
        {
            i->lastUseDate = QDateTime::currentDateTimeUtc();

            // fill in useragent string if not already exist
            if (i->useragent.isEmpty())
            {
                if (req.hdr.hasKey("User-Agent"))
                {
                    i->useragent = req.hdr.value("User-Agent");
                    DBG_Printf(DBG_HTTP, "set useragent '%s' for apikey '%s'\n", qPrintable(i->useragent), qPrintable(i->apikey));
                }
            }

            i->needSaveDatabase = true;
            if (!apiAuthSaveDatabaseTime.isValid() || apiAuthSaveDatabaseTime.elapsed() > (1000 * 60 * 30))
            {
                apiAuthSaveDatabaseTime.start();
                queSaveDb(DB_AUTH, DB_LONG_SAVE_DELAY);
            }
            return true;
        }
    }

#if 0
    // allow non registered devices to use the api if the link button is pressed
    if (gwLinkButton)
    {
        ApiAuth auth;
        auth.needSaveDatabase = true;
        auth.apikey = apikey;
        auth.devicetype = "unknown";
        auth.createDate = QDateTime::currentDateTimeUtc();
        auth.lastUseDate = QDateTime::currentDateTimeUtc();
        apiAuths.push_back(auth);
        queSaveDb(DB_AUTH, DB_SHORT_SAVE_DELAY);
        return true;
    }
#endif

    rsp.httpStatus = HttpStatusForbidden;
    rsp.list.append(errorToMap(ERR_UNAUTHORIZED_USER, req.path.join("/"), "unauthorized user"));

    return false;
}

/*! Encrypts a string with using crypt() MD5 + salt. (unix only)
    \param str the input string
    \return the encrypted string on success or the unchanged input string on fail
 */
QString DeRestPluginPrivate::encryptString(const QString &str)
{
#ifdef Q_OS_UNIX
        // further encrypt and salt the hash
        const char *enc = crypt(str.toLocal8Bit().constData(), pwsalt);

        if (enc)
        {
            return QString(enc);
        }
        else
        {
            DBG_Printf(DBG_ERROR, "crypt(): %s failed\n", qPrintable(str));
            // fall through and return str
        }

#endif // Q_OS_UNIX
        return str;
}
<|endoftext|>


<commit_before>/*
 * StructureContainerComponent.cpp
 *
 *  Created on: 09/02/2012
 *      Author: victor
 */

#include "StructureContainerComponent.h"
#include "server/zone/objects/building/BuildingObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/tangible/components/vendor/VendorDataComponent.h"

bool StructureContainerComponent::checkContainerPermission(SceneObject* sceneObject, CreatureObject* creature, uint16 permission) {
	StructureObject* building = dynamic_cast<StructureObject*>(sceneObject);

	if(permission == ContainerPermissions::MOVEVENDOR) {
		if(building->isPublicStructure() && (building->isOnPermissionList("VENDOR", creature) || building->isOnAdminList(creature)))
			return true;
		else {
			if(building->isPrivateStructure())
				creature->sendSystemMessage("@player_structure:vendor_public_only"); //
			else
				creature->sendSystemMessage("@player_structure:drop_npc_vendor_perm"); // You do not have vendor permission in this building
			return false;
		}
	}

	if (building->isOwnerOf(creature) || building->isOnAdminList(creature))
		return true;

	if ((permission == ContainerPermissions::OPEN)  && building->isStaticObject())
		return true;

	if (building->isBuildingObject()) {
		BuildingObject* buio = cast<BuildingObject*>(building);

		if (!buio->isAllowedEntry(creature))
			return false;
	}

	return ContainerComponent::checkContainerPermission(sceneObject, creature, permission);
}
<commit_msg>[fixed] Pushed TA's structure container fix to prevent terminals from being removed from buildings.<commit_after>/*
 * StructureContainerComponent.cpp
 *
 *  Created on: 09/02/2012
 *      Author: victor
 */

#include "StructureContainerComponent.h"
#include "server/zone/objects/building/BuildingObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/tangible/components/vendor/VendorDataComponent.h"

bool StructureContainerComponent::checkContainerPermission(SceneObject* sceneObject, CreatureObject* creature, uint16 permission) {
	StructureObject* building = dynamic_cast<StructureObject*>(sceneObject);

	if(permission == ContainerPermissions::MOVEVENDOR) {
		if(building->isPublicStructure() && (building->isOnPermissionList("VENDOR", creature) || building->isOnAdminList(creature)))
			return true;
		else {
			if(building->isPrivateStructure())
				creature->sendSystemMessage("@player_structure:vendor_public_only"); //
			else
				creature->sendSystemMessage("@player_structure:drop_npc_vendor_perm"); // You do not have vendor permission in this building
			return false;
		}
	}

	if(permission != ContainerPermissions::OPEN && building->containsChildObject(sceneObject))
		return false;

	if (building->isOwnerOf(creature) || building->isOnAdminList(creature))
		return true;

	if ((permission == ContainerPermissions::OPEN)  && building->isStaticObject())
		return true;

	if (building->isBuildingObject()) {
		BuildingObject* buio = cast<BuildingObject*>(building);

		if (!buio->isAllowedEntry(creature))
			return false;
	}

	return ContainerComponent::checkContainerPermission(sceneObject, creature, permission);
}
<|endoftext|>