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

#include <grpc/support/port_platform.h>

#include <limits.h>
#include <memory.h>

#include <grpc/fork.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/init.h"
#include "src/core/lib/surface/lame_client.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/transport_impl.h"

/* (generated) built in registry of plugins */
extern void grpc_register_built_in_plugins(void);

#define MAX_PLUGINS 128

static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu;
static int g_initializations;
static gpr_cv* g_shutting_down_cv;
static bool g_shutting_down;

static void do_basic_init(void) {
  gpr_log_verbosity_init();
  gpr_mu_init(&g_init_mu);
  g_shutting_down_cv = static_cast<gpr_cv*>(malloc(sizeof(gpr_cv)));
  gpr_cv_init(g_shutting_down_cv);
  g_shutting_down = false;
  grpc_register_built_in_plugins();
  grpc_cq_global_init();
  g_initializations = 0;
}

static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
  return grpc_channel_stack_builder_append_filter(
      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
}

static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) {
  return grpc_channel_stack_builder_prepend_filter(
      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
}

static void register_builtin_channel_init() {
  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   grpc_add_connected_filter, nullptr);
  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   grpc_add_connected_filter, nullptr);
  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   grpc_add_connected_filter, nullptr);
  grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   append_filter, (void*)&grpc_lame_filter);
  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter,
                                   (void*)&grpc_server_top_filter);
}

typedef struct grpc_plugin {
  void (*init)();
  void (*destroy)();
} grpc_plugin;

static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS];
static int g_number_of_plugins = 0;

void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) {
  GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2,
                 ((void*)(intptr_t)init, (void*)(intptr_t)destroy));
  GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS);
  g_all_of_the_plugins[g_number_of_plugins].init = init;
  g_all_of_the_plugins[g_number_of_plugins].destroy = destroy;
  g_number_of_plugins++;
}

void grpc_init(void) {
  int i;
  gpr_once_init(&g_basic_init, do_basic_init);

  gpr_mu_lock(&g_init_mu);
  if (++g_initializations == 1) {
    if (g_shutting_down) {
      g_shutting_down = false;
      gpr_cv_broadcast(g_shutting_down_cv);
    }
    grpc_core::Fork::GlobalInit();
    grpc_fork_handlers_auto_register();
    gpr_time_init();
    gpr_arena_init();
    grpc_stats_init();
    grpc_slice_intern_init();
    grpc_mdctx_global_init();
    grpc_channel_init_init();
    grpc_core::channelz::ChannelzRegistry::Init();
    grpc_security_pre_init();
    grpc_core::ApplicationCallbackExecCtx::GlobalInit();
    grpc_core::ExecCtx::GlobalInit();
    grpc_iomgr_init();
    gpr_timers_global_init();
    grpc_core::HandshakerRegistry::Init();
    grpc_security_init();
    for (i = 0; i < g_number_of_plugins; i++) {
      if (g_all_of_the_plugins[i].init != nullptr) {
        g_all_of_the_plugins[i].init();
      }
    }
    /* register channel finalization AFTER all plugins, to ensure that it's run
     * at the appropriate time */
    grpc_register_security_filters();
    register_builtin_channel_init();
    grpc_tracer_init("GRPC_TRACE");
    /* no more changes to channel init pipelines */
    grpc_channel_init_finalize();
    grpc_iomgr_start();
  }
  gpr_mu_unlock(&g_init_mu);

  GRPC_API_TRACE("grpc_init(void)", 0, ());
}

void grpc_shutdown_internal(void* ignored) {
  int i;
  GRPC_API_TRACE("grpc_shutdown_internal", 0, ());
  gpr_mu_lock(&g_init_mu);
  // We have released lock from the shutdown thread and it is possible that
  // another grpc_init has been called, and do nothing if that is the case.
  if (--g_initializations != 0) {
    gpr_mu_unlock(&g_init_mu);
    return;
  }
  {
    grpc_core::ExecCtx exec_ctx(0);
    grpc_iomgr_shutdown_background_closure();
    {
      grpc_timer_manager_set_threading(
          false);  // shutdown timer_manager thread
      grpc_core::Executor::ShutdownAll();
      for (i = g_number_of_plugins; i >= 0; i--) {
        if (g_all_of_the_plugins[i].destroy != nullptr) {
          g_all_of_the_plugins[i].destroy();
        }
      }
    }
    grpc_iomgr_shutdown();
    gpr_timers_global_destroy();
    grpc_tracer_shutdown();
    grpc_mdctx_global_shutdown();
    grpc_core::HandshakerRegistry::Shutdown();
    grpc_slice_intern_shutdown();
    grpc_core::channelz::ChannelzRegistry::Shutdown();
    grpc_stats_shutdown();
    grpc_core::Fork::GlobalShutdown();
  }
  grpc_core::ExecCtx::GlobalShutdown();
  grpc_core::ApplicationCallbackExecCtx::GlobalShutdown();
  g_shutting_down = false;
  gpr_cv_broadcast(g_shutting_down_cv);
  gpr_mu_unlock(&g_init_mu);
}

void grpc_shutdown(void) {
  GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
  gpr_mu_lock(&g_init_mu);
  if (--g_initializations == 0) {
    g_initializations++;
    g_shutting_down = true;
    // spawn a detached thread to do the actual clean up in case we are
    // currently in an executor thread.
    grpc_core::Thread cleanup_thread(
        "grpc_shutdown", grpc_shutdown_internal, nullptr, nullptr,
        grpc_core::Thread::Options().set_joinable(false).set_tracked(false));
    cleanup_thread.Start();
  }
  gpr_mu_unlock(&g_init_mu);
}

int grpc_is_initialized(void) {
  int r;
  gpr_once_init(&g_basic_init, do_basic_init);
  gpr_mu_lock(&g_init_mu);
  r = g_initializations > 0;
  gpr_mu_unlock(&g_init_mu);
  return r;
}

void grpc_maybe_wait_for_async_shutdown(void) {
  gpr_once_init(&g_basic_init, do_basic_init);
  gpr_mu_lock(&g_init_mu);
  while (g_shutting_down) {
    gpr_cv_wait(g_shutting_down_cv, &g_init_mu,
                gpr_inf_future(GPR_CLOCK_REALTIME));
  }
  gpr_mu_unlock(&g_init_mu);
}
<commit_msg>clang-format<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include <limits.h>
#include <memory.h>

#include <grpc/fork.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/channel/connected_channel.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/debug/stats.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/http/parser.h"
#include "src/core/lib/iomgr/call_combiner.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr.h"
#include "src/core/lib/iomgr/resource_quota.h"
#include "src/core/lib/iomgr/timer_manager.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/surface/channel_init.h"
#include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/init.h"
#include "src/core/lib/surface/lame_client.h"
#include "src/core/lib/surface/server.h"
#include "src/core/lib/transport/bdp_estimator.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/transport_impl.h"

/* (generated) built in registry of plugins */
extern void grpc_register_built_in_plugins(void);

#define MAX_PLUGINS 128

static gpr_once g_basic_init = GPR_ONCE_INIT;
static gpr_mu g_init_mu;
static int g_initializations;
static gpr_cv* g_shutting_down_cv;
static bool g_shutting_down;

static void do_basic_init(void) {
  gpr_log_verbosity_init();
  gpr_mu_init(&g_init_mu);
  g_shutting_down_cv = static_cast<gpr_cv*>(malloc(sizeof(gpr_cv)));
  gpr_cv_init(g_shutting_down_cv);
  g_shutting_down = false;
  grpc_register_built_in_plugins();
  grpc_cq_global_init();
  g_initializations = 0;
}

static bool append_filter(grpc_channel_stack_builder* builder, void* arg) {
  return grpc_channel_stack_builder_append_filter(
      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
}

static bool prepend_filter(grpc_channel_stack_builder* builder, void* arg) {
  return grpc_channel_stack_builder_prepend_filter(
      builder, static_cast<const grpc_channel_filter*>(arg), nullptr, nullptr);
}

static void register_builtin_channel_init() {
  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   grpc_add_connected_filter, nullptr);
  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   grpc_add_connected_filter, nullptr);
  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   grpc_add_connected_filter, nullptr);
  grpc_channel_init_register_stage(GRPC_CLIENT_LAME_CHANNEL,
                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                   append_filter, (void*)&grpc_lame_filter);
  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX, prepend_filter,
                                   (void*)&grpc_server_top_filter);
}

typedef struct grpc_plugin {
  void (*init)();
  void (*destroy)();
} grpc_plugin;

static grpc_plugin g_all_of_the_plugins[MAX_PLUGINS];
static int g_number_of_plugins = 0;

void grpc_register_plugin(void (*init)(void), void (*destroy)(void)) {
  GRPC_API_TRACE("grpc_register_plugin(init=%p, destroy=%p)", 2,
                 ((void*)(intptr_t)init, (void*)(intptr_t)destroy));
  GPR_ASSERT(g_number_of_plugins != MAX_PLUGINS);
  g_all_of_the_plugins[g_number_of_plugins].init = init;
  g_all_of_the_plugins[g_number_of_plugins].destroy = destroy;
  g_number_of_plugins++;
}

