text:
/**
 * Copyright (c) 2013-2016, The Kovri I2P Router Project
 *
 * 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.
 *
 * Parts of the project are originally copyright (c) 2013-2015 The PurpleI2P Project
 */

#include "NetworkDatabase.h"

#include <boost/asio.hpp>

#include <string.h>

#include <fstream>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "Garlic.h"
#include "I2NPProtocol.h"
#include "RouterContext.h"
#include "crypto/Rand.h"
#include "crypto/util/Compression.h"
#include "transport/Transports.h"
#include "tunnel/Tunnel.h"
#include "util/Base64.h"
#include "util/I2PEndian.h"
#include "util/Log.h"
#include "util/Timestamp.h"

namespace i2p {
namespace data {

const char NetDb::m_NetDbPath[] = "netDb";

NetDb netdb;

NetDb::NetDb()
    : m_IsRunning(false),
      m_Thread(nullptr),
      m_Reseed(nullptr) {}

NetDb::~NetDb() {
  Stop();
  if (m_Reseed) {
    m_Reseed.reset(nullptr);
  }
}

bool NetDb::Start() {
  Load();
  if (m_RouterInfos.size() < 25) {  // reseed if # of router less than 50
    if (!Reseed()) {
      return false;
    }
  }
  m_IsRunning = true;
  m_Thread = std::make_unique<std::thread>(std::bind(&NetDb::Run, this));
  return true;
}

void NetDb::Stop() {
  if (m_IsRunning) {
    for (auto it : m_RouterInfos)
      it.second->SaveProfile();
    DeleteObsoleteProfiles();
    m_RouterInfos.clear();
    m_Floodfills.clear();
    if (m_Thread) {
      m_IsRunning = false;
      m_Queue.WakeUp();
      m_Thread->join();
      m_Thread.reset(nullptr);
    }
    m_LeaseSets.clear();
    m_Requests.Stop();
  }
}

void NetDb::Run() {
  uint32_t last_save = 0,
           last_publish = 0,
           last_exploratory = 0,
           last_manage_request = 0;
  while (m_IsRunning) {
    try {
      auto msg = m_Queue.GetNextWithTimeout(15000);  // 15 sec
      if (msg) {
        int numMsgs = 0;
        while (msg) {
          switch (msg->GetTypeID()) {
            case e_I2NPDatabaseStore:
              LogPrint(eLogDebug, "NetDb: DatabaseStore");
              HandleDatabaseStoreMsg(msg);
            break;
            case e_I2NPDatabaseSearchReply:
              LogPrint(eLogDebug, "NetDb: DatabaseSearchReply");
              HandleDatabaseSearchReplyMsg(msg);
            break;
            case e_I2NPDatabaseLookup:
              LogPrint(eLogDebug, "NetDb: DatabaseLookup");
              HandleDatabaseLookupMsg(msg);
            break;
            default:
              // TODO(unassigned): error handling
              LogPrint(eLogError,
                  "NetDb: unexpected message type ", msg->GetTypeID());
              // i2p::HandleI2NPMessage(msg);
          }
          if (numMsgs > 100)
            break;
          msg = m_Queue.Get();
          numMsgs++;
        }
      }
      if (!m_IsRunning)
        break;
      uint64_t ts = i2p::util::GetSecondsSinceEpoch();
      if (ts - last_manage_request >= 15) {  // manage requests every 15 seconds
        m_Requests.ManageRequests();
        last_manage_request = ts;
      }
      // save routers, manage leasesets and validate subscriptions every minute
      if (ts - last_save >= 60) {
        if (last_save) {
          SaveUpdated();
          ManageLeaseSets();
        }
        last_save = ts;
      }
      if (ts - last_publish >= 2400) {  // publish every 40 minutes
        Publish();
        last_publish = ts;
      }
      if (ts - last_exploratory >= 30) {  // exploratory every 30 seconds
        auto num_routers = m_RouterInfos.size();
        // TODO(anonimal): research these numbers
        if (num_routers < 2500 || ts - last_exploratory >= 90) {
          if (num_routers > 0) {
            num_routers = 800 / num_routers;
          }
          if (num_routers < 1)
            num_routers = 1;
          if (num_routers > 9)
            num_routers = 9;
          m_Requests.ManageRequests();
          Explore(num_routers);
          last_exploratory = ts;
        }
      }
    } catch(std::exception& ex) {
      LogPrint(eLogError, "NetDb::Run(): ", ex.what());
    }
  }
}

bool NetDb::AddRouterInfo(
    const uint8_t* buf,
    int len) {
  IdentityEx identity;
  if (!identity.FromBuffer(buf, len)) {
    LogPrint(eLogError, "NetDb: unable to add router info");
    return false;
  }
  AddRouterInfo(identity.GetIdentHash(), buf, len);
  return true;
}

void NetDb::AddRouterInfo(
    const IdentHash& ident,
    const uint8_t* buf,
    int len) {
  auto r = FindRouter(ident);
  if (r) {
    auto ts = r->GetTimestamp();
    r->Update(buf, len);
    if (r->GetTimestamp() > ts)
      LogPrint(eLogInfo, "NetDb: RouterInfo updated");
  } else {
    LogPrint(eLogDebug, "NetDb: new RouterInfo added");
    r = std::make_shared<RouterInfo> (buf, len); {
      std::unique_lock<std::mutex> l(m_RouterInfosMutex);
      m_RouterInfos[r->GetIdentHash()] = r;
    }
    if (r->IsFloodfill()) {
      std::unique_lock<std::mutex> l(m_FloodfillsMutex);
      m_Floodfills.push_back(r);
    }
  }
  // take care about requested destination
  m_Requests.RequestComplete(ident, r);
}

void NetDb::AddLeaseSet(
    const IdentHash& ident,
    const uint8_t* buf,
    int len,
    std::shared_ptr<i2p::tunnel::InboundTunnel> from) {
  if (!from) {  // unsolicited LS must be received directly
    auto it = m_LeaseSets.find(ident);
    if (it != m_LeaseSets.end()) {
      it->second->Update(buf, len);
      if (it->second->IsValid()) {
        LogPrint(eLogInfo, "NetDb: LeaseSet updated");
      } else {
        LogPrint(eLogInfo, "NetDb: LeaseSet update failed");
        m_LeaseSets.erase(it);
      }
    } else {
      auto lease_set = std::make_shared<LeaseSet>(buf, len);
      if (lease_set->IsValid()) {
        LogPrint(eLogInfo, "NetDb: new LeaseSet added");
        m_LeaseSets[ident] = lease_set;
      } else {
        LogPrint(eLogError, "NetDb: new LeaseSet validation failed");
      }
    }
  }
}

std::shared_ptr<RouterInfo> NetDb::FindRouter(
    const IdentHash& ident) const {
  std::unique_lock<std::mutex> l(m_RouterInfosMutex);
  auto it = m_RouterInfos.find(ident);
  if (it != m_RouterInfos.end())
    return it->second;
  else
    return nullptr;
}

std::shared_ptr<LeaseSet> NetDb::FindLeaseSet(
    const IdentHash& destination) const {
  auto it = m_LeaseSets.find(destination);
  if (it != m_LeaseSets.end())
    return it->second;
  else
    return nullptr;
}

void NetDb::SetUnreachable(
    const IdentHash& ident,
    bool unreachable) {
  auto it = m_RouterInfos.find(ident);
  if (it != m_RouterInfos.end())
    return it->second->SetUnreachable(unreachable);
}

// TODO(unassigned): Move to reseed and/or scheduled tasks.
// (In java version, scheduler fixes this as well as sort RIs.)
bool NetDb::CreateNetDb(
    boost::filesystem::path directory) {
  LogPrint(eLogInfo, "NetDb: creating ", directory.string());
  if (!boost::filesystem::create_directory(directory)) {
    LogPrint(eLogError, "NetDb: failed to create ", directory.string());
    return false;
  }
  // list of chars might appear in base64 string
  const char* chars = i2p::util::GetBase64SubstitutionTable();  // 64 bytes
  boost::filesystem::path suffix;
  for (int i = 0; i < 64; i++) {
#ifndef _WIN32
    suffix = std::string("/r") + chars[i];
#else
    suffix = std::string("\\r") + chars[i];
#endif
    if (!boost::filesystem::create_directory(
          boost::filesystem::path(
            directory / suffix) ))
      return false;
  }
  return true;
}

bool NetDb::Reseed() {
  if (m_Reseed == nullptr) {
    m_Reseed = std::make_unique<i2p::data::Reseed>(i2p::context.ReseedFrom());
    if (!m_Reseed->ReseedImpl()) {
      m_Reseed.reset(nullptr);
      LogPrint(eLogError, "NetDb: reseed failed");
      return false;
    }
  }
  return true;
}

void NetDb::Load() {
  boost::filesystem::path p(i2p::context.GetDataPath() / m_NetDbPath);
  if (!boost::filesystem::exists(p)) {
    // seems netDb doesn't exist yet
    if (!CreateNetDb(p))
      return;
  }
  // make sure we cleanup netDb from previous attempts
  m_RouterInfos.clear();
  m_Floodfills.clear();
  // load routers now
  uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
  int num_routers = 0;
  boost::filesystem::directory_iterator end;
  for (boost::filesystem::directory_iterator it(p); it != end; ++it) {
    if (boost::filesystem::is_directory(it->status())) {
      for (boost::filesystem::directory_iterator it1(it->path());
          it1 != end;
          ++it1) {
#if BOOST_VERSION > 10500
        const std::string& fullPath = it1->path().string();
#else
        const std::string& fullPath = it1->path();
#endif
        auto r = std::make_shared<RouterInfo>(fullPath);
        if (!r->IsUnreachable() &&
            (!r->UsesIntroducer() ||
             ts < r->GetTimestamp() + 3600 * 1000LL)) {  // 1 hour
          r->DeleteBuffer();
          r->ClearProperties();  // properties are not used for regular routers
          m_RouterInfos[r->GetIdentHash()] = r;
          if (r->IsFloodfill())
            m_Floodfills.push_back(r);
          num_routers++;
        } else {
          if (boost::filesystem::exists(fullPath))
            boost::filesystem::remove(fullPath);
        }
      }
    }
  }
  LogPrint(eLogInfo, "NetDb: ", num_routers, " routers loaded");
  LogPrint(eLogInfo, "NetDb: ", m_Floodfills.size(), " floodfills loaded");
}

void NetDb::SaveUpdated() {
  auto GetFilePath = [](
      const boost::filesystem::path& directory,
      const RouterInfo* routerInfo) {
    std::string s(routerInfo->GetIdentHashBase64());
    return directory / (std::string("r") + s[0]) / ("routerInfo-" + s + ".dat");
  };
  boost::filesystem::path fullDirectory(
      i2p::context.GetDataPath() / m_NetDbPath);
  int count = 0,
      deletedCount = 0;
  auto total = m_RouterInfos.size();
  uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
  for (auto it : m_RouterInfos) {
    if (it.second->IsUpdated()) {
      std::string f = GetFilePath(fullDirectory, it.second.get()).string();
      it.second->SaveToFile(f);
      it.second->SetUpdated(false);
      it.second->SetUnreachable(false);
      it.second->DeleteBuffer();
      count++;
    } else {
      // RouterInfo expires after 1 hour if it uses an introducer
      if (it.second->UsesIntroducer() &&
          ts > it.second->GetTimestamp() + 3600 * 1000LL) {  // 1 hour
        it.second->SetUnreachable(true);
      } else if (total > 75 && ts >
          (i2p::context.GetStartupTime() + 600) * 1000LL) {
        // ^ routers don't expire if less than 25
        // or uptime is less than 10 minutes
        if (i2p::context.IsFloodfill()) {
          if (ts > it.second->GetTimestamp() + 3600 * 1000LL) {
            it.second->SetUnreachable(true);
            total--;
          }
        } else if (total > 300) {
          // 30 hours
          if (ts > it.second->GetTimestamp() + 30 * 3600 * 1000LL) {
            it.second->SetUnreachable(true);
            total--;
          }
        } else if (total > 120) {
          // 72 hours
          if (ts > it.second->GetTimestamp() + 72 * 3600 * 1000LL) {
            it.second->SetUnreachable(true);
            total--;
          }
        }
      }
      if (it.second->IsUnreachable()) {
        total--;
        // delete RI file
        if (boost::filesystem::exists(
              GetFilePath(
                  fullDirectory,
                  it.second.get()))) {
          boost::filesystem::remove(
              GetFilePath(
                  fullDirectory,
                  it.second.get()));
          deletedCount++;
        }
        // delete from floodfills list
        if (it.second->IsFloodfill()) {
          std::unique_lock<std::mutex> l(m_FloodfillsMutex);
          m_Floodfills.remove(it.second);
        }
      }
    }
  }
  if (count > 0)
    LogPrint(eLogInfo, "NetDb: ", count, " new/updated routers saved");
  if (deletedCount > 0) {
    LogPrint(eLogInfo, "NetDb: ", deletedCount, " routers deleted");
    // clean up RouterInfos table
    std::unique_lock<std::mutex> l(m_RouterInfosMutex);
    for (auto it = m_RouterInfos.begin(); it != m_RouterInfos.end();) {
      if (it->second->IsUnreachable()) {
        it->second->SaveProfile();
        it = m_RouterInfos.erase(it);
      } else {
        it++;
      }
    }
  }
}

void NetDb::RequestDestination(
    const IdentHash& destination,
    RequestedDestination::RequestComplete request_complete) {
  auto dest =
    m_Requests.CreateRequest(
        destination,
        false,
        request_complete);  // non-exploratory
  if (!dest) {
    LogPrint(eLogWarn,
        "NetDb: destination ", destination.ToBase64(), " was already requested");
    return;
  }
  auto floodfill =
    GetClosestFloodfill(
        destination,
        dest->GetExcludedPeers());
  if (floodfill) {
    i2p::transport::transports.SendMessage(
        floodfill->GetIdentHash(),
        dest->CreateRequestMessage(
            floodfill->GetIdentHash()));
  } else {
    LogPrint(eLogError, "NetDb: no floodfills found");
    m_Requests.RequestComplete(destination, nullptr);
  }
}

void NetDb::HandleDatabaseStoreMsg(
    std::shared_ptr<const I2NPMessage> m) {
  const uint8_t* buf = m->GetPayload();
  size_t len = m->GetSize();
  IdentHash ident(buf + DATABASE_STORE_KEY_OFFSET);
  if (ident.IsZero()) {
    LogPrint(eLogError, "NetDb: database store with zero ident, dropped");
    return;
  }
  uint32_t replyToken = bufbe32toh(buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
  size_t offset = DATABASE_STORE_HEADER_SIZE;
  if (replyToken) {
    auto deliveryStatus = CreateDeliveryStatusMsg(replyToken);
    uint32_t tunnelID = bufbe32toh(buf + offset);
    offset += 4;
    if (!tunnelID) {  // send response directly
      i2p::transport::transports.SendMessage(buf + offset, deliveryStatus);
    } else {
      auto pool = i2p::tunnel::tunnels.GetExploratoryPool();
      auto outbound = pool ? pool->GetNextOutboundTunnel() : nullptr;
      if (outbound)
        outbound->SendTunnelDataMsg(buf + offset, tunnelID, deliveryStatus);
      else
        LogPrint(eLogError,
            "NetDb: no outbound tunnels for DatabaseStore reply found");
    }
    offset += 32;
    if (context.IsFloodfill()) {
      // flood it
      auto flood_msg = ToSharedI2NPMessage(NewI2NPShortMessage());
      uint8_t* payload = flood_msg->GetPayload();
      memcpy(payload, buf, 33);  // key + type
      // zero reply token
      htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
      memcpy(payload + DATABASE_STORE_HEADER_SIZE, buf + offset, len - offset);
      flood_msg->len += DATABASE_STORE_HEADER_SIZE + len -offset;
      flood_msg->FillI2NPMessageHeader(e_I2NPDatabaseStore);
      std::set<IdentHash> excluded;
      for (int i = 0; i < 3; i++) {
        auto floodfill = GetClosestFloodfill(ident, excluded);
        if (floodfill)
          i2p::transport::transports.SendMessage(
              floodfill->GetIdentHash(),
              flood_msg);
      }
    }
  }
  if (buf[DATABASE_STORE_TYPE_OFFSET]) {  // type
    LogPrint(eLogDebug, "NetDb: LeaseSet");
    AddLeaseSet(ident, buf + offset, len - offset, m->from);
  } else {
    LogPrint(eLogDebug, "NetDb: RouterInfo");
    size_t size = bufbe16toh(buf + offset);
    offset += 2;
    if (size > 2048 || size > len - offset) {
      LogPrint(eLogError,
          "NetDb: invalid RouterInfo length ", static_cast<int>(size));
      return;
    }
    try {
      i2p::crypto::util::Gunzip decompressor;
      decompressor.Put(buf + offset, size);
      uint8_t uncompressed[2048];
      size_t uncompressed_size = decompressor.MaxRetrievable();
      if (uncompressed_size <= 2048) {
        decompressor.Get(uncompressed, uncompressed_size);
        AddRouterInfo(ident, uncompressed, uncompressed_size);
      } else {
        LogPrint(eLogError,
            "NetDb: invalid RouterInfo uncompressed length ",
            static_cast<int>(uncompressed_size));
      }
    } catch (...) {
      LogPrint(eLogError,
          "NetDb: HandleDatabaseStoreMsg() caught exception ");
    }
  }
}

void NetDb::HandleDatabaseSearchReplyMsg(
    std::shared_ptr<const I2NPMessage> msg) {
  const uint8_t* buf = msg->GetPayload();
  char key[48];
  int l = i2p::util::ByteStreamToBase64(buf, 32, key, 48);
  key[l] = 0;
  int num = buf[32];  // num
  LogPrint(eLogInfo, "NetDb: DatabaseSearchReply for ", key, " num=", num);
  IdentHash ident(buf);
  auto dest = m_Requests.FindRequest(ident);
  if (dest) {
    bool delete_dest = true;
    if (num > 0) {
      auto pool = i2p::tunnel::tunnels.GetExploratoryPool();
      auto outbound = pool ? pool->GetNextOutboundTunnel() : nullptr;
      auto inbound = pool ? pool->GetNextInboundTunnel() : nullptr;
      if (!dest->IsExploratory()) {
        // reply to our destination. Try other floodfills
        if (outbound && inbound) {
          std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
          auto count = dest->GetExcludedPeers().size();
          std::size_t max_ff(7);
          if (count < max_ff) {
            auto nextFloodfill = GetClosestFloodfill(
                dest->GetDestination(),
                dest->GetExcludedPeers());
            if (nextFloodfill) {
              // tell floodfill about us
              msgs.push_back(
                  i2p::tunnel::TunnelMessageBlock {
                  i2p::tunnel::e_DeliveryTypeRouter,
                  nextFloodfill->GetIdentHash(),
                  0,
                  CreateDatabaseStoreMsg()
                  });
              // request destination
              LogPrint(eLogInfo,
                  "NetDb: trying ", key,
                  " at ", count,
                  " floodfill ", nextFloodfill->GetIdentHash().ToBase64());
              auto msg = dest->CreateRequestMessage(nextFloodfill, inbound);
              msgs.push_back(
                  i2p::tunnel::TunnelMessageBlock {
                  i2p::tunnel::e_DeliveryTypeRouter,
                  nextFloodfill->GetIdentHash(),
                  0,
                  msg
                });
              delete_dest = false;
            }
          } else {
            LogPrint(eLogWarn,
                "NetDb: ", key, " was not found in ", max_ff, "floodfills");
          }
          if (msgs.size() > 0)
            outbound->SendTunnelDataMsg(msgs);
        }
      }
      if (delete_dest)
        // no more requests for the destination. delete it
        m_Requests.RequestComplete(ident, nullptr);
    } else {
      // no more requests for destination possible. delete it
      m_Requests.RequestComplete(ident, nullptr);
    }
  } else {
    LogPrint(eLogWarn,
        "NetDb: requested destination for ", key, " not found");
  }
  // try responses
  for (int i = 0; i < num; i++) {
    const uint8_t* router = buf + 33 + i * 32;
    char peer_hash[48];
    int l1 = i2p::util::ByteStreamToBase64(router, 32, peer_hash, 48);
    peer_hash[l1] = 0;
    LogPrint(eLogInfo, "NetDb: ", i, ": ", peer_hash);
    auto r = FindRouter(router);
    if (!r ||
        i2p::util::GetMillisecondsSinceEpoch() >
        r->GetTimestamp() + 3600 * 1000LL)  {
      // router with ident not found or too old (1 hour)
      LogPrint(eLogInfo,
          "NetDb: found new/outdated router, requesting RouterInfo");
      RequestDestination(router);
    } else {
      LogPrint(eLogInfo,
          "NetDb: router with ident found");
    }
  }
}

void NetDb::HandleDatabaseLookupMsg(
    std::shared_ptr<const I2NPMessage> msg) {
  const uint8_t* buf = msg->GetPayload();
  IdentHash ident(buf);
  if (ident.IsZero()) {
    LogPrint(eLogError, "NetDb: DatabaseLookup for zero ident. Ignored");
    return;
  }
  char key[48];
  int l = i2p::util::ByteStreamToBase64(buf, 32, key, 48);
  key[l] = 0;
  uint8_t flag = buf[64];
  LogPrint(eLogInfo, "NetDb: DatabaseLookup for ", key,
      " received flags=", static_cast<int>(flag));
  uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
  const uint8_t* excluded = buf + 65;
  uint32_t reply_tunnel_ID = 0;
  if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) {  // reply to tunnel
    reply_tunnel_ID = bufbe32toh(buf + 64);
    excluded += 4;
  }
  uint16_t num_excluded = bufbe16toh(excluded);
  excluded += 2;
  if (num_excluded > 512) {
    LogPrint(eLogWarn,
        "NetDb: number of excluded peers", num_excluded, " exceeds 512");
    num_excluded = 0;  // TODO(unassigned): ???
  }
  std::shared_ptr<I2NPMessage> reply_msg;
  if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP) {
    LogPrint(eLogInfo,
        "NetDb: exploratory close to  ", key, " ", num_excluded, " excluded");
    std::set<IdentHash> excluded_routers;
    for (int i = 0; i < num_excluded; i++) {
      excluded_routers.insert(excluded);
      excluded += 32;
    }
    std::vector<IdentHash> routers;
    for (int i = 0; i < 3; i++) {
      auto r = GetClosestNonFloodfill(ident, excluded_routers);
      if (r) {
        routers.push_back(r->GetIdentHash());
        excluded_routers.insert(r->GetIdentHash());
      }
    }
    reply_msg = CreateDatabaseSearchReply(ident, routers);
  } else {
    if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP  ||
        lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP) {
      auto router = FindRouter(ident);
      if (router) {
        LogPrint(eLogInfo, "NetDb: requested RouterInfo ", key, " found");
        router->LoadBuffer();
        if (router->GetBuffer())
          reply_msg = CreateDatabaseStoreMsg(router);
      }
    }
    if (!reply_msg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP  ||
          lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)) {
      auto lease_set = FindLeaseSet(ident);
      if (lease_set) {  // we don't send back our LeaseSets
        LogPrint(eLogInfo, "NetDb: requested LeaseSet ", key, " found");
        reply_msg = CreateDatabaseStoreMsg(lease_set);
      }
    }
    if (!reply_msg) {
      LogPrint(eLogInfo,
          "NetDb: requested ", key, " not found. ", num_excluded, " excluded");
      std::set<IdentHash> excluded_routers;
      for (int i = 0; i < num_excluded; i++) {
        excluded_routers.insert(excluded);
        excluded += 32;
      }
      reply_msg = CreateDatabaseSearchReply(
          ident,
          GetClosestFloodfills(
              ident,
              3,
              excluded_routers));
    }
  }
  if (reply_msg) {
    if (reply_tunnel_ID) {
      // encryption might be used though tunnel only
      if (flag & DATABASE_LOOKUP_ENCYPTION_FLAG) {  // encrypted reply requested
        const uint8_t* session_key = excluded;
        uint8_t num_tags = session_key[32];
        if (num_tags > 0)  {
          const uint8_t* sessionTag = session_key + 33;  // take first tag
          i2p::garlic::GarlicRoutingSession garlic(session_key, sessionTag);
          reply_msg = garlic.WrapSingleMessage(reply_msg);
        }
      }
      auto exploratory_pool = i2p::tunnel::tunnels.GetExploratoryPool();
      auto outbound =
        exploratory_pool ? exploratory_pool->GetNextOutboundTunnel() : nullptr;
      if (outbound)
        outbound->SendTunnelDataMsg(
            buf+32,
            reply_tunnel_ID,
            reply_msg);
      else
        i2p::transport::transports.SendMessage(
            buf+32,
            i2p::CreateTunnelGatewayMsg(
                reply_tunnel_ID,
                reply_msg));
    } else {
      i2p::transport::transports.SendMessage(buf+32, reply_msg);
    }
  }
}

void NetDb::Explore(
    int num_destinations) {
  // new requests
  auto exploratory_pool = i2p::tunnel::tunnels.GetExploratoryPool();
  auto outbound =
    exploratory_pool ? exploratory_pool->GetNextOutboundTunnel() : nullptr;
  auto inbound =
    exploratory_pool ? exploratory_pool->GetNextInboundTunnel() : nullptr;
  bool throughTunnels = outbound && inbound;
  uint8_t randomHash[32];
  std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
  std::set<const RouterInfo *> floodfills;
  // TODO(unassigned): docs
  LogPrint(eLogInfo, "NetDb: exploring new ", num_destinations, " routers");
  for (int i = 0; i < num_destinations; i++) {
    i2p::crypto::RandBytes(randomHash, 32);
    auto dest = m_Requests.CreateRequest(randomHash, true);  // exploratory
    if (!dest) {
      LogPrint(eLogWarn,
          "NetDb: exploratory destination was already requested");
      return;
    }
    auto floodfill = GetClosestFloodfill(randomHash, dest->GetExcludedPeers());
    if (floodfill &&
        !floodfills.count(floodfill.get())) {  // request floodfill only once
      floodfills.insert(floodfill.get());
      if (i2p::transport::transports.IsConnected(floodfill->GetIdentHash()))
        throughTunnels = false;
      if (throughTunnels) {
        msgs.push_back(
            i2p::tunnel::TunnelMessageBlock {
            i2p::tunnel::e_DeliveryTypeRouter,
            floodfill->GetIdentHash(),
            0,
            CreateDatabaseStoreMsg()  // tell floodfill about us
          });
        msgs.push_back(
            i2p::tunnel::TunnelMessageBlock  {
            i2p::tunnel::e_DeliveryTypeRouter,
            floodfill->GetIdentHash(),
            0,
            dest->CreateRequestMessage(
                floodfill,
                inbound)  // explore
          });
      } else {
        i2p::transport::transports.SendMessage(
            floodfill->GetIdentHash(),
            dest->CreateRequestMessage(
              floodfill->GetIdentHash()));
      }
    } else {
      m_Requests.RequestComplete(randomHash, nullptr);
    }
  }
  if (throughTunnels && msgs.size() > 0)
    outbound->SendTunnelDataMsg(msgs);
}

void NetDb::Publish() {
  std::set<IdentHash> excluded;  // TODO(unassigned): fill up later
  for (int i = 0; i < 2; i++) {
    auto floodfill = GetClosestFloodfill(
        i2p::context.GetRouterInfo().GetIdentHash(),
        excluded);
    if (floodfill) {
      uint32_t replyToken = i2p::crypto::Rand<uint32_t>();
      LogPrint(eLogInfo,
          "NetDb: publishing our RouterInfo to ",
          floodfill->GetIdentHashAbbreviation(),
          ". reply token=", replyToken);
      i2p::transport::transports.SendMessage(
          floodfill->GetIdentHash(),
          CreateDatabaseStoreMsg(
              i2p::context.GetSharedRouterInfo(),
              replyToken));
      excluded.insert(floodfill->GetIdentHash());
    }
  }
}

std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter() const {
  return GetRandomRouter(
      [](std::shared_ptr<const RouterInfo> router)->bool {
      return !router->IsHidden();
    });
}

std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter(
    std::shared_ptr<const RouterInfo> compatible_with) const {
  return GetRandomRouter(
      [compatible_with](std::shared_ptr<const RouterInfo> router)->bool {
      return !router->IsHidden() && router != compatible_with &&
        router->IsCompatible(*compatible_with);
    });
}

std::shared_ptr<const RouterInfo> NetDb::GetRandomPeerTestRouter() const {
  return GetRandomRouter(
    [](std::shared_ptr<const RouterInfo> router)->bool {
      return !router->IsHidden() && router->IsPeerTesting();
    });
}

std::shared_ptr<const RouterInfo> NetDb::GetRandomIntroducer() const {
  return GetRandomRouter (
    [](std::shared_ptr<const RouterInfo> router)->bool {
      return !router->IsHidden() && router->IsIntroducer();
    });
}

std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter(
    std::shared_ptr<const RouterInfo> compatible_with) const {
  return GetRandomRouter (
    [compatible_with](std::shared_ptr<const RouterInfo> router)->bool {
      return !router->IsHidden() &&
      router != compatible_with &&
      router->IsCompatible(*compatible_with) &&
      (router->GetCaps() & RouterInfo::eHighBandwidth);
    });
}

template<typename Filter>
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter(
    Filter filter) const {
  uint32_t ind = i2p::crypto::RandInRange<uint32_t>(0, m_RouterInfos.size() - 1);
  for (int j = 0; j < 2; j++) {
    uint32_t i = 0;
    std::unique_lock<std::mutex> l(m_RouterInfosMutex);
    for (auto it : m_RouterInfos) {
      if (i >= ind) {
        if (!it.second->IsUnreachable() && filter(it.second))
          return it.second;
      } else {
        i++;
      }
    }
    // we couldn't find anything, try second pass
    ind = 0;
  }
  return nullptr;  // seems we have too few routers
}

void NetDb::PostI2NPMsg(
    std::shared_ptr<const I2NPMessage> msg) {
  if (msg)
    m_Queue.Put(msg);
}

std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill(
    const IdentHash& destination,
    const std::set<IdentHash>& excluded) const {
  std::shared_ptr<const RouterInfo> r;
  XORMetric min_metric;
  IdentHash dest_key = CreateRoutingKey(destination);
  min_metric.SetMax();
  std::unique_lock<std::mutex> l(m_FloodfillsMutex);
  for (auto it : m_Floodfills) {
    if (!it->IsUnreachable()) {
      XORMetric m = dest_key ^ it->GetIdentHash();
      if (m < min_metric && !excluded.count(it->GetIdentHash())) {
        min_metric = m;
        r = it;
      }
    }
  }
  return r;
}

std::vector<IdentHash> NetDb::GetClosestFloodfills(
    const IdentHash& destination,
    size_t num,
    std::set<IdentHash>& excluded) const {
  struct Sorted {
    std::shared_ptr<const RouterInfo> r;
    XORMetric metric;
    bool operator<(const Sorted& other) const {
      return metric < other.metric;
    }
  };
  std::set<Sorted> sorted;
  IdentHash dest_key = CreateRoutingKey(destination); {
    std::unique_lock<std::mutex> l(m_FloodfillsMutex);
    for (auto it : m_Floodfills) {
      if (!it->IsUnreachable()) {
        XORMetric m = dest_key ^ it->GetIdentHash();
        if (sorted.size() < num) {
          sorted.insert({it, m});
        } else if (m < sorted.rbegin()->metric) {
          sorted.insert({it, m});
          sorted.erase(std::prev(sorted.end()));
        }
      }
    }
  }
  std::vector<IdentHash> res;
  size_t i = 0;
  for (auto it : sorted) {
    if (i < num) {
      auto& ident = it.r->GetIdentHash();
      if (!excluded.count(ident)) {
        res.push_back(ident);
        i++;
      }
    } else {
      break;
    }
  }
  return res;
}

std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill(
    const IdentHash& destination,
    const std::set<IdentHash>& excluded) const {
  std::shared_ptr<const RouterInfo> r;
  XORMetric min_metric;
  IdentHash dest_key = CreateRoutingKey(destination);
  min_metric.SetMax();
  // must be called from NetDb thread only
  for (auto it : m_RouterInfos) {
    if (!it.second->IsFloodfill()) {
      XORMetric m = dest_key ^ it.first;
      if (m < min_metric && !excluded.count(it.first)) {
        min_metric = m;
        r = it.second;
      }
    }
  }
  return r;
}

void NetDb::ManageLeaseSets() {
  for (auto it = m_LeaseSets.begin(); it != m_LeaseSets.end();) {
    if (!it->second->HasNonExpiredLeases()) {  // all leases expired
      LogPrint(eLogInfo,
          "NetDb: LeaseSet ", it->second->GetIdentHash().ToBase64(), " expired");
      it = m_LeaseSets.erase(it);
    } else {
      it++;
    }
  }
}

}  // namespace data
}  // namespace i2p

max_stars_repo_name: moneromooo-monero/kovri

max_issues_repo_name: Menutra/kovri

max_forks_repo_name: Menutra/kovri


text:
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022 Scipp contributors (https://github.com/scipp)
#include <gtest/gtest.h>

#include <Eigen/Geometry>

#include "scipp/common/constants.h"
#include "scipp/core/element/geometric_operations.h"
#include "scipp/units/unit.h"

#include "fix_typed_test_suite_warnings.h"

using namespace scipp;
using namespace scipp::core::element;

TEST(ElementPositionTest, unit_in) {
  const units::Unit m(units::m);
  const units::Unit s(units::s); // Not supported
  EXPECT_THROW(geometry::position(s, m, m), except::UnitError);
  EXPECT_THROW(geometry::position(m, s, m), except::UnitError);
  EXPECT_THROW(geometry::position(m, m, s), except::UnitError);
  EXPECT_NO_THROW(geometry::position(s, s, s));
  EXPECT_NO_THROW(geometry::position(m, m, m));
}

TEST(ElementPositionTest, unit_out) {
  const units::Unit m(units::m);
  EXPECT_EQ(geometry::position(m, m, m), m);
}

TEST(ElementPositionTest, zip_position_values) {
  EXPECT_EQ((Eigen::Vector3d(1, 2, 3)), geometry::position(1.0, 2.0, 3.0));
}

TEST(ElementPositionNTest, unzip_position) {
  Eigen::Vector3d a{1.0, 2.0, 3.0};
  EXPECT_EQ(geometry::x(a), a[0]);
  EXPECT_EQ(geometry::y(a), a[1]);
  EXPECT_EQ(geometry::z(a), a[2]);
  EXPECT_EQ(geometry::x(units::m), units::m);
  EXPECT_EQ(geometry::y(units::m), units::m);
  EXPECT_EQ(geometry::z(units::m), units::m);
}

ext: cpp

max_stars_repo_name: mlund/scipp

max_issues_repo_name: mlund/scipp

max_forks_repo_name: mlund/scipp


text:
/*
 * Copyright (c) 2015, Linear Technology. All rights reserved.
 */

#include "ProcessInputArguments.h"
#include <boost/algorithm/string.hpp>
#include <sstream>
#include <fstream>

using namespace std;
namespace po = boost::program_options;

CProcessInputArguments::CProcessInputArguments(const string& baseName, const char * hdr)
{
   m_defVal.apiProto    = DEFAULT_API_PROTO;
   m_defVal.apiIpcpath  = DEFAULT_API_IPCPATH_DIR;
   m_defVal.apiHost     = DEFAULT_API_HOST;
   m_defVal.apiPort     = DEFAULT_API_BASE_PORT;
   m_defVal.wdName      = "";
   m_defVal.logName     = baseName + ".log";
   m_defVal.confName    = baseName + ".conf";
   m_defVal.logLevel    = DEFAULT_LOG_LEVEL;
   if (hdr)
      m_hdr = hdr;
}

bool CProcessInputArguments::parse(int argc, char* argv[], bool isWdClnt, bool isHost)
{
   string proto,   ipcpath,
          host,    port,
          logName, logLevel,
          wdname;

   m_val = m_defVal;

   if (m_hdr.empty())
      m_hdr = "Arguments";
   po::options_description desc(m_hdr);
   desc.add_options()
   ("help", "Help message")
   ("api-proto",   po::value<string>(&proto),          "API protocol: IPC or TCP")
   ("api-ipcpath", po::value<string>(&m_val.apiIpcpath),  "Path to IPC files (only for IPC)");

   if (isHost)  {
      desc.add_options()
      ("api-host", po::value<string>(&m_val.apiHost), "RPC server address (only for TCP)");
   }

   desc.add_options()
   ("api-port",  po::value<uint16_t>(&m_val.apiPort), "Base IP port for services (only for TCP)")
   ("config-file,c", po::value<string>(&m_val.confName),  "Name of configuration file")
   ("log-file",  po::value<string>(&m_val.logName),   "Name of log file")
   ("log-level", po::value<string>(&logLevel),        "Initial default log level");

   if (isWdClnt) {
      desc.add_options()
      ("wd-name",   po::value<string>(&m_val.wdName), "Watchdog application name");
   }

   add_options(desc);

   try {
      po::variables_map vm;
      po::store(po::parse_command_line(argc, argv, desc), vm);
      po::notify(vm);

      if (vm.count("help"))
         throw po::error("");

      m_val.confName = getFullFileName(DEFAULT_CONF_DIR, m_val.confName);
      ifstream fIn(m_val.confName);
      if (fIn.good()) {
         try { // Read configuration file
            vm.clear();
            po::store(po::parse_config_file<char>(fIn, desc), vm);
            po::notify(vm);
         } catch(const std::exception& e) {
            ostringstream os;
            os << "Can not parse file: " << m_val.confName << " (" << e.what() << ")";
            throw runtime_error(os.str().c_str());
         }
         // Re-read command line for overwrite configuration-file parameters
         vm.clear();
         po::store(po::parse_command_line(argc, argv, desc), vm);
         po::notify(vm);
      }
      fIn.close();

      if (!proto.empty())
         m_val.apiProto = str2proto_p(proto);

      if (!logLevel.empty())
         m_val.logLevel = log4cxx::Level::toLevel(logLevel, m_val.logLevel);

      m_val.logName    = getFullFileName(DEFAULT_LOG_DIR, m_val.logName);

      process(vm);

   } catch (const std::exception& e) {
      if (strlen(e.what()) > 0)
         std::cerr << e.what() << std::endl;
      std::cout << desc << std::endl;
      return false;
   }

   return true;
}

string CProcessInputArguments::toString() const
{
   ostringstream os;
   if (getVal().apiProto == APIPROTO_IPC) {
      string ipcsubdir = getVal().apiIpcpath;
      if (ipcsubdir.empty())
         ipcsubdir = DEFAULT_API_IPCPATH_DIR;
      os << "API protocol: IPC. IPC directory: " << getFullFileName(ipcsubdir, " ");
   } else {
      os << "API protocol: TCP. " << getVal().apiHost << ":" << getVal().apiPort;
   }
   return os.str();
}

apiproto_t  CProcessInputArguments::str2proto_p(std::string s) const
{
   if (boost::iequals(s, "ipc"))
      return APIPROTO_IPC;
   if (boost::iequals(s, "tcp"))
      return APIPROTO_TCP;
   throw po::error(string("Unsupported protocol: ") + s);
}

max_stars_repo_name: wattsonelements/apbridge

max_issues_repo_name: wattsonelements/apbridge

max_forks_repo_name: wattsonelements/apbridge


text:
//
// execution/prefer_only.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP
#define BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/is_applicable_property.hpp>
#include <boost/asio/prefer.hpp>
#include <boost/asio/query.hpp>
#include <boost/asio/traits/static_query.hpp>

#include <boost/asio/detail/push_options.hpp>

namespace boost {
namespace asio {

#if defined(GENERATING_DOCUMENTATION)

namespace execution {

/// A property adapter that is used with the polymorphic executor wrapper
/// to mark properties as preferable, but not requirable.
template <typename Property>
struct prefer_only
{
  /// The prefer_only adapter applies to the same types as the nested property.
  template <typename T>
  static constexpr bool is_applicable_property_v =
    is_applicable_property<T, Property>::value;

  /// The context_t property cannot be required.
  static constexpr bool is_requirable = false;

  /// The context_t property can be preferred, it the underlying property can
  /// be preferred.
  /**
   * @c true if @c Property::is_preferable is @c true, otherwise @c false.
   */
  static constexpr bool is_preferable = automatically_determined;

  /// The type returned by queries against an @c any_executor.
  typedef typename Property::polymorphic_query_result_type
    polymorphic_query_result_type;
};

} // namespace execution

#else // defined(GENERATING_DOCUMENTATION)

namespace execution {
namespace detail {

template <typename InnerProperty, typename = void>
struct prefer_only_is_preferable
{
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false);
};

template <typename InnerProperty>
struct prefer_only_is_preferable<InnerProperty,
    typename enable_if<
      InnerProperty::is_preferable
    >::type>
{
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
};

template <typename InnerProperty, typename = void>
struct prefer_only_polymorphic_query_result_type
{
};

template <typename InnerProperty>
struct prefer_only_polymorphic_query_result_type<InnerProperty,
    typename void_type<
      typename InnerProperty::polymorphic_query_result_type
    >::type>
{
  typedef typename InnerProperty::polymorphic_query_result_type
    polymorphic_query_result_type;
};

template <typename InnerProperty, typename = void>
struct prefer_only_property
{
  InnerProperty property;

  prefer_only_property(const InnerProperty& p)
    : property(p)
  {
  }
};

#if defined(BOOST_ASIO_HAS_DECLTYPE) \
  && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE)

template <typename InnerProperty>
struct prefer_only_property<InnerProperty,
    typename void_type<
      decltype(boost::asio::declval<const InnerProperty>().value())
    >::type>
{
  InnerProperty property;

  prefer_only_property(const InnerProperty& p)
    : property(p)
  {
  }

  BOOST_ASIO_CONSTEXPR auto value() const
    BOOST_ASIO_NOEXCEPT_IF((
      noexcept(boost::asio::declval<const InnerProperty>().value())))
    -> decltype(boost::asio::declval<const InnerProperty>().value())
  {
    return property.value();
  }
};

#else // defined(BOOST_ASIO_HAS_DECLTYPE)
      //   && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE)

struct prefer_only_memfns_base
{
  void value();
};

template <typename T>
struct prefer_only_memfns_derived
  : T, prefer_only_memfns_base
{
};

template <typename T, T>
struct prefer_only_memfns_check
{
};

template <typename>
char (&prefer_only_value_memfn_helper(...))[2];

template <typename T>
char prefer_only_value_memfn_helper(
    prefer_only_memfns_check<
      void (prefer_only_memfns_base::*)(),
      &prefer_only_memfns_derived<T>::value>*);

template <typename InnerProperty>
struct prefer_only_property<InnerProperty,
    typename enable_if<
      sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1
        && !is_same<typename InnerProperty::polymorphic_query_result_type,
          void>::value
    >::type>
{
  InnerProperty property;

  prefer_only_property(const InnerProperty& p)
    : property(p)
  {
  }

  BOOST_ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type
  value() const
  {
    return property.value();
  }
};

#endif // defined(BOOST_ASIO_HAS_DECLTYPE)
       //   && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE)

} // namespace detail

template <typename InnerProperty>
struct prefer_only :
  detail::prefer_only_is_preferable<InnerProperty>,
  detail::prefer_only_polymorphic_query_result_type<InnerProperty>,
  detail::prefer_only_property<InnerProperty>
{
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false);

  BOOST_ASIO_CONSTEXPR prefer_only(const InnerProperty& p)
    : detail::prefer_only_property<InnerProperty>(p)
  {
  }

#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
  && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
  template <typename T>
  static BOOST_ASIO_CONSTEXPR
  typename traits::static_query<T, InnerProperty>::result_type
  static_query()
    BOOST_ASIO_NOEXCEPT_IF((
      traits::static_query<T, InnerProperty>::is_noexcept))
  {
    return traits::static_query<T, InnerProperty>::value();
  }

  template <typename E, typename T = decltype(prefer_only::static_query<E>())>
  static BOOST_ASIO_CONSTEXPR const T static_query_v
    = prefer_only::static_query<E>();
#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
       //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)

  template <typename Executor, typename Property>
  friend BOOST_ASIO_CONSTEXPR
  typename prefer_result<const Executor&, const InnerProperty&>::type
  prefer(const Executor& ex, const prefer_only<Property>& p,
      typename enable_if<
        is_same<Property, InnerProperty>::value
          && can_prefer<const Executor&, const InnerProperty&>::value
      >::type* = 0)
#if !defined(BOOST_ASIO_MSVC) \
  && !defined(__clang__) // Clang crashes if noexcept is used here.
    BOOST_ASIO_NOEXCEPT_IF((
      is_nothrow_prefer<const Executor&, const InnerProperty&>::value))
#endif // !defined(BOOST_ASIO_MSVC)
       //   && !defined(__clang__)
  {
    return boost::asio::prefer(ex, p.property);
  }

  template <typename Executor, typename Property>
  friend BOOST_ASIO_CONSTEXPR
  typename query_result<const Executor&, const InnerProperty&>::type
  query(const Executor& ex, const prefer_only<Property>& p,
      typename enable_if<
        is_same<Property, InnerProperty>::value
          && can_query<const Executor&, const InnerProperty&>::value
      >::type* = 0)
#if !defined(BOOST_ASIO_MSVC) \
  && !defined(__clang__) // Clang crashes if noexcept is used here.
    BOOST_ASIO_NOEXCEPT_IF((
      is_nothrow_query<const Executor&, const InnerProperty&>::value))
#endif // !defined(BOOST_ASIO_MSVC)
       //   && !defined(__clang__)
  {
    return boost::asio::query(ex, p.property);
  }
};

#if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
  && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
template <typename InnerProperty> template <typename E, typename T>
const T prefer_only<InnerProperty>::static_query_v;
#endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
       //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)

} // namespace execution

template <typename T, typename InnerProperty>
struct is_applicable_property<T, execution::prefer_only<InnerProperty> >
  : is_applicable_property<T, InnerProperty>
{
};

namespace traits {

#if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
  || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)

template <typename T, typename InnerProperty>
struct static_query<T, execution::prefer_only<InnerProperty> > :
  static_query<T, const InnerProperty&>
{
};

#endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
       //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)

#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)

template <typename T, typename InnerProperty>
struct prefer_free_default<T, execution::prefer_only<InnerProperty>,
    typename enable_if<
      can_prefer<const T&, const InnerProperty&>::value
    >::type>
{
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
    (is_nothrow_prefer<const T&, const InnerProperty&>::value));

  typedef typename prefer_result<const T&,
      const InnerProperty&>::type result_type;
};

#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT)

#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)

template <typename T, typename InnerProperty>
struct query_free<T, execution::prefer_only<InnerProperty>,
    typename enable_if<
      can_query<const T&, const InnerProperty&>::value
    >::type>
{
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
  BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept =
    (is_nothrow_query<const T&, const InnerProperty&>::value));

  typedef typename query_result<const T&,
      const InnerProperty&>::type result_type;
};

#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT)

} // namespace traits

#endif // defined(GENERATING_DOCUMENTATION)

} // namespace asio
} // namespace boost

#include <boost/asio/detail/pop_options.hpp>

#endif // BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP

ext: hpp

max_stars_repo_name: kindlychung/mediasoup-sfu-cpp

max_issues_repo_name: kindlychung/mediasoup-sfu-cpp

max_forks_repo_name: kindlychung/mediasoup-sfu-cpp


text:
/*
 * @ClassName: ConcurrentQueueMain
 * @Description:
 * @Author:  Ravitn
 * @Date: 2021-03-05 14:53
*/
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include "ConcurrentQueue.h"
#include <boost/lockfree/queue.hpp>
//#include <functional>

boost::lockfree::queue<int> queue;
using namespace std;
void writer(ConcurrentQueue<int>& concurrentQueue , int start, int size) {
    for(int i = start; i< start+size ; i++){
        concurrentQueue.push(i);
    }
}
void waitRead(ConcurrentQueue<int>& concurrentQueue ) {
    while(true){
        std::shared_ptr<int> sharedPtr = concurrentQueue.wait_and_pop();
        cout << "waitRead:" << sharedPtr;
    }
}
void tryRead(ConcurrentQueue<int>& concurrentQueue ) {
    while(true){
        std::shared_ptr<int> sharedPtr = concurrentQueue.try_pop();
        if(nullptr != sharedPtr){
            cout << "tryRead:" << sharedPtr;
        }
    }
}
int main() {
    vector<thread> vc;
    ConcurrentQueue<int> cq;
    vc.emplace_back(thread(waitRead,std::ref(cq)));
    vc.emplace_back(thread(tryRead,std::ref(cq)));
    vc.emplace_back(thread(writer,std::ref(cq), 0, 10));
    vc.emplace_back(thread(writer,std::ref(cq), 10, 10));
    for(int i =0; i< vc.size(); i++){
        vc[i].join();
    }
//    for_each(vc.begin(), vc.end(), [&](thread t){t.join();});
}

max_stars_repo_name: Donaldhan/Cprimer-Demo

max_issues_repo_name: Donaldhan/Cprimer-Demo

max_forks_repo_name: Donaldhan/Cprimer-Demo


text:
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007 Anthony Williams
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H

#include <boost/thread/detail/config.hpp>

//  pdm: Sorry, but this class is used all over the place & I end up
//       with recursive headers if I don't separate it
//  wek: Not sure why recursive headers would cause compilation problems
//       given the include guards, but regardless it makes sense to
//       seperate this out any way.

#include <string>
#include <stdexcept>

namespace boost {

class BOOST_THREAD_DECL thread_exception : public std::exception
{
protected:
    thread_exception();
    thread_exception(int sys_err_code);

public:
    ~thread_exception() throw();

    int native_error() const;

private:
    int m_sys_err;
};

    class condition_error:
        public std::exception
    {
    public:
        const char* what() const throw()
        {
            return "Condition error";
        }
    };

class BOOST_THREAD_DECL lock_error : public thread_exception
{
public:
    lock_error();
    lock_error(int sys_err_code);
    ~lock_error() throw();

    virtual const char* what() const throw();
};

class BOOST_THREAD_DECL thread_resource_error : public thread_exception
{
public:
    thread_resource_error();
    thread_resource_error(int sys_err_code);
    ~thread_resource_error() throw();

    virtual const char* what() const throw();
};

class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
{
public:
    unsupported_thread_option();
    unsupported_thread_option(int sys_err_code);
    ~unsupported_thread_option() throw();

    virtual const char* what() const throw();
};

class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
{
public:
    invalid_thread_argument();
    invalid_thread_argument(int sys_err_code);
    ~invalid_thread_argument() throw();

    virtual const char* what() const throw();
};

class BOOST_THREAD_DECL thread_permission_error : public thread_exception
{
public:
    thread_permission_error();
    thread_permission_error(int sys_err_code);
    ~thread_permission_error() throw();

    virtual const char* what() const throw();
};

} // namespace boost

#endif // BOOST_THREAD_CONFIG_PDM070801_H

// Change log:
//    3 Jan 03  WEKEMPF Modified for DLL implementation.

max_stars_repo_name: foxostro/CheeseTesseract

max_issues_repo_name: foxostro/CheeseTesseract

max_forks_repo_name: foxostro/CheeseTesseract


text:
/**
 *  @file
 *  @copyright defined in bes/LICENSE.txt
 */
#pragma once
#include <boost/asio/ip/tcp.hpp>
#include <boost/pool/object_pool.hpp>
#include <fc/io/raw.hpp>
#include <deque>
#include <array>
#include <fc/exception/exception.hpp>

namespace fc {
  template <uint32_t buffer_len>
  class mb_datastream;

  /**
   *  @brief abstraction for a message buffer that spans a chain of physical buffers
   *
   *  This message buffer abstraction will allocate individual character arrays
   *  of size buffer_len from a boost::object_pool.  It supports creation of a
   *  vector of boost::mutable_buffer for use with async_read() and async_read_some().
   *  It also supports use with the fc unpack() functionality via a datastream
   *  helper class.
   */
  template <uint32_t buffer_len>
  class message_buffer {
  public:
    /*
     *  index abstraction that references a point in the chain of buffers.
     *  first refers to the buffer's index in the deque.
     *  second refers to the byte in the character buffer.
     */
    typedef std::pair<uint32_t, uint32_t> index_t;

    message_buffer() : buffers{pool().malloc()}, read_ind{0,0}, write_ind{0,0}, sanity_check (1) { }

    ~message_buffer() {
      while (buffers.size() > 0) {
        pool().destroy(buffers.back());
        buffers.pop_back();
      }
    }

    /*
     *  Returns the current read index referencing the byte in the buffer
     *  that is next to be read.
     */
    index_t read_index() const { return read_ind; }

    /*
     *  Returns the current write index referencing the byte in the buffer
     *  that is next to be written to.
     */
    index_t write_index() const { return write_ind; }

    /*
     *  Returns the current read pointer pointing to the memory location
     *  of the next byte to be read.
     */
    char* read_ptr() {
      return &buffers[read_ind.first]->at(read_ind.second);
    }

    /*
     *  Returns the current write pointer pointing to the memory location
     *  of the next byte to be written to.
     */
    char* write_ptr() {
      return &buffers[write_ind.first]->at(write_ind.second);
    }

    /*
     *  Adds an additional buffer of buffer_len to the chain of buffers.
     *  Does not affect the read or write pointer.
     */
    void add_buffer_to_chain() {
      sanity_check++;
      buffers.push_back(pool().malloc());
    }

    /*
     *  Adds additional buffers of length buffer_len to the chain of buffers
     *  in order to add at least bytes to the space available.
     *  Does not affect the read or write pointer.
     */
    void add_space(uint32_t bytes) {
      int buffers_to_add = bytes / buffer_len + 1;
      for (int i = 0; i < buffers_to_add; i++) {
        sanity_check++;
        buffers.push_back(pool().malloc());
      }
    }

    /*
     *  Resets the message buffer to the initial state. Any unread data is
     *  discarded.
     */
    void reset() {
      // some condition exists that can send *both* buffers.size() and sanity_check to well over 10^6.
      // this seems to be related to some sort of memory overrun possibly. By forcing an exit here, an
      // external watchdog can be used to restart the process and avoid hanging.
      if( buffers.size() != sanity_check || buffers.size() > 1000000) {
        elog ("read_ind = ${r1}, ${r2} write_ind = ${w1}, ${w2}, buff.size = ${bs}, sanity = ${s}",
              ("r1",read_ind.first)("r2",read_ind.second)("w1",write_ind.first)("w2",write_ind.second)("bs",buffers.size())("s",sanity_check));
        elog("Buffer manager overwrite detected. Terminating to allow external restart");
        exit(1);
      }
      while (buffers.size() > 1) {
        sanity_check--;
        pool().destroy(buffers.back());
        buffers.pop_back();
      }

      read_ind = { 0, 0 };
      write_ind = { 0, 0 };
    }

    /*
     *  Returns the current number of bytes remaining to be read.
     *  Logically, this is the different between where the read and write pointers are.
     */
    uint32_t bytes_to_read() const {
      return bytes_to_read_from_index(read_ind);
    }

    /*
     *  Returns the current number of bytes remaining to be read from a given index
     *  Logically, this is the different between where the given index is and the write pointers.
     */
    uint32_t bytes_to_read_from_index(index_t ind) const {
      return (write_ind.first - ind.first) * buffer_len + write_ind.second - ind.second;
    }

    /*
     *  Returns the current number of bytes available to be written.
     *  Logically, this is the different between the write pointer and the
     *  end of the buffer.  If this is not enough room, call either
     *  add_buffer_to_chain() or add_room() to create more space.
     */
    uint32_t bytes_to_write() const {
      return total_bytes() - write_ind.first * buffer_len - write_ind.second;
    }

    /*
     *  Returns the total number of bytes in the buffer chain.
     */
    uint32_t total_bytes() const {
      return buffer_len * buffers.size();
    }

    /*
     *  Advances the read pointer/index the supplied number of bytes along
     *  the buffer chain.  Any buffers that the read pointer moves beyond
     *  will be removed from the buffer chain.  If the read pointer becomes
     *  equal to the write pointer, the message buffer will be reset to
     *  its initial state (one buffer with read and write pointers at the
     *  start).
     */
    void advance_read_ptr(uint32_t bytes) {
      advance_index(read_ind, bytes);
      if (read_ind == write_ind) {
        reset();
      } else if (read_ind.first > 0) {
        while (read_ind.first > 0) {
          pool().destroy(buffers.front());
          buffers.pop_front();
          sanity_check--;
          read_ind.first--;
          write_ind.first--;
        }
      }
    }

    /*
     *  Advances the write pointer/index the supplied number of bytes along
     *  the buffer chain.
     */
    void advance_write_ptr(uint32_t bytes) {
      advance_index(write_ind, bytes);
      while (write_ind.first >= buffers.size()) {
        sanity_check++;
        buffers.push_back(pool().malloc());
      }
    }

    /*
     *  Creates and returns a vector of boost mutable_buffers that can
     *  be passed to boost async_read() and async_read_some() functions.
     *  The beginning of the vector will be the write pointer, which
     *  should be advanced the number of bytes read after the read returns.
     */
    std::vector<boost::asio::mutable_buffer> get_buffer_sequence_for_boost_async_read() {
      std::vector<boost::asio::mutable_buffer> seq;
      FC_ASSERT(write_ind.first < buffers.size());
      seq.push_back(boost::asio::buffer(&buffers[write_ind.first]->at(write_ind.second),
                                                buffer_len - write_ind.second));
      for (std::size_t i = write_ind.first + 1; i < buffers.size(); i++) {
        seq.push_back(boost::asio::buffer(&buffers[i]->at(0), buffer_len));
      }
      return seq;
    }

    /*
     *  Reads size bytes from the buffer chain starting at the read pointer.
     *  The read pointer is advanced size bytes.
     */
    bool read(void* s, uint32_t size) {
      if (bytes_to_read() < size) {
        FC_THROW_EXCEPTION(out_of_range_exception, "tried to read ${r} but only ${s} left", ("r", size)("s", bytes_to_read()));
      }
      if (read_ind.second + size <= buffer_len) {
        memcpy(s, read_ptr(), size);
        advance_read_ptr(size);
      } else {
        uint32_t num_in_buffer = buffer_len - read_ind.second;
        memcpy(s, read_ptr(), num_in_buffer);
        advance_read_ptr(num_in_buffer);
        read((char*)s + num_in_buffer, size - num_in_buffer);
      }
      return true;
    }

    /*
     *  Reads size bytes from the buffer chain starting at the supplied index.
     *  The supplied index is advanced, but the read pointer is unaffected.
     */
    bool peek(void* s, uint32_t size, index_t& index) {
      if (bytes_to_read_from_index(index) < size) {
        FC_THROW_EXCEPTION(out_of_range_exception, "tried to peek ${r} but only ${s} left", ("r", size)("s",bytes_to_read_from_index(index)));
      }
      if (index.second + size <= buffer_len) {
        memcpy(s, get_ptr(index), size);
        advance_index(index, size);
      } else {
        uint32_t num_in_buffer = buffer_len - index.second;
        memcpy(s, get_ptr(index), num_in_buffer);
        advance_index(index, num_in_buffer);
        peek((char*)s + num_in_buffer, size - num_in_buffer, index);
      }
      return true;
    }

    /*
     *  Creates an mb_datastream object that can be used with the
     *  fc library's unpack functionality.
     */
    mb_datastream<buffer_len> create_datastream();

  private:
    static boost::object_pool<std::array<char, buffer_len> >& pool() {
      static boost::object_pool<std::array<char, buffer_len> > pool;
      return pool;
    }

    /*
     *  Advances the supplied index along the buffer chain the specified
     *  number of bytes.
     */
    static void advance_index(index_t& index, uint32_t bytes) {
      index.first += (bytes + index.second) / buffer_len;
      index.second = (bytes + index.second) % buffer_len;
    }

    /*
     *  Returns the character pointer associated with the supplied index.
     */
    char* get_ptr(index_t index) {
      return &buffers[index.first]->at(index.second);
    }

    std::deque<std::array<char, buffer_len>* > buffers;
    index_t read_ind;
    index_t write_ind;
    size_t sanity_check;

  };

  /*
   *  @brief datastream adapter that adapts message_buffer for use with fc unpack
   *
   *  This class supports unpack functionality but not pack.
   */
  // Stream adapter for use with the fc unpack functionality
  template <uint32_t buffer_len>
  class mb_datastream {
     public:
        mb_datastream( message_buffer<buffer_len>& m ) : mb(m) {}

        inline void skip( size_t s ) { mb.advance_read_ptr(s); }
        inline bool read( char* d, size_t s ) {
          if (mb.bytes_to_read() >= s) {
            mb.read(d, s);
            return true;
          }
          fc::detail::throw_datastream_range_error( "read", mb.bytes_to_read(), s - mb.bytes_to_read());
        }

        inline bool   get( unsigned char& c ) { return mb.read(&c, 1); }
        inline bool   get( char& c ) { return mb.read(&c, 1); }

      private:
        message_buffer<buffer_len>& mb;
  };

  template <uint32_t buffer_len>
  inline mb_datastream<buffer_len> message_buffer<buffer_len>::create_datastream() {
    return mb_datastream<buffer_len>(*this);
  }

} // namespace fc

max_stars_repo_name: apolloaotc/src

max_issues_repo_name: biteosorg/BitEOS

max_forks_repo_name: apolloaotc/src


text:
#pragma once

#include <boost/asio/awaitable.hpp>

#if !defined(BOOST_ASIO_HAS_CO_AWAIT)
#error "Need co_await!"
#endif

namespace v60 {
template<class T>
using task = boost::asio::awaitable<T>;
}


text:
#pragma once

#include <sou/chain/webassembly/sou-vm-oc/config.hpp>

#include <boost/asio/local/datagram_protocol.hpp>
#include <sou/chain/webassembly/sou-vm-oc/ipc_helpers.hpp>

namespace sou { namespace chain { namespace souvmoc {

wrapped_fd get_connection_to_compile_monitor(int cache_fd);

}}}

max_stars_repo_name: sdhjob/ttt

max_issues_repo_name: sdhjob/ttt

max_forks_repo_name: sdhjob/ttt


text:
#include <crete/cluster/vm_node.h>
#include <crete/exception.h>
#include <crete/process.h>
#include <crete/asio/server.h>
#include <crete/run_config.h>
#include <crete/serialize.h>

#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/range/irange.hpp>
#include <boost/thread.hpp>
#include <boost/property_tree/ptree.hpp>

#include <boost/process.hpp>

#include <memory>

#include "vm_node_fsm.cpp" // Unfortunate workaround to accommodate Boost.MSM.

namespace bp = boost::process;
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

namespace crete
{
namespace cluster
{

VMNode::VMNode(const node::option::VMNode& node_options,
               const fs::path& pwd)
    : Node{packet_type::cluster_request_vm_node}
    , node_options_{node_options}
    , pwd_{pwd}
{
    if(node_options_.vm.count < 1)
    {
        BOOST_THROW_EXCEPTION(Exception{} << err::arg_invalid_uint(node_options_.vm.count));
    }

    init_image_info();
    add_instances(node_options_.vm.count);
}

auto VMNode::run() -> void
{
    if(!commenced())
    {
        return;
    }

    poll();
}

auto VMNode::poll() -> void
{
    using namespace node::vm;

    auto any_active = false;

    for(auto& vm : vms_)
    {
        if(vm->is_flag_active<flag::error>())
        {
            using node::vm::fsm::QemuFSM;

            push(vm->error());

            std::cerr << "pushing error!\n";

            auto pwd = vm->pwd();

            vm.reset(new QemuFSM{}); // TODO: may leak. Can I do vm = std::make_shared<QemuFSM>()?

            vm->start();

            ev::start start_ev{
                master_options(),
                        node_options_,
                        pwd,
                        image_path(),
                        false,
                        target_,
                        (traces().size() == 0)
            };

            vm->process_event(start_ev);
        }
        else if(vm->is_flag_active<flag::trace_ready>())
        {
            push(vm->trace());
            push_guest_data_post_exec(vm->get_guest_data_post_exec());

            vm->process_event(ev::trace_queued{});
        }
        else if(vm->is_flag_active<flag::next_test>())
        {
            auto has_tests = !tests().empty();

            if(has_tests)
            {
                using boost::msm::back::HANDLED_TRUE;

                auto t = next_test();

                if(HANDLED_TRUE == vm->process_event(ev::next_test{t}))
                {
                    pop_test();
                }
            }
        }
        else if(vm->is_flag_active<flag::guest_data_rxed>())
        {
            guest_data_ = vm->guest_data();
            vm->process_event(ev::poll{});
        }
        else if(vm->is_flag_active<flag::terminated>())
        {
            // Do nothing.
        }
        else
        {
            vm->process_event(ev::poll{});
        }

        any_active = any_active
                     || (!vm->is_flag_active<flag::next_test>()
                         && !vm->is_flag_active<flag::terminated>());
    }

    active(any_active);
}

auto VMNode::start_FSMs() -> void
{
    using namespace node::vm;

    auto vm_path = pwd_.string();

    if(master_options().mode.distributed)
    {
        vm_path = vm_inst_pwd.string();
    }

    ev::start start_ev{
        master_options(),
        node_options_,
        vm_path,
        image_path(),
        false,
        target_,
        (traces().size() == 0)
    };

    auto vm_num = 1u;

    for(auto& fsm : vms_)
    {
        fsm->start();

        auto s = start_ev;

        if(vm_num == 1)
        {
            s.first_vm_ = true;
        }

        if(master_options().mode.distributed)
        {
            s.vm_dir_ /= std::to_string(vm_num++);
        }

        fsm->process_event(s);
    }
}

auto VMNode::init_image_info() -> void
{
    auto infop = pwd_ / node_image_dir / image_info_name;

    if(fs::exists(infop))
    {

        {
            auto imagep = pwd_ / node_image_dir / image_name;

            if(!fs::exists(imagep))
            {
                fs::remove(infop);

                return;
            }
        }

        fs::ifstream ifs{infop};

        if(!ifs.good())
        {
            BOOST_THROW_EXCEPTION(Exception{} << err::file_open_failed{infop.string()});
        }

        serialize::read_text(ifs,
                             image_info_);
    }
}

auto VMNode::update(const ImageInfo& ii) -> void
{
    image_info_ = ii;
    auto img_dir = pwd_ / node_image_dir;
    auto infop = img_dir / image_info_name;

    if(!fs::exists(img_dir))
    {
        fs::create_directories(img_dir);
    }

    fs::ofstream ofs{infop};

    if(!ofs.good())
    {
        BOOST_THROW_EXCEPTION(Exception{} << err::file_open_failed{infop.string()});
    }

    serialize::write_text(ofs,
                          image_info_);
}

auto VMNode::image_info() -> const ImageInfo&
{
    return image_info_;
}

auto VMNode::image_path() -> fs::path
{
    return pwd_ / node_image_dir / image_name;
}

auto VMNode::reset() -> void
{
    using namespace node::vm;

    std::cerr << "reset()" << std::endl;

    if(!commenced())
    {
        return;
    }

    auto count = vms_.size();

    for(auto& vm : vms_)
    {
        vm->process_event(ev::terminate{});
    }

    Node::reset();

    vms_.clear();

    add_instances(count);
}

auto VMNode::target(const std::string& target) -> void
{
    target_ = target;
}

auto VMNode::guest_data() -> const boost::optional<GuestData>&
{
    return guest_data_;
}

auto VMNode::reset_guest_data() -> void
{
    guest_data_ = boost::optional<GuestData>();
}

auto VMNode::push_guest_data_post_exec(const GuestDataPostExec& input) ->void
{
    guest_data_post_exec_.emplace_front(input);
}

auto VMNode::pop_guest_data_post_exec() -> const GuestDataPostExec
{
    assert(!guest_data_post_exec_.empty());
    auto ret = guest_data_post_exec_.back();
    guest_data_post_exec_.pop_back();

    return ret;
}

auto process(AtomicGuard<VMNode>& node,
             NodeRequest& request) -> bool
{
    switch(request.pkinfo_.type)
    {
    case packet_type::cluster_image_info_request:
        transmit_image_info(node,
                            request.client_);
        return true;
    case packet_type::cluster_image_info:
        receive_image_info(node,
                           request.sbuf_);
        return true;
    case packet_type::cluster_image:
        receive_image(node,
                      request.client_);
        return true;
    case packet_type::cluster_next_target:
        receive_target(node,
                       request.sbuf_);
        return true;
    case packet_type::cluster_commence:
    {
        auto lock = node.acquire();

        lock->start_FSMs(); // Once we have the options from Dispatch, we can start the VM instances.
        lock->commence();

        return true;
    }
    case packet_type::cluster_request_guest_data:
    {
        transmit_guest_data(node,
                            request.client_);

        return true;
    }
    case packet_type::cluster_request_guest_data_post_exec:
        transmit_guest_data_post_exec(node,
                                      request.client_);

        return true;
    }

    return false;
}

auto transmit_guest_data(AtomicGuard<VMNode>& node,
                         Client& client) -> void
{
    auto guest_data = decltype(node.acquire()->guest_data()){};
    auto pkinfo = PacketInfo{0, 0, 0};
    pkinfo.type = packet_type::cluster_tx_guest_data;

    while(!guest_data)
    {
        auto lock = node.acquire();

        pkinfo.id = lock->id();
        guest_data = lock->guest_data();
        lock->reset_guest_data();
    }

    write_serialized_binary(client,
                            pkinfo,
                            *guest_data);
}

auto transmit_guest_data_post_exec(AtomicGuard<VMNode>& node,
                         Client& client) -> void
{
    auto lock = node.acquire();

    auto pkinfo = PacketInfo{0, 0, 0};
    pkinfo.id = lock->id();
    pkinfo.type = packet_type::cluster_tx_guest_data_post_exec;

    GuestDataPostExec guest_data_post_exec = lock->pop_guest_data_post_exec();

    write_serialized_binary(client,
                            pkinfo,
                            guest_data_post_exec);
}

auto transmit_image_info(AtomicGuard<VMNode>& node,
                           Client& client) -> void
{
    auto pkinfo = PacketInfo{0,0,0};
    auto ii = ImageInfo{};

    {
        auto lock = node.acquire();

        pkinfo.id = lock->id();
        pkinfo.type = packet_type::cluster_image_info;

        ii = lock->image_info();
    }

    write_serialized_binary(client,
                            pkinfo,
                            ii);
}

auto receive_image_info(AtomicGuard<VMNode>& node,
                        boost::asio::streambuf& sbuf) -> void
{
    std::cout << "receive_image_info" << std::endl;
    auto ii = ImageInfo{};

    read_serialized_binary(sbuf,
                           ii);

    node.acquire()->update(ii);
}

auto receive_image(AtomicGuard<VMNode>& node,
                   Client& client) -> void
{
    auto image_path = node.acquire()->image_path();

    std::cout << "receive_image: " << image_path.string() << std::endl;

    if(!fs::exists(image_path.parent_path()))
    {
        fs::create_directories(image_path.parent_path());
    }

    if(fs::exists(image_path))
    {
        fs::remove(image_path);
    }

    fs::ofstream ofs{image_path};

    CRETE_EXCEPTION_ASSERT(ofs.good(), err::file_open_failed{image_path.string()});

    read(client,
         ofs);

    std::cout << "receive_image: success" << std::endl;
}

auto receive_target(AtomicGuard<VMNode>& node,
                    boost::asio::streambuf& sbuf) -> void
{
    auto target = std::string{};

    read_serialized_binary(sbuf,
                           target);

    node.acquire()->target(target);
}

auto VMNode::add_instance() -> void
{
    vms_.emplace_back(std::make_shared<node::vm::fsm::QemuFSM>());
}

auto VMNode::add_instances(size_t count) -> void
{
    for(const auto& i : boost::irange(size_t(0), count))
    {
        (void)i;

        add_instance();
    }
}

} // namespace cluster
} // namespace crete


text:
/**************************************************************************\
|
|    Copyright (C) 2009 Marc Stevens
|
|    This program is free software: you can redistribute it and/or modify
|    it under the terms of the GNU 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 General Public License for more details.
|
|    You should have received a copy of the GNU General Public License
|    along with this program.  If not, see <http://www.gnu.org/licenses/>.
|
\**************************************************************************/

#include <stdexcept>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

#include <boost/program_options.hpp>

#include "main.hpp"

#include <hashclash/md5detail.hpp>
#include <hashclash/timer.hpp>

using namespace hashclash;
using namespace std;
namespace po = boost::program_options;
namespace fs = boost::filesystem;

std::string workdir;

int main(int argc, char** argv)
{
	int result = 0;
	timer runtime(true);

	cout <<
		"Birthday search for MD5 chosen-prefix collisions\n"
		"Copyright (C) 2009 Marc Stevens\n"
		"http://homepages.cwi.nl/~stevens/\n"
		<< endl;

	try {
		birthday_parameters parameters;

		// Define program options
		po::options_description
			desc("Allowed options"),
			all("Allowed options");

		desc.add_options()
			("help,h", "Show options.")
			("mod,m"
				, po::value<unsigned>(&parameters.modn)->default_value(1)
				, "Do only 1/m of all work.")

			("index,i"
				, po::value<unsigned>(&parameters.modi)->default_value(0)
				, "Do i-th part of all work (i=0,...,m-1).")

			("workdir,w"
				, po::value<string>(&workdir)->default_value("./data")
				, "Set working directory.")

			("inputfile1"
				, po::value<string>(&parameters.inputfile1)
				, "Use specified inputfile as first message.")

			("inputfile2"
				, po::value<string>(&parameters.inputfile2)
				, "Use specified inputfile as second message.")

			("outputfile1"
				, po::value<string>(&parameters.outputfile1)->default_value("file1.bin")
				, "Use specified outputfile for first message.")

			("outputfile2"
				, po::value<string>(&parameters.outputfile2)->default_value("file2.bin")
				, "Use specified outputfile for second message.")

			("distribution"
				, po::bool_switch(&parameters.distribution)
				, "Show workdistribution.\nDepends on hybridbits and pathtyperange.")

			("hybridbits"
				, po::value<unsigned>(&parameters.hybridbits)->default_value(0)
				, "Set 0 for 64-bit, 32 for 96-bit birthdaying.")

			("pathtyperange"
				, po::value<unsigned>(&parameters.pathtyperange)->default_value(2)
				, "Increases potential # diffs eliminated per n.c.")

			("maxblocks"
				, po::value<unsigned>(&parameters.maxblocks)->default_value(9)
				, "Upperbound on the amount of near-collisions.")

			("logtraillength"
				, po::value<int>(&parameters.logpathlength)->default_value(-1)
				, "Specify avg. trail length in bits.")

			("maxmemory"
				, po::value<unsigned>(&parameters.maxmemory)->default_value(100)
				, "Max. memory in MB used for storing trails.")

			("memhardlimit"
				, po::bool_switch(&parameters.memhardlimit)
				, "Hard limit max. memory instead of average.")
			("threads"
				, po::value<unsigned>(&parameters.threads)->default_value(0)
				, "Number of computing threads to start.")
			;

#ifdef HAVE_CUDA
		desc.add_options()
			("cuda_dev_query", "Query CUDA devices")
			("cuda_enable", po::bool_switch(&parameters.cuda_enabled), "Enable CUDA")
			;
#else
		all.add_options()
			("cuda_dev_query", "Query CUDA devices")
			("cuda_enable", po::bool_switch(&parameters.cuda_enabled), "Enable CUDA")
			;
#endif

		all.add(desc);

		// Parse program options
		po::variables_map vm;
		po::store(po::parse_command_line(argc, argv, all), vm);
		{
			std::ifstream ifs("md5birthdaysearch.cfg");
			if (ifs) po::store(po::parse_config_file(ifs, all), vm);
		}
		po::notify(vm);

		// Process program options
		if (vm.count("help")) {
			cout << desc << endl;
			return 0;
		}
		if (parameters.distribution) {
			determine_nrblocks_distribution(parameters);
			return 0;
		}

		if (parameters.modi >= parameters.modn) {
			cerr << "Error: i must be strictly less than m!" << endl;
			return 1;
		}
		if (parameters.modn != 1)
			cout << "System " << parameters.modi << " of " << parameters.modn << endl;
		if (parameters.inputfile1.size() == 0)
		{
			cerr << "Error: inputfile1 must be given!" << endl;
			return 2;
		}
		if (parameters.inputfile2.size() == 0)
		{
			cerr << "Error: inputfile2 must be given!" << endl;
			return 2;
		}
		if (parameters.logpathlength < 0 && parameters.maxmemory == 0)
		{
			cerr << "Cannot determine logtraillength when maxmemory is unspecified!" << endl;
			return 3;
		}
		if (parameters.modi == 0)
		{
			if (parameters.outputfile1.size() == 0)
			{
				cerr << "Error: outputfile1 must be given!" << endl;
				return 2;
			}
			if (parameters.outputfile2.size() == 0)
			{
				cerr << "Error: outputfile2 must be given!" << endl;
				return 2;
			}
		}
#ifdef HAVE_CUDA
		if (vm.count("cuda_dev_query")) {
			cuda_device_query();
			return 0;
		}
#endif // CUDA
		result = dostep(parameters);
	} catch (exception& e) {
		cout << "Runtime: " << runtime.time() << endl;
		cerr << "Caught exception!!:" << endl << e.what() << endl;
		throw;
	} catch (...) {
		cout << "Runtime: " << runtime.time() << endl;
		cerr << "Unknown exception caught!!" << endl;
		throw;
	}
	cout << "Runtime: " << runtime.time() << endl;
	return result;
}


text:
// Copyright 2010, François Bleibel, Thomas Moulard, Olivier Stasse,
// JRL, CNRS/AIST.
//

#include <boost/foreach.hpp>

#include "dynamic-graph/debug.h"
#include "dynamic-graph/factory.h"

using namespace std;
using namespace dynamicgraph;

namespace dynamicgraph {
FactoryStorage *FactoryStorage::getInstance() {
  if (instance_ == 0) {
    instance_ = new FactoryStorage;
  }
  return instance_;
}

void FactoryStorage::destroy() {
  delete instance_;
  instance_ = NULL;
}

FactoryStorage::FactoryStorage() : entityMap() {}

FactoryStorage::~FactoryStorage() {
  instance_ = 0;
  dgDEBUGINOUT(25);
}

void FactoryStorage::registerEntity(const std::string &entname,
                                    FactoryStorage::EntityConstructor_ptr ent) {
  dgDEBUGIN(25);
  if (existEntity(entname)) {
    DG_THROW ExceptionFactory(
        ExceptionFactory::OBJECT_CONFLICT,
        "Another entity class already defined with the same name. ",
        "(while adding entity class <%s> inside the factory).",
        entname.c_str());
    dgERRORF("Another entity class already defined with the same name. "
             "(while adding entity class <%s> inside the factory).",
             entname.c_str());
  } else {
    if (!ent) {
      // FIXME: we should have a better error code for that.
      DG_THROW ExceptionFactory(ExceptionFactory::OBJECT_CONFLICT,
                                "Bad entity constructor.");
    }

    dgDEBUG(30) << "Register entity <" << entname << "> in the factory."
                << std::endl;
    entityMap[entname] = ent;
  }
  dgDEBUGOUT(25);
}

void FactoryStorage::deregisterEntity(const std::string &entname) {
  dgDEBUGIN(25);
  if (!existEntity(entname)) {
    DG_THROW ExceptionFactory(
        ExceptionFactory::OBJECT_CONFLICT, "Entity class not defined yet. ",
        "(while removing entity class <%s>).", entname.c_str());
    dgERRORF(ExceptionFactory::OBJECT_CONFLICT,
             "Entity class not defined yet. "
             "(while removing entity class <%s>).",
             entname.c_str());
  } else {
    dgDEBUG(30) << "Deregister entity <" << entname << "> from the factory."
                << std::endl;
    entityMap.erase(entname);
  }
  dgDEBUGOUT(25);
}

Entity *FactoryStorage::newEntity(const std::string &classname,
                                  const std::string &objname) const {
  dgDEBUG(15) << "New <" << classname << ">Entity <" << objname << ">"
              << std::endl;

  EntityMap::const_iterator entPtr = entityMap.find(classname);
  if (entPtr == entityMap.end()) {
    DG_THROW ExceptionFactory(
        ExceptionFactory::UNREFERED_OBJECT, "Unknown entity.",
        " (while calling new_entity <%s>)", classname.c_str());
  }
  return entPtr->second(objname);
}

// This checks efficiently if a key exists in an STL map using the
// approach suggested by Scott Meyer's Effective STL (item 24).
bool FactoryStorage::existEntity(const std::string &name) const {
  EntityMap::const_iterator lb = entityMap.lower_bound(name);
  return lb != entityMap.end() && !(entityMap.key_comp()(name, lb->first));
}

// FIXME: this should be removed at some point.
void FactoryStorage::listEntities(std::vector<std::string> &outList) const {
  typedef std::pair<std::string, EntityConstructor_ptr> iter_t;
  BOOST_FOREACH (const iter_t &entity, entityMap)
    outList.push_back(entity.first);
}

EntityRegisterer::EntityRegisterer(const std::string &entityClassName,
                                   FactoryStorage::EntityConstructor_ptr maker)
    : entityName(entityClassName) {
  dgDEBUGIN(15);
  FactoryStorage::getInstance()->registerEntity(entityClassName, maker);
  dgDEBUGOUT(15);
}

EntityRegisterer::~EntityRegisterer() {
  dgDEBUGIN(15);
  FactoryStorage::getInstance()->deregisterEntity(entityName);
  dgDEBUGOUT(15);
}

// The global factory.
FactoryStorage *FactoryStorage::instance_ = NULL;
} // end of namespace dynamicgraph.

max_stars_repo_name: Rascof/dynamic-graph

max_issues_repo_name: Rascof/dynamic-graph

max_forks_repo_name: Rascof/dynamic-graph