<commit_before>// Copyright 2012-2013 Samplecount S.L.
//
// 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 "Methcla/Audio/Engine.hpp"
#include "Methcla/Audio/Group.hpp"

using namespace Methcla::Audio;

#define METHCLA_ASSERT_NODE_IS_BLANK(node) \
    BOOST_ASSERT(node != nullptr); \
    BOOST_ASSERT(node->m_parent == nullptr); \
    BOOST_ASSERT(node->m_prev == nullptr); \
    BOOST_ASSERT(node->m_next == nullptr); \

#define METHCLA_ASSERT_NODE_IS_LINKED(node) \
    BOOST_ASSERT(m_first != nullptr); \
    BOOST_ASSERT(m_last != nullptr); \
    BOOST_ASSERT(node->m_prev != nullptr || node == m_first); \
    BOOST_ASSERT(node->m_next != nullptr || node == m_last); \
    BOOST_ASSERT(m_first != m_last || (m_first == node && node == m_last));

Group::Group(Environment& env, NodeId nodeId)
    : Node(env, nodeId)
    , m_first(nullptr)
    , m_last(nullptr)
{
}

Group::~Group()
{
    freeAll();
}

Group* Group::construct(Environment& env, NodeId nodeId)
{
    return new (env.rtMem().alloc(sizeof(Group))) Group(env, nodeId);
}

void Group::doProcess(size_t numFrames)
{
    Node* node = m_first;
    while (node != nullptr) {
        // Store pointer to next node because current node might be destroyed by done action after process.
        Node* nextNode = node->m_next;
        node->process(numFrames);
        node = nextNode;
    }
}

void Group::addToHead(Node* node)
{
    assert(node != nullptr);
    assert(node->parent() == nullptr);
    assert(node->m_prev == nullptr);
    assert(node->m_next == nullptr);

    node->m_parent = this;
    node->m_next = m_first;

    if (m_first != nullptr) {
        m_first->m_prev = node;
    }

    m_first = node;

    if (m_last == nullptr) {
        m_last = node;
    }
}

void Group::addToTail(Node* node)
{
    assert(node != nullptr);
    assert(node->parent() == nullptr);
    assert(node->m_prev == nullptr);
    assert(node->m_next == nullptr);

    node->m_parent = this;
    node->m_prev = m_last;

    if (m_last != nullptr) {
        m_last->m_next = node;
    }

    m_last = node;

    if (m_first == nullptr) {
        m_first = node;
    }
}

void Group::addBefore(Node* target, Node* node)
{
    BOOST_ASSERT(target != nullptr);
    BOOST_ASSERT(target->parent() == this);
    METHCLA_ASSERT_NODE_IS_BLANK(node);

    node->m_parent = this;
    node->m_prev = target->m_prev;
    target->m_prev = node;
    node->m_next = target;

    if (target == m_first) {
        BOOST_ASSERT(node->m_prev == nullptr);
        m_first = node;
    } else {
        BOOST_ASSERT(node->m_prev != nullptr);
        node->m_prev->m_next = node;
    }

    METHCLA_ASSERT_NODE_IS_LINKED(node);
}

void Group::addAfter(Node* target, Node* node)
{
    BOOST_ASSERT(target != nullptr);
    BOOST_ASSERT(target->parent() == this);
    METHCLA_ASSERT_NODE_IS_BLANK(node);

    node->m_parent = this;
    node->m_next = target->m_next;
    target->m_next = node;
    node->m_prev = target;

    if (target == m_last) {
        BOOST_ASSERT(node->m_next == nullptr);
        m_last = node;
    } else {
        BOOST_ASSERT(node->m_next != nullptr);
        node->m_next->m_prev = node;
    }

    METHCLA_ASSERT_NODE_IS_LINKED(node);
}

void Group::remove(Node* node)
{
    assert(node != nullptr);
    assert(node->parent() == this);
    assert(   (node == m_first && node == m_last && node->m_prev == nullptr && node->m_next == nullptr)
           || !((node->m_prev == nullptr) && (node->m_next == nullptr)) );

    Node* prev = node->m_prev;
    Node* next = node->m_next;

    if (node == m_first)
    {
        assert( prev == nullptr );
        m_first = next;
        if (m_first != nullptr)
            m_first->m_prev = nullptr;
    }
    else
    {
        prev->m_next = next;
    }

    if (node == m_last)
    {
        assert( next == nullptr );
        m_last = prev;
        if (m_last != nullptr)
            m_last->m_next = nullptr;
    }
    else
    {
        next->m_prev = prev;
    }

    node->m_parent = nullptr;
    node->m_prev = nullptr;
    node->m_next = nullptr;
}

bool Group::isEmpty() const
{
    return m_first == nullptr;
}

void Group::freeAll()
{
    Node* node = m_first;
    while (node != nullptr) {
        // Store pointer to next node because current node might be destroyed by done action after process.
        Node* nextNode = node->m_next;
        node->free();
        node = nextNode;
    }
}
<commit_msg>Use BOOST_ASSERT instead of assert<commit_after>// Copyright 2012-2013 Samplecount S.L.
//
// 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 "Methcla/Audio/Engine.hpp"
#include "Methcla/Audio/Group.hpp"

using namespace Methcla::Audio;

#define METHCLA_ASSERT_NODE_IS_BLANK(node) \
    BOOST_ASSERT(node != nullptr); \
    BOOST_ASSERT(node->m_parent == nullptr); \
    BOOST_ASSERT(node->m_prev == nullptr); \
    BOOST_ASSERT(node->m_next == nullptr); \

#define METHCLA_ASSERT_NODE_IS_LINKED(node) \
    BOOST_ASSERT(m_first != nullptr); \
    BOOST_ASSERT(m_last != nullptr); \
    BOOST_ASSERT(node->m_prev != nullptr || node == m_first); \
    BOOST_ASSERT(node->m_next != nullptr || node == m_last); \
    BOOST_ASSERT(m_first != m_last || (m_first == node && node == m_last));

Group::Group(Environment& env, NodeId nodeId)
    : Node(env, nodeId)
    , m_first(nullptr)
    , m_last(nullptr)
{
}

Group::~Group()
{
    freeAll();
}

Group* Group::construct(Environment& env, NodeId nodeId)
{
    return new (env.rtMem().alloc(sizeof(Group))) Group(env, nodeId);
}

void Group::doProcess(size_t numFrames)
{
    Node* node = m_first;
    while (node != nullptr) {
        // Store pointer to next node because current node might be destroyed by done action after process.
        Node* nextNode = node->m_next;
        node->process(numFrames);
        node = nextNode;
    }
}

void Group::addToHead(Node* node)
{
    METHCLA_ASSERT_NODE_IS_BLANK(node);

    node->m_parent = this;
    node->m_next = m_first;

    if (m_first != nullptr) {
        m_first->m_prev = node;
    }

    m_first = node;

    if (m_last == nullptr) {
        m_last = node;
    }

    METHCLA_ASSERT_NODE_IS_LINKED(node);
}

void Group::addToTail(Node* node)
{
    METHCLA_ASSERT_NODE_IS_BLANK(node);

    node->m_parent = this;
    node->m_prev = m_last;

    if (m_last != nullptr) {
        m_last->m_next = node;
    }

    m_last = node;

    if (m_first == nullptr) {
        m_first = node;
    }

    METHCLA_ASSERT_NODE_IS_LINKED(node);
}

void Group::addBefore(Node* target, Node* node)
{
    BOOST_ASSERT(target != nullptr);
    BOOST_ASSERT(target->parent() == this);
    METHCLA_ASSERT_NODE_IS_BLANK(node);

    node->m_parent = this;
    node->m_prev = target->m_prev;
    target->m_prev = node;
    node->m_next = target;

    if (target == m_first) {
        BOOST_ASSERT(node->m_prev == nullptr);
        m_first = node;
    } else {
        BOOST_ASSERT(node->m_prev != nullptr);
        node->m_prev->m_next = node;
    }

    METHCLA_ASSERT_NODE_IS_LINKED(node);
}

void Group::addAfter(Node* target, Node* node)
{
    BOOST_ASSERT(target != nullptr);
    BOOST_ASSERT(target->parent() == this);
    METHCLA_ASSERT_NODE_IS_BLANK(node);

    node->m_parent = this;
    node->m_next = target->m_next;
    target->m_next = node;
    node->m_prev = target;

    if (target == m_last) {
        BOOST_ASSERT(node->m_next == nullptr);
        m_last = node;
    } else {
        BOOST_ASSERT(node->m_next != nullptr);
        node->m_next->m_prev = node;
    }

    METHCLA_ASSERT_NODE_IS_LINKED(node);
}

void Group::remove(Node* node)
{
    BOOST_ASSERT(node != nullptr);
    BOOST_ASSERT(node->parent() == this);
    BOOST_ASSERT(   (node == m_first && node == m_last && node->m_prev == nullptr && node->m_next == nullptr)
                || !((node->m_prev == nullptr) && (node->m_next == nullptr)) );

    if (node == m_first) {
        BOOST_ASSERT(node->m_prev == nullptr);
        m_first = node->m_next;
        if (m_first != nullptr) {
            m_first->m_prev = nullptr;
        }
    } else {
        node->m_prev->m_next = node->m_next;
    }

    if (node == m_last) {
        BOOST_ASSERT(node->m_next == nullptr);
        m_last = node->m_prev;
        if (m_last != nullptr) {
            m_last->m_next = nullptr;
        }
    } else {
        node->m_next->m_prev = node->m_prev;
    }

    node->m_parent = nullptr;
    node->m_prev = nullptr;
    node->m_next = nullptr;
}

bool Group::isEmpty() const
{
    return m_first == nullptr;
}

void Group::freeAll()
{
    Node* node = m_first;
    while (node != nullptr) {
        // Store pointer to next node because current node might be destroyed by done action after process.
        Node* nextNode = node->m_next;
        node->free();
        node = nextNode;
    }
}
<|endoftext|>


<commit_before>#include <libdariadb/storage/memstorage.h>
#include <memory>
#include <unordered_map>
#include <stx/btree_map.h>
using namespace dariadb;
using namespace dariadb::storage;
/**
Map:
  id ->
       hash:
           step-> Chunk{from,to,step,data_array}
*/

struct MemChunk {
    Time from;
    Time to;
    Time step;
    MeasArray values;
};
using MemChunk_Ptr = std::shared_ptr<MemChunk>;
using Step2Chunk = std::unordered_map<Time, MemChunk_Ptr>;
using Id2Step = stx::btree_map<Id, Step2Chunk>;

struct MemStorage::Private : public IMeasStorage {
  Private(const MemStorage::Params &p) {}

  virtual Time minTime() override { return Time(); }
  virtual Time maxTime() override { return Time(); }
  virtual bool minMaxTime(dariadb::Id id, dariadb::Time *minResult,
                          dariadb::Time *maxResult) override {
    return false;
  }
  virtual void foreach (const QueryInterval &q, IReaderClb * clbk) override {}
  virtual Id2Meas readTimePoint(const QueryTimePoint &q) override { return Id2Meas(); }
  virtual Id2Meas currentValue(const IdArray &ids, const Flag &flag) override {
    return Id2Meas();
  }
  append_result append(const MeasArray & values) {
      return append_result();
  }
  append_result append(const Meas &value) override{
      return append_result();
  }
  void flush() override{

  }

  void foreach(const QueryTimePoint &q, IReaderClb *clbk) override{

  }
  MeasList readInterval(const QueryInterval &q) override{
      return MeasList{};
  }

  Id2Step _id2steps;
};

MemStorage::MemStorage(const MemStorage::Params &p) : _impl(new MemStorage::Private(p)) {}

MemStorage::~MemStorage() {
  _impl = nullptr;
}

Time dariadb::storage::MemStorage::minTime() {
    return _impl->minTime();
}

Time dariadb::storage::MemStorage::maxTime() {
    return _impl->maxTime();
}

bool dariadb::storage::MemStorage::minMaxTime(dariadb::Id id, dariadb::Time *minResult,
                                            dariadb::Time *maxResult) {
  return _impl->minMaxTime(id,minResult, maxResult);
}

void dariadb::storage::MemStorage::foreach (const QueryInterval &q, IReaderClb * clbk) {
    _impl->foreach(q, clbk);
}

Id2Meas dariadb::storage::MemStorage::readTimePoint(const QueryTimePoint &q) {
    return _impl->readTimePoint(q);
}

Id2Meas dariadb::storage::MemStorage::currentValue(const IdArray &ids, const Flag &flag) {
    return _impl->currentValue(ids, flag);
}

append_result dariadb::storage::MemStorage::append(const Meas &value){
    return _impl->append(value);
}

void dariadb::storage::MemStorage::flush(){
    _impl->flush();
}
<commit_msg>time track.<commit_after>#include <libdariadb/storage/memstorage.h>
#include <memory>
#include <unordered_map>
#include <stx/btree_map.h>
using namespace dariadb;
using namespace dariadb::storage;

/**
Map:
  QueryId -> TimeTrack{ from,to,step MemChunkList[MemChunk{data}]}
*/

struct MemChunk {
    static const size_t MAX_MEM_CHUNK_SIZE = 512;
    std::array<Meas, MAX_MEM_CHUNK_SIZE> values;
};

using MemChunk_Ptr = std::shared_ptr<MemChunk>;
using MemChunkList = std::list<MemChunk_Ptr>;

struct TimeTrack {
    TimeTrack(const Time _step, const Id _meas_id, const Time _from, const Time _to) {
        step = _step;
        meas_id = _meas_id;
        from = _from;
        to = _to;
    }

    Id   meas_id;
    Time step;
    Time from;
    Time to;
    MemChunkList chunks;
};

using TimeTrack_ptr = std::shared_ptr<TimeTrack>;
using Id2Track = stx::btree_map<Id, TimeTrack_ptr>;

struct MemStorage::Private : public IMeasStorage {
  Private(const MemStorage::Params &p) {}

  virtual Time minTime() override { return Time(); }
  virtual Time maxTime() override { return Time(); }
  virtual bool minMaxTime(dariadb::Id id, dariadb::Time *minResult,
                          dariadb::Time *maxResult) override {
    return false;
  }
  virtual void foreach (const QueryInterval &q, IReaderClb * clbk) override {}
  virtual Id2Meas readTimePoint(const QueryTimePoint &q) override { return Id2Meas(); }
  virtual Id2Meas currentValue(const IdArray &ids, const Flag &flag) override {
    return Id2Meas();
  }
  append_result append(const MeasArray & values) {
      return append_result();
  }
  append_result append(const Meas &value) override{
      return append_result();
  }
  void flush() override{

  }

  void foreach(const QueryTimePoint &q, IReaderClb *clbk) override{

  }
  MeasList readInterval(const QueryInterval &q) override{
      return MeasList{};
  }

  Id2Track _id2steps;
};

MemStorage::MemStorage(const MemStorage::Params &p) : _impl(new MemStorage::Private(p)) {}

MemStorage::~MemStorage() {
  _impl = nullptr;
}

Time dariadb::storage::MemStorage::minTime() {
    return _impl->minTime();
}

Time dariadb::storage::MemStorage::maxTime() {
    return _impl->maxTime();
}

bool dariadb::storage::MemStorage::minMaxTime(dariadb::Id id, dariadb::Time *minResult,
                                            dariadb::Time *maxResult) {
  return _impl->minMaxTime(id,minResult, maxResult);
}

void dariadb::storage::MemStorage::foreach (const QueryInterval &q, IReaderClb * clbk) {
    _impl->foreach(q, clbk);
}

Id2Meas dariadb::storage::MemStorage::readTimePoint(const QueryTimePoint &q) {
    return _impl->readTimePoint(q);
}

Id2Meas dariadb::storage::MemStorage::currentValue(const IdArray &ids, const Flag &flag) {
    return _impl->currentValue(ids, flag);
}

append_result dariadb::storage::MemStorage::append(const Meas &value){
    return _impl->append(value);
}

void dariadb::storage::MemStorage::flush(){
    _impl->flush();
}
<|endoftext|>


<commit_before>#include "ipdb.h"
#include <cstdio>
#include <cstring>
#include <endian.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdexcept>

IPDB::IPDB(const char* filename)
{
  fd_ = open(filename, O_RDWR);
  if (fd_<0) {
    throw std::runtime_error(strerror(errno));
  }
  struct stat buf;
  bzero(&buf, sizeof(buf));
  if (fstat(fd_, &buf)<0) {
    close(fd_);
    throw std::runtime_error(strerror(errno));
  }
  size_ = buf.st_size;
  m_ = mmap(0, size_, PROT_READ|PROT_WRITE, MAP_SHARED, fd_, 0);
  if (!m_) {
    close(fd_);
    throw std::runtime_error(strerror(errno));
  }
  offset_ = be32toh(*(uint32_t*)m_);
}

IPDB::~IPDB()
{
  if (m_&&munmap(m_, size_)<0) {
    perror("munmap");
  };
  if (fd_>=0&&close(fd_)<0) {
    perror("close");
  }
}

std::string IPDB::Find(const std::string& ip) const
{
  uint32_t nip = IP2Long(ip);
  const char* index = (char*)m_ + 4;
  uint32_t start = le32toh(*(uint32_t*)(index + (nip >> 24)*4));
  const uint32_t* q = (uint32_t*)(index + 1024) + start*2;
  const uint32_t* limit = (uint32_t*)((char*)m_ + offset_ - 1024);
  for (; q<limit; q+=2) {
    if (be32toh(*q) >= nip) {
      uint32_t t = le32toh(*(q + 1));
      uint32_t d_offset = t & 0x00FFFFFF;
      uint8_t d_len = t >> 24;
      const char* r = (char*)m_ + offset_ + d_offset - 1024;
      return std::string(r, d_len);
    }
  }
  throw std::runtime_error("invalid ip");
}

uint32_t IPDB::IP2Long(const std::string& ip) const
{
  uint32_t nip = 0;
  size_t prev = -1;
  for (int i=0; i<4; i++) {
    size_t pos = ip.find(".", prev+1);
    if ((pos==-1&&i<3) || (pos!=-1&&i==3)) {
      throw std::runtime_error("invalid ip");
    }
    pos = pos!=-1?pos:ip.length();
    int x = stoi(ip.substr(prev+1, pos-prev-1));
    if ((x&~0xFF)!=0) {
      throw std::runtime_error("invalid ip");
    }
    nip <<= 8;
    nip |= x & 0xFF;
    prev = pos;
  }
  return nip;
}
<commit_msg>remove c++11 function<commit_after>#include "ipdb.h"
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <endian.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdexcept>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

IPDB::IPDB(const char* filename)
{
  fd_ = open(filename, O_RDWR);
  if (fd_<0) {
    throw std::runtime_error(strerror(errno));
  }
  struct stat buf;
  bzero(&buf, sizeof(buf));
  if (fstat(fd_, &buf)<0) {
    close(fd_);
    throw std::runtime_error(strerror(errno));
  }
  size_ = buf.st_size;
  m_ = mmap(0, size_, PROT_READ|PROT_WRITE, MAP_SHARED, fd_, 0);
  if (!m_) {
    close(fd_);
    throw std::runtime_error(strerror(errno));
  }
  offset_ = be32toh(*(uint32_t*)m_);
}

IPDB::~IPDB()
{
  if (m_&&munmap(m_, size_)<0) {
    perror("munmap");
  };
  if (fd_>=0&&close(fd_)<0) {
    perror("close");
  }
}

std::string IPDB::Find(const std::string& ip) const
{
  uint32_t nip = IP2Long(ip);
  const char* index = (char*)m_ + 4;
  uint32_t start = le32toh(*(uint32_t*)(index + (nip >> 24)*4));
  const uint32_t* q = (uint32_t*)(index + 1024) + start*2;
  const uint32_t* limit = (uint32_t*)((char*)m_ + offset_ - 1024);
  for (; q<limit; q+=2) {
    if (be32toh(*q) >= nip) {
      uint32_t t = le32toh(*(q + 1));
      uint32_t d_offset = t & 0x00FFFFFF;
      uint8_t d_len = t >> 24;
      const char* r = (char*)m_ + offset_ + d_offset - 1024;
      return std::string(r, d_len);
    }
  }
  throw std::runtime_error("invalid ip");
}

uint32_t IPDB::IP2Long(const std::string& ip) const
{
  uint32_t nip = 0;
  size_t prev = -1;
  for (int i=0; i<4; i++) {
    size_t pos = ip.find(".", prev+1);
    if ((pos==-1&&i<3) || (pos!=-1&&i==3)) {
      throw std::runtime_error("invalid ip");
    }
    pos = pos!=-1?pos:ip.length();
    int x = atoi(ip.substr(prev+1, pos-prev-1).c_str());
    if ((x&~0xFF)!=0) {
      throw std::runtime_error("invalid ip");
    }
    nip <<= 8;
    nip |= x & 0xFF;
    prev = pos;
  }
  return nip;
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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.
#include <iostream>
#include <Common/Colorful.hh>
#include <GC/MarkSweep.hh>

namespace Tadpole::GC {

MarkSweep::MarkSweep() noexcept {
}

MarkSweep::~MarkSweep() {
  while (!objects_.empty()) {
    auto* o = objects_.back();
    objects_.pop_back();

    reclaim_object(o);
  }
}

void MarkSweep::collect() {
  mark_from_roots();
  sweep();

  gc_threshold_ = std::max(std::min(gc_threshold_, kGCThresholdMin), objects_.size() * kGCFactor);
  gc_threshold_ = Common::as_align(gc_threshold_, kGCAlign);
}

void MarkSweep::append_object(Object::BaseObject* o) {
  if (objects_.size() >= gc_threshold_)
    collect();
  objects_.push_back(o);
}

void MarkSweep::mark_object(Object::BaseObject* o) {
  if (o == nullptr || o->is_marked())
    return;

#if defined(_TADPOLE_DEBUG_GC)
  std::cout
    << Common::Colorful::fg::lightcyan
    << "[" << o << "] mark object: `" << o->stringify() << "`"
    << Common::Colorful::reset
    << std::endl;
#endif

  o->set_marked(true);
  worklist_.push_back(o);
}

sz_t MarkSweep::get_count() const {
  return objects_.size();
}

sz_t MarkSweep::get_threshold() const {
  return gc_threshold_;
}

void MarkSweep::set_threshold(sz_t threshold) {
  gc_threshold_ = Common::as_align(threshold, kGCAlign);
}

void MarkSweep::mark() {
  while (!worklist_.empty()) {
    Object::BaseObject* o = worklist_.back();
    worklist_.pop_back();

    o->iter_children([this](Object::BaseObject* child) { mark_object(child); });
  }
}

void MarkSweep::mark_from_roots() {
  for (auto& r : roots_) {
    r.second->iter_objects([this](Object::BaseObject* o) {
          mark_object(o);
          mark();
        });
  }

  for (auto& s : interned_strings_) {
    mark_object(s.second);
    mark();
  }
}

void MarkSweep::sweep() {
  for (auto it = interned_strings_.begin(); it != interned_strings_.end();) {
    if (!it->second->is_marked())
      interned_strings_.erase(it++);
    else
      ++it;
  }

  for (auto it = objects_.begin(); it != objects_.end();) {
    if (!(*it)->is_marked()) {
      reclaim_object(*it);
      objects_.erase(it++);
    }
    else {
      (*it)->set_marked(true);
      ++it;
    }
  }
}

void MarkSweep::reclaim_object(Object::BaseObject* o) {
#if defined(_TADPOLE_DEBUG_GC)
  std::cout
    << Common::Colorful::fg::gray
    << "[" << o << "] reclaim object type: `" << o->type_asstr() << "`"
    << Common::Colorful::reset
    << std::endl;
#endif

  delete o;
}

}
<commit_msg>:construction: chore(gc): updated the implementation of virtual methods<commit_after>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// 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.
#include <iostream>
#include <Common/Colorful.hh>
#include <GC/MarkSweep.hh>

namespace Tadpole::GC {

MarkSweep::MarkSweep() noexcept {
}

MarkSweep::~MarkSweep() {
  while (!objects_.empty()) {
    auto* o = objects_.back();
    objects_.pop_back();

    reclaim_object(o);
  }
}

void MarkSweep::collect() {
  mark_from_roots();
  sweep();

  gc_threshold_ = std::max(std::min(gc_threshold_, kGCThresholdMin), objects_.size() * kGCFactor);
  gc_threshold_ = Common::as_align(gc_threshold_, kGCAlign);
}

void MarkSweep::append_object(Object::BaseObject* o) {
  if (objects_.size() >= gc_threshold_)
    collect();
  objects_.push_back(o);
}

void MarkSweep::mark_object(Object::BaseObject* o) {
  if (o == nullptr || o->is_marked())
    return;

#if defined(_TADPOLE_DEBUG_GC)
  std::cout
    << Common::Colorful::fg::lightcyan
    << "[" << o << "] mark object: `" << o->stringify() << "`"
    << Common::Colorful::reset
    << std::endl;
#endif

  o->set_marked(true);
  worklist_.push_back(o);
}

sz_t MarkSweep::get_count() const {
  return objects_.size();
}

sz_t MarkSweep::get_threshold() const {
  return gc_threshold_;
}

void MarkSweep::set_threshold(sz_t threshold) {
  gc_threshold_ = Common::as_align(threshold, kGCAlign);
}

bool MarkSweep::is_enabled() const { return true; }
void MarkSweep::enable() {}
void MarkSweep::disable() {}

void MarkSweep::mark() {
  while (!worklist_.empty()) {
    Object::BaseObject* o = worklist_.back();
    worklist_.pop_back();

    o->iter_children([this](Object::BaseObject* child) { mark_object(child); });
  }
}

void MarkSweep::mark_from_roots() {
  for (auto& r : roots_) {
    r.second->iter_objects([this](Object::BaseObject* o) {
          mark_object(o);
          mark();
        });
  }

  for (auto& s : interned_strings_) {
    mark_object(s.second);
    mark();
  }
}

void MarkSweep::sweep() {
  for (auto it = interned_strings_.begin(); it != interned_strings_.end();) {
    if (!it->second->is_marked())
      interned_strings_.erase(it++);
    else
      ++it;
  }

  for (auto it = objects_.begin(); it != objects_.end();) {
    if (!(*it)->is_marked()) {
      reclaim_object(*it);
      objects_.erase(it++);
    }
    else {
      (*it)->set_marked(true);
      ++it;
    }
  }
}

void MarkSweep::reclaim_object(Object::BaseObject* o) {
#if defined(_TADPOLE_DEBUG_GC)
  std::cout
    << Common::Colorful::fg::gray
    << "[" << o << "] reclaim object type: `" << o->type_asstr() << "`"
    << Common::Colorful::reset
    << std::endl;
#endif

  delete o;
}

}
<|endoftext|>


<commit_before>// Copyright 2020 DeepMind Technologies Limited.
//
// 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
//
//     https://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 "pybind_utils.h"  // controller

#include <dlfcn.h>

#include <string>

#include "dm_robotics/support/logging.h"
#include "absl/strings/substitute.h"
#include "dm_robotics/mujoco/mjlib.h"
#include "pybind11/pybind11.h"  // pybind

namespace dm_robotics::internal {
namespace {

namespace py = pybind11;

constexpr char kDmControlMjModelClassName[] = "MjModel";
constexpr char kDmControlMjDataClassName[] = "MjData";

// Returns a ctypes module for use through pybind.
py::module GetCtypesModule() {
  static PyObject* const ctypes_module_ptr = []() -> PyObject* {
    py::module ctypes_module = py::module::import("ctypes");
    PyObject* ctypes_module_ptr = ctypes_module.ptr();
    Py_XINCREF(ctypes_module_ptr);
    return ctypes_module_ptr;
  }();
  return py::reinterpret_borrow<py::module>(ctypes_module_ptr);
}

// Returns a pointer to the underlying object pointed to by `ctypes_obj`.
// Note that does not increment the reference count.
template <class T>
T* GetPointer(py::handle ctypes_obj) {
  auto ctypes_module = GetCtypesModule();
  return reinterpret_cast<T*>(
      ctypes_module.attr("addressof")(ctypes_obj.attr("contents"))
          .cast<std::uintptr_t>());
}

// Returns a pointer to a MuJoCo mjModel or mjData from the dm_control wrappers
// around these objects. The dm_control wrappers are such that the `ptr`
// attributes return a ctypes object bound to underlying MuJoCo native type.
//
// Raises a `RuntimeError` exception in Python if the handle does not contain a
// `ptr` attribute.
template <class T>
T* GetMujocoPointerFromDmControlWrapperHandle(py::handle dm_control_wrapper) {
  if (!py::hasattr(dm_control_wrapper, "ptr")) {
    RaiseRuntimeErrorWithMessage(
        "GetMujocoPointerFromDmControlWrapperHandle: handle does not have a "
        "`ptr` attribute. This function assumes that dm_control wrappers "
        "around mjModel and mjData contain a `ptr` attribute with the MuJoCo "
        "native type.");
  }
  return GetPointer<T>(dm_control_wrapper.attr("ptr"));
}

}  // namespace

void RaiseRuntimeErrorWithMessage(absl::string_view message) {
  PyErr_SetString(PyExc_RuntimeError, std::string(message).c_str());
  throw py::error_already_set();
}

const MjLib* LoadMjLibFromDmControl() {
  py::gil_scoped_acquire gil;
  // Get the path to the DSO.
  const py::module mjbindings(
      py::module::import("dm_control.mujoco.wrapper.mjbindings"));
  const std::string dso_path =
      mjbindings.attr("mjlib").attr("_name").cast<std::string>();
  // Create the MjLib object by dlopen'ing the DSO.
  return new MjLib(dso_path, RTLD_NOW);
}

// Helper function for getting an mjModel object from a py::handle.
const mjModel* GetmjModelOrRaise(py::handle obj) {
  const std::string class_name =
      obj.attr("__class__").attr("__name__").cast<std::string>();
  if (class_name != kDmControlMjModelClassName) {
    RaiseRuntimeErrorWithMessage(absl::Substitute(
        "GetmjModelOrRaise: the class name of the argument [$0] does not match "
        "the expected dm_control type name for mjModel [$1].",
        class_name, kDmControlMjModelClassName));
  }
  return GetMujocoPointerFromDmControlWrapperHandle<mjModel>(obj);
}

// Helper function for getting an mjData object from a py::handle.
const mjData* GetmjDataOrRaise(py::handle obj) {
  const std::string class_name =
      obj.attr("__class__").attr("__name__").cast<std::string>();
  if (class_name != kDmControlMjDataClassName) {
    RaiseRuntimeErrorWithMessage(absl::Substitute(
        "GetmjDataOrRaise: the class name of the argument [$0] does not match "
        "the expected dm_control type name for mjData [$1].",
        class_name, kDmControlMjDataClassName));
  }
  return GetMujocoPointerFromDmControlWrapperHandle<mjData>(obj);
}

}  // namespace dm_robotics::internal
<commit_msg>Use new MuJoCo python bindings to implement dm_control/mujoco.<commit_after>// Copyright 2020 DeepMind Technologies Limited.
//
// 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
//
//     https://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 "pybind_utils.h"  // controller

#include <dlfcn.h>

#include <string>

#include "dm_robotics/support/logging.h"
#include "absl/strings/substitute.h"
#include "dm_robotics/mujoco/mjlib.h"
#include "pybind11/pybind11.h"  // pybind

namespace dm_robotics::internal {
namespace {

namespace py = pybind11;

constexpr char kDmControlMjModelClassName[] = "MjModel";
constexpr char kDmControlMjDataClassName[] = "MjData";

// Returns a ctypes module for use through pybind.
py::module GetCtypesModule() {
  static PyObject* const ctypes_module_ptr = []() -> PyObject* {
    py::module ctypes_module = py::module::import("ctypes");
    PyObject* ctypes_module_ptr = ctypes_module.ptr();
    Py_XINCREF(ctypes_module_ptr);
    return ctypes_module_ptr;
  }();
  return py::reinterpret_borrow<py::module>(ctypes_module_ptr);
}

// Returns a pointer to the underlying object pointed to by `ctypes_obj`.
// Note that does not increment the reference count.
template <class T>
T* GetPointer(py::handle mjwrapper_object) {
#ifdef DM_ROBOTICS_USE_NEW_MUJOCO_BINDINGS
  return reinterpret_cast<T*>(
      mjwrapper_object.attr("_address").cast<std::uintptr_t>());
#else
  auto ctypes_module = GetCtypesModule();
  return reinterpret_cast<T*>(
      ctypes_module.attr("addressof")(mjwrapper_object.attr("contents"))
          .cast<std::uintptr_t>());
#endif
}

// Returns a pointer to a MuJoCo mjModel or mjData from the dm_control wrappers
// around these objects. The dm_control wrappers are such that the `ptr`
// attributes return a ctypes object bound to underlying MuJoCo native type.
//
// Raises a `RuntimeError` exception in Python if the handle does not contain a
// `ptr` attribute.
template <class T>
T* GetMujocoPointerFromDmControlWrapperHandle(py::handle dm_control_wrapper) {
  if (!py::hasattr(dm_control_wrapper, "ptr")) {
    RaiseRuntimeErrorWithMessage(
        "GetMujocoPointerFromDmControlWrapperHandle: handle does not have a "
        "`ptr` attribute. This function assumes that dm_control wrappers "
        "around mjModel and mjData contain a `ptr` attribute with the MuJoCo "
        "native type.");
  }
  return GetPointer<T>(dm_control_wrapper.attr("ptr"));
}

}  // namespace

void RaiseRuntimeErrorWithMessage(absl::string_view message) {
  PyErr_SetString(PyExc_RuntimeError, std::string(message).c_str());
  throw py::error_already_set();
}

const MjLib* LoadMjLibFromDmControl() {
  py::gil_scoped_acquire gil;
  // Get the path to the DSO.
  const py::module mjbindings(
      py::module::import("dm_control.mujoco.wrapper.mjbindings"));
  const std::string dso_path =
      mjbindings.attr("mjlib").attr("_name").cast<std::string>();
  // Create the MjLib object by dlopen'ing the DSO.
  return new MjLib(dso_path, RTLD_NOW);
}

// Helper function for getting an mjModel object from a py::handle.
const mjModel* GetmjModelOrRaise(py::handle obj) {
  const std::string class_name =
      obj.attr("__class__").attr("__name__").cast<std::string>();
  if (class_name != kDmControlMjModelClassName) {
    RaiseRuntimeErrorWithMessage(absl::Substitute(
        "GetmjModelOrRaise: the class name of the argument [$0] does not match "
        "the expected dm_control type name for mjModel [$1].",
        class_name, kDmControlMjModelClassName));
  }
  return GetMujocoPointerFromDmControlWrapperHandle<mjModel>(obj);
}

// Helper function for getting an mjData object from a py::handle.
const mjData* GetmjDataOrRaise(py::handle obj) {
  const std::string class_name =
      obj.attr("__class__").attr("__name__").cast<std::string>();
  if (class_name != kDmControlMjDataClassName) {
    RaiseRuntimeErrorWithMessage(absl::Substitute(
        "GetmjDataOrRaise: the class name of the argument [$0] does not match "
        "the expected dm_control type name for mjData [$1].",
        class_name, kDmControlMjDataClassName));
  }
  return GetMujocoPointerFromDmControlWrapperHandle<mjData>(obj);
}

}  // namespace dm_robotics::internal
<|endoftext|>


<commit_before><?hh //strict

namespace HHPack\Codegen\Example;

use HHPack\Codegen\{OutputNamespace, GeneratorName};
use HHPack\Codegen\Contract\{FileGeneratable, GeneratorProvider};
use HHPack\Codegen\HackUnit\{TestClassGenerator};
use HHPack\Codegen\Project\{PackageClassGenerator};
use function HHPack\Codegen\Cli\{define_generator, namespace_of, map_to};

final class Generators implements GeneratorProvider {
  const LIB = 'HHPack\\Codegen\\Example';
  const LIB_TEST = 'HHPack\\Codegen\\Example\\Test';

  public function generators(
  ): Iterator<Pair<GeneratorName, FileGeneratable<string>>> {
    yield define_generator("lib:class", "generate library class file.")
      ->mapTo(
        namespace_of(static::LIB, 'example/src')
          ->map(PackageClassGenerator::class),
      );

    yield define_generator("lib:testclass", "generate test class file.")
      ->mapTo(
        namespace_of(static::LIB_TEST, 'example/test')
          ->map(TestClassGenerator::class),
      );
  }
}
<commit_msg>fix unused types<commit_after><?hh //strict

namespace HHPack\Codegen\Example;

use HHPack\Codegen\{GeneratorName};
use HHPack\Codegen\Contract\{FileGeneratable, GeneratorProvider};
use HHPack\Codegen\HackUnit\{TestClassGenerator};
use HHPack\Codegen\Project\{PackageClassGenerator};
use function HHPack\Codegen\Cli\{define_generator, namespace_of};

final class Generators implements GeneratorProvider {
  const LIB = 'HHPack\\Codegen\\Example';
  const LIB_TEST = 'HHPack\\Codegen\\Example\\Test';

  public function generators(
  ): Iterator<Pair<GeneratorName, FileGeneratable<string>>> {
    yield define_generator("lib:class", "generate library class file.")
      ->mapTo(
        namespace_of(static::LIB, 'example/src')
          ->map(PackageClassGenerator::class),
      );

    yield define_generator("lib:testclass", "generate test class file.")
      ->mapTo(
        namespace_of(static::LIB_TEST, 'example/test')
          ->map(TestClassGenerator::class),
      );
  }
}
<|endoftext|>


<commit_before>/*
 This file is part of SWGANH. For more information, visit http://swganh.com

 Copyright (c) 2006 - 2011 The SWG:ANH Team

 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 2
 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, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "anh/network/soe/session.h"

#include <algorithm>

#include <glog/logging.h>

#include "anh/network/soe/server_interface.h"

#include "anh/network/soe/protocol_opcodes.h"
#include "anh/network/soe/packet_utilities.h"

using namespace anh;
using namespace anh::event_dispatcher;
using namespace anh::network;
using namespace anh::network::soe;
using namespace std;

Session::Session(boost::asio::ip::udp::endpoint remote_endpoint, ServerInterface* server)
    : std::enable_shared_from_this<Session>()
    , remote_endpoint_(remote_endpoint)
    , connected_(false)
    , server_(server)
    , strand_(server->socket()->get_io_service())
    , crc_seed_(0xDEADBABE)
    , server_net_stats_(0, 0, 0, 0, 0, 0)
    , last_acknowledged_sequence_(0)
    , current_client_sequence_(0)
    , next_client_sequence_(0)
    , server_sequence_()
    , outgoing_data_message_(0)
    , incoming_fragmented_total_len_(0)
    , incoming_fragmented_curr_len_(0)
    , decompression_filter_(server_->max_receive_size())
    , security_filter_(server_->max_receive_size())
{
    server_sequence_ = 0;
}

Session::~Session(void)
{
    Close();

    LOG(WARNING) << "Session [" << connection_id_ << "] Closed.";
}

uint16_t Session::server_sequence() const {
    return server_sequence_;
}

uint32_t Session::receive_buffer_size() const {
    return receive_buffer_size_;
}

void Session::receive_buffer_size(uint32_t receive_buffer_size) {
    receive_buffer_size_ = receive_buffer_size;
}

uint32_t Session::crc_length() const {
    return crc_length_;
}

void Session::crc_length(uint32_t crc_length) {
    crc_length_ = crc_length;
}

void Session::crc_seed(uint32_t crc_seed) {
    crc_seed_ = crc_seed;
}

uint32_t Session::crc_seed() const {
    return crc_seed_;
}

void Session::datachannel_handler(DatachannelHandler handler) {
    datachannel_handler_ = make_shared<DatachannelHandler>(handler);
}

vector<shared_ptr<ByteBuffer>> Session::GetUnacknowledgedMessages() const {
    vector<shared_ptr<ByteBuffer>> unacknowledged_messages;

    for_each(
        sent_messages_.begin(),
        sent_messages_.end(),
        [&unacknowledged_messages] (const SequencedMessageMap::value_type& i)
    {
        unacknowledged_messages.push_back(i.second);
    });

    return unacknowledged_messages;
}

void Session::Update() {
    // Exit as quickly as possible if there is no work currently.
    if (!connected_ || outgoing_data_messages_.empty()) {
        return;
    }

    // Build up a list of data messages to process
    uint32_t message_count = outgoing_data_messages_.unsafe_size();
    list<shared_ptr<ByteBuffer>> process_list;
    shared_ptr<ByteBuffer> tmp;

    for (uint32_t i = 0; i < message_count; ++i) {
        if (outgoing_data_messages_.try_pop(tmp)) {
            process_list.push_back(tmp);
        }
    }

    // Pack the message list into a single data channel payload and send it.
    ByteBuffer data_channel_payload = PackDataChannelMessages(process_list);

    // Split up the message if it's too big
    // @note: in determining the max size 3 is the size of the soe header + the compression flag.
    uint32_t max_data_channel_size = receive_buffer_size_ - crc_length_ - 3;

    if (data_channel_payload.size() > max_data_channel_size) {
        list<ByteBuffer> fragmented_message = SplitDataChannelMessage(
            data_channel_payload,
            max_data_channel_size);

        for_each(fragmented_message.begin(), fragmented_message.end(), [this] (ByteBuffer& fragment) {
            SendSequencedMessage_(&BuildFragmentedDataChannelHeader, move(fragment));
        });
    } else {
        SendSequencedMessage_(&BuildDataChannelHeader, move(data_channel_payload));
    }
}

void Session::SendMessage(ByteBuffer message) {
    auto message_buffer = server_->AllocateBuffer();
    message_buffer->swap(message);

    outgoing_data_messages_.push(message_buffer);
}

void Session::Close(void)
{
    if(connected_)
    {
        connected_ = false;

        Disconnect disconnect(connection_id_);
        auto buffer = server_->AllocateBuffer();

        disconnect.serialize(*buffer);
        SendSoePacket_(buffer);

        server_->RemoveSession(shared_from_this());
    }
}

void Session::HandleMessage(const std::shared_ptr<anh::ByteBuffer>& message)
{
    auto session = this->shared_from_this();
    strand_.post([=] ()
    {
        switch(message->peek<uint16_t>(true))
        {
            case CHILD_DATA_A:	   { ChildDataA child_data_a(*message); session->handleChildDataA_(child_data_a); break; }
            case MULTI_PACKET:	   { MultiPacket multi_packet(*message); session->handleMultiPacket_(multi_packet); break; }
            case DATA_FRAG_A:	   { DataFragA data_frag_a(*message); session->handleDataFragA_(data_frag_a); break; }
            case ACK_A:			   { AckA ack_a(*message); session->handleAckA_(ack_a); break; }
            case PING:			   { Ping ping(*message); session->handlePing_(ping); break; }
            case NET_STATS_CLIENT: { NetStatsClient net_stats_client(*message); session->handleNetStatsClient_(net_stats_client); break; }
            case OUT_OF_ORDER_A:   { OutOfOrderA out_of_order_a(*message); session->handleOutOfOrderA_(out_of_order_a); break; }
            case DISCONNECT:	   { Disconnect disconnect(*message); session->handleDisconnect_(disconnect); break; }
            case SESSION_REQUEST:  { SessionRequest session_request(*message); session->handleSessionRequest_(session_request); break; }
            case FATAL_ERROR:      { session->Close(); break; }
            default:
                if (message->peek<uint8_t>() != 0)
                {
                    server_->HandleMessage(session, message);
                }
                else
                {
                    LOG(WARNING) << "Unhandled SOE Opcode: " << std::hex << message->peek<uint16_t>(true)
                        << "\n\n" << message;
                }
        }
    });
}

void Session::HandleProtocolMessage(const std::shared_ptr<anh::ByteBuffer>& message)
{
    auto session = this->shared_from_this();
    strand_.post([=] ()
    {
        security_filter_(session, message);

        if (connected())
        {
            crc_input_filter_(session, message);
            decryption_filter_(session, message);
            decompression_filter_(session, message);
        }

        HandleMessage(message);
    });
}

void Session::SendSequencedMessage_(HeaderBuilder header_builder, ByteBuffer message) {
    // Get the next sequence number
    uint16_t message_sequence = server_sequence_++;

    // Allocate a new packet
    auto data_channel_message = server_->AllocateBuffer();
    data_channel_message->append(header_builder(message_sequence));
    data_channel_message->append(message);

    // Send it over the wire
    SendSoePacket_(data_channel_message);

    // Store it for resending later if necessary
    sent_messages_.push_back(make_pair(message_sequence, data_channel_message));

    // If the data channel message is too big
    uint32_t max_data_channel_size = receive_buffer_size_ - crc_length_ - 5;
}

void Session::handleSessionRequest_(SessionRequest& packet)
{
    connection_id_ = packet.connection_id;
    crc_length_ = packet.crc_length;
    receive_buffer_size_ = packet.client_udp_buffer_size;

    SessionResponse session_response(connection_id_, crc_seed_);
    session_response.server_udp_buffer_size = server_->max_receive_size();

    auto buffer = server_->AllocateBuffer();
    session_response.serialize(*buffer);

    // Directly put this on the wire, it requires no outgoing processing.
    server_->SendTo(remote_endpoint_, buffer);

    connected_ = true;
    LOG(INFO) << "Created Session [" << connection_id_ << "] @ " << remote_endpoint_.address().to_string() << ":" << remote_endpoint_.port();
}

void Session::handleMultiPacket_(MultiPacket& packet)
{
    VLOG(3) << "Handling MULTIPACKET";
    std::for_each(packet.packets.begin(), packet.packets.end(), [=](anh::ByteBuffer& buffer) {
        HandleMessage(make_shared<ByteBuffer>(buffer));
    });
}

void Session::handleDisconnect_(Disconnect& packet)
{
    VLOG(3) << "Handling DISCONNECT";
    Close();
}

void Session::handlePing_(Ping& packet)
{
    VLOG(3) << "Handling PING";
    Ping pong;

    auto buffer = server_->AllocateBuffer();
    pong.serialize(*buffer);

    SendSoePacket_(buffer);
}

void Session::handleNetStatsClient_(NetStatsClient& packet)
{
    VLOG(3) << "Handling NET_STATS_CLIENT";
    server_net_stats_.client_tick_count = packet.client_tick_count;

    auto buffer = server_->AllocateBuffer();
    server_net_stats_.serialize(*buffer);
    SendSoePacket_(buffer);
}

void Session::handleChildDataA_(ChildDataA& packet)
{
    VLOG(3) << "Handling CHILD_DATA_A";
    if(!SequenceIsValid_(packet.sequence)) {
        DLOG(WARNING) << "Invalid sequence: " << packet.sequence << "; Current sequence " << this->next_client_sequence_;
        return;
    }

    AcknowledgeSequence_(packet.sequence);

    std::for_each(packet.messages.begin(), packet.messages.end(), [this] (shared_ptr<ByteBuffer> message) {
        server_->HandleMessage(this->shared_from_this(), message);
    });
}

void Session::handleDataFragA_(DataFragA& packet)
{
    VLOG(3) << "Handling DATA_FRAG_A";
    if(!SequenceIsValid_(packet.sequence))
        return;

    AcknowledgeSequence_(packet.sequence);

    // Continuing a frag
    if(incoming_fragmented_total_len_ > 0)
    {
        incoming_fragmented_curr_len_ += packet.data.size();
        incoming_fragmented_messages_.push_back(packet.data);

        if(incoming_fragmented_total_len_ == incoming_fragmented_curr_len_)
        {
            // Send to translator.
            incoming_fragmented_total_len_ = 0;
            incoming_fragmented_curr_len_ = 0;

            ByteBuffer full_packet;
            std::for_each(
                incoming_fragmented_messages_.cbegin(),
                incoming_fragmented_messages_.cend(),
                [&full_packet] (const ByteBuffer& buffer) {
                    full_packet.append(buffer);
                }
            );

            ChildDataA child_data_a(full_packet);
            handleChildDataA_(child_data_a);

            incoming_fragmented_messages_.clear();
        }
    }
    // Starting a new frag
    else
    {
        incoming_fragmented_total_len_ = packet.data.read<uint16_t>();
        incoming_fragmented_curr_len_ += packet.data.size();
        incoming_fragmented_messages_.push_back(anh::ByteBuffer(packet.data.data()+2, packet.data.size()-2));
    }

}

void Session::handleAckA_(AckA& packet)
{
    VLOG(3) << "Handle ACK_A";

    auto it = find_if(
        sent_messages_.begin(),
        sent_messages_.end(),
        [this, &packet] (const SequencedMessageMap::value_type& message)
    {
        return (message.first == packet.sequence) ? true : false;
    });

    sent_messages_.erase(sent_messages_.begin(), it);

    last_acknowledged_sequence_ = packet.sequence;
}

void Session::handleOutOfOrderA_(OutOfOrderA& packet)
{
    VLOG(3) << "Handle OUT_OF_ORDER_A";

    std::for_each(sent_messages_.begin(), sent_messages_.end(), [=](SequencedMessageMap::value_type& item) {
        SendSoePacket_(item.second);
    });
}

void Session::SendSoePacket_(const std::shared_ptr<anh::ByteBuffer>& message)
{
    auto session = this->shared_from_this();

    strand_.post([=] ()
    {
        compression_filter_(session, message);
        encryption_filter_(session, message);
        crc_output_filter_(session, message);

        server_->SendTo(session->remote_endpoint(), message);
    });
}

bool Session::SequenceIsValid_(const uint16_t& sequence)
{
    if(next_client_sequence_ == sequence)
    {
        return true;
    }
    else
    {
        // Tell the client we have received an Out of Order sequence.
        OutOfOrderA	out_of_order(sequence);
        auto buffer = server_->AllocateBuffer();
        out_of_order.serialize(*buffer);
        SendSoePacket_(buffer);

        return false;
    }
}

void Session::AcknowledgeSequence_(const uint16_t& sequence)
{
    AckA ack(sequence);
    auto buffer = server_->AllocateBuffer();
    ack.serialize(*buffer);
    SendSoePacket_(buffer);

    next_client_sequence_ = sequence + 1;
    current_client_sequence_ = sequence;
}
<commit_msg>Fixed an issue with object lifetime<commit_after>/*
 This file is part of SWGANH. For more information, visit http://swganh.com

 Copyright (c) 2006 - 2011 The SWG:ANH Team

 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 2
 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, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include "anh/network/soe/session.h"

#include <algorithm>

#include <glog/logging.h>

#include "anh/network/soe/server_interface.h"

#include "anh/network/soe/protocol_opcodes.h"
#include "anh/network/soe/packet_utilities.h"

using namespace anh;
using namespace anh::event_dispatcher;
using namespace anh::network;
using namespace anh::network::soe;
using namespace std;

Session::Session(boost::asio::ip::udp::endpoint remote_endpoint, ServerInterface* server)
    : std::enable_shared_from_this<Session>()
    , remote_endpoint_(remote_endpoint)
    , connected_(false)
    , server_(server)
    , strand_(server->socket()->get_io_service())
    , crc_seed_(0xDEADBABE)
    , server_net_stats_(0, 0, 0, 0, 0, 0)
    , last_acknowledged_sequence_(0)
    , current_client_sequence_(0)
    , next_client_sequence_(0)
    , server_sequence_()
    , outgoing_data_message_(0)
    , incoming_fragmented_total_len_(0)
    , incoming_fragmented_curr_len_(0)
    , decompression_filter_(server_->max_receive_size())
    , security_filter_(server_->max_receive_size())
{
    server_sequence_ = 0;
}

Session::~Session(void)
{
    Close();

    LOG(WARNING) << "Session [" << connection_id_ << "] Closed.";
}

uint16_t Session::server_sequence() const {
    return server_sequence_;
}

uint32_t Session::receive_buffer_size() const {
    return receive_buffer_size_;
}

void Session::receive_buffer_size(uint32_t receive_buffer_size) {
    receive_buffer_size_ = receive_buffer_size;
}

uint32_t Session::crc_length() const {
    return crc_length_;
}

void Session::crc_length(uint32_t crc_length) {
    crc_length_ = crc_length;
}

void Session::crc_seed(uint32_t crc_seed) {
    crc_seed_ = crc_seed;
}

uint32_t Session::crc_seed() const {
    return crc_seed_;
}

void Session::datachannel_handler(DatachannelHandler handler) {
    datachannel_handler_ = make_shared<DatachannelHandler>(handler);
}

vector<shared_ptr<ByteBuffer>> Session::GetUnacknowledgedMessages() const {
    vector<shared_ptr<ByteBuffer>> unacknowledged_messages;

    for_each(
        sent_messages_.begin(),
        sent_messages_.end(),
        [&unacknowledged_messages] (const SequencedMessageMap::value_type& i)
    {
        unacknowledged_messages.push_back(i.second);
    });

    return unacknowledged_messages;
}

void Session::Update() {
    // Exit as quickly as possible if there is no work currently.
    if (!connected_ || outgoing_data_messages_.empty()) {
        return;
    }

    // Build up a list of data messages to process
    uint32_t message_count = outgoing_data_messages_.unsafe_size();
    list<shared_ptr<ByteBuffer>> process_list;
    shared_ptr<ByteBuffer> tmp;

    for (uint32_t i = 0; i < message_count; ++i) {
        if (outgoing_data_messages_.try_pop(tmp)) {
            process_list.push_back(tmp);
        }
    }

    // Pack the message list into a single data channel payload and send it.
    ByteBuffer data_channel_payload = PackDataChannelMessages(process_list);

    // Split up the message if it's too big
    // @note: in determining the max size 3 is the size of the soe header + the compression flag.
    uint32_t max_data_channel_size = receive_buffer_size_ - crc_length_ - 3;

    if (data_channel_payload.size() > max_data_channel_size) {
        list<ByteBuffer> fragmented_message = SplitDataChannelMessage(
            data_channel_payload,
            max_data_channel_size);

        for_each(fragmented_message.begin(), fragmented_message.end(), [this] (ByteBuffer& fragment) {
            SendSequencedMessage_(&BuildFragmentedDataChannelHeader, move(fragment));
        });
    } else {
        SendSequencedMessage_(&BuildDataChannelHeader, move(data_channel_payload));
    }
}

void Session::SendMessage(ByteBuffer message) {
    auto message_buffer = server_->AllocateBuffer();
    message_buffer->swap(message);

    outgoing_data_messages_.push(message_buffer);
}

void Session::Close(void)
{
    if(connected_)
    {
        connected_ = false;

        Disconnect disconnect(connection_id_);
        auto buffer = server_->AllocateBuffer();

        disconnect.serialize(*buffer);
        SendSoePacket_(buffer);

        server_->RemoveSession(shared_from_this());
    }
}

void Session::HandleMessage(const std::shared_ptr<anh::ByteBuffer>& message)
{
    auto session = shared_from_this();
    strand_.post([=] ()
    {
        switch(message->peek<uint16_t>(true))
        {
            case CHILD_DATA_A:	   { ChildDataA child_data_a(*message); session->handleChildDataA_(child_data_a); break; }
            case MULTI_PACKET:	   { MultiPacket multi_packet(*message); session->handleMultiPacket_(multi_packet); break; }
            case DATA_FRAG_A:	   { DataFragA data_frag_a(*message); session->handleDataFragA_(data_frag_a); break; }
            case ACK_A:			   { AckA ack_a(*message); session->handleAckA_(ack_a); break; }
            case PING:			   { Ping ping(*message); session->handlePing_(ping); break; }
            case NET_STATS_CLIENT: { NetStatsClient net_stats_client(*message); session->handleNetStatsClient_(net_stats_client); break; }
            case OUT_OF_ORDER_A:   { OutOfOrderA out_of_order_a(*message); session->handleOutOfOrderA_(out_of_order_a); break; }
            case DISCONNECT:	   { Disconnect disconnect(*message); session->handleDisconnect_(disconnect); break; }
            case SESSION_REQUEST:  { SessionRequest session_request(*message); session->handleSessionRequest_(session_request); break; }
            case FATAL_ERROR:      { session->Close(); break; }
            default:
                if (message->peek<uint8_t>() != 0)
                {
                    server_->HandleMessage(session, message);
                }
                else
                {
                    LOG(WARNING) << "Unhandled SOE Opcode: " << std::hex << message->peek<uint16_t>(true)
                        << "\n\n" << message;
                }
        }
    });
}

void Session::HandleProtocolMessage(const std::shared_ptr<anh::ByteBuffer>& message)
{
    auto session = shared_from_this();
    strand_.post([=] ()
    {
        security_filter_(session, message);

        if (connected())
        {
            crc_input_filter_(session, message);
            decryption_filter_(session, message);
            decompression_filter_(session, message);
        }

        HandleMessage(message);
    });
}

void Session::SendSequencedMessage_(HeaderBuilder header_builder, ByteBuffer message) {
    // Get the next sequence number
    uint16_t message_sequence = server_sequence_++;

    // Allocate a new packet
    auto data_channel_message = server_->AllocateBuffer();
    data_channel_message->append(header_builder(message_sequence));
    data_channel_message->append(message);

    // Send it over the wire
    SendSoePacket_(data_channel_message);

    // Store it for resending later if necessary
    sent_messages_.push_back(make_pair(message_sequence, data_channel_message));

    // If the data channel message is too big
    uint32_t max_data_channel_size = receive_buffer_size_ - crc_length_ - 5;
}

void Session::handleSessionRequest_(SessionRequest& packet)
{
    connection_id_ = packet.connection_id;
    crc_length_ = packet.crc_length;
    receive_buffer_size_ = packet.client_udp_buffer_size;

    SessionResponse session_response(connection_id_, crc_seed_);
    session_response.server_udp_buffer_size = server_->max_receive_size();

    auto buffer = server_->AllocateBuffer();
    session_response.serialize(*buffer);

    // Directly put this on the wire, it requires no outgoing processing.
    server_->SendTo(remote_endpoint_, buffer);

    connected_ = true;
    LOG(INFO) << "Created Session [" << connection_id_ << "] @ " << remote_endpoint_.address().to_string() << ":" << remote_endpoint_.port();
}

void Session::handleMultiPacket_(MultiPacket& packet)
{
    VLOG(3) << "Handling MULTIPACKET";
    std::for_each(packet.packets.begin(), packet.packets.end(), [=](anh::ByteBuffer& buffer) {
        HandleMessage(make_shared<ByteBuffer>(buffer));
    });
}

void Session::handleDisconnect_(Disconnect& packet)
{
    VLOG(3) << "Handling DISCONNECT";
    Close();
}

void Session::handlePing_(Ping& packet)
{
    VLOG(3) << "Handling PING";
    Ping pong;

    auto buffer = server_->AllocateBuffer();
    pong.serialize(*buffer);

    SendSoePacket_(buffer);
}

void Session::handleNetStatsClient_(NetStatsClient& packet)
{
    VLOG(3) << "Handling NET_STATS_CLIENT";
    server_net_stats_.client_tick_count = packet.client_tick_count;

    auto buffer = server_->AllocateBuffer();
    server_net_stats_.serialize(*buffer);
    SendSoePacket_(buffer);
}

void Session::handleChildDataA_(ChildDataA& packet)
{
    VLOG(3) << "Handling CHILD_DATA_A";
    if(!SequenceIsValid_(packet.sequence)) {
        DLOG(WARNING) << "Invalid sequence: " << packet.sequence << "; Current sequence " << this->next_client_sequence_;
        return;
    }

    AcknowledgeSequence_(packet.sequence);

    std::for_each(packet.messages.begin(), packet.messages.end(), [this] (shared_ptr<ByteBuffer> message) {
        server_->HandleMessage(this->shared_from_this(), message);
    });
}

void Session::handleDataFragA_(DataFragA& packet)
{
    VLOG(3) << "Handling DATA_FRAG_A";
    if(!SequenceIsValid_(packet.sequence))
        return;

    AcknowledgeSequence_(packet.sequence);

    // Continuing a frag
    if(incoming_fragmented_total_len_ > 0)
    {
        incoming_fragmented_curr_len_ += packet.data.size();
        incoming_fragmented_messages_.push_back(packet.data);

        if(incoming_fragmented_total_len_ == incoming_fragmented_curr_len_)
        {
            // Send to translator.
            incoming_fragmented_total_len_ = 0;
            incoming_fragmented_curr_len_ = 0;

            ByteBuffer full_packet;
            std::for_each(
                incoming_fragmented_messages_.cbegin(),
                incoming_fragmented_messages_.cend(),
                [&full_packet] (const ByteBuffer& buffer) {
                    full_packet.append(buffer);
                }
            );

            ChildDataA child_data_a(full_packet);
            handleChildDataA_(child_data_a);

            incoming_fragmented_messages_.clear();
        }
    }
    // Starting a new frag
    else
    {
        incoming_fragmented_total_len_ = packet.data.read<uint16_t>();
        incoming_fragmented_curr_len_ += packet.data.size();
        incoming_fragmented_messages_.push_back(anh::ByteBuffer(packet.data.data()+2, packet.data.size()-2));
    }

}

void Session::handleAckA_(AckA& packet)
{
    VLOG(3) << "Handle ACK_A";

    auto it = find_if(
        sent_messages_.begin(),
        sent_messages_.end(),
        [this, &packet] (const SequencedMessageMap::value_type& message)
    {
        return (message.first == packet.sequence) ? true : false;
    });

    sent_messages_.erase(sent_messages_.begin(), it);

    last_acknowledged_sequence_ = packet.sequence;
}

void Session::handleOutOfOrderA_(OutOfOrderA& packet)
{
    VLOG(3) << "Handle OUT_OF_ORDER_A";

    std::for_each(sent_messages_.begin(), sent_messages_.end(), [=](SequencedMessageMap::value_type& item) {
        SendSoePacket_(item.second);
    });
}

void Session::SendSoePacket_(const std::shared_ptr<anh::ByteBuffer>& message)
{
    auto session = shared_from_this();
    strand_.post([=] ()
    {
        compression_filter_(session, message);
        encryption_filter_(session, message);
        crc_output_filter_(session, message);

        server_->SendTo(session->remote_endpoint(), message);
    });
}

bool Session::SequenceIsValid_(const uint16_t& sequence)
{
    if(next_client_sequence_ == sequence)
    {
        return true;
    }
    else
    {
        // Tell the client we have received an Out of Order sequence.
        OutOfOrderA	out_of_order(sequence);
        auto buffer = server_->AllocateBuffer();
        out_of_order.serialize(*buffer);
        SendSoePacket_(buffer);

        return false;
    }
}

void Session::AcknowledgeSequence_(const uint16_t& sequence)
{
    AckA ack(sequence);
    auto buffer = server_->AllocateBuffer();
    ack.serialize(*buffer);
    SendSoePacket_(buffer);

    next_client_sequence_ = sequence + 1;
    current_client_sequence_ = sequence;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Logger.h"
#include <memory>
#include <locale> // wstring_convert

std::shared_ptr<spdlog::logger> getFallbackLogger()
{
    constexpr const char *fallbackLoggerName = "Fallback_stderr";
    spdlog::drop(fallbackLoggerName);
    return spdlog::stderr_logger_mt(fallbackLoggerName);
}

void createLogger(std::string loggerName, spdlog::filename_t loggerFile)
{
    try
    {
        spdlog::set_level(spdlog::level::debug);
        spdlog::set_sync_mode();
        Logger::logfile = spdlog::rotating_logger_mt(loggerName, loggerFile, 1024 * 1024 * 10, 3);
        LOG_INFO("Synchronous logger created");
        LOG_FLUSH();
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        Logger::logfile = getFallbackLogger();
        LOG_ERROR(std::string("Could not create regular logger! ") + ex.what());
    }
}

// Do NOT call this function in dllmain.cpp!!!
// It creates new threads which is forbidden while attaching the dll
void switchToAsyncLogger(std::string loggerName, spdlog::filename_t loggerFile)
{
    LOG_INFO("Switching to asynchronous logger...");
    LOG_FLUSH();
    Logger::logfile = nullptr;
    spdlog::drop(loggerName);

    try
    {
        spdlog::set_level(spdlog::level::debug);
        spdlog::set_async_mode(131072, spdlog::async_overflow_policy::block_retry,
            nullptr,
            std::chrono::milliseconds(500));

        Logger::logfile = spdlog::rotating_logger_mt(loggerName, loggerFile, 1024 * 1024 * 10, 3);
        LOG_INFO("Switching to asynchronous logger done!");
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        // Try creating the regular logger again. Might work.
        try
        {
            createLogger(loggerName, loggerFile);
        }
        catch (const spdlog::spdlog_ex& ex)
        {
            Logger::logfile = getFallbackLogger();
            LOG_ERROR(std::string("Could not create regular logger! ") + ex.what());
        }

        LOG_ERROR(std::string("Could not create asynchronous logger! ") + ex.what());
    }
}

namespace Logger
{
    // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#721
    template<class I, class E, class S>
    struct codecvt : std::codecvt<I, E, S>
    {
        ~codecvt()
        { }
    };

    std::string w2s(const std::wstring &var)
    {
        static std::locale loc("");
        auto &facet = std::use_facet<codecvt<wchar_t, char, std::mbstate_t>>(loc);
        return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
    }

    std::wstring s2w(const std::string &var)
    {
        static std::locale loc("");
        auto &facet = std::use_facet<codecvt<wchar_t, char, std::mbstate_t>>(loc);
        return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
    }
}
<commit_msg>utf conversions for linux<commit_after>#include "stdafx.h"
#include "Logger.h"
#include <memory>
#include <locale> // wstring_convert
#include <codecvt> // codecvt_utf8_utf16

std::shared_ptr<spdlog::logger> getFallbackLogger()
{
    constexpr const char *fallbackLoggerName = "Fallback_stderr";
    spdlog::drop(fallbackLoggerName);
    return spdlog::stderr_logger_mt(fallbackLoggerName);
}

void createLogger(std::string loggerName, spdlog::filename_t loggerFile)
{
    try
    {
        spdlog::set_level(spdlog::level::debug);
        spdlog::set_sync_mode();
        Logger::logfile = spdlog::rotating_logger_mt(loggerName, loggerFile, 1024 * 1024 * 10, 3);
        LOG_INFO("Synchronous logger created");
        LOG_FLUSH();
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        Logger::logfile = getFallbackLogger();
        LOG_ERROR(std::string("Could not create regular logger! ") + ex.what());
    }
}

// Do NOT call this function in dllmain.cpp!!!
// It creates new threads which is forbidden while attaching the dll
void switchToAsyncLogger(std::string loggerName, spdlog::filename_t loggerFile)
{
    LOG_INFO("Switching to asynchronous logger...");
    LOG_FLUSH();
    Logger::logfile = nullptr;
    spdlog::drop(loggerName);

    try
    {
        spdlog::set_level(spdlog::level::debug);
        spdlog::set_async_mode(131072, spdlog::async_overflow_policy::block_retry,
            nullptr,
            std::chrono::milliseconds(500));

        Logger::logfile = spdlog::rotating_logger_mt(loggerName, loggerFile, 1024 * 1024 * 10, 3);
        LOG_INFO("Switching to asynchronous logger done!");
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        // Try creating the regular logger again. Might work.
        try
        {
            createLogger(loggerName, loggerFile);
        }
        catch (const spdlog::spdlog_ex& ex)
        {
            Logger::logfile = getFallbackLogger();
            LOG_ERROR(std::string("Could not create regular logger! ") + ex.what());
        }

        LOG_ERROR(std::string("Could not create asynchronous logger! ") + ex.what());
    }
}

namespace Logger
{
    // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-closed.html#721
    template<class I, class E, class S>
    struct codecvt : std::codecvt<I, E, S>
    {
        ~codecvt()
        { }
    };

    std::string w2s(const std::wstring &var)
    {
    #ifdef _WIN32 // If it ain't broke, don't fix it
        static std::locale loc("");
        auto &facet = std::use_facet<codecvt<wchar_t, char, std::mbstate_t>>(loc);
        return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).to_bytes(var);
    #else
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.to_bytes(var);
    #endif
    }

    std::wstring s2w(const std::string &var)
    {
    #ifdef _WIN32 // If it ain't broke, don't fix it
        static std::locale loc("");
        auto &facet = std::use_facet<codecvt<wchar_t, char, std::mbstate_t>>(loc);
        return std::wstring_convert<std::remove_reference<decltype(facet)>::type, wchar_t>(&facet).from_bytes(var);
    #else
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.from_bytes(var);
    #endif
    }
}
<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef registrardb_hh
#define registrardb_hh

#include <map>
#include <list>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <algorithm>

#include <sofia-sip/sip.h>
#include "agent.hh"

#define AOR_KEY_SIZE 128

typedef struct extended_contact {
	su_home_t home;
	char *mSipUri;
	float mQ;
	time_t mExpireAt;
	time_t mUpdatedTime;
	char *mCallId;
	uint32_t mCSeq;
	char *mLineValueCopy;
	char *mRoute;
	char *mContactId;

	void common_init(const char *contactId, const char *route, const char* callId, const char *lineValue){
		mCallId=su_strdup(&home, callId);
		if (lineValue) mLineValueCopy=su_strdup(&home,lineValue);
		if (route) mRoute=su_strdup(&home,route);
		mContactId=su_strdup(&home, contactId);

	}
	extended_contact(const sip_contact_t *sip_contact, const char *contactId, const char *route, const char *lineValue, int global_expire, const char *callId, uint32_t cseq, time_t updateTime):
			mQ(0),mUpdatedTime(updateTime),mCallId(NULL),mCSeq(cseq),mLineValueCopy(NULL),mRoute(NULL),mContactId(NULL) {
		su_home_init(&home);

		const url_t *url=sip_contact->m_url;
		const char * port = (url->url_port)? url->url_port : "5060";
		if (url->url_params){
			if (url->url_user) {
				mSipUri=su_sprintf(&home, "<sip:%s@%s:%s;%s>", url->url_user, url->url_host, port, url->url_params);
			} else {
				mSipUri=su_sprintf(&home, "<sip:%s:%s;%s>", url->url_host, port, url->url_params);
			}
		} else {
			if (url->url_user) {
				mSipUri=su_sprintf(&home,"<sip:%s@%s:%s>", url->url_user, url->url_host, port);
			} else {
				mSipUri=su_sprintf(&home,"<sip:%s:%s>", url->url_host, port);
			}
		}

		if (sip_contact->m_q){
			mQ=atof(sip_contact->m_q);
		}

		if (sip_contact->m_expires){
			mExpireAt=updateTime+atoi(sip_contact->m_expires);
		} else {
			mExpireAt=updateTime+global_expire;
		}

		common_init(contactId, route, callId, lineValue);
	}

	extended_contact(const char *sip_contact, const char *contactId, const char *route, const char *lineValue, long expireAt, float q, const char *callId, uint32_t cseq, time_t updateTime)
			:mSipUri(NULL),mQ(q),mExpireAt(expireAt),mUpdatedTime(updateTime),
			mCallId(NULL),mCSeq(cseq),mLineValueCopy(NULL),mRoute(NULL),mContactId(NULL){
		su_home_init(&home);
		mSipUri=su_strdup(&home, sip_contact);
		common_init(contactId, route, callId, lineValue);
	}
	~extended_contact(){
		su_home_destroy(&home);
	}

} extended_contact;

class Record{
	static void init();
	void insertOrUpdateBinding(extended_contact *ec);
	std::list<extended_contact *> mContacts;
	static std::string sLineFieldName;
	static int sMaxContacts;
	public:
		Record();
		static sip_contact_t *extendedContactToSofia(su_home_t *home, extended_contact *ec, time_t now);
		const sip_contact_t * getContacts(su_home_t *home, time_t now);
		bool isInvalidRegister(const char *call_id, uint32_t cseq);
		void clean(const sip_contact_t *sip, const char *call_id, uint32_t cseq, time_t time);
		void clean(time_t time);
		void bind(const sip_contact_t *contacts, const char* route, int globalExpire, const char *call_id, uint32_t cseq, time_t now);
		void bind(const char *contact, const char* route, const char *transport, const char *lineValue, long expireAt, float q, const char *call_id, uint32_t cseq, time_t now);
		void print();
		int count(){return mContacts.size();}
		std::list<extended_contact *> &getExtendedContacts() {return mContacts;}
		static int getMaxContacts(){
			if (sMaxContacts == -1) init();
			return sMaxContacts;}
		~Record();
};

class RegistrarDbListener : public StatFinishListener {
public:
	~RegistrarDbListener(){}
	virtual void onRecordFound(Record *r)=0;
	virtual void onError()=0;
	virtual void onInvalid(){/*let the registration timeout;*/};
};

/**
 * A singleton class which holds records contact addresses associated with a from.
 * Both local and remote storage implementations exist.
 * It is used by the Registrar module.
**/
class RegistrarDb {
	public:
		static RegistrarDb *get(Agent *ag);
                virtual void bind(const url_t* fromUrl, const sip_contact_t *sip_contact, const char * calld_id, uint32_t cs_seq, const char *route, int global_expire, RegistrarDbListener *listener)=0;
		virtual void bind(const sip_t *sip, const char* route, int global_expire, RegistrarDbListener *listener)=0;
		virtual void clear(const sip_t *sip, RegistrarDbListener *listener)=0;
		virtual void fetch(const url_t *url, RegistrarDbListener *listener)=0;
	protected:
		int count_sip_contacts(const sip_contact_t *contact);
		bool errorOnTooMuchContactInBind(const sip_contact_t *sip_contact, const char *key, RegistrarDbListener *listener);
		static void defineKeyFromUrl(char *key, int len, const url_t *url);
		RegistrarDb();
		std::map<std::string,Record*> mRecords;
		static RegistrarDb *sUnique;
		unsigned long long int mTotalNumberOfAddRecords;
		unsigned long long int mTotalNumberOfExpiredRecords;
};

#endif
<commit_msg>Remove unused.<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef registrardb_hh
#define registrardb_hh

#include <map>
#include <list>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <algorithm>

#include <sofia-sip/sip.h>
#include "agent.hh"

#define AOR_KEY_SIZE 128

typedef struct extended_contact {
	su_home_t home;
	char *mSipUri;
	float mQ;
	time_t mExpireAt;
	time_t mUpdatedTime;
	char *mCallId;
	uint32_t mCSeq;
	char *mLineValueCopy;
	char *mRoute;
	char *mContactId;

	void common_init(const char *contactId, const char *route, const char* callId, const char *lineValue){
		mCallId=su_strdup(&home, callId);
		if (lineValue) mLineValueCopy=su_strdup(&home,lineValue);
		if (route) mRoute=su_strdup(&home,route);
		mContactId=su_strdup(&home, contactId);

	}
	extended_contact(const sip_contact_t *sip_contact, const char *contactId, const char *route, const char *lineValue, int global_expire, const char *callId, uint32_t cseq, time_t updateTime):
			mQ(0),mUpdatedTime(updateTime),mCallId(NULL),mCSeq(cseq),mLineValueCopy(NULL),mRoute(NULL),mContactId(NULL) {
		su_home_init(&home);

		const url_t *url=sip_contact->m_url;
		const char * port = (url->url_port)? url->url_port : "5060";
		if (url->url_params){
			if (url->url_user) {
				mSipUri=su_sprintf(&home, "<sip:%s@%s:%s;%s>", url->url_user, url->url_host, port, url->url_params);
			} else {
				mSipUri=su_sprintf(&home, "<sip:%s:%s;%s>", url->url_host, port, url->url_params);
			}
		} else {
			if (url->url_user) {
				mSipUri=su_sprintf(&home,"<sip:%s@%s:%s>", url->url_user, url->url_host, port);
			} else {
				mSipUri=su_sprintf(&home,"<sip:%s:%s>", url->url_host, port);
			}
		}

		if (sip_contact->m_q){
			mQ=atof(sip_contact->m_q);
		}

		if (sip_contact->m_expires){
			mExpireAt=updateTime+atoi(sip_contact->m_expires);
		} else {
			mExpireAt=updateTime+global_expire;
		}

		common_init(contactId, route, callId, lineValue);
	}

	extended_contact(const char *sip_contact, const char *contactId, const char *route, const char *lineValue, long expireAt, float q, const char *callId, uint32_t cseq, time_t updateTime)
			:mSipUri(NULL),mQ(q),mExpireAt(expireAt),mUpdatedTime(updateTime),
			mCallId(NULL),mCSeq(cseq),mLineValueCopy(NULL),mRoute(NULL),mContactId(NULL){
		su_home_init(&home);
		mSipUri=su_strdup(&home, sip_contact);
		common_init(contactId, route, callId, lineValue);
	}
	~extended_contact(){
		su_home_destroy(&home);
	}

} extended_contact;

class Record{
	static void init();
	void insertOrUpdateBinding(extended_contact *ec);
	std::list<extended_contact *> mContacts;
	static std::string sLineFieldName;
	static int sMaxContacts;
	public:
		Record();
		static sip_contact_t *extendedContactToSofia(su_home_t *home, extended_contact *ec, time_t now);
		const sip_contact_t * getContacts(su_home_t *home, time_t now);
		bool isInvalidRegister(const char *call_id, uint32_t cseq);
		void clean(const sip_contact_t *sip, const char *call_id, uint32_t cseq, time_t time);
		void clean(time_t time);
		void bind(const sip_contact_t *contacts, const char* route, int globalExpire, const char *call_id, uint32_t cseq, time_t now);
		void bind(const char *contact, const char* route, const char *transport, const char *lineValue, long expireAt, float q, const char *call_id, uint32_t cseq, time_t now);
		void print();
		int count(){return mContacts.size();}
		std::list<extended_contact *> &getExtendedContacts() {return mContacts;}
		static int getMaxContacts(){
			if (sMaxContacts == -1) init();
			return sMaxContacts;}
		~Record();
};

class RegistrarDbListener : public StatFinishListener {
public:
	~RegistrarDbListener(){}
	virtual void onRecordFound(Record *r)=0;
	virtual void onError()=0;
	virtual void onInvalid(){/*let the registration timeout;*/};
};

/**
 * A singleton class which holds records contact addresses associated with a from.
 * Both local and remote storage implementations exist.
 * It is used by the Registrar module.
**/
class RegistrarDb {
	public:
		static RegistrarDb *get(Agent *ag);
                virtual void bind(const url_t* fromUrl, const sip_contact_t *sip_contact, const char * calld_id, uint32_t cs_seq, const char *route, int global_expire, RegistrarDbListener *listener)=0;
		virtual void bind(const sip_t *sip, const char* route, int global_expire, RegistrarDbListener *listener)=0;
		virtual void clear(const sip_t *sip, RegistrarDbListener *listener)=0;
		virtual void fetch(const url_t *url, RegistrarDbListener *listener)=0;
	protected:
		int count_sip_contacts(const sip_contact_t *contact);
		bool errorOnTooMuchContactInBind(const sip_contact_t *sip_contact, const char *key, RegistrarDbListener *listener);
		static void defineKeyFromUrl(char *key, int len, const url_t *url);
		RegistrarDb();
		std::map<std::string,Record*> mRecords;
		static RegistrarDb *sUnique;
};

#endif
<|endoftext|>