void grpc_init(void) {
  int i;
  gpr_once_init(&g_basic_init, do_basic_init);

  gpr_mu_lock(&g_init_mu);
  if (++g_initializations == 1) {
    if (g_shutting_down) {
      g_shutting_down = false;
      gpr_cv_broadcast(g_shutting_down_cv);
    }
    grpc_core::Fork::GlobalInit();
    grpc_fork_handlers_auto_register();
    gpr_time_init();
    gpr_arena_init();
    grpc_stats_init();
    grpc_slice_intern_init();
    grpc_mdctx_global_init();
    grpc_channel_init_init();
    grpc_core::channelz::ChannelzRegistry::Init();
    grpc_security_pre_init();
    grpc_core::ApplicationCallbackExecCtx::GlobalInit();
    grpc_core::ExecCtx::GlobalInit();
    grpc_iomgr_init();
    gpr_timers_global_init();
    grpc_core::HandshakerRegistry::Init();
    grpc_security_init();
    for (i = 0; i < g_number_of_plugins; i++) {
      if (g_all_of_the_plugins[i].init != nullptr) {
        g_all_of_the_plugins[i].init();
      }
    }
    /* register channel finalization AFTER all plugins, to ensure that it's run
     * at the appropriate time */
    grpc_register_security_filters();
    register_builtin_channel_init();
    grpc_tracer_init("GRPC_TRACE");
    /* no more changes to channel init pipelines */
    grpc_channel_init_finalize();
    grpc_iomgr_start();
  }
  gpr_mu_unlock(&g_init_mu);

  GRPC_API_TRACE("grpc_init(void)", 0, ());
}

void grpc_shutdown_internal(void* ignored) {
  int i;
  GRPC_API_TRACE("grpc_shutdown_internal", 0, ());
  gpr_mu_lock(&g_init_mu);
  // We have released lock from the shutdown thread and it is possible that
  // another grpc_init has been called, and do nothing if that is the case.
  if (--g_initializations != 0) {
    gpr_mu_unlock(&g_init_mu);
    return;
  }
  {
    grpc_core::ExecCtx exec_ctx(0);
    grpc_iomgr_shutdown_background_closure();
    {
      grpc_timer_manager_set_threading(false);  // shutdown timer_manager thread
      grpc_core::Executor::ShutdownAll();
      for (i = g_number_of_plugins; i >= 0; i--) {
        if (g_all_of_the_plugins[i].destroy != nullptr) {
          g_all_of_the_plugins[i].destroy();
        }
      }
    }
    grpc_iomgr_shutdown();
    gpr_timers_global_destroy();
    grpc_tracer_shutdown();
    grpc_mdctx_global_shutdown();
    grpc_core::HandshakerRegistry::Shutdown();
    grpc_slice_intern_shutdown();
    grpc_core::channelz::ChannelzRegistry::Shutdown();
    grpc_stats_shutdown();
    grpc_core::Fork::GlobalShutdown();
  }
  grpc_core::ExecCtx::GlobalShutdown();
  grpc_core::ApplicationCallbackExecCtx::GlobalShutdown();
  g_shutting_down = false;
  gpr_cv_broadcast(g_shutting_down_cv);
  gpr_mu_unlock(&g_init_mu);
}

void grpc_shutdown(void) {
  GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
  gpr_mu_lock(&g_init_mu);
  if (--g_initializations == 0) {
    g_initializations++;
    g_shutting_down = true;
    // spawn a detached thread to do the actual clean up in case we are
    // currently in an executor thread.
    grpc_core::Thread cleanup_thread(
        "grpc_shutdown", grpc_shutdown_internal, nullptr, nullptr,
        grpc_core::Thread::Options().set_joinable(false).set_tracked(false));
    cleanup_thread.Start();
  }
  gpr_mu_unlock(&g_init_mu);
}

int grpc_is_initialized(void) {
  int r;
  gpr_once_init(&g_basic_init, do_basic_init);
  gpr_mu_lock(&g_init_mu);
  r = g_initializations > 0;
  gpr_mu_unlock(&g_init_mu);
  return r;
}

void grpc_maybe_wait_for_async_shutdown(void) {
  gpr_once_init(&g_basic_init, do_basic_init);
  gpr_mu_lock(&g_init_mu);
  while (g_shutting_down) {
    gpr_cv_wait(g_shutting_down_cv, &g_init_mu,
                gpr_inf_future(GPR_CLOCK_REALTIME));
  }
  gpr_mu_unlock(&g_init_mu);
}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------//
//!
//! \file   MonteCarlo_Photoatom.cpp
//! \author Alex Robinson
//! \brief  The photoatom base class definition
//!
//---------------------------------------------------------------------------//

// FRENSIE Includes
#include "MonteCarlo_Photoatom.hpp"
#include "Utility_RandomNumberGenerator.hpp"
#include "Utility_ExceptionTestMacros.hpp"
#include "Utility_ContractException.hpp"

namespace MonteCarlo{

// Return the reactions that are treated as absorption
const boost::unordered_set<PhotoatomicReactionType>&
Photoatom::getAbsorptionReactionTypes()
{
  return PhotoatomCore::absorption_reaction_types;
}

//! Constructor (from a core)
Photoatom::Photoatom( const std::string& name,
		      const unsigned atomic_number,
		      const double atomic_weight,
		      const PhotoatomCore& core )
  : d_name( name ),
    d_atomic_number( atomic_number ),
    d_atomic_weight( atomic_weight ),
    d_core( core )
{
  // Make sure the atomic weight is valid
  testPrecondition( atomic_weight > 0.0 );
  // There must be at least one reaction specified
  testPrecondition( core.getScatteringReactions().size() +
		    core.getAbsorptionReactions().size() > 0 );
  // Make sure all reactions have a shared energy grid
  testPrecondition( core.hasSharedEnergyGrid() );
}

// Return the atom name
const std::string& Photoatom::getAtomName() const
{
  return d_name;
}

// Return the atomic number
unsigned Photoatom::getAtomicNumber() const
{
  return d_atomic_number;
}

// Return the atomic weight
double Photoatom::getAtomicWeight() const
{
  return d_atomic_weight;
}

// Return the total cross section from atomic interactions
double Photoatom::getAtomicTotalCrossSection( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  return d_core.getTotalReaction().getCrossSection( energy );
}

// Return the total absorption cross section from atomic interactions
double Photoatom::getAtomicAbsorptionCrossSection( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  return d_core.getTotalAbsorptionReaction().getCrossSection( energy );
}

// Return the survival probability at the desired energy
double Photoatom::getSurvivalProbability( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  double survival_prob;

  // Find the energy bin index
  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( energy ) )
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( energy );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( energy, energy_grid_bin );

    if( total_cross_section > 0.0 )
    {
      survival_prob = 1.0 -
	d_core.getTotalAbsorptionReaction().getCrossSection( energy,
							     energy_grid_bin )/
	total_cross_section;
    }
    else
      survival_prob = 1.0;
  }
  else
    survival_prob = 1.0;

  // Make sure the survival probability is valid
  testPostcondition( !ST::isnaninf( survival_prob ) );
  testPostcondition( survival_prob >= 0.0 );
  testPostcondition( survival_prob <= 1.0 );

  return survival_prob;
}

// Return the survival probability from atomic interactions
double Photoatom::getAtomicSurvivalProbability( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  double survival_prob;

  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( energy ) )
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( energy );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( energy, energy_grid_bin );

    if( total_cross_section > 0.0 )
    {
      survival_prob = 1.0 -
	d_core.getTotalAbsorptionReaction().getCrossSection( energy,
							     energy_grid_bin )/
	total_cross_section;
    }
    else
      survival_prob = 1.0;
  }
  else
    survival_prob = 1.0;

  // Make sure the survival probability is valid
  testPostcondition( !ST::isnaninf( survival_prob ) );
  testPostcondition( survival_prob >= 0.0 );
  testPostcondition( survival_prob <= 1.0 );

  return survival_prob;
}

// Return the survival probability from nuclear interactions
double Photoatom::getNuclearSurvivalProbability( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  double survival_prob;
  double total_cross_section = this->getNuclearTotalCrossSection( energy );

  if( total_cross_section > 0.0 )
  {
    survival_prob = 1.0 -
      this->getNuclearAbsorptionCrossSection( energy )/total_cross_section;
  }
  else
    survival_prob = 1.0;

  // Make sure the survival probability is valid
  testPostcondition( !ST::isnaninf( survival_prob ) );
  testPostcondition( survival_prob >= 0.0 );
  testPostcondition( survival_prob <= 1.0 );

  return survival_prob;
}

// Return the cross section for a specific photoatomic reaction
double Photoatom::getReactionCrossSection(
			        const double energy,
			        const PhotoatomicReactionType reaction ) const
{
  switch( reaction )
  {
  case TOTAL_PHOTOATOMIC_REACTION:
    return this->getTotalCrossSection( energy );
  case TOTAL_ABSORPTION_PHOTOATOMIC_REACTION:
    return this->getAbsorptionCrossSection( energy );
  default:
    ConstReactionMap::const_iterator photoatomic_reaction =
      d_core.getScatteringReactions().find( reaction );

    if( photoatomic_reaction != d_core.getScatteringReactions().end() )
      return photoatomic_reaction->second->getCrossSection( energy );

    photoatomic_reaction = d_core.getAbsorptionReactions().find( reaction );

    if( photoatomic_reaction != d_core.getAbsorptionReactions().end() )
      return photoatomic_reaction->second->getCrossSection( energy );

    photoatomic_reaction = d_core.getMiscReactions().find( reaction );

    if( photoatomic_reaction != d_core.getMiscReactions().end() )
      return photoatomic_reaction->second->getCrossSection( energy );
    else // If the reaction does not exist for an atom, return 0
      return 0.0;
  }
}

// Collide with a photon
void Photoatom::collideAnalogue( PhotonState& photon,
				 ParticleBank& bank ) const
{
  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( photon.getEnergy() ))
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( photon.getEnergy() );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( photon.getEnergy(),
						 energy_grid_bin );

    double scaled_random_number =
      Utility::RandomNumberGenerator::getRandomNumber<double>()*
      total_cross_section;

    double absorption_cross_section =
      d_core.getTotalAbsorptionReaction().getCrossSection( photon.getEnergy(),
							   energy_grid_bin );

    // Check if absorption occurs
    if( scaled_random_number < absorption_cross_section )
    {
      sampleAbsorptionReaction( scaled_random_number,
				energy_grid_bin,
				photon,
				bank );

      // Set the photon as gone regardless of the reaction that occurred
      photon.setAsGone();
    }
    else
    {
      sampleScatteringReaction(scaled_random_number - absorption_cross_section,
			       energy_grid_bin,
			       photon,
			       bank );
    }
  }
}

// Collide with a photon and survival bias
void Photoatom::collideSurvivalBias( PhotonState& photon,
				     ParticleBank& bank ) const
{
  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( photon.getEnergy() ))
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( photon.getEnergy() );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( photon.getEnergy(),
						 energy_grid_bin );

    double scattering_cross_section = total_cross_section -
      d_core.getTotalAbsorptionReaction().getCrossSection( photon.getEnergy(),
							   energy_grid_bin );

    double survival_prob = scattering_cross_section/total_cross_section;

    // Multiply the photon's weigth by the survival probabilty
    if( survival_prob > 0.0 )
    {
      // Create a copy of the photon for sampling the absorption reaction
      PhotonState photon_copy( photon, false, false );

      photon.multiplyWeight( survival_prob );

      sampleScatteringReaction(
		     Utility::RandomNumberGenerator::getRandomNumber<double>()*
		     scattering_cross_section,
		     energy_grid_bin,
		     photon,
		     bank );

      photon_copy.multiplyWeight( 1.0 - survival_prob );

      sampleAbsorptionReaction(
		     Utility::RandomNumberGenerator::getRandomNumber<double>()*
		     (total_cross_section - scattering_cross_section),
		     energy_grid_bin,
		     photon_copy,
		     bank );
    }
    else
      photon.setAsGone();
  }
}

// Sample an absorption reaction
void Photoatom::sampleAbsorptionReaction( const double scaled_random_number,
					  unsigned energy_grid_bin,
					  PhotonState& photon,
					  ParticleBank& bank ) const
{
  double partial_cross_section = 0.0;

  ConstReactionMap::const_iterator photoatomic_reaction =
    d_core.getAbsorptionReactions().begin();

  while( photoatomic_reaction != d_core.getAbsorptionReactions().end() )
  {
    partial_cross_section +=
      photoatomic_reaction->second->getCrossSection( photon.getEnergy(),
						     energy_grid_bin );

    if( scaled_random_number < partial_cross_section )
      break;

    ++photoatomic_reaction;
  }

  // Make sure a reaction was selected
  testPostcondition( photoatomic_reaction !=
		     d_core.getAbsorptionReactions().end() );

  // Undergo reaction selected
  SubshellType subshell_vacancy;

  photoatomic_reaction->second->react( photon, bank, subshell_vacancy );

  // Relax the atom
  d_core.getAtomicRelaxationModel().relaxAtom( subshell_vacancy,
					       photon,
					       bank );
}

// Sample a scattering reaction
void Photoatom::sampleScatteringReaction( const double scaled_random_number,
					  unsigned energy_grid_bin,
					  PhotonState& photon,
					  ParticleBank& bank ) const
{
  double partial_cross_section = 0.0;

  ConstReactionMap::const_iterator photoatomic_reaction =
    d_core.getScatteringReactions().begin();

  while( photoatomic_reaction != d_core.getScatteringReactions().end() )
  {
    partial_cross_section +=
      photoatomic_reaction->second->getCrossSection( photon.getEnergy(),
						     energy_grid_bin );

    if( scaled_random_number < partial_cross_section )
      break;

    ++photoatomic_reaction;
  }

  if( photoatomic_reaction == d_core.getScatteringReactions().end() )
  {
    // #pragma omp critical
    // {
    //   std::cerr.precision( 18 );
    //   std::cout << "Warning: the scaled random number ("
    // 		<< scaled_random_number << "/"
    // 		<< this->getTotalCrossSection( photon.getEnergy() ) -
    // 	this->getAbsorptionCrossSection( photon.getEnergy() )
    // 		<< ") is larger than the "
    // 		<< "scattering cross section ("
    // 		<< partial_cross_section << ")" << std::endl;
    // }

    photoatomic_reaction = d_core.getScatteringReactions().begin();

    std::advance( photoatomic_reaction,
		  d_core.getScatteringReactions().size()-1 );
  }

  // Make sure the reaction was found
  testPostcondition( photoatomic_reaction !=
		     d_core.getScatteringReactions().end() );

  // Undergo reaction selected
  SubshellType subshell_vacancy;

  photoatomic_reaction->second->react( photon, bank, subshell_vacancy );

  // Relax the atom
  d_core.getAtomicRelaxationModel().relaxAtom( subshell_vacancy,
					       photon,
					       bank );
}

} // end MonteCarlo namespace

//---------------------------------------------------------------------------//
// end MonteCarlo_Photoatom.cpp
//---------------------------------------------------------------------------//

<commit_msg>Fixed a bug in the sampling of absorption reactions in the photoatom class.<commit_after>//---------------------------------------------------------------------------//
//!
//! \file   MonteCarlo_Photoatom.cpp
//! \author Alex Robinson
//! \brief  The photoatom base class definition
//!
//---------------------------------------------------------------------------//

// FRENSIE Includes
#include "MonteCarlo_Photoatom.hpp"
#include "Utility_RandomNumberGenerator.hpp"
#include "Utility_ExceptionTestMacros.hpp"
#include "Utility_ContractException.hpp"

namespace MonteCarlo{

// Return the reactions that are treated as absorption
const boost::unordered_set<PhotoatomicReactionType>&
Photoatom::getAbsorptionReactionTypes()
{
  return PhotoatomCore::absorption_reaction_types;
}

//! Constructor (from a core)
Photoatom::Photoatom( const std::string& name,
		      const unsigned atomic_number,
		      const double atomic_weight,
		      const PhotoatomCore& core )
  : d_name( name ),
    d_atomic_number( atomic_number ),
    d_atomic_weight( atomic_weight ),
    d_core( core )
{
  // Make sure the atomic weight is valid
  testPrecondition( atomic_weight > 0.0 );
  // There must be at least one reaction specified
  testPrecondition( core.getScatteringReactions().size() +
		    core.getAbsorptionReactions().size() > 0 );
  // Make sure all reactions have a shared energy grid
  testPrecondition( core.hasSharedEnergyGrid() );
}

// Return the atom name
const std::string& Photoatom::getAtomName() const
{
  return d_name;
}

// Return the atomic number
unsigned Photoatom::getAtomicNumber() const
{
  return d_atomic_number;
}

// Return the atomic weight
double Photoatom::getAtomicWeight() const
{
  return d_atomic_weight;
}

// Return the total cross section from atomic interactions
double Photoatom::getAtomicTotalCrossSection( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  return d_core.getTotalReaction().getCrossSection( energy );
}

// Return the total absorption cross section from atomic interactions
double Photoatom::getAtomicAbsorptionCrossSection( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  return d_core.getTotalAbsorptionReaction().getCrossSection( energy );
}

// Return the survival probability at the desired energy
double Photoatom::getSurvivalProbability( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  double survival_prob;

  // Find the energy bin index
  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( energy ) )
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( energy );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( energy, energy_grid_bin );

    if( total_cross_section > 0.0 )
    {
      survival_prob = 1.0 -
	d_core.getTotalAbsorptionReaction().getCrossSection( energy,
							     energy_grid_bin )/
	total_cross_section;
    }
    else
      survival_prob = 1.0;
  }
  else
    survival_prob = 1.0;

  // Make sure the survival probability is valid
  testPostcondition( !ST::isnaninf( survival_prob ) );
  testPostcondition( survival_prob >= 0.0 );
  testPostcondition( survival_prob <= 1.0 );

  return survival_prob;
}

// Return the survival probability from atomic interactions
double Photoatom::getAtomicSurvivalProbability( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  double survival_prob;

  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( energy ) )
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( energy );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( energy, energy_grid_bin );

    if( total_cross_section > 0.0 )
    {
      survival_prob = 1.0 -
	d_core.getTotalAbsorptionReaction().getCrossSection( energy,
							     energy_grid_bin )/
	total_cross_section;
    }
    else
      survival_prob = 1.0;
  }
  else
    survival_prob = 1.0;

  // Make sure the survival probability is valid
  testPostcondition( !ST::isnaninf( survival_prob ) );
  testPostcondition( survival_prob >= 0.0 );
  testPostcondition( survival_prob <= 1.0 );

  return survival_prob;
}

// Return the survival probability from nuclear interactions
double Photoatom::getNuclearSurvivalProbability( const double energy ) const
{
  // Make sure the energy is valid
  testPrecondition( !ST::isnaninf( energy ) );
  testPrecondition( energy > 0.0 );

  double survival_prob;
  double total_cross_section = this->getNuclearTotalCrossSection( energy );

  if( total_cross_section > 0.0 )
  {
    survival_prob = 1.0 -
      this->getNuclearAbsorptionCrossSection( energy )/total_cross_section;
  }
  else
    survival_prob = 1.0;

  // Make sure the survival probability is valid
  testPostcondition( !ST::isnaninf( survival_prob ) );
  testPostcondition( survival_prob >= 0.0 );
  testPostcondition( survival_prob <= 1.0 );

  return survival_prob;
}

// Return the cross section for a specific photoatomic reaction
double Photoatom::getReactionCrossSection(
			        const double energy,
			        const PhotoatomicReactionType reaction ) const
{
  switch( reaction )
  {
  case TOTAL_PHOTOATOMIC_REACTION:
    return this->getTotalCrossSection( energy );
  case TOTAL_ABSORPTION_PHOTOATOMIC_REACTION:
    return this->getAbsorptionCrossSection( energy );
  default:
    ConstReactionMap::const_iterator photoatomic_reaction =
      d_core.getScatteringReactions().find( reaction );

    if( photoatomic_reaction != d_core.getScatteringReactions().end() )
      return photoatomic_reaction->second->getCrossSection( energy );

    photoatomic_reaction = d_core.getAbsorptionReactions().find( reaction );

    if( photoatomic_reaction != d_core.getAbsorptionReactions().end() )
      return photoatomic_reaction->second->getCrossSection( energy );

    photoatomic_reaction = d_core.getMiscReactions().find( reaction );

    if( photoatomic_reaction != d_core.getMiscReactions().end() )
      return photoatomic_reaction->second->getCrossSection( energy );
    else // If the reaction does not exist for an atom, return 0
      return 0.0;
  }
}

// Collide with a photon
void Photoatom::collideAnalogue( PhotonState& photon,
				 ParticleBank& bank ) const
{
  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( photon.getEnergy() ))
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( photon.getEnergy() );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( photon.getEnergy(),
						 energy_grid_bin );

    double scaled_random_number =
      Utility::RandomNumberGenerator::getRandomNumber<double>()*
      total_cross_section;

    double absorption_cross_section =
      d_core.getTotalAbsorptionReaction().getCrossSection( photon.getEnergy(),
							   energy_grid_bin );

    // Check if absorption occurs
    if( scaled_random_number < absorption_cross_section )
    {
      sampleAbsorptionReaction( scaled_random_number,
				energy_grid_bin,
				photon,
				bank );

      // Set the photon as gone regardless of the reaction that occurred
      photon.setAsGone();
    }
    else
    {
      sampleScatteringReaction(scaled_random_number - absorption_cross_section,
			       energy_grid_bin,
			       photon,
			       bank );
    }
  }
}

// Collide with a photon and survival bias
void Photoatom::collideSurvivalBias( PhotonState& photon,
				     ParticleBank& bank ) const
{
  if( d_core.getTotalReaction().isEnergyWithinEnergyGrid( photon.getEnergy() ))
  {
    unsigned energy_grid_bin =
      d_core.getGridSearcher().findLowerBinIndex( photon.getEnergy() );

    double total_cross_section =
      d_core.getTotalReaction().getCrossSection( photon.getEnergy(),
						 energy_grid_bin );

    double scattering_cross_section = total_cross_section -
      d_core.getTotalAbsorptionReaction().getCrossSection( photon.getEnergy(),
							   energy_grid_bin );

    double survival_prob = scattering_cross_section/total_cross_section;

    // Multiply the photon's weigth by the survival probabilty
    if( survival_prob > 0.0 )
    {
      // Create a copy of the photon for sampling the absorption reaction
      PhotonState photon_copy( photon, false, false );

      photon.multiplyWeight( survival_prob );

      sampleScatteringReaction(
		     Utility::RandomNumberGenerator::getRandomNumber<double>()*
		     scattering_cross_section,
		     energy_grid_bin,
		     photon,
		     bank );

      photon_copy.multiplyWeight( 1.0 - survival_prob );

      sampleAbsorptionReaction(
		     Utility::RandomNumberGenerator::getRandomNumber<double>()*
		     (total_cross_section - scattering_cross_section),
		     energy_grid_bin,
		     photon_copy,
		     bank );
    }
    else
      photon.setAsGone();
  }
}

// Sample an absorption reaction
void Photoatom::sampleAbsorptionReaction( const double scaled_random_number,
					  unsigned energy_grid_bin,
					  PhotonState& photon,
					  ParticleBank& bank ) const
{
  double partial_cross_section = 0.0;

  ConstReactionMap::const_iterator photoatomic_reaction =
    d_core.getAbsorptionReactions().begin();

  while( photoatomic_reaction != d_core.getAbsorptionReactions().end() )
  {
    partial_cross_section +=
      photoatomic_reaction->second->getCrossSection( photon.getEnergy(),
						     energy_grid_bin );

    if( scaled_random_number < partial_cross_section )
      break;

    ++photoatomic_reaction;
  }

  // Note: the absorption cross section is calculated at run time. However, if
  // the cross sections are stored on a log-log grid, the absorption cross
  // section won't be exactly equal to the sum of the stored cross sections.
  // This test ensures that a valid reaction is always sampled.
  if( photoatomic_reaction == d_core.getAbsorptionReactions().end() )
  {
    photoatomic_reaction = d_core.getAbsorptionReactions().begin();

    std::advance( photoatomic_reaction,
		  d_core.getAbsorptionReactions().size()-1 );
  }

  // Make sure a reaction was selected
  testPostcondition( photoatomic_reaction !=
		     d_core.getAbsorptionReactions().end() );

  // Undergo reaction selected
  SubshellType subshell_vacancy;

  photoatomic_reaction->second->react( photon, bank, subshell_vacancy );

  // Relax the atom
  d_core.getAtomicRelaxationModel().relaxAtom( subshell_vacancy,
					       photon,
					       bank );
}

// Sample a scattering reaction
void Photoatom::sampleScatteringReaction( const double scaled_random_number,
					  unsigned energy_grid_bin,
					  PhotonState& photon,
					  ParticleBank& bank ) const
{
  double partial_cross_section = 0.0;

  ConstReactionMap::const_iterator photoatomic_reaction =
    d_core.getScatteringReactions().begin();

  while( photoatomic_reaction != d_core.getScatteringReactions().end() )
  {
    partial_cross_section +=
      photoatomic_reaction->second->getCrossSection( photon.getEnergy(),
						     energy_grid_bin );

    if( scaled_random_number < partial_cross_section )
      break;

    ++photoatomic_reaction;
  }

  // Note: the total cross section is calculated at run time. However, if the
  // cross sections are stored on a log-log grid, the total cross section
  // won't be exactly equal to the sum of the stored cross sections. This
  // test ensures that a valid reaction is always sampled
  if( photoatomic_reaction == d_core.getScatteringReactions().end() )
  {
    photoatomic_reaction = d_core.getScatteringReactions().begin();

    std::advance( photoatomic_reaction,
		  d_core.getScatteringReactions().size()-1 );
  }

  // Make sure the reaction was found
  testPostcondition( photoatomic_reaction !=
		     d_core.getScatteringReactions().end() );

  // Undergo reaction selected
  SubshellType subshell_vacancy;

  photoatomic_reaction->second->react( photon, bank, subshell_vacancy );

  // Relax the atom
  d_core.getAtomicRelaxationModel().relaxAtom( subshell_vacancy,
					       photon,
					       bank );
}

} // end MonteCarlo namespace

//---------------------------------------------------------------------------//
// end MonteCarlo_Photoatom.cpp
//---------------------------------------------------------------------------//

<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <cstdio>             /* for std::snprintf() */

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>        /* for ioctl() */
#endif

#define CAML_NAME_SPACE
#include <caml/alloc.h>       /* for caml_copy_*() */
#include <caml/bigarray.h>    /* for Caml_ba_data_val() */
#include <caml/memory.h>      /* for CAMLlocal1(), CAMLparam?(), CAMLreturn() */
#include <caml/mlvalues.h>    /* for value */
#include <caml/threads.h>     /* for caml_{enter,leave}_blocking_section() */
#include <caml/unixsupport.h> /* for uerror() */

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_void(value v_fd,
                           value v_cmd) {
  CAMLparam2(v_fd, v_cmd);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);

  caml_enter_blocking_section();
  const int rc = ioctl(fd, cmd, NULL);
  caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx", fd, cmd);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(rc);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_int64_val(value v_fd,
                                value v_cmd,
                                value v_arg) {
  CAMLparam3(v_fd, v_cmd, v_arg);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);
  const unsigned long arg = Int64_val(v_arg);

  caml_enter_blocking_section();
  const int rc = ioctl(fd, cmd, arg);
  caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx, 0x%08lx", fd, cmd, arg);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(rc);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_int64_ref(value v_fd,
                                value v_cmd,
                                value v_arg) {
  CAMLparam3(v_fd, v_cmd, v_arg);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);
  unsigned long arg = Int64_val(v_arg);

  caml_enter_blocking_section();
  const int rc = ioctl(fd, cmd, &arg);
  caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx, 0x%08lx", fd, cmd, arg);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(arg);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_bigarray(value v_fd,
                               value v_cmd,
                               value v_arg) {
  CAMLparam3(v_fd, v_cmd, v_arg);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);
  void* arg = Caml_ba_data_val(v_arg);

  //caml_enter_blocking_section(); // FIXME
  const int rc = ioctl(fd, cmd, arg);
  //caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx, %p", fd, cmd, arg);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(rc);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}
<commit_msg>Fixed linking errors when building with OCaml 4.01.<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <cstdio>             /* for std::snprintf() */

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>        /* for ioctl() */
#endif

#define CAML_NAME_SPACE
extern "C" {
#include <caml/alloc.h>       /* for caml_copy_*() */
#include <caml/bigarray.h>    /* for Caml_ba_data_val() */
#include <caml/memory.h>      /* for CAMLlocal1(), CAMLparam?(), CAMLreturn() */
#include <caml/mlvalues.h>    /* for value */
#include <caml/threads.h>     /* for caml_{enter,leave}_blocking_section() */
#include <caml/unixsupport.h> /* for uerror() */
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_void(value v_fd,
                           value v_cmd) {
  CAMLparam2(v_fd, v_cmd);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);

  caml_enter_blocking_section();
  const int rc = ioctl(fd, cmd, NULL);
  caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx", fd, cmd);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(rc);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_int64_val(value v_fd,
                                value v_cmd,
                                value v_arg) {
  CAMLparam3(v_fd, v_cmd, v_arg);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);
  const unsigned long arg = Int64_val(v_arg);

  caml_enter_blocking_section();
  const int rc = ioctl(fd, cmd, arg);
  caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx, 0x%08lx", fd, cmd, arg);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(rc);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_int64_ref(value v_fd,
                                value v_cmd,
                                value v_arg) {
  CAMLparam3(v_fd, v_cmd, v_arg);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);
  unsigned long arg = Int64_val(v_arg);

  caml_enter_blocking_section();
  const int rc = ioctl(fd, cmd, &arg);
  caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx, 0x%08lx", fd, cmd, arg);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(arg);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}

////////////////////////////////////////////////////////////////////////////////

extern "C" CAMLprim value
caml_conreality_ioctl_bigarray(value v_fd,
                               value v_cmd,
                               value v_arg) {
  CAMLparam3(v_fd, v_cmd, v_arg);
  CAMLlocal1(v_result);

#ifdef HAVE_SYS_IOCTL_H
  const int fd = Int_val(v_fd);
  const unsigned long cmd = Int64_val(v_cmd);
  void* arg = Caml_ba_data_val(v_arg);

  //caml_enter_blocking_section(); // FIXME
  const int rc = ioctl(fd, cmd, arg);
  //caml_leave_blocking_section();

  if (rc == -1) {
    char arg_string[64];
    std::snprintf(arg_string, sizeof(arg_string), "%d, 0x%08lx, %p", fd, cmd, arg);
    uerror(const_cast<char*>("ioctl"), caml_copy_string(arg_string));
  }

  v_result = caml_copy_int64(rc);
#else
  v_result = caml_copy_int64(0);
#endif /* HAVE_SYS_IOCTL_H */
  CAMLreturn(v_result);
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 */

/**
 * @file
 *   This file implements common MeshCoP utility functions.
 */

#include "meshcop.hpp"

#include "common/crc16.hpp"
#include "common/debug.hpp"
#include "common/locator-getters.hpp"
#include "crypto/pbkdf2_cmac.h"
#include "crypto/sha256.hpp"
#include "mac/mac_types.hpp"
#include "thread/thread_netif.hpp"

namespace ot {
namespace MeshCoP {

otError JoinerPskd::SetFrom(const char *aPskdString)
{
    otError error = OT_ERROR_NONE;

    VerifyOrExit(IsPskdValid(aPskdString), error = OT_ERROR_INVALID_ARGS);

    Clear();
    memcpy(m8, aPskdString, StringLength(aPskdString, sizeof(m8)));

exit:
    return error;
}

bool JoinerPskd::operator==(const JoinerPskd &aOther) const
{
    bool isEqual = true;

    for (uint8_t i = 0; i < sizeof(m8); i++)
    {
        if (m8[i] != aOther.m8[i])
        {
            isEqual = false;
            ExitNow();
        }

        if (m8[i] == '\0')
        {
            break;
        }
    }

exit:
    return isEqual;
}

bool JoinerPskd::IsPskdValid(const char *aPskString)
{
    bool     valid      = false;
    uint16_t pskdLength = StringLength(aPskString, kMaxLength + 1);

    VerifyOrExit(pskdLength >= kMinLength && pskdLength <= kMaxLength, OT_NOOP);

    for (uint16_t i = 0; i < pskdLength; i++)
    {
        char c = aPskString[i];

        VerifyOrExit(isdigit(c) || isupper(c), OT_NOOP);
        VerifyOrExit(c != 'I' && c != 'O' && c != 'Q' && c != 'Z', OT_NOOP);
    }

    valid = true;

exit:
    return valid;
}

void JoinerDiscerner::GenerateJoinerId(Mac::ExtAddress &aJoinerId) const
{
    aJoinerId.GenerateRandom();
    CopyTo(aJoinerId);
    aJoinerId.SetLocal(true);
}

bool JoinerDiscerner::Matches(const Mac::ExtAddress &aJoinerId) const
{
    uint64_t mask;

    OT_ASSERT(IsValid());

    mask = GetMask();

    return (Encoding::BigEndian::ReadUint64(aJoinerId.m8) & mask) == (mValue & mask);
}

void JoinerDiscerner::CopyTo(Mac::ExtAddress &aExtAddress) const
{
    // Copies the discerner value up to its bit length to `aExtAddress`
    // array, assuming big-endian encoding (i.e., the discerner lowest bits
    // are copied at end of `aExtAddress.m8[]` array). Any initial/remaining
    // bits of `aExtAddress` array remain unchanged.

    uint8_t *cur       = &aExtAddress.m8[sizeof(Mac::ExtAddress) - 1];
    uint8_t  remaining = mLength;
    uint64_t value     = mValue;

    OT_ASSERT(IsValid());

    // Write full bytes
    while (remaining >= CHAR_BIT)
    {
        *cur = static_cast<uint8_t>(value & 0xff);
        value >>= CHAR_BIT;
        cur--;
        remaining -= CHAR_BIT;
    }

    // Write any remaining bits (not a full byte)
    if (remaining != 0)
    {
        uint8_t mask = static_cast<uint8_t>((1U << remaining) - 1);

        // `mask` has it lower (lsb) `remaining` bits as `1` and rest as `0`.
        // Example with `remaining = 3` -> (1 << 3) - 1 = 0b1000 - 1 = 0b0111.

        *cur &= ~mask;
        *cur |= static_cast<uint8_t>(value & mask);
    }
}

bool JoinerDiscerner::operator==(const JoinerDiscerner &aOther) const
{
    uint64_t mask = GetMask();

    return IsValid() && (mLength == aOther.mLength) && ((mValue & mask) == (aOther.mValue & mask));
}

JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const
{
    InfoString str;

    if (mLength <= sizeof(uint16_t) * CHAR_BIT)
    {
        IgnoreError(str.Set("0x%04x", static_cast<uint16_t>(mValue)));
    }
    else if (mLength <= sizeof(uint32_t) * CHAR_BIT)
    {
        IgnoreError(str.Set("0x%08x", static_cast<uint32_t>(mValue)));
    }
    else
    {
        IgnoreError(str.Set("0x%x-%08x", static_cast<uint32_t>(mValue >> 32), static_cast<uint32_t>(mValue)));
    }

    IgnoreError(str.Append("/len:%d", mLength));

    return str;
}

void SteeringData::Init(uint8_t aLength)
{
    OT_ASSERT(aLength <= kMaxLength);
    mLength = aLength;
    memset(m8, 0, sizeof(m8));
}

void SteeringData::SetToPermitAllJoiners(void)
{
    Init(1);
    m8[0] = kPermitAll;
}

void SteeringData::UpdateBloomFilter(const Mac::ExtAddress &aJoinerId)
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aJoinerId, indexes);
    UpdateBloomFilter(indexes);
}

void SteeringData::UpdateBloomFilter(const JoinerDiscerner &aDiscerner)
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aDiscerner, indexes);
    UpdateBloomFilter(indexes);
}

void SteeringData::UpdateBloomFilter(const HashBitIndexes &aIndexes)
{
    OT_ASSERT((mLength > 0) && (mLength <= kMaxLength));

    SetBit(aIndexes.mIndex[0] % GetNumBits());
    SetBit(aIndexes.mIndex[1] % GetNumBits());
}

bool SteeringData::Contains(const Mac::ExtAddress &aJoinerId) const
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aJoinerId, indexes);

    return Contains(indexes);
}

bool SteeringData::Contains(const JoinerDiscerner &aDiscerner) const
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aDiscerner, indexes);

    return Contains(indexes);
}

bool SteeringData::Contains(const HashBitIndexes &aIndexes) const
{
    return (mLength > 0) && GetBit(aIndexes.mIndex[0] % GetNumBits()) && GetBit(aIndexes.mIndex[1] % GetNumBits());
}

void SteeringData::CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes)
{
    Crc16 ccitt(Crc16::kCcitt);
    Crc16 ansi(Crc16::kAnsi);

    for (uint8_t b : aJoinerId.m8)
    {
        ccitt.Update(b);
        ansi.Update(b);
    }

    aIndexes.mIndex[0] = ccitt.Get();
    aIndexes.mIndex[1] = ansi.Get();
}

void SteeringData::CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes)
{
    Mac::ExtAddress address;

    address.Clear();
    aDiscerner.CopyTo(address);

    CalculateHashBitIndexes(address, aIndexes);
}

bool SteeringData::DoesAllMatch(uint8_t aMatch) const
{
    bool matches = true;

    for (uint8_t i = 0; i < mLength; i++)
    {
        if (m8[i] != aMatch)
        {
            matches = false;
            break;
        }
    }

    return matches;
}

void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId)
{
    Crypto::Sha256 sha256;
    uint8_t        hash[Crypto::Sha256::kHashSize];

    sha256.Start();
    sha256.Update(aEui64.m8, sizeof(aEui64));
    sha256.Finish(hash);

    memcpy(&aJoinerId, hash, sizeof(aJoinerId));
    aJoinerId.SetLocal(true);
}

otError GetBorderAgentRloc(ThreadNetif &aNetif, uint16_t &aRloc)
{
    otError                      error = OT_ERROR_NONE;
    const BorderAgentLocatorTlv *borderAgentLocator;

    borderAgentLocator = static_cast<const BorderAgentLocatorTlv *>(
        aNetif.Get<NetworkData::Leader>().GetCommissioningDataSubTlv(Tlv::kBorderAgentLocator));
    VerifyOrExit(borderAgentLocator != nullptr, error = OT_ERROR_NOT_FOUND);

    aRloc = borderAgentLocator->GetBorderAgentLocator();

exit:
    return error;
}

#if OPENTHREAD_FTD
otError GeneratePskc(const char *              aPassPhrase,
                     const Mac::NetworkName &  aNetworkName,
                     const Mac::ExtendedPanId &aExtPanId,
                     Pskc &                    aPskc)
{
    otError    error        = OT_ERROR_NONE;
    const char saltPrefix[] = "Thread";
    uint8_t    salt[OT_PBKDF2_SALT_MAX_LEN];
    uint16_t   saltLen = 0;
    uint16_t   passphraseLen;
    uint8_t    networkNameLen;

    passphraseLen  = static_cast<uint16_t>(StringLength(aPassPhrase, OT_COMMISSIONING_PASSPHRASE_MAX_SIZE + 1));
    networkNameLen = static_cast<uint8_t>(StringLength(aNetworkName.GetAsCString(), OT_NETWORK_NAME_MAX_SIZE + 1));

    VerifyOrExit((passphraseLen >= OT_COMMISSIONING_PASSPHRASE_MIN_SIZE) &&
                     (passphraseLen <= OT_COMMISSIONING_PASSPHRASE_MAX_SIZE) &&
                     (networkNameLen <= OT_NETWORK_NAME_MAX_SIZE),
                 error = OT_ERROR_INVALID_ARGS);

    memset(salt, 0, sizeof(salt));
    memcpy(salt, saltPrefix, sizeof(saltPrefix) - 1);
    saltLen += static_cast<uint16_t>(sizeof(saltPrefix) - 1);

    memcpy(salt + saltLen, aExtPanId.m8, sizeof(aExtPanId));
    saltLen += OT_EXT_PAN_ID_SIZE;

    memcpy(salt + saltLen, aNetworkName.GetAsCString(), networkNameLen);
    saltLen += networkNameLen;

    otPbkdf2Cmac(reinterpret_cast<const uint8_t *>(aPassPhrase), passphraseLen, reinterpret_cast<const uint8_t *>(salt),
                 saltLen, 16384, OT_PSKC_MAX_SIZE, aPskc.m8);

exit:
    return error;
}
#endif // OPENTHREAD_FTD

#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN) && (OPENTHREAD_CONFIG_LOG_MESHCOP == 1)
void LogError(const char *aActionText, otError aError)
{
    if (aError != OT_ERROR_NONE)
    {
        otLogWarnMeshCoP("Failed to %s: %s", aActionText, otThreadErrorToString(aError));
    }
}
#endif

} // namespace MeshCoP
} // namespace ot
<commit_msg>[meshcop] include logging.hpp for helper function 'LogError()' (#5562)<commit_after>/*
 *  Copyright (c) 2017, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the copyright holder 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 HOLDER 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.
 */

/**
 * @file
 *   This file implements common MeshCoP utility functions.
 */

#include "meshcop.hpp"

#include "common/crc16.hpp"
#include "common/debug.hpp"
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
#include "crypto/pbkdf2_cmac.h"
#include "crypto/sha256.hpp"
#include "mac/mac_types.hpp"
#include "thread/thread_netif.hpp"

namespace ot {
namespace MeshCoP {

otError JoinerPskd::SetFrom(const char *aPskdString)
{
    otError error = OT_ERROR_NONE;

    VerifyOrExit(IsPskdValid(aPskdString), error = OT_ERROR_INVALID_ARGS);

    Clear();
    memcpy(m8, aPskdString, StringLength(aPskdString, sizeof(m8)));

exit:
    return error;
}

bool JoinerPskd::operator==(const JoinerPskd &aOther) const
{
    bool isEqual = true;

    for (uint8_t i = 0; i < sizeof(m8); i++)
    {
        if (m8[i] != aOther.m8[i])
        {
            isEqual = false;
            ExitNow();
        }

        if (m8[i] == '\0')
        {
            break;
        }
    }

exit:
    return isEqual;
}

bool JoinerPskd::IsPskdValid(const char *aPskString)
{
    bool     valid      = false;
    uint16_t pskdLength = StringLength(aPskString, kMaxLength + 1);

    VerifyOrExit(pskdLength >= kMinLength && pskdLength <= kMaxLength, OT_NOOP);

    for (uint16_t i = 0; i < pskdLength; i++)
    {
        char c = aPskString[i];

        VerifyOrExit(isdigit(c) || isupper(c), OT_NOOP);
        VerifyOrExit(c != 'I' && c != 'O' && c != 'Q' && c != 'Z', OT_NOOP);
    }

    valid = true;

exit:
    return valid;
}

void JoinerDiscerner::GenerateJoinerId(Mac::ExtAddress &aJoinerId) const
{
    aJoinerId.GenerateRandom();
    CopyTo(aJoinerId);
    aJoinerId.SetLocal(true);
}

bool JoinerDiscerner::Matches(const Mac::ExtAddress &aJoinerId) const
{
    uint64_t mask;

    OT_ASSERT(IsValid());

    mask = GetMask();

    return (Encoding::BigEndian::ReadUint64(aJoinerId.m8) & mask) == (mValue & mask);
}

void JoinerDiscerner::CopyTo(Mac::ExtAddress &aExtAddress) const
{
    // Copies the discerner value up to its bit length to `aExtAddress`
    // array, assuming big-endian encoding (i.e., the discerner lowest bits
    // are copied at end of `aExtAddress.m8[]` array). Any initial/remaining
    // bits of `aExtAddress` array remain unchanged.

    uint8_t *cur       = &aExtAddress.m8[sizeof(Mac::ExtAddress) - 1];
    uint8_t  remaining = mLength;
    uint64_t value     = mValue;

    OT_ASSERT(IsValid());

    // Write full bytes
    while (remaining >= CHAR_BIT)
    {
        *cur = static_cast<uint8_t>(value & 0xff);
        value >>= CHAR_BIT;
        cur--;
        remaining -= CHAR_BIT;
    }

    // Write any remaining bits (not a full byte)
    if (remaining != 0)
    {
        uint8_t mask = static_cast<uint8_t>((1U << remaining) - 1);

        // `mask` has it lower (lsb) `remaining` bits as `1` and rest as `0`.
        // Example with `remaining = 3` -> (1 << 3) - 1 = 0b1000 - 1 = 0b0111.

        *cur &= ~mask;
        *cur |= static_cast<uint8_t>(value & mask);
    }
}

bool JoinerDiscerner::operator==(const JoinerDiscerner &aOther) const
{
    uint64_t mask = GetMask();

    return IsValid() && (mLength == aOther.mLength) && ((mValue & mask) == (aOther.mValue & mask));
}

JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const
{
    InfoString str;

    if (mLength <= sizeof(uint16_t) * CHAR_BIT)
    {
        IgnoreError(str.Set("0x%04x", static_cast<uint16_t>(mValue)));
    }
    else if (mLength <= sizeof(uint32_t) * CHAR_BIT)
    {
        IgnoreError(str.Set("0x%08x", static_cast<uint32_t>(mValue)));
    }
    else
    {
        IgnoreError(str.Set("0x%x-%08x", static_cast<uint32_t>(mValue >> 32), static_cast<uint32_t>(mValue)));
    }

    IgnoreError(str.Append("/len:%d", mLength));

    return str;
}

void SteeringData::Init(uint8_t aLength)
{
    OT_ASSERT(aLength <= kMaxLength);
    mLength = aLength;
    memset(m8, 0, sizeof(m8));
}

void SteeringData::SetToPermitAllJoiners(void)
{
    Init(1);
    m8[0] = kPermitAll;
}

void SteeringData::UpdateBloomFilter(const Mac::ExtAddress &aJoinerId)
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aJoinerId, indexes);
    UpdateBloomFilter(indexes);
}

void SteeringData::UpdateBloomFilter(const JoinerDiscerner &aDiscerner)
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aDiscerner, indexes);
    UpdateBloomFilter(indexes);
}

void SteeringData::UpdateBloomFilter(const HashBitIndexes &aIndexes)
{
    OT_ASSERT((mLength > 0) && (mLength <= kMaxLength));

    SetBit(aIndexes.mIndex[0] % GetNumBits());
    SetBit(aIndexes.mIndex[1] % GetNumBits());
}

bool SteeringData::Contains(const Mac::ExtAddress &aJoinerId) const
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aJoinerId, indexes);

    return Contains(indexes);
}

bool SteeringData::Contains(const JoinerDiscerner &aDiscerner) const
{
    HashBitIndexes indexes;

    CalculateHashBitIndexes(aDiscerner, indexes);

    return Contains(indexes);
}

bool SteeringData::Contains(const HashBitIndexes &aIndexes) const
{
    return (mLength > 0) && GetBit(aIndexes.mIndex[0] % GetNumBits()) && GetBit(aIndexes.mIndex[1] % GetNumBits());
}

void SteeringData::CalculateHashBitIndexes(const Mac::ExtAddress &aJoinerId, HashBitIndexes &aIndexes)
{
    Crc16 ccitt(Crc16::kCcitt);
    Crc16 ansi(Crc16::kAnsi);

    for (uint8_t b : aJoinerId.m8)
    {
        ccitt.Update(b);
        ansi.Update(b);
    }

    aIndexes.mIndex[0] = ccitt.Get();
    aIndexes.mIndex[1] = ansi.Get();
}

void SteeringData::CalculateHashBitIndexes(const JoinerDiscerner &aDiscerner, HashBitIndexes &aIndexes)
{
    Mac::ExtAddress address;

    address.Clear();
    aDiscerner.CopyTo(address);

    CalculateHashBitIndexes(address, aIndexes);
}

bool SteeringData::DoesAllMatch(uint8_t aMatch) const
{
    bool matches = true;

    for (uint8_t i = 0; i < mLength; i++)
    {
        if (m8[i] != aMatch)
        {
            matches = false;
            break;
        }
    }

    return matches;
}

void ComputeJoinerId(const Mac::ExtAddress &aEui64, Mac::ExtAddress &aJoinerId)
{
    Crypto::Sha256 sha256;
    uint8_t        hash[Crypto::Sha256::kHashSize];

    sha256.Start();
    sha256.Update(aEui64.m8, sizeof(aEui64));
    sha256.Finish(hash);

    memcpy(&aJoinerId, hash, sizeof(aJoinerId));
    aJoinerId.SetLocal(true);
}

otError GetBorderAgentRloc(ThreadNetif &aNetif, uint16_t &aRloc)
{
    otError                      error = OT_ERROR_NONE;
    const BorderAgentLocatorTlv *borderAgentLocator;

    borderAgentLocator = static_cast<const BorderAgentLocatorTlv *>(
        aNetif.Get<NetworkData::Leader>().GetCommissioningDataSubTlv(Tlv::kBorderAgentLocator));
    VerifyOrExit(borderAgentLocator != nullptr, error = OT_ERROR_NOT_FOUND);

    aRloc = borderAgentLocator->GetBorderAgentLocator();

exit:
    return error;
}

#if OPENTHREAD_FTD
otError GeneratePskc(const char *              aPassPhrase,
                     const Mac::NetworkName &  aNetworkName,
                     const Mac::ExtendedPanId &aExtPanId,
                     Pskc &                    aPskc)
{
    otError    error        = OT_ERROR_NONE;
    const char saltPrefix[] = "Thread";
    uint8_t    salt[OT_PBKDF2_SALT_MAX_LEN];
    uint16_t   saltLen = 0;
    uint16_t   passphraseLen;
    uint8_t    networkNameLen;

    passphraseLen  = static_cast<uint16_t>(StringLength(aPassPhrase, OT_COMMISSIONING_PASSPHRASE_MAX_SIZE + 1));
    networkNameLen = static_cast<uint8_t>(StringLength(aNetworkName.GetAsCString(), OT_NETWORK_NAME_MAX_SIZE + 1));

    VerifyOrExit((passphraseLen >= OT_COMMISSIONING_PASSPHRASE_MIN_SIZE) &&
                     (passphraseLen <= OT_COMMISSIONING_PASSPHRASE_MAX_SIZE) &&
                     (networkNameLen <= OT_NETWORK_NAME_MAX_SIZE),
                 error = OT_ERROR_INVALID_ARGS);

    memset(salt, 0, sizeof(salt));
    memcpy(salt, saltPrefix, sizeof(saltPrefix) - 1);
    saltLen += static_cast<uint16_t>(sizeof(saltPrefix) - 1);

    memcpy(salt + saltLen, aExtPanId.m8, sizeof(aExtPanId));
    saltLen += OT_EXT_PAN_ID_SIZE;

    memcpy(salt + saltLen, aNetworkName.GetAsCString(), networkNameLen);
    saltLen += networkNameLen;

    otPbkdf2Cmac(reinterpret_cast<const uint8_t *>(aPassPhrase), passphraseLen, reinterpret_cast<const uint8_t *>(salt),
                 saltLen, 16384, OT_PSKC_MAX_SIZE, aPskc.m8);

exit:
    return error;
}
#endif // OPENTHREAD_FTD

#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_WARN) && (OPENTHREAD_CONFIG_LOG_MESHCOP == 1)
void LogError(const char *aActionText, otError aError)
{
    if (aError != OT_ERROR_NONE)
    {
        otLogWarnMeshCoP("Failed to %s: %s", aActionText, otThreadErrorToString(aError));
    }
}
#endif

} // namespace MeshCoP
} // namespace ot
<|endoftext|>


<commit_before>#ifndef PVER_TOKEN_H
#define PVER_TOKEN_H 1

#include <string>
#include <forward_list>

namespace pver {
    class token {
    private:
        typedef enum {
            PUNCTUATION,
            NUMERIC,
            ALHPANUMERIC
        } token_type;
        std::string token;
        token_type tag;
    public:
        token(const std::string & token_string);
        bool is_punct() const;
        bool is_numeric() const;
        bool is_alphanumeric() const;
        const std::string & str() const;
    };
    typedef std::forward_list<token> token_list_type;
    token_list_type tokenize(const std::string & ver);
    int compare_tokens(token_list_type a, token_list_type b);
}

#endif
<commit_msg>Add `matches` to token header<commit_after>#ifndef PVER_TOKEN_H
#define PVER_TOKEN_H 1

#include <string>
#include <forward_list>

namespace pver {
    class token {
    private:
        typedef enum {
            PUNCTUATION,
            NUMERIC,
            ALHPANUMERIC
        } tag_type;
        std::string token;
        tag_type tag;
    public:
        token(const std::string & token_string);
        bool is_punct() const;
        bool is_numeric() const;
        bool is_alphanumeric() const;
        const std::string & str() const;
    };
    typedef std::forward_list<token> token_list_type;
    token_list_type tokenize(const std::string & ver);
    int compare_tokens(token_list_type a, token_list_type b);
    bool matches(token_list_type a, token_list_type b);
}

#endif
<|endoftext|>


<commit_before>#include <QWebSocketServer>
#include <QWebSocket>
#include <QDebug>
#include <QFile>
#include <QSslCertificate>
#include <QSslKey>
#include <QThreadPool>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QPointer>

#include "w3cserver.h"
#include "jsonrequestparser.h"
#include "request-handler/processrequesttask.h"
#include "qjsonwebtoken.h"
#include "jwt-utility/visstokenvalidator.h"
#include "VSSSignalinterface/vsssignalinterfaceimpl.h"
#include "VSSSignalinterface/vsssignalinterface.h"
#include "messaging/websocketwrapper.h"
#include "OpenDSHandler/opendshandler.h"

#include "logger.h"

QT_USE_NAMESPACE

class W3CServer;
int W3CServer::m_nrOfClients;
W3CServer::W3CServer(quint16 port,bool usesecureprotocol, QObject *parent) : QObject(parent),
    m_pWebSocketServer(0),
    m_clients(),
    m_secure(usesecureprotocol)
{
    QThreadPool::globalInstance()->setMaxThreadCount(100);

    if (usesecureprotocol)
    {
        m_pWebSocketServer = new QWebSocketServer(QStringLiteral("W3CServer"),
                QWebSocketServer::SecureMode,
                this);
        // m_pWebSocketServer ->
        QSslConfiguration sslConfiguration;

        QFile keyFile(QStringLiteral(":/server.key"));
        QFile certFile(QStringLiteral(":/server.crt"));

        certFile.open(QIODevice::ReadOnly);
        const QByteArray bytes = certFile.readAll();
        QJsonWebToken e;

        TRACE("Server","Certification file length : " + QString::number(bytes.length()));

        QSslCertificate certificate(bytes, QSsl::Pem);

        keyFile.open(QIODevice::ReadOnly);
        const QByteArray passphrase("6610");
        QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem,QSsl::PrivateKey,passphrase);

        certFile.close();
        keyFile.close();

        sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
        sslConfiguration.setLocalCertificate(certificate);
        sslConfiguration.setPrivateKey(sslKey);
        sslConfiguration.setProtocol(QSsl::TlsV1SslV3);

        m_pWebSocketServer->setSslConfiguration(sslConfiguration);
    }
    else
    {
        m_pWebSocketServer = new QWebSocketServer(QStringLiteral("W3CServer Test"),QWebSocketServer::NonSecureMode,this);

    }
    if (m_pWebSocketServer->listen(QHostAddress::Any, port))
    {
        INFO("Server","W3CServer is listening on port " + QString::number(port));

        //Connect QWebSocketServer newConnection signal with W3cServer slot onNewConnection
        connect(m_pWebSocketServer, &QWebSocketServer::newConnection,this,&W3CServer::onNewConnection);
        //Connect QWebsocketServer signal with W3CServer signal closed
        // connect(m_pWebSocketServer,&QWebSocketServer::closed, this, &W3CServer::closed);
        //SSL error handler
        connect(m_pWebSocketServer, &QWebSocketServer::sslErrors,
                this, &W3CServer::onSslErrors);
    }

    // TODO: select implementation based on application configuration

    const QString vssFile = "/etc/vss_rel_1.json";
    m_vsssInterface = QSharedPointer<VSSSignalInterfaceImpl>(new VSSSignalInterfaceImpl(vssFile));
    m_openDSHandler = QSharedPointer<OpenDSHandler>(new OpenDSHandler());
    connect(m_openDSHandler.data(), &OpenDSHandler::valueChanged, static_cast <VSSSignalInterfaceImpl*>(m_vsssInterface.data()), &VSSSignalInterfaceImpl::updateValue);
}

W3CServer::~W3CServer()
{
    m_pWebSocketServer->close();
    //clean out all connected clients
    qDeleteAll(m_clients.begin(),m_clients.end());
    m_vsssInterface.clear();
}

void W3CServer::onNewConnection()
{
    QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
<<<<<<< HEAD
    pSocket ->ignoreSslErrors();
    // pSocket ->
    qDebug() << " attempting to connect " << pSocket;
=======

    DEBUG("Server","Attemping to connect");
>>>>>>> 2be540b533bceacded03eb83d9bef2a89a88d5d5

    // Connect socket textMessageReceived signal with server processTextMessage slot
    connect(pSocket, &QWebSocket::textMessageReceived, this, &W3CServer::processTextMessage);
    // Connect socket disconnected signal with server socketDisconnected slot
    connect(pSocket, &QWebSocket::disconnected, this, &W3CServer::socketDisconnected);

    // add socket to list of clients
    m_clients.insert(pSocket, new QMutex());
    W3CServer::m_nrOfClients++;
}

void W3CServer::processTextMessage(const QString& message)
{

    DEBUG("Server","Message received");
    TRACE("Server", message);

    QWebSocket *zeClient = qobject_cast<QWebSocket *> (sender());
    if (m_clients.contains(zeClient))
    {
        // we need a mutex per client .
        QMutex* mutex = m_clients.find(zeClient).value();
        QPointer<WebSocketWrapper> socketWrapper = new WebSocketWrapper(zeClient, mutex);
        startRequestProcess(socketWrapper, message);
    }
    else
    {
        WARNING("Server","Fatal connection error, Websocket client not found.");
    }
}

void W3CServer::socketDisconnected()
{
    QWebSocket *zeClient = qobject_cast<QWebSocket *> (sender());

    DEBUG("Server","Socket disconnected");// : " + zeClient);

    //remove from client list and delete from heap
    if (zeClient)
    {
        m_clients.remove(zeClient);
        zeClient->deleteLater();
        W3CServer::m_nrOfClients--;
    }
}

void W3CServer::onSslErrors(const QList<QSslError> &l)
{
    TRACE("Server","SSL Error occurred."); // Change to WARNING
}

void W3CServer::startRequestProcess(WebSocketWrapper* sw, const QString& message)
{
    ProcessRequestTask* requesttask = new ProcessRequestTask(sw, m_vsssInterface, message, true);
    // QThreadPool takes ownership and deletes 'requesttask' automatically

    if(!QThreadPool::globalInstance()->tryStart(requesttask))
    {
        WARNING("Server","Failed to start thread! Active threads : " + QString::number(QThreadPool::globalInstance()->activeThreadCount()));
        WARNING("Server","Max threads alloved : " + QString::number(QThreadPool::globalInstance()->maxThreadCount()));
    }
    else
    {
        DEBUG("Server","New thread started! Active threads : " + QString::number(QThreadPool::globalInstance()->activeThreadCount()));
    }
}
<commit_msg>Removed merge crap<commit_after>#include <QWebSocketServer>
#include <QWebSocket>
#include <QDebug>
#include <QFile>
#include <QSslCertificate>
#include <QSslKey>
#include <QThreadPool>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QPointer>

#include "w3cserver.h"
#include "jsonrequestparser.h"
#include "request-handler/processrequesttask.h"
#include "qjsonwebtoken.h"
#include "jwt-utility/visstokenvalidator.h"
#include "VSSSignalinterface/vsssignalinterfaceimpl.h"
#include "VSSSignalinterface/vsssignalinterface.h"
#include "messaging/websocketwrapper.h"
#include "OpenDSHandler/opendshandler.h"

#include "logger.h"

QT_USE_NAMESPACE

class W3CServer;
int W3CServer::m_nrOfClients;
W3CServer::W3CServer(quint16 port,bool usesecureprotocol, QObject *parent) : QObject(parent),
    m_pWebSocketServer(0),
    m_clients(),
    m_secure(usesecureprotocol)
{
    QThreadPool::globalInstance()->setMaxThreadCount(100);

    if (usesecureprotocol)
    {
        m_pWebSocketServer = new QWebSocketServer(QStringLiteral("W3CServer"),
                QWebSocketServer::SecureMode,
                this);
        // m_pWebSocketServer ->
        QSslConfiguration sslConfiguration;

        QFile keyFile(QStringLiteral(":/server.key"));
        QFile certFile(QStringLiteral(":/server.crt"));

        certFile.open(QIODevice::ReadOnly);
        const QByteArray bytes = certFile.readAll();
        QJsonWebToken e;

        TRACE("Server","Certification file length : " + QString::number(bytes.length()));

        QSslCertificate certificate(bytes, QSsl::Pem);

        keyFile.open(QIODevice::ReadOnly);
        const QByteArray passphrase("6610");
        QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem,QSsl::PrivateKey,passphrase);

        certFile.close();
        keyFile.close();

        sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
        sslConfiguration.setLocalCertificate(certificate);
        sslConfiguration.setPrivateKey(sslKey);
        sslConfiguration.setProtocol(QSsl::TlsV1SslV3);

        m_pWebSocketServer->setSslConfiguration(sslConfiguration);
    }
    else
    {
        m_pWebSocketServer = new QWebSocketServer(QStringLiteral("W3CServer Test"),QWebSocketServer::NonSecureMode,this);

    }
    if (m_pWebSocketServer->listen(QHostAddress::Any, port))
    {
        INFO("Server","W3CServer is listening on port " + QString::number(port));

        //Connect QWebSocketServer newConnection signal with W3cServer slot onNewConnection
        connect(m_pWebSocketServer, &QWebSocketServer::newConnection,this,&W3CServer::onNewConnection);
        //Connect QWebsocketServer signal with W3CServer signal closed
        // connect(m_pWebSocketServer,&QWebSocketServer::closed, this, &W3CServer::closed);
        //SSL error handler
        connect(m_pWebSocketServer, &QWebSocketServer::sslErrors,
                this, &W3CServer::onSslErrors);
    }

    // TODO: select implementation based on application configuration

    const QString vssFile = "/etc/vss_rel_1.json";
    m_vsssInterface = QSharedPointer<VSSSignalInterfaceImpl>(new VSSSignalInterfaceImpl(vssFile));
    m_openDSHandler = QSharedPointer<OpenDSHandler>(new OpenDSHandler());
    connect(m_openDSHandler.data(), &OpenDSHandler::valueChanged, static_cast <VSSSignalInterfaceImpl*>(m_vsssInterface.data()), &VSSSignalInterfaceImpl::updateValue);
}

W3CServer::~W3CServer()
{
    m_pWebSocketServer->close();
    //clean out all connected clients
    qDeleteAll(m_clients.begin(),m_clients.end());
    m_vsssInterface.clear();
}

void W3CServer::onNewConnection()
{
    QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();

    pSocket ->ignoreSslErrors();

    DEBUG("Server","Attemping to connect");

    // Connect socket textMessageReceived signal with server processTextMessage slot
    connect(pSocket, &QWebSocket::textMessageReceived, this, &W3CServer::processTextMessage);
    // Connect socket disconnected signal with server socketDisconnected slot
    connect(pSocket, &QWebSocket::disconnected, this, &W3CServer::socketDisconnected);

    // add socket to list of clients
    m_clients.insert(pSocket, new QMutex());
    W3CServer::m_nrOfClients++;
}

void W3CServer::processTextMessage(const QString& message)
{

    DEBUG("Server","Message received");
    TRACE("Server", message);

    QWebSocket *zeClient = qobject_cast<QWebSocket *> (sender());
    if (m_clients.contains(zeClient))
    {
        // we need a mutex per client .
        QMutex* mutex = m_clients.find(zeClient).value();
        QPointer<WebSocketWrapper> socketWrapper = new WebSocketWrapper(zeClient, mutex);
        startRequestProcess(socketWrapper, message);
    }
    else
    {
        WARNING("Server","Fatal connection error, Websocket client not found.");
    }
}

void W3CServer::socketDisconnected()
{
    QWebSocket *zeClient = qobject_cast<QWebSocket *> (sender());

    DEBUG("Server","Socket disconnected");// : " + zeClient);

    //remove from client list and delete from heap
    if (zeClient)
    {
        m_clients.remove(zeClient);
        zeClient->deleteLater();
        W3CServer::m_nrOfClients--;
    }
}

void W3CServer::onSslErrors(const QList<QSslError> &l)
{
    TRACE("Server","SSL Error occurred."); // Change to WARNING
}

void W3CServer::startRequestProcess(WebSocketWrapper* sw, const QString& message)
{
    ProcessRequestTask* requesttask = new ProcessRequestTask(sw, m_vsssInterface, message, true);
    // QThreadPool takes ownership and deletes 'requesttask' automatically

    if(!QThreadPool::globalInstance()->tryStart(requesttask))
    {
        WARNING("Server","Failed to start thread! Active threads : " + QString::number(QThreadPool::globalInstance()->activeThreadCount()));
        WARNING("Server","Max threads alloved : " + QString::number(QThreadPool::globalInstance()->maxThreadCount()));
    }
    else
    {
        DEBUG("Server","New thread started! Active threads : " + QString::number(QThreadPool::globalInstance()->activeThreadCount()));
    }
}
<|endoftext|>