<commit_before>// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// 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 "util/linux/exception_handler_client.h"

#include <errno.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>

#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "util/file/file_io.h"
#include "util/linux/ptrace_broker.h"
#include "util/posix/signals.h"

namespace crashpad {

ExceptionHandlerClient::ExceptionHandlerClient(int sock)
    : server_sock_(sock), ptracer_(-1), can_set_ptracer_(true) {}

ExceptionHandlerClient::~ExceptionHandlerClient() = default;

int ExceptionHandlerClient::RequestCrashDump(const ClientInformation& info) {
  int status = SendCrashDumpRequest(info);
  if (status != 0) {
    return status;
  }
  return WaitForCrashDumpComplete();
}

int ExceptionHandlerClient::SetPtracer(pid_t pid) {
  if (ptracer_ == pid) {
    return 0;
  }

  if (!can_set_ptracer_) {
    return EPERM;
  }

  if (prctl(PR_SET_PTRACER, pid, 0, 0, 0) == 0) {
    return 0;
  }
  return errno;
}

void ExceptionHandlerClient::SetCanSetPtracer(bool can_set_ptracer) {
  can_set_ptracer_ = can_set_ptracer;
}

int ExceptionHandlerClient::SendCrashDumpRequest(
    const ClientInformation& info) {
  ClientToServerMessage message;
  message.type = ClientToServerMessage::kCrashDumpRequest;
  message.client_info = info;

  iovec iov;
  iov.iov_base = &message;
  iov.iov_len = sizeof(message);

  msghdr msg;
  msg.msg_name = nullptr;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

  ucred creds;
  creds.pid = getpid();
  creds.uid = geteuid();
  creds.gid = getegid();

  char cmsg_buf[CMSG_SPACE(sizeof(creds))];
  msg.msg_control = cmsg_buf;
  msg.msg_controllen = sizeof(cmsg_buf);

  cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_CREDENTIALS;
  cmsg->cmsg_len = CMSG_LEN(sizeof(creds));
  *reinterpret_cast<ucred*>(CMSG_DATA(cmsg)) = creds;

  if (sendmsg(server_sock_, &msg, MSG_NOSIGNAL) < 0) {
    PLOG(ERROR) << "sendmsg";
    return errno;
  }

  return 0;
}

int ExceptionHandlerClient::WaitForCrashDumpComplete() {
  ServerToClientMessage message;

  // If the server hangs up, ReadFileExactly will return false without setting
  // errno.
  errno = 0;
  while (ReadFileExactly(server_sock_, &message, sizeof(message))) {
    switch (message.type) {
      case ServerToClientMessage::kTypeForkBroker: {
        Signals::InstallDefaultHandler(SIGCHLD);

        pid_t pid = fork();
        if (pid < 0) {
          Errno error = errno;
          if (!WriteFile(server_sock_, &error, sizeof(error))) {
            return errno;
          }
          continue;
        }

        if (pid == 0) {
#if defined(ARCH_CPU_64_BITS)
          constexpr bool am_64_bit = true;
#else
          constexpr bool am_64_bit = false;
#endif  // ARCH_CPU_64_BITS

          PtraceBroker broker(server_sock_, am_64_bit);
          _exit(broker.Run());
        }

        int status = 0;
        pid_t child = HANDLE_EINTR(waitpid(pid, &status, 0));
        DCHECK_EQ(child, pid);

        if (child == pid && status != 0) {
          return status;
        }
        continue;
      }

      case ServerToClientMessage::kTypeSetPtracer: {
        Errno result = SetPtracer(message.pid);
        if (!WriteFile(server_sock_, &result, sizeof(result))) {
          return errno;
        }
        continue;
      }

      case ServerToClientMessage::kTypeCrashDumpComplete:
      case ServerToClientMessage::kTypeCrashDumpFailed:
        return 0;
    }

    DCHECK(false);
  }

  return errno;
}

}  // namespace crashpad
<commit_msg>linux: Add missing build_config.h include<commit_after>// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// 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 "util/linux/exception_handler_client.h"

#include <errno.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>

#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include "util/file/file_io.h"
#include "util/linux/ptrace_broker.h"
#include "util/posix/signals.h"

namespace crashpad {

ExceptionHandlerClient::ExceptionHandlerClient(int sock)
    : server_sock_(sock), ptracer_(-1), can_set_ptracer_(true) {}

ExceptionHandlerClient::~ExceptionHandlerClient() = default;

int ExceptionHandlerClient::RequestCrashDump(const ClientInformation& info) {
  int status = SendCrashDumpRequest(info);
  if (status != 0) {
    return status;
  }
  return WaitForCrashDumpComplete();
}

int ExceptionHandlerClient::SetPtracer(pid_t pid) {
  if (ptracer_ == pid) {
    return 0;
  }

  if (!can_set_ptracer_) {
    return EPERM;
  }

  if (prctl(PR_SET_PTRACER, pid, 0, 0, 0) == 0) {
    return 0;
  }
  return errno;
}

void ExceptionHandlerClient::SetCanSetPtracer(bool can_set_ptracer) {
  can_set_ptracer_ = can_set_ptracer;
}

int ExceptionHandlerClient::SendCrashDumpRequest(
    const ClientInformation& info) {
  ClientToServerMessage message;
  message.type = ClientToServerMessage::kCrashDumpRequest;
  message.client_info = info;

  iovec iov;
  iov.iov_base = &message;
  iov.iov_len = sizeof(message);

  msghdr msg;
  msg.msg_name = nullptr;
  msg.msg_namelen = 0;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;

  ucred creds;
  creds.pid = getpid();
  creds.uid = geteuid();
  creds.gid = getegid();

  char cmsg_buf[CMSG_SPACE(sizeof(creds))];
  msg.msg_control = cmsg_buf;
  msg.msg_controllen = sizeof(cmsg_buf);

  cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_CREDENTIALS;
  cmsg->cmsg_len = CMSG_LEN(sizeof(creds));
  *reinterpret_cast<ucred*>(CMSG_DATA(cmsg)) = creds;

  if (sendmsg(server_sock_, &msg, MSG_NOSIGNAL) < 0) {
    PLOG(ERROR) << "sendmsg";
    return errno;
  }

  return 0;
}

int ExceptionHandlerClient::WaitForCrashDumpComplete() {
  ServerToClientMessage message;

  // If the server hangs up, ReadFileExactly will return false without setting
  // errno.
  errno = 0;
  while (ReadFileExactly(server_sock_, &message, sizeof(message))) {
    switch (message.type) {
      case ServerToClientMessage::kTypeForkBroker: {
        Signals::InstallDefaultHandler(SIGCHLD);

        pid_t pid = fork();
        if (pid < 0) {
          Errno error = errno;
          if (!WriteFile(server_sock_, &error, sizeof(error))) {
            return errno;
          }
          continue;
        }

        if (pid == 0) {
#if defined(ARCH_CPU_64_BITS)
          constexpr bool am_64_bit = true;
#else
          constexpr bool am_64_bit = false;
#endif  // ARCH_CPU_64_BITS

          PtraceBroker broker(server_sock_, am_64_bit);
          _exit(broker.Run());
        }

        int status = 0;
        pid_t child = HANDLE_EINTR(waitpid(pid, &status, 0));
        DCHECK_EQ(child, pid);

        if (child == pid && status != 0) {
          return status;
        }
        continue;
      }

      case ServerToClientMessage::kTypeSetPtracer: {
        Errno result = SetPtracer(message.pid);
        if (!WriteFile(server_sock_, &result, sizeof(result))) {
          return errno;
        }
        continue;
      }

      case ServerToClientMessage::kTypeCrashDumpComplete:
      case ServerToClientMessage::kTypeCrashDumpFailed:
        return 0;
    }

    DCHECK(false);
  }

  return errno;
}

}  // namespace crashpad
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/type.hpp"
#include "libbirch/Any.hpp"
#include "libbirch/Label.hpp"
#include "libbirch/Nil.hpp"
#include "libbirch/thread.hpp"

namespace libbirch {
/**
 * Wraps a pointer type to apply lazy deep clone semantics.
 *
 * @ingroup libbirch
 *
 * @tparam P Pointer type. Either SharedPtr, WeakPtr or InitPtr.
 */
template<class P>
class Lazy {
  template<class U> friend class Lazy;
public:
  using pointer_type = P;
  using value_type = typename P::value_type;

  Lazy& operator=(const Lazy&) = delete;
  Lazy& operator=(Lazy&&) = delete;

  /**
   * Constructor.
   */
  Lazy(const Nil& = nil) :
      object(),
      label(0),
      cross(false) {
    //
  }

  /**
   * Constructor.
   */
  Lazy(Label* context, const Nil& = nil) :
      object(),
      label(0),
      cross(false) {
    //
  }

  /**
   * Constructor.
   */
  Lazy(Label* context, value_type* object, const bool cross = false) :
      object(object),
      label(reinterpret_cast<intptr_t>(context)),
      cross(cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Constructor.
   */
  Lazy(Label* context, const P& object, const bool cross = false) :
      object(object),
      label(reinterpret_cast<intptr_t>(context)),
      cross(cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Copy constructor.
   */
  Lazy(const Lazy<P>& o) :
      object(o.get()),
      label(o.label),
      cross(o.cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Copy constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(const Lazy<Q>& o) :
      object(o.get()),
      label(o.label),
      cross(o.cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Copy constructor.
   */
  Lazy(Label* context, const Lazy<P>& o) :
      object(o.get()),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Copy constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(Label* context, const Lazy<Q>& o) :
      object(o.get()),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Move constructor.
   */
  Lazy(Lazy<P>&& o) :
      object(std::move(o.object)),
      label(o.label),
      cross(o.cross) {
    o.label = 0;
    o.cross = false;
  }

  /**
   * Move constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(Lazy<Q>&& o) :
      object(std::move(o.object)),
      label(o.label),
      cross(o.cross) {
    o.label = 0;
    o.cross = false;
  }

  /**
   * Move constructor.
   */
  Lazy(Label* context, Lazy<P>&& o) :
      object(std::move(o.object)),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Move constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(Label* context, Lazy<Q>&& o) :
      object(std::move(o.object)),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Deep copy constructor.
   */
  Lazy(Label* context, Label* label, const Lazy<P>& o) :
      object(),
      label(0),
      cross(false) {
    assert(context == label);
    if (o.object) {
      if (o.isCross()) {
        o.finish();
        o.freeze();
      }
      object = o.object;
      setLabel(label, false);
    }
  }

  /**
   * Destructor.
   */
  ~Lazy() {
    releaseLabel();
  }

  /**
   * Copy assignment.
   */
  template<class Q>
  Lazy& assign(Label* context, const Lazy<Q>& o) {
    if (object) {
      replaceLabel(o.getLabel(), o.getLabel() != context);
    } else {
      releaseLabel();
    }
    object = o.get();
    return *this;
  }

  /**
   * Move assignment.
   */
  template<class Q>
  Lazy& assign(Label* context, Lazy<Q>&& o) {
    if (object) {
      replaceLabel(o.getLabel(), o.getLabel() != context);
    } else {
      releaseLabel();
    }
    object = std::move(o.get());
    return *this;
  }

  /**
   * Value assignment.
   */
  template<class U, typename = std::enable_if_t<is_value<U>::value>>
  Lazy<P>& assign(Label* context, const U& o) {
    *get() = o;
    return *this;
  }

  /**
   * Release the pointer.
   */
  void release() {
    object.release();
    releaseLabel();
  }

  /**
   * Value conversion.
   */
  template<class U, IS_CONVERTIBLE(value_type,U)>
  operator U() const {
    return static_cast<U>(*get());
  }

  /**
   * Is the pointer not null?
   */
  bool query() const {
    return static_cast<bool>(object);
  }

  /**
   * Get the raw pointer, with lazy cloning.
   */
  P& get() {
    auto raw = object.get();
    if (raw && raw->isFrozen()) {
      raw = static_cast<value_type*>(getLabel()->get(raw));
      object.replace(raw);
      assert(object);
    }
    return object;
  }

  /**
   * Get the raw pointer, with lazy cloning.
   */
  auto get() const {
    return const_cast<Lazy<P>*>(this)->get();
  }

  /**
   * Get the raw pointer for read-only use, without cloning.
   */
  P& pull() {
    auto raw = object.get();
    if (raw && raw->isFrozen()) {
      raw = static_cast<value_type*>(getLabel()->pull(raw));
      object.replace(raw);
      assert(object);
    }
    return object;
  }

  /**
   * Get the raw pointer for read-only use, without cloning.
   */
  auto pull() const {
    return const_cast<Lazy<P>*>(this)->pull();
  }

  /**
   * Start lazy deep clone.
   */
  Lazy<P> clone(Label* context) const {
    assert(object);
    pull();
    startFreeze();
    return Lazy<P>(getLabel()->fork(), object, true);
  }

  /**
   * Start a freeze operation. This is just like freeze(), but manages thread
   * safety on entry and exit.
   */
  void startFreeze() {
    if (object) {
      freezeLock.enter();
      freeze();
      freezeLock.exit();
    }
  }

  /**
   * Start a freeze operation. This is just like freeze(), but manages thread
   * safety on entry and exit.
   */
  void startFreeze() const {
    return const_cast<Lazy<P>*>(this)->startFreeze();
  }

  /**
   * Freeze.
   */
  void freeze() {
    if (object) {
      object->freeze();
      getLabel()->freeze();
    }
  }

  /**
   * Freeze.
   */
  void freeze() const {
    return const_cast<Lazy<P>*>(this)->freeze();
  }

  /**
   * Thaw.
   */
  void thaw(Label* label) {
    if (isCross()) {
      startFinish();
      startFreeze();
    }
    if (object) {
      this->label = reinterpret_cast<intptr_t>(label);
    }
  }

  /**
   * Thaw.
   */
  void thaw(Label* label) const {
    return const_cast<Lazy<P>*>(this)->thaw(label);
  }

  /**
   * Start a finish operation. This is just like finish(), but manages thread
   * safety on entry and exit.
   */
  void startFinish() {
    if (object) {
      finishLock.enter();
      finish();
      finishLock.exit();
    }
  }

  /**
   * Start a freeze operation. This is just like finish(), but manages thread
   * safety on entry and exit.
   */
  void startFinish() const {
    return const_cast<Lazy<P>*>(this)->startFinish();
  }

  /**
   * Finish.
   */
  void finish() {
    if (object) {
      get();
      object->finish();
    }
  }

  /**
   * Finish.
   */
  void finish() const {
    return const_cast<Lazy<P>*>(this)->finish();
  }

  /**
   * Dereference.
   */
  auto& operator*() const {
    return *get();
  }

  /**
   * Member access.
   */
  auto operator->() const {
    return get();
  }

  /**
   * Equal comparison.
   */
  template<class U>
  bool operator==(const Lazy<U>& o) const {
    return get() == o.get();
  }

  /**
   * Not equal comparison.
   */
  template<class U>
  bool operator!=(const Lazy<U>& o) const {
    return get() != o.get();
  }

  /**
   * Dynamic cast.
   */
  template<class U>
  auto dynamic_pointer_cast(Label* context) const {
    auto cast = get().template dynamic_pointer_cast<typename U::pointer_type>();
    return Lazy<decltype(cast)>(getLabel(), cast);
  }

  /**
   * Static cast.
   */
  template<class U>
  auto static_pointer_cast(Label* context) const {
    auto cast = get().template static_pointer_cast<typename U::pointer_type>();
    return Lazy<decltype(cast)>(getLabel(), cast);
  }

private:
  /**
   * Constructor.
   */
  Lazy(Label* context, Label* label, const P& object) :
      object(object),
      label(0),
      cross(false) {
    if (object) {
      setLabel(label, label != context);
    }
  }

  /**
   * Get the label.
   */
  Label* getLabel() const {
    return reinterpret_cast<Label*>(this->label);
  }

  /**
   * Is this pointer crossed? A crossed pointer is to a context different to
   * that of the context in which it was created (e.g. the context of the
   * object to which it belongs).
   */
  bool isCross() const {
    return cross;
  }

  /**
   * Set the label.
   */
  void setLabel(Label* label, bool cross) {
    assert(this->label == 0);
    assert(!this->cross);
    this->label = reinterpret_cast<intptr_t>(label);
    this->cross = cross;
    if (label && cross) {
      label->incShared();
    }
  }

  /**
   * Replace the label.
   */
  void replaceLabel(Label* label, bool cross) {
    auto oldLabel = this->getLabel();
    auto oldCross = this->isCross();
    this->label = reinterpret_cast<intptr_t>(label);
    this->cross = cross;
    if (label && cross) {
      label->incShared();
    }
    if (oldLabel && oldCross) {
      oldLabel->decShared();
    }
  }

  /**
   * Release the label.
   */
  void releaseLabel() {
    auto label = getLabel();
    auto cross = isCross();
    this->label = 0;
    this->cross = false;
    if (label && cross) {
      label->decShared();
    }
  }

  /**
   * Object.
   */
  P object;

  /**
   * Raw pointer.
   */
  intptr_t label:63;

  /**
   * Is this pointer crossed? A crossed pointer is to a context different to
   * that of the context in which it was created (e.g. the context of the
   * object to which it belongs).
   */
  bool cross:1;
};

template<class P>
struct is_value<Lazy<P>> {
  static const bool value = false;
};

template<class P>
struct is_pointer<Lazy<P>> {
  static const bool value = true;
};
}
<commit_msg>Fix to assignment functions in Lazy.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/type.hpp"
#include "libbirch/Any.hpp"
#include "libbirch/Label.hpp"
#include "libbirch/Nil.hpp"
#include "libbirch/thread.hpp"

namespace libbirch {
/**
 * Wraps a pointer type to apply lazy deep clone semantics.
 *
 * @ingroup libbirch
 *
 * @tparam P Pointer type. Either SharedPtr, WeakPtr or InitPtr.
 */
template<class P>
class Lazy {
  template<class U> friend class Lazy;
public:
  using pointer_type = P;
  using value_type = typename P::value_type;

  Lazy& operator=(const Lazy&) = delete;
  Lazy& operator=(Lazy&&) = delete;

  /**
   * Constructor.
   */
  Lazy(const Nil& = nil) :
      object(),
      label(0),
      cross(false) {
    //
  }

  /**
   * Constructor.
   */
  Lazy(Label* context, const Nil& = nil) :
      object(),
      label(0),
      cross(false) {
    //
  }

  /**
   * Constructor.
   */
  Lazy(Label* context, value_type* object, const bool cross = false) :
      object(object),
      label(reinterpret_cast<intptr_t>(context)),
      cross(cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Constructor.
   */
  Lazy(Label* context, const P& object, const bool cross = false) :
      object(object),
      label(reinterpret_cast<intptr_t>(context)),
      cross(cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Copy constructor.
   */
  Lazy(const Lazy<P>& o) :
      object(o.get()),
      label(o.label),
      cross(o.cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Copy constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(const Lazy<Q>& o) :
      object(o.get()),
      label(o.label),
      cross(o.cross) {
    if (cross) {
      getLabel()->incShared();
    }
  }

  /**
   * Copy constructor.
   */
  Lazy(Label* context, const Lazy<P>& o) :
      object(o.get()),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Copy constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(Label* context, const Lazy<Q>& o) :
      object(o.get()),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Move constructor.
   */
  Lazy(Lazy<P>&& o) :
      object(std::move(o.object)),
      label(o.label),
      cross(o.cross) {
    o.label = 0;
    o.cross = false;
  }

  /**
   * Move constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(Lazy<Q>&& o) :
      object(std::move(o.object)),
      label(o.label),
      cross(o.cross) {
    o.label = 0;
    o.cross = false;
  }

  /**
   * Move constructor.
   */
  Lazy(Label* context, Lazy<P>&& o) :
      object(std::move(o.object)),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Move constructor.
   */
  template<class Q, IS_CONVERTIBLE(Q,P)>
  Lazy(Label* context, Lazy<Q>&& o) :
      object(std::move(o.object)),
      label(0),
      cross(false) {
    if (object) {
      setLabel(o.getLabel(), o.getLabel() != context);
    }
  }

  /**
   * Deep copy constructor.
   */
  Lazy(Label* context, Label* label, const Lazy<P>& o) :
      object(),
      label(0),
      cross(false) {
    assert(context == label);
    if (o.object) {
      if (o.isCross()) {
        o.finish();
        o.freeze();
      }
      object = o.object;
      setLabel(label, false);
    }
  }

  /**
   * Destructor.
   */
  ~Lazy() {
    releaseLabel();
  }

  /**
   * Copy assignment.
   */
  template<class Q>
  Lazy& assign(Label* context, const Lazy<Q>& o) {
    if (o.query()) {
      replaceLabel(o.getLabel(), o.getLabel() != context);
    } else {
      releaseLabel();
    }
    object = o.get();
    return *this;
  }

  /**
   * Move assignment.
   */
  template<class Q>
  Lazy& assign(Label* context, Lazy<Q>&& o) {
    if (o.query()) {
      replaceLabel(o.getLabel(), o.getLabel() != context);
    } else {
      releaseLabel();
    }
    object = std::move(o.get());
    return *this;
  }

  /**
   * Value assignment.
   */
  template<class U, typename = std::enable_if_t<is_value<U>::value>>
  Lazy<P>& assign(Label* context, const U& o) {
    *get() = o;
    return *this;
  }

  /**
   * Release the pointer.
   */
  void release() {
    object.release();
    releaseLabel();
  }

  /**
   * Value conversion.
   */
  template<class U, IS_CONVERTIBLE(value_type,U)>
  operator U() const {
    return static_cast<U>(*get());
  }

  /**
   * Is the pointer not null?
   */
  bool query() const {
    return static_cast<bool>(object);
  }

  /**
   * Get the raw pointer, with lazy cloning.
   */
  P& get() {
    auto raw = object.get();
    if (raw && raw->isFrozen()) {
      raw = static_cast<value_type*>(getLabel()->get(raw));
      object.replace(raw);
      assert(object);
    }
    return object;
  }

  /**
   * Get the raw pointer, with lazy cloning.
   */
  auto get() const {
    return const_cast<Lazy<P>*>(this)->get();
  }

  /**
   * Get the raw pointer for read-only use, without cloning.
   */
  P& pull() {
    auto raw = object.get();
    if (raw && raw->isFrozen()) {
      raw = static_cast<value_type*>(getLabel()->pull(raw));
      object.replace(raw);
      assert(object);
    }
    return object;
  }

  /**
   * Get the raw pointer for read-only use, without cloning.
   */
  auto pull() const {
    return const_cast<Lazy<P>*>(this)->pull();
  }

  /**
   * Start lazy deep clone.
   */
  Lazy<P> clone(Label* context) const {
    assert(object);
    pull();
    startFreeze();
    return Lazy<P>(getLabel()->fork(), object, true);
  }

  /**
   * Start a freeze operation. This is just like freeze(), but manages thread
   * safety on entry and exit.
   */
  void startFreeze() {
    if (object) {
      freezeLock.enter();
      freeze();
      freezeLock.exit();
    }
  }

  /**
   * Start a freeze operation. This is just like freeze(), but manages thread
   * safety on entry and exit.
   */
  void startFreeze() const {
    return const_cast<Lazy<P>*>(this)->startFreeze();
  }

  /**
   * Freeze.
   */
  void freeze() {
    if (object) {
      object->freeze();
      getLabel()->freeze();
    }
  }

  /**
   * Freeze.
   */
  void freeze() const {
    return const_cast<Lazy<P>*>(this)->freeze();
  }

  /**
   * Thaw.
   */
  void thaw(Label* label) {
    if (isCross()) {
      startFinish();
      startFreeze();
    }
    if (object) {
      this->label = reinterpret_cast<intptr_t>(label);
    }
  }

  /**
   * Thaw.
   */
  void thaw(Label* label) const {
    return const_cast<Lazy<P>*>(this)->thaw(label);
  }

  /**
   * Start a finish operation. This is just like finish(), but manages thread
   * safety on entry and exit.
   */
  void startFinish() {
    if (object) {
      finishLock.enter();
      finish();
      finishLock.exit();
    }
  }

  /**
   * Start a freeze operation. This is just like finish(), but manages thread
   * safety on entry and exit.
   */
  void startFinish() const {
    return const_cast<Lazy<P>*>(this)->startFinish();
  }

  /**
   * Finish.
   */
  void finish() {
    if (object) {
      get();
      object->finish();
    }
  }

  /**
   * Finish.
   */
  void finish() const {
    return const_cast<Lazy<P>*>(this)->finish();
  }

  /**
   * Dereference.
   */
  auto& operator*() const {
    return *get();
  }

  /**
   * Member access.
   */
  auto operator->() const {
    return get();
  }

  /**
   * Equal comparison.
   */
  template<class U>
  bool operator==(const Lazy<U>& o) const {
    return get() == o.get();
  }

  /**
   * Not equal comparison.
   */
  template<class U>
  bool operator!=(const Lazy<U>& o) const {
    return get() != o.get();
  }

  /**
   * Dynamic cast.
   */
  template<class U>
  auto dynamic_pointer_cast(Label* context) const {
    auto cast = get().template dynamic_pointer_cast<typename U::pointer_type>();
    return Lazy<decltype(cast)>(getLabel(), cast);
  }

  /**
   * Static cast.
   */
  template<class U>
  auto static_pointer_cast(Label* context) const {
    auto cast = get().template static_pointer_cast<typename U::pointer_type>();
    return Lazy<decltype(cast)>(getLabel(), cast);
  }

private:
  /**
   * Constructor.
   */
  Lazy(Label* context, Label* label, const P& object) :
      object(object),
      label(0),
      cross(false) {
    if (object) {
      setLabel(label, label != context);
    }
  }

  /**
   * Get the label.
   */
  Label* getLabel() const {
    return reinterpret_cast<Label*>(this->label);
  }

  /**
   * Is this pointer crossed? A crossed pointer is to a context different to
   * that of the context in which it was created (e.g. the context of the
   * object to which it belongs).
   */
  bool isCross() const {
    return cross;
  }

  /**
   * Set the label.
   */
  void setLabel(Label* label, bool cross) {
    assert(this->label == 0);
    assert(!this->cross);
    this->label = reinterpret_cast<intptr_t>(label);
    this->cross = cross;
    if (label && cross) {
      label->incShared();
    }
  }

  /**
   * Replace the label.
   */
  void replaceLabel(Label* label, bool cross) {
    auto oldLabel = this->getLabel();
    auto oldCross = this->isCross();
    this->label = reinterpret_cast<intptr_t>(label);
    this->cross = cross;
    if (label && cross) {
      label->incShared();
    }
    if (oldLabel && oldCross) {
      oldLabel->decShared();
    }
  }

  /**
   * Release the label.
   */
  void releaseLabel() {
    auto label = getLabel();
    auto cross = isCross();
    this->label = 0;
    this->cross = false;
    if (label && cross) {
      label->decShared();
    }
  }

  /**
   * Object.
   */
  P object;

  /**
   * Raw pointer.
   */
  intptr_t label:63;

  /**
   * Is this pointer crossed? A crossed pointer is to a context different to
   * that of the context in which it was created (e.g. the context of the
   * object to which it belongs).
   */
  bool cross:1;
};

template<class P>
struct is_value<Lazy<P>> {
  static const bool value = false;
};

template<class P>
struct is_pointer<Lazy<P>> {
  static const bool value = true;
};
}
<|endoftext|>


<commit_before>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2017 Axel Waggershauser
*
* 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 "ByteArray.h"
#include "BlackboxTestRunner.h"
#include "ImageLoader.h"
#include "TestReader.h"
#include "GenericLuminanceSource.h"
#include "HybridBinarizer.h"
#include "TextUtfEncoding.h"
#include "ZXContainerAlgorithms.h"
#include "lodepng.h"

#include <iostream>
#include <fstream>
#include <set>

#if __has_include(<filesystem>)
#  include <filesystem>
#  ifdef __cpp_lib_filesystem
     namespace fs = std::filesystem;
#    define ZXING_HAS_FILESYSTEM
#  endif
#endif
#if !defined(ZXING_HAS_FILESYSTEM) && __has_include(<experimental/filesystem>)
#  include <experimental/filesystem>
#  ifdef __cpp_lib_experimental_filesystem
     namespace fs = std::experimental::filesystem;
#    define ZXING_HAS_FILESYSTEM
#  endif
#endif
#if defined(__APPLE__) && !defined(__clang__) &&                                                                       \
	__has_include(<dirent.h>) && defined(__SANITIZE_ADDRESS__) && defined(ZXING_HAS_FILESYSTEM)
#  warning detected gcc + macos + <filesystem> + address_sanitizer == bad -> disable <filesystem>
#  undef ZXING_HAS_FILESYSTEM
#endif
#if !defined(ZXING_HAS_FILESYSTEM)
#  if __has_include(<dirent.h>)
#    include <dirent.h>
#  else
#    error need <filesystem> or <dirent.h>
#  endif
#endif

// compiling this with clang (e.g. version 6) might require linking against libc++experimental.a or libc++fs.a.
// E.g.: CMAKE_EXE_LINKER_FLAGS = -L/usr/local/Cellar/llvm/6.0.1/lib -lc++experimental

using namespace ZXing;
using namespace ZXing::Test;

static std::string getExtension(const std::string& fn)
{
	auto p = fn.find_last_of(".");
	return p != std::string::npos ?	fn.substr(p) : "";
}

static std::shared_ptr<LuminanceSource> readPNM(FILE* f)
{
	int w, h;
	if (fscanf(f, "P5\n%d %d\n255\n", &w, &h) != 2)
		throw std::runtime_error("Failed to parse PNM file header.");
	auto ba = std::make_shared<ByteArray>(w * h);
	auto read = fread(ba->data(), sizeof(uint8_t), w*h, f);
//	if (read != w * h)
//		throw std::runtime_error("Failed to read PNM file data: " + std::to_string(read) + " != " + std::to_string(w * h) + " -> " + std::to_string(feof(f)));
	return std::make_shared<GenericLuminanceSource>(0, 0, w, h, ba, w);
}

static std::shared_ptr<LuminanceSource> readPNG(const std::string& filename)
{
	std::vector<unsigned char> buffer;
	unsigned width, height;
	unsigned error = lodepng::decode(buffer, width, height, filename);
	if (error) {
		throw std::runtime_error("Failed to read image");
	}
	return std::make_shared<GenericLuminanceSource>((int)width, (int)height, buffer.data(), width*4, 4, 0, 1, 2);
}

static std::shared_ptr<LuminanceSource> readImage(const std::string& filename)
{
	if( getExtension(filename) == ".png" )
		return readPNG(filename);

	std::string cmd = "convert '" + filename + "' -intensity Rec601Luma -colorspace gray +set comment pgm:-";
	bool pipe = getExtension(filename) != ".pgm";
	FILE* f = pipe ? popen(cmd.c_str(), "r") : fopen(filename.c_str(), "r");
	if (!f)
		throw std::runtime_error("Failed to open pipe '" + cmd + "': " + std::strerror(errno));
	try {
		auto res = readPNM(f);
		pipe ? pclose(f) : fclose(f);
		return res;
	} catch (std::runtime_error& e) {
		pipe ? pclose(f) : fclose(f);
		throw std::runtime_error("Failed to read pipe '" + cmd + "': " + e.what());
	}
}

class GenericImageLoader : public ImageLoader
{
public:
	std::shared_ptr<LuminanceSource> load(const std::wstring& filename) const final
	{
		return readImage(TextUtfEncoding::ToUtf8(filename));
	}
};

class GenericBlackboxTestRunner : public BlackboxTestRunner
{
public:
	GenericBlackboxTestRunner(const std::wstring& pathPrefix)
		: BlackboxTestRunner(pathPrefix, std::make_shared<GenericImageLoader>())
	{
	}

	std::vector<std::wstring> getImagesInDirectory(const std::wstring& dirPath) final
	{
		std::vector<std::wstring> result;
#ifndef ZXING_HAS_FILESYSTEM
		if (auto dir = opendir(TextUtfEncoding::ToUtf8(pathPrefix() + L"/" + dirPath).c_str())) {
			while (auto entry = readdir(dir)) {
				if (Contains({".png", ".jpg", ".pgm", ".gif"}, getExtension(entry->d_name))) {
					result.push_back(dirPath + L"/" + TextUtfEncoding::FromUtf8(entry->d_name));
				}
			}
			closedir(dir);
		}
		else {
			std::cerr << "Error open dir " << TextUtfEncoding::ToUtf8(dirPath) << std::endl;
		}
#else
		for (const auto& entry : fs::directory_iterator(fs::path(pathPrefix()) / dirPath))
			if (fs::is_regular_file(entry.status()) &&
			        Contains({".png", ".jpg", ".pgm", ".gif"}, entry.path().extension()))
				result.push_back(dirPath + L"/" + entry.path().filename().generic_wstring());
#endif
		return result;
	}
};

int main(int argc, char** argv)
{
	if (argc <= 1) {
		std::cout << "Usage: " << argv[0] << " <test_path_prefix>" << std::endl;
		return 0;
	}

	std::string pathPrefix = argv[1];

	GenericBlackboxTestRunner runner(TextUtfEncoding::FromUtf8(pathPrefix));

	if (Contains({".png", ".jpg", ".pgm", ".gif"}, getExtension(pathPrefix))) {
#if 0
		TestReader reader = runner.createReader(false, false, "QR_CODE");
#else
		TestReader reader = runner.createReader(true, true);
#endif
		bool isPure = getenv("IS_PURE");
		int rotation = getenv("ROTATION") ? atoi(getenv("ROTATION")) : 0;

		for (int i = 1; i < argc; ++i) {
			auto result = reader.read(TextUtfEncoding::FromUtf8(argv[i]), rotation, isPure);
			std::cout << argv[i] << ": ";
			if (result)
				std::cout << result.format << ": " << TextUtfEncoding::ToUtf8(result.text) << "\n";
			else
				std::cout << "FAILED\n";
		}
		return 0;
	}

	std::set<std::string> includedTests;
	for (int i = 2; i < argc; ++i) {
		if (std::strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 't') {
			includedTests.insert(argv[i] + 2);
		}
	}

	runner.run(includedTests);
}
<commit_msg>TestReader: support output of decoded text to file<commit_after>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2017 Axel Waggershauser
*
* 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 "ByteArray.h"
#include "BlackboxTestRunner.h"
#include "ImageLoader.h"
#include "TestReader.h"
#include "GenericLuminanceSource.h"
#include "HybridBinarizer.h"
#include "TextUtfEncoding.h"
#include "ZXContainerAlgorithms.h"
#include "lodepng.h"

#include <iostream>
#include <fstream>
#include <set>

#if __has_include(<filesystem>)
#  include <filesystem>
#  ifdef __cpp_lib_filesystem
     namespace fs = std::filesystem;
#    define ZXING_HAS_FILESYSTEM
#  endif
#endif
#if !defined(ZXING_HAS_FILESYSTEM) && __has_include(<experimental/filesystem>)
#  include <experimental/filesystem>
#  ifdef __cpp_lib_experimental_filesystem
     namespace fs = std::experimental::filesystem;
#    define ZXING_HAS_FILESYSTEM
#  endif
#endif
#if defined(__APPLE__) && !defined(__clang__) &&                                                                       \
	__has_include(<dirent.h>) && defined(__SANITIZE_ADDRESS__) && defined(ZXING_HAS_FILESYSTEM)
#  warning detected gcc + macos + <filesystem> + address_sanitizer == bad -> disable <filesystem>
#  undef ZXING_HAS_FILESYSTEM
#endif
#if !defined(ZXING_HAS_FILESYSTEM)
#  if __has_include(<dirent.h>)
#    include <dirent.h>
#  else
#    error need <filesystem> or <dirent.h>
#  endif
#endif

// compiling this with clang (e.g. version 6) might require linking against libc++experimental.a or libc++fs.a.
// E.g.: CMAKE_EXE_LINKER_FLAGS = -L/usr/local/Cellar/llvm/6.0.1/lib -lc++experimental

using namespace ZXing;
using namespace ZXing::Test;

static std::string getExtension(const std::string& fn)
{
	auto p = fn.find_last_of(".");
	return p != std::string::npos ?	fn.substr(p) : "";
}

static std::shared_ptr<LuminanceSource> readPNM(FILE* f)
{
	int w, h;
	if (fscanf(f, "P5\n%d %d\n255\n", &w, &h) != 2)
		throw std::runtime_error("Failed to parse PNM file header.");
	auto ba = std::make_shared<ByteArray>(w * h);
	auto read = fread(ba->data(), sizeof(uint8_t), w*h, f);
//	if (read != w * h)
//		throw std::runtime_error("Failed to read PNM file data: " + std::to_string(read) + " != " + std::to_string(w * h) + " -> " + std::to_string(feof(f)));
	return std::make_shared<GenericLuminanceSource>(0, 0, w, h, ba, w);
}

static std::shared_ptr<LuminanceSource> readPNG(const std::string& filename)
{
	std::vector<unsigned char> buffer;
	unsigned width, height;
	unsigned error = lodepng::decode(buffer, width, height, filename);
	if (error) {
		throw std::runtime_error("Failed to read image");
	}
	return std::make_shared<GenericLuminanceSource>((int)width, (int)height, buffer.data(), width*4, 4, 0, 1, 2);
}

static std::shared_ptr<LuminanceSource> readImage(const std::string& filename)
{
	if( getExtension(filename) == ".png" )
		return readPNG(filename);

	std::string cmd = "convert '" + filename + "' -intensity Rec601Luma -colorspace gray +set comment pgm:-";
	bool pipe = getExtension(filename) != ".pgm";
	FILE* f = pipe ? popen(cmd.c_str(), "r") : fopen(filename.c_str(), "r");
	if (!f)
		throw std::runtime_error("Failed to open pipe '" + cmd + "': " + std::strerror(errno));
	try {
		auto res = readPNM(f);
		pipe ? pclose(f) : fclose(f);
		return res;
	} catch (std::runtime_error& e) {
		pipe ? pclose(f) : fclose(f);
		throw std::runtime_error("Failed to read pipe '" + cmd + "': " + e.what());
	}
}

class GenericImageLoader : public ImageLoader
{
public:
	std::shared_ptr<LuminanceSource> load(const std::wstring& filename) const final
	{
		return readImage(TextUtfEncoding::ToUtf8(filename));
	}
};

class GenericBlackboxTestRunner : public BlackboxTestRunner
{
public:
	GenericBlackboxTestRunner(const std::wstring& pathPrefix)
		: BlackboxTestRunner(pathPrefix, std::make_shared<GenericImageLoader>())
	{
	}

	std::vector<std::wstring> getImagesInDirectory(const std::wstring& dirPath) final
	{
		std::vector<std::wstring> result;
#ifndef ZXING_HAS_FILESYSTEM
		if (auto dir = opendir(TextUtfEncoding::ToUtf8(pathPrefix() + L"/" + dirPath).c_str())) {
			while (auto entry = readdir(dir)) {
				if (Contains({".png", ".jpg", ".pgm", ".gif"}, getExtension(entry->d_name))) {
					result.push_back(dirPath + L"/" + TextUtfEncoding::FromUtf8(entry->d_name));
				}
			}
			closedir(dir);
		}
		else {
			std::cerr << "Error open dir " << TextUtfEncoding::ToUtf8(dirPath) << std::endl;
		}
#else
		for (const auto& entry : fs::directory_iterator(fs::path(pathPrefix()) / dirPath))
			if (fs::is_regular_file(entry.status()) &&
			        Contains({".png", ".jpg", ".pgm", ".gif"}, entry.path().extension()))
				result.push_back(dirPath + L"/" + entry.path().filename().generic_wstring());
#endif
		return result;
	}
};

int main(int argc, char** argv)
{
	if (argc <= 1) {
		std::cout << "Usage: " << argv[0] << " <test_path_prefix>" << std::endl;
		return 0;
	}

	std::string pathPrefix = argv[1];

	GenericBlackboxTestRunner runner(TextUtfEncoding::FromUtf8(pathPrefix));

	if (Contains({".png", ".jpg", ".pgm", ".gif"}, getExtension(pathPrefix))) {
#if 0
		TestReader reader = runner.createReader(false, false, "QR_CODE");
#else
		TestReader reader = runner.createReader(true, true);
#endif
		bool isPure = getenv("IS_PURE");
		int rotation = getenv("ROTATION") ? atoi(getenv("ROTATION")) : 0;

		for (int i = 1; i < argc; ++i) {
			auto result = reader.read(TextUtfEncoding::FromUtf8(argv[i]), rotation, isPure);
			std::cout << argv[i] << ": ";
			if (result)
				std::cout << result.format << ": " << TextUtfEncoding::ToUtf8(result.text) << "\n";
			else
				std::cout << "FAILED\n";
#ifdef ZXING_HAS_FILESYSTEM
			if (result && getenv("WRITE_TEXT")) {
				std::ofstream f(fs::path(argv[i]).replace_extension(".txt"));
				f << TextUtfEncoding::ToUtf8(result.text);
			}
#endif
		}
		return 0;
	}

	std::set<std::string> includedTests;
	for (int i = 2; i < argc; ++i) {
		if (std::strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 't') {
			includedTests.insert(argv[i] + 2);
		}
	}

	runner.run(includedTests);
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "test/gtest.h"
#include "test/scenario/scenario.h"

namespace webrtc {
namespace test {
namespace {
void CreateAnalyzedStream(Scenario* s,
                          NetworkNodeConfig network_config,
                          VideoQualityAnalyzer* analyzer) {
  VideoStreamConfig config;
  config.encoder.codec = VideoStreamConfig::Encoder::Codec::kVideoCodecVP8;
  config.encoder.implementation =
      VideoStreamConfig::Encoder::Implementation::kSoftware;
  config.hooks.frame_pair_handlers = {analyzer->Handler()};
  auto route = s->CreateRoutes(s->CreateClient("caller", CallClientConfig()),
                               {s->CreateSimulationNode(network_config)},
                               s->CreateClient("callee", CallClientConfig()),
                               {s->CreateSimulationNode(NetworkNodeConfig())});
  s->CreateVideoStream(route->forward(), config);
}
}  // namespace

TEST(ScenarioAnalyzerTest, PsnrIsHighWhenNetworkIsGood) {
  VideoQualityAnalyzer analyzer;
  {
    Scenario s;
    NetworkNodeConfig good_network;
    good_network.simulation.bandwidth = DataRate::kbps(1000);
    CreateAnalyzedStream(&s, good_network, &analyzer);
    s.RunFor(TimeDelta::seconds(1));
  }
  // This is mainty a regression test, the target is based on previous runs and
  // might change due to changes in configuration and encoder etc.
  EXPECT_GT(analyzer.stats().psnr.Mean(), 45);
}

TEST(ScenarioAnalyzerTest, PsnrIsLowWhenNetworkIsBad) {
  VideoQualityAnalyzer analyzer;
  {
    Scenario s;
    NetworkNodeConfig bad_network;
    bad_network.simulation.bandwidth = DataRate::kbps(100);
    bad_network.simulation.loss_rate = 0.02;
    CreateAnalyzedStream(&s, bad_network, &analyzer);
    s.RunFor(TimeDelta::seconds(1));
  }
  // This is mainty a regression test, the target is based on previous runs and
  // might change due to changes in configuration and encoder etc.
  EXPECT_LT(analyzer.stats().psnr.Mean(), 43);
}
}  // namespace test
}  // namespace webrtc
<commit_msg>Running scenario quality unit tests in simulated time.<commit_after>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "test/gtest.h"
#include "test/scenario/scenario.h"

namespace webrtc {
namespace test {
namespace {
void CreateAnalyzedStream(Scenario* s,
                          NetworkNodeConfig network_config,
                          VideoQualityAnalyzer* analyzer) {
  VideoStreamConfig config;
  config.encoder.codec = VideoStreamConfig::Encoder::Codec::kVideoCodecVP8;
  config.encoder.implementation =
      VideoStreamConfig::Encoder::Implementation::kSoftware;
  config.hooks.frame_pair_handlers = {analyzer->Handler()};
  auto route = s->CreateRoutes(s->CreateClient("caller", CallClientConfig()),
                               {s->CreateSimulationNode(network_config)},
                               s->CreateClient("callee", CallClientConfig()),
                               {s->CreateSimulationNode(NetworkNodeConfig())});
  s->CreateVideoStream(route->forward(), config);
}
}  // namespace

TEST(ScenarioAnalyzerTest, PsnrIsHighWhenNetworkIsGood) {
  VideoQualityAnalyzer analyzer;
  {
    Scenario s("", /*real_time*/ false);
    NetworkNodeConfig good_network;
    good_network.simulation.bandwidth = DataRate::kbps(1000);
    CreateAnalyzedStream(&s, good_network, &analyzer);
    s.RunFor(TimeDelta::seconds(1));
  }
  // This is mainty a regression test, the target is based on previous runs and
  // might change due to changes in configuration and encoder etc.
  EXPECT_GT(analyzer.stats().psnr.Mean(), 45);
}

TEST(ScenarioAnalyzerTest, PsnrIsLowWhenNetworkIsBad) {
  VideoQualityAnalyzer analyzer;
  {
    Scenario s("", /*real_time*/ false);
    NetworkNodeConfig bad_network;
    bad_network.simulation.bandwidth = DataRate::kbps(100);
    bad_network.simulation.loss_rate = 0.02;
    CreateAnalyzedStream(&s, bad_network, &analyzer);
    s.RunFor(TimeDelta::seconds(1));
  }
  // This is mainty a regression test, the target is based on previous runs and
  // might change due to changes in configuration and encoder etc.
  EXPECT_LT(analyzer.stats().psnr.Mean(), 43);
}
}  // namespace test
}  // namespace webrtc
<|endoftext|>


<commit_before>#include "microbench/microbench.h"

#include <cstdio>
#include <cstdlib>
#include <atomic>
#include <thread>
#include <cstdint>

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#define THREAD_LOCAL __declspec(thread)
#else
#define THREAD_LOCAL thread_local
#endif

uintptr_t ghetto_thread_id()
{
	static THREAD_LOCAL int x;
	return reinterpret_cast<uintptr_t>(&x);
}

int main(int argc, char** argv)
{
	std::atomic<int> x32(0);
	int y32 = rand();
	int z32 = rand();
	if (sizeof(x32) != 4) exit(1);

	std::atomic<long long> x64(0);
	long long y64 = rand();
	long long z64 = rand();
	if (sizeof(x64) != 8) exit(2);

	printf("32-bit CAS takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x32.compare_exchange_strong(y32, z32, std::memory_order_acq_rel); },
			1000000, /* iterations per test run */
			50 /* number of test runs */
		) * 1000 * 1000    // ms -> ns
	);

	printf("64-bit CAS takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x64.compare_exchange_strong(y64, z64, std::memory_order_acq_rel); },
			1000000,
			50
		) * 1000 * 1000
	);

	printf("32-bit FAA takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x32.fetch_add(y32, std::memory_order_acq_rel); },
			1000000,
			50
		) * 1000 * 1000
	);

	printf("64-bit FAA takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x64.fetch_add(y64, std::memory_order_acq_rel); },
			1000000,
			50
		) * 1000 * 1000
	);

	printf("std::this_thread::get_id() takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { std::this_thread::get_id(); },
			10000,
			50
		) * 1000 * 1000
	);

#ifdef _WIN32
	printf("GetCurrentThreadId() takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { GetCurrentThreadId(); },
			1000000,
			50
		) * 1000 * 1000
	);
#endif

#if !defined(__APPLE__) || (!defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE))
	volatile uintptr_t ghettoId = 0;
	printf("ghetto_thread_id() takes %.4fns on average\n",
		moodycamel::microbench(
		[&]() { ghettoId += ghetto_thread_id(); },
			1000000,
			50
		) * 1000 * 1000
	);
#endif

	return 0;
}
<commit_msg>Added mach pthread ID benchmark -- untested!<commit_after>#include "microbench/microbench.h"

#include <cstdio>
#include <cstdlib>
#include <atomic>
#include <thread>
#include <cstdint>

#ifdef __APPLE__
#include <pthread.h>
#endif

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#define THREAD_LOCAL __declspec(thread)
#else
#define THREAD_LOCAL thread_local
#endif

uintptr_t ghetto_thread_id()
{
	static THREAD_LOCAL int x;
	return reinterpret_cast<uintptr_t>(&x);
}

int main(int argc, char** argv)
{
	std::atomic<int> x32(0);
	int y32 = rand();
	int z32 = rand();
	if (sizeof(x32) != 4) exit(1);

	std::atomic<long long> x64(0);
	long long y64 = rand();
	long long z64 = rand();
	if (sizeof(x64) != 8) exit(2);

	printf("32-bit CAS takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x32.compare_exchange_strong(y32, z32, std::memory_order_acq_rel); },
			1000000, /* iterations per test run */
			50 /* number of test runs */
		) * 1000 * 1000    // ms -> ns
	);

	printf("64-bit CAS takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x64.compare_exchange_strong(y64, z64, std::memory_order_acq_rel); },
			1000000,
			50
		) * 1000 * 1000
	);

	printf("32-bit FAA takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x32.fetch_add(y32, std::memory_order_acq_rel); },
			1000000,
			50
		) * 1000 * 1000
	);

	printf("64-bit FAA takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { x64.fetch_add(y64, std::memory_order_acq_rel); },
			1000000,
			50
		) * 1000 * 1000
	);

	printf("std::this_thread::get_id() takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { std::this_thread::get_id(); },
			10000,
			50
		) * 1000 * 1000
	);

#ifdef _WIN32
	printf("GetCurrentThreadId() takes %.4fns on average\n",
		moodycamel::microbench(
			[&]() { GetCurrentThreadId(); },
			1000000,
			50
		) * 1000 * 1000
	);
#endif

#if !defined(__APPLE__) || (!defined(TARGET_IPHONE_SIMULATOR) && !defined(TARGET_OS_IPHONE))
	volatile uintptr_t ghettoId = 0;
	printf("ghetto_thread_id() takes %.4fns on average\n",
		moodycamel::microbench(
		[&]() { ghettoId += ghetto_thread_id(); },
			1000000,
			50
		) * 1000 * 1000
	);
#endif

#ifdef __APPLE__
	volatile mach_port_t machId = 0;
	printf("pthread_mach_thread_np(pthread_self()) takes %.4fns on average\n",
		moodycamel::microbench(
		[&]() { machId = pthread_mach_thread_np(pthread_self()); },
			1000000,
			50
		) * 1000 * 1000
	);
#endif

	return 0;
}
<|endoftext|>


<commit_before>#include <ncurses.h>
#include <utility>

#include "board.hpp"
#include "print.hpp"
#include "reversi.hpp"

namespace roadagain
{

Reversi::Reversi() : black_(2), white_(2)
{
}

Reversi::~Reversi()
{
}

void Reversi::start()
{
    print();
}

std::pair<int, int> Reversi::put()
{
    int y = 0;
    int x = 0;
    char c = getch();

    while (c != '\n'){

        switch (c){
          case 'h':
            x = (x + Board::COL - 1) % Board::COL;
            break;
          case 'j':
            y = (y + 1) % Board::ROW;
            break;
          case 'k':
            y = (y + Board::ROW - 1) % Board::ROW;
            break;
          case 'l':
            x = (x + 1) % Board::COL;
            break;
        }
        print_stone(y, x, BLACK);
    }

    return (std::pair<int, int>(y, x));
}

}
<commit_msg>Moved getch from initialize to substitute<commit_after>#include <ncurses.h>
#include <utility>

#include "board.hpp"
#include "print.hpp"
#include "reversi.hpp"

namespace roadagain
{

Reversi::Reversi() : black_(2), white_(2)
{
}

Reversi::~Reversi()
{
}

void Reversi::start()
{
    print();
}

std::pair<int, int> Reversi::put()
{
    int y = 0;
    int x = 0;
    char c;

    c = getch();
    while (c != '\n'){
        switch (c){
          case 'h':
            x = (x + Board::COL - 1) % Board::COL;
            break;
          case 'j':
            y = (y + 1) % Board::ROW;
            break;
          case 'k':
            y = (y + Board::ROW - 1) % Board::ROW;
            break;
          case 'l':
            x = (x + 1) % Board::COL;
            break;
        }
        print_stone(y, x, BLACK);
        c = getch();
    }

    return (std::pair<int, int>(y, x));
}

}
<|endoftext|>


<commit_before>#include "VM.hpp"
#include "detail/ruby.hpp"

#ifndef RUBY_VM
extern C
{
#include "env.h"
}
#endif

#include <stdexcept>

Rice::VM::
VM(char * app_name)
{
  Object o;
  init_stack(&o);
  init(1, &app_name);
}

Rice::VM::
VM(int argc, char * argv[])
{
  Object o;
  init_stack(&o);
  init(argc, argv);
}

Rice::VM::
VM(std::vector<char *> const & args)
{
  check_not_initialized();
  Object o;
  init_stack(&o);
  init(args.size(), const_cast<char * *>(&args[0]));
}

Rice::VM::
~VM()
{
  Object o;
  init_stack(&o);
}

#if RUBY_VERSION_CODE < 186
  extern "C"
  void Init_stack(VALUE *);
#endif

void Rice::VM::
init_stack(Object * location_on_stack)
{
  VALUE * v = const_cast<VALUE *>(&location_on_stack->value());
#if RUBY_VERSION_CODE >= 186
  ruby_init_stack(v);
#else
  Init_stack(v);
#endif
}

void Rice::VM::
run()
{
  Object o;
  init_stack(&o);
#ifdef RUBY_VM
#else
  ruby_run();
#endif
}

extern "C"
{

RUBY_EXTERN VALUE * rb_gc_stack_start;

}

void Rice::VM::
check_not_initialized() const
{
  if(rb_gc_stack_start)
  {
    throw std::runtime_error("Only one VM allowed per application");
  }
}

void Rice::VM::
init(int argc, char * argv[])
{
  ruby_init();
  ruby_options(argc, argv);
}

<commit_msg>Fixed extern C to extern "C".<commit_after>#include "VM.hpp"
#include "detail/ruby.hpp"

#ifndef RUBY_VM
extern "C"
{
#include "env.h"
}
#endif

#include <stdexcept>

Rice::VM::
VM(char * app_name)
{
  Object o;
  init_stack(&o);
  init(1, &app_name);
}

Rice::VM::
VM(int argc, char * argv[])
{
  Object o;
  init_stack(&o);
  init(argc, argv);
}

Rice::VM::
VM(std::vector<char *> const & args)
{
  check_not_initialized();
  Object o;
  init_stack(&o);
  init(args.size(), const_cast<char * *>(&args[0]));
}

Rice::VM::
~VM()
{
  Object o;
  init_stack(&o);
}

#if RUBY_VERSION_CODE < 186
  extern "C"
  void Init_stack(VALUE *);
#endif

void Rice::VM::
init_stack(Object * location_on_stack)
{
  VALUE * v = const_cast<VALUE *>(&location_on_stack->value());
#if RUBY_VERSION_CODE >= 186
  ruby_init_stack(v);
#else
  Init_stack(v);
#endif
}

void Rice::VM::
run()
{
  Object o;
  init_stack(&o);
#ifdef RUBY_VM
#else
  ruby_run();
#endif
}

extern "C"
{

RUBY_EXTERN VALUE * rb_gc_stack_start;

}

void Rice::VM::
check_not_initialized() const
{
  if(rb_gc_stack_start)
  {
    throw std::runtime_error("Only one VM allowed per application");
  }
}

void Rice::VM::
init(int argc, char * argv[])
{
  ruby_init();
  ruby_options(argc, argv);
}

<|endoftext|>


<commit_before>/*
   Source File : RotatedPagesPDF.cpp

   Copyright 2011 Gal Kahana PDFWriter

   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 "RotatedPagesPDF.h"
#include "PageContentContext.h"
#include "PDFWriter.h"
#include "PDFPage.h"
#include "PDFRectangle.h"
#include "PDFPageInput.h"
#include "TestsRunner.h"

#include <iostream>

using namespace std;
using namespace PDFHummus;

RotatedPagesPDF::RotatedPagesPDF(void)
{
}

RotatedPagesPDF::~RotatedPagesPDF(void)
{
}

EStatusCode RotatedPagesPDF::Run(const TestConfiguration& inTestConfiguration)
{
	LogConfiguration logConfiguration(true,true,RelativeURLToLocalPath(inTestConfiguration.mSampleFileBase,"RotatedPagesLog.txt"));
	EStatusCode status;

	do
	{
		// PDF Page rotation writing

		PDFWriter pdfWriter;
		status = pdfWriter.StartPDF(RelativeURLToLocalPath(inTestConfiguration.mSampleFileBase,"RotatedPages.PDF"),ePDFVersion13,logConfiguration);
		if(status != PDFHummus::eSuccess)
		{
			cout<<"failed to start PDF\n";
			break;
		}

		AbstractContentContext::TextOptions textOptions(pdfWriter.GetFontForFile(
																			RelativeURLToLocalPath(
                                                                            inTestConfiguration.mSampleFileBase,
                                                                            "TestMaterials/fonts/arial.ttf")),
																			14,
																			AbstractContentContext::eGray,
																			0);

		for(int i=0;i<4 && PDFHummus::eSuccess == status;++i)
		{
			PDFPage page;
			page.SetMediaBox(PDFRectangle(0,0,595,842));
			page.SetRotate(i*90);

			std::ostringstream s;
			s << "Page rotated by " << i*90 << " degrees.";

			PageContentContext* cxt = pdfWriter.StartPageContentContext(&page);
			cxt->WriteText(75,805,s.str(),textOptions);
			status = pdfWriter.EndPageContentContext(cxt);
			if(status != eSuccess)
			{
				status = PDFHummus::eFailure;
				cout<<"Failed to end content context\n";
				break;
			}

			status = pdfWriter.WritePage(&page);
			if(status != PDFHummus::eSuccess)
				cout<<"failed to write page "<<i<<"\n";
		}

		status = pdfWriter.EndPDF();
		if(status != PDFHummus::eSuccess)
		{
			cout<<"failed in end PDF\n";
			break;
		}

		// PDF Page rotation parsing

		InputFile pdfFile;
		PDFParser pdfParser;

		status = pdfFile.OpenFile(RelativeURLToLocalPath(inTestConfiguration.mSampleFileBase,"RotatedPages.PDF"));
		if(status != PDFHummus::eSuccess)
		{
			cout<<"unable to open file for reading. should be in TestMaterials/XObjectContent.PDF\n";
			break;
		}

		status = pdfParser.StartPDFParsing(pdfFile.GetInputStream());
		if(status != PDFHummus::eSuccess)
		{
			cout<<"unable to parse input file";
			break;
		}

		if(pdfParser.GetPagesCount() != 4)
		{
			cout<<"expecting 4 pages, got "<<pdfParser.GetPagesCount()<<"\n";
			status = PDFHummus::eFailure;
			break;
		}

		for(int i=0;i<4 && PDFHummus::eSuccess == status;++i)
		{
			RefCountPtr<PDFDictionary> page = pdfParser.ParsePage(i);
			if (!page)
			{
				cout << i << ". page parsing failed\n";
				status = PDFHummus::eFailure;
				break;
			}

			PDFPageInput input( &pdfParser, page );
			if ( input.GetRotate() != i*90 )
			{
				cout<< i << ". page has invalid rotation\n";
				status = PDFHummus::eFailure;
				break;
			}
		}

	}while(false);
	return status;
}

ADD_CATEGORIZED_TEST(RotatedPagesPDF,"PDF")
<commit_msg>Add test for invalid rotation (must be multiple of 90)<commit_after>/*
   Source File : RotatedPagesPDF.cpp

   Copyright 2011 Gal Kahana PDFWriter

   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 "RotatedPagesPDF.h"
#include "PageContentContext.h"
#include "PDFWriter.h"
#include "PDFPage.h"
#include "PDFRectangle.h"
#include "PDFPageInput.h"
#include "TestsRunner.h"

#include <iostream>

using namespace std;
using namespace PDFHummus;

RotatedPagesPDF::RotatedPagesPDF(void)
{
}

RotatedPagesPDF::~RotatedPagesPDF(void)
{
}

EStatusCode RotatedPagesPDF::Run(const TestConfiguration& inTestConfiguration)
{
	LogConfiguration logConfiguration(true,true,RelativeURLToLocalPath(inTestConfiguration.mSampleFileBase,"RotatedPagesLog.txt"));
	EStatusCode status;

	do
	{
		// PDF Page rotation writing

		PDFWriter pdfWriter;
		status = pdfWriter.StartPDF(RelativeURLToLocalPath(inTestConfiguration.mSampleFileBase,"RotatedPages.PDF"),ePDFVersion13,logConfiguration);
		if(status != PDFHummus::eSuccess)
		{
			cout<<"failed to start PDF\n";
			break;
		}

		AbstractContentContext::TextOptions textOptions(pdfWriter.GetFontForFile(
																			RelativeURLToLocalPath(
                                                                            inTestConfiguration.mSampleFileBase,
                                                                            "TestMaterials/fonts/arial.ttf")),
																			14,
																			AbstractContentContext::eGray,
																			0);

		for(int i=0;i<4 && PDFHummus::eSuccess == status;++i)
		{
			PDFPage page;
			page.SetMediaBox(PDFRectangle(0,0,595,842));

			page.SetRotate(33);
			if ( page.GetRotate().second != 0 )
			{
				status = PDFHummus::eFailure;
				cout<<"Failed to reject invalid rotation\n";
				break;
			}

			page.SetRotate(i*90);

			std::ostringstream s;
			s << "Page rotated by " << i*90 << " degrees.";

			PageContentContext* cxt = pdfWriter.StartPageContentContext(&page);
			cxt->WriteText(75,805,s.str(),textOptions);
			status = pdfWriter.EndPageContentContext(cxt);
			if(status != eSuccess)
			{
				status = PDFHummus::eFailure;
				cout<<"Failed to end content context\n";
				break;
			}

			status = pdfWriter.WritePage(&page);
			if(status != PDFHummus::eSuccess)
				cout<<"failed to write page "<<i<<"\n";
		}

		status = pdfWriter.EndPDF();
		if(status != PDFHummus::eSuccess)
		{
			cout<<"failed in end PDF\n";
			break;
		}

		// PDF Page rotation parsing

		InputFile pdfFile;
		PDFParser pdfParser;

		status = pdfFile.OpenFile(RelativeURLToLocalPath(inTestConfiguration.mSampleFileBase,"RotatedPages.PDF"));
		if(status != PDFHummus::eSuccess)
		{
			cout<<"unable to open file for reading. should be in TestMaterials/XObjectContent.PDF\n";
			break;
		}

		status = pdfParser.StartPDFParsing(pdfFile.GetInputStream());
		if(status != PDFHummus::eSuccess)
		{
			cout<<"unable to parse input file";
			break;
		}

		if(pdfParser.GetPagesCount() != 4)
		{
			cout<<"expecting 4 pages, got "<<pdfParser.GetPagesCount()<<"\n";
			status = PDFHummus::eFailure;
			break;
		}

		for(int i=0;i<4 && PDFHummus::eSuccess == status;++i)
		{
			RefCountPtr<PDFDictionary> page = pdfParser.ParsePage(i);
			if (!page)
			{
				cout << i << ". page parsing failed\n";
				status = PDFHummus::eFailure;
				break;
			}

			PDFPageInput input( &pdfParser, page );
			if ( input.GetRotate() != i*90 )
			{
				cout<< i << ". page has invalid rotation\n";
				status = PDFHummus::eFailure;
				break;
			}
		}

	}while(false);
	return status;
}

ADD_CATEGORIZED_TEST(RotatedPagesPDF,"PDF")
<|endoftext|>


<commit_before>#include "server_functions.h"
#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *> * > proc_loc_dict;
static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/
void registration_request_handler(RegisterRequestMessage * message, int sock){
	char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature * key = new procedure_signature(name, argTypes);

  int status = 0;

  //if no key dosnt exist in map
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //Adding to the map

    //int *memArgTypes = copyArgTypes(argTypes);
    //key = procedure_signature(name, memArgTypes);

    proc_loc_dict[key] = new list<server_info *>();
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, key);
    roundRobinList.push_back(info);

  }else{

    bool sameLoc = false;
    list<server_info *> *hostList = proc_loc_dict[key]; // proc_loc_dict.find[key]

    for (list<server_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      // IF THEY ARE AT THE SAME PLACE, THEY SHOULD HAVE TEH SAME SOCKET
      if((*it)->socket == sock){
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something
        sameLoc = true;
      }

    }
    //Same procedure signature, different location
  	if(!sameLoc){
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList->push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

    //If the name are the same
    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){

      exist = true;

      LocSuccessMessage * success_message = new LocSuccessMessage((*it)->si->server_identifier, (*it)->si->port);

      success_message->send(sock);

      //When we have identified the correct procedure_signature use round robin and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);

      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

// Returns the binder address
string getBinderAddress() {
   char hostname[MAXHOSTNAMELEN + 1] = {'\0'};
   gethostname(hostname, sizeof(hostname));
   return string(hostname);
}

// Returns the binder port
int getBinderPort(int welcomeSocket) {
   struct sockaddr_in binderAddress;
   socklen_t binderAddressLength = sizeof(binderAddress);

   int result = getsockname(welcomeSocket, (struct sockaddr*) &binderAddress,
      &binderAddressLength);
   if (result < 0) {
      exit(-1);
   } // if

   return ntohs(binderAddress.sin_port);
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  cout << "BINDER_ADDRESS " << getBinderAddress() << endl;
  cout << "BINDER_PORT " << getBinderPort(sock) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            status = Segment::receive(sock, segment);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return status;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return status;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<commit_msg>changes<commit_after>#include "server_functions.h"
#include <string.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include <netdb.h>
#include <stdlib.h>

#include "segment.h"
#include "message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"

#include "rpc.h"
#include "constants.h"
#include "helper_function.h"
#include "message_types.h"

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

static map<procedure_signature, list<server_info *> * > proc_loc_dict;
static list<server_function_info *> roundRobinList;

/*
TODO:
ADD FUNCTION TO MAP
ADD FUNCTION TO ROUND ROBIN
IF FUNCTION EXISTS IN ROUND ROBIN DELETE OLD REPLACE WITH NEW (where)
*/
void registration_request_handler(RegisterRequestMessage * message, int sock){
	char * name = message->getName().c_str();
  int * argTypes = message->getArgTypes();
  string server_identifier = message->getServerIdentifier();
  int port = message->getPort();

  procedure_signature * key = new procedure_signature(name, argTypes);

  int status = 0;

  //if no key dosnt exist in map
	if (proc_loc_dict.find(key) == proc_loc_dict.end()) {
    //Adding to the map

    //int *memArgTypes = copyArgTypes(argTypes);
    //key = procedure_signature(name, memArgTypes);

    proc_loc_dict[key] = new list<server_info *>();
    server_info * entry = new server_info(server_identifier, port, sock);

    //Adding to roundRobinList
    server_function_info * info = new server_function_info(entry, key);
    roundRobinList.push_back(info);

  }else{

    bool sameLoc = false;
    //list<server_info *> *hostList = proc_loc_dict[key];
    list<server_info *> *hostList = proc_loc_dict.find(key);

    for (list<server_info *>::iterator it = hostList->begin(); it != hostList->end(); it++) {
      // IF THEY ARE AT THE SAME PLACE, THEY SHOULD HAVE TEH SAME SOCKET
      if((*it)->socket == sock){
        //The same procedure signature already exists on the same location
        //TODO: Move to end of round robin or something
        sameLoc = true;
      }

    }
    //Same procedure signature, different location
  	if(!sameLoc){
       server_info * new_msg_loc = new server_info(server_identifier, port, sock);
       hostList->push_back(new_msg_loc);
    }
  }

  RegisterSuccessMessage * success_message = new RegisterSuccessMessage(status);
  success_message->send(sock);
}

/*
TODO:
USE ROUND ROBIN TO ACCESS THE CORRECT SERVER/FUNCTION FOR THE CLIENT
*/
int location_request_handler(LocRequestMessage * message, int sock){

  bool exist = false;
	for (list<server_function_info *>::iterator it = roundRobinList.begin(); it != roundRobinList.end(); it++){

    //If the name are the same
    if((*it)->ps->name == message->getName() && compareArr((*it)->ps->argTypes, message->getArgTypes() )){

      exist = true;

      LocSuccessMessage * success_message = new LocSuccessMessage((*it)->si->server_identifier, (*it)->si->port);

      success_message->send(sock);

      //When we have identified the correct procedure_signature use round robin and move that service to the end
      roundRobinList.splice(roundRobinList.end(), roundRobinList, it);

      break;
 		}
	}

  if(!exist){
    int reasoncode = 0;
    LocFailureMessage * failure_message = new LocFailureMessage(reasoncode);
    failure_message->send(sock);
  }

	return 0; //LOC_FAILURE
}

int request_handler(Segment * segment, int sock){
  int retval = 0;
  if(segment->getType() == MSG_TYPE_REGISTER_REQUEST){ //'LOC_REQUEST'
    Message * cast1 = segment->getMessage();
    RegisterRequestMessage * rrm = dynamic_cast<RegisterRequestMessage*>(cast1);
    registration_request_handler(rrm, sock);

  }else if (segment->getType() == MSG_TYPE_LOC_REQUEST){ //'REGISTER'
    Message * cast2 = segment->getMessage();
    LocRequestMessage * lqm = dynamic_cast<LocRequestMessage*>(cast2);
    retval = location_request_handler(lqm, sock);
  }

	return retval;
}

// Returns the binder address
string getBinderAddress() {
   char hostname[MAXHOSTNAMELEN + 1] = {'\0'};
   gethostname(hostname, sizeof(hostname));
   return string(hostname);
}

// Returns the binder port
int getBinderPort(int welcomeSocket) {
   struct sockaddr_in binderAddress;
   socklen_t binderAddressLength = sizeof(binderAddress);

   int result = getsockname(welcomeSocket, (struct sockaddr*) &binderAddress,
      &binderAddressLength);
   if (result < 0) {
      exit(-1);
   } // if

   return ntohs(binderAddress.sin_port);
}

//TODO:
//Create helper functions that can be used for rpcServer.cc
int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  cout << "BINDER_ADDRESS " << getBinderAddress() << endl;
  cout << "BINDER_PORT " << getBinderPort(sock) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
       if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;
          if (FD_ISSET(tempConnection, &readfds)) {

            Segment * segment = 0;
            status = Segment::receive(sock, segment);

            if (status < 0) {
                RegisterFailureMessage * failure_message = new RegisterFailureMessage(status);
                failure_message->send(sock);
                return status;
            }

            if (status == 0) {
              // client has closed the connection
              myToRemove.push_back(sock);
              return status;
            }

            request_handler(segment, sock);
          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<|endoftext|>