<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_MAYBE_HPP
#define CAF_MAYBE_HPP

#include <new>
#include <utility>
#include <system_error>

#include "caf/none.hpp"
#include "caf/unit.hpp"
#include "caf/config.hpp"

#include "caf/detail/safe_equal.hpp"

namespace caf {

/// Represents a computation returning either `T` or `std::error_condition`.
/// Note that the error condition might be default-constructed. In this case,
/// a `maybe` represents simply `none`. Hence, this type has three possible
/// states:
/// - A value of `T` is available
///   + `available()` returns `true`
///   + `empty()` returns `false`
///   + `error()` evaluates to `false`
/// -  No value is available but no error occurred
///   + `available()` returns `false`
///   + `empty()` returns `true`
///   + `error()` evaluates to `false`
/// - An error occurred (no value available)
///   + `available()` returns `false`
///   + `empty()` returns `false`
///   + `error()` evaluates to `true`
template <class T>
class maybe {
public:
  using type = typename std::remove_reference<T>::type;
  using reference = type&;
  using const_reference = const type&;
  using pointer = type*;
  using const_pointer = const type*;
  using error_type = std::error_condition;

  /// Type for storing values.
  using storage =
    typename std::conditional<
      std::is_reference<T>::value,
      std::reference_wrapper<type>,
      T
    >::type;

  /// Creates an instance representing an error.
  maybe(error_type err) {
    cr_error(std::move(err));
  }

  /// Creates an instance representing `value`.
  maybe(T value) {
    cr_moved_value(value);
  }

  /// Creates an instance representing an error
  /// from an error condition enum.
  template <class E,
            class = typename std::enable_if<
                      std::is_error_condition_enum<E>::value
                    >::type>
  maybe(E error_code_enum) {
    cr_error(std::make_error_condition(error_code_enum));
  }

  /// Creates an empty instance.
  maybe() {
    cr_error(error_type{});
  }

  /// Creates an empty instance.
  maybe(const none_t&) {
    cr_error(error_type{});
  }

  maybe(const maybe& other) {
    if (other.available_)
      cr_value(other.value_);
    else
      cr_error(other.error_);
  }

  maybe(maybe&& other) {
    if (other.available_)
      cr_moved_value(other.value_);
    else
      cr_error(std::move(other.error_));
  }

  template <class U>
  maybe(maybe<U>&& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    if (other)
      cr_moved_value(*other);
    else
      cr_error(std::move(other.error()));
  }

  template <class U>
  maybe(const maybe<U>& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    if (other)
      cr_value(*other);
    else
      cr_error(other.error());
  }

  ~maybe() {
    destroy();
  }

  maybe& operator=(const none_t&) {
    if (available_) {
      destroy();
      cr_error(error_type{});
    } else if (error_) {
      error_ = error_type{};
    }
    return *this;
  }

  maybe& operator=(T value) {
    if (! available_) {
      destroy();
      cr_moved_value(value);
    } else {
      assign_moved_value(value);
    }
    return *this;
  }

  maybe& operator=(error_type err) {
    if (available_) {
      destroy();
      cr_error(std::move(err));
    } else {
      error_ = std::move(err);
    }
    return *this;
  }

  template <class E,
            class = typename std::enable_if<
              std::is_error_condition_enum<E>::value
            >::type>
  maybe& operator=(E error_code_enum) {
    return *this = std::make_error_condition(error_code_enum);
  }

  maybe& operator=(maybe&& other) {
    return other ? *this = std::move(*other) : *this = std::move(other.error());
  }

  maybe& operator=(const maybe& other) {
    return other ? *this = *other : *this = other.error();
  }

  template <class U>
  maybe& operator=(maybe<U>&& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    return other ? *this = std::move(*other) : *this = std::move(other.error());
  }

  template <class U>
  maybe& operator=(const maybe<U>& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    return other ? *this = *other : *this = other.error();
  }

  /// Queries whether this instance holds a value.
  bool available() const {
    return available_;
  }

  /// Returns `available()`.
  explicit operator bool() const {
    return available();
  }

  /// Returns `! available()`.
  bool operator!() const {
    return ! available();
  }

  /// Returns the value.
  reference get() {
    CAF_ASSERT(available());
    return value_;
  }

  /// Returns the value.
  const_reference get() const {
    CAF_ASSERT(available());
    return value_;
  }

  /// Returns the value.
  reference operator*() {
    return get();
  }

  /// Returns the value.
  const_reference operator*() const {
    return get();
  }

  /// Returns a pointer to the value.
  pointer operator->() {
    return &get();
  }

  /// Returns a pointer to the value.
  const_pointer operator->() const {
    return &get();
  }

  /// Returns whether this objects holds neither a value nor an actual error.
  bool empty() const {
    return ! available() && ! error();
  }

  /// Returns the error.
  const error_type& error() const {
    CAF_ASSERT(! available());
    return error_;
  }

private:
  void destroy() {
    if (available_)
      value_.~storage();
    else
      error_.~error_type();
  }

  void cr_moved_value(reference x) {
    // convert to rvalue if possible
    using fwd_type =
      typename std::conditional<
        ! std::is_reference<T>::value,
        type&&,
        type&
      >::type;
    available_ = true;
    new (&value_) storage(static_cast<fwd_type>(x));
  }

  void assign_moved_value(reference x) {
    using fwd_type =
      typename std::conditional<
        ! std::is_reference<T>::value,
        type&&,
        type&
      >::type;
    value_ = static_cast<fwd_type>(x);
  }

  template <class V>
  void cr_value(V&& x) {
    available_ = true;
    new (&value_) storage(std::forward<V>(x));
  }

  void cr_error(std::error_condition ec) {
    available_ = false;
    new (&error_) error_type(std::move(ec));
  }

  bool available_;
  union {
    storage value_;
    error_type error_;
  };
};

/// Returns `true` if both objects represent either the same
/// value or the same error, `false` otherwise.
/// @relates maybe
template <class T, typename U>
bool operator==(const maybe<T>& lhs, const maybe<U>& rhs) {
  if (lhs)
    return (rhs) ? detail::safe_equal(*lhs, *rhs) : false;
  if (! rhs)
    return lhs.error() == rhs.error();
  return false;
}

/// Returns `true` if `lhs` is available and its value is equal to `rhs`.
template <class T, typename U>
bool operator==(const maybe<T>& lhs, const U& rhs) {
  return (lhs) ? *lhs == rhs : false;
}

/// Returns `true` if `rhs` is available and its value is equal to `lhs`.
/// @relates maybe
template <class T, typename U>
bool operator==(const T& lhs, const maybe<U>& rhs) {
  return rhs == lhs;
}

/// Returns `true` if the objects represent different
/// values or errors, `false` otherwise.
/// @relates maybe
template <class T, typename U>
bool operator!=(const maybe<T>& lhs, const maybe<U>& rhs) {
  return !(lhs == rhs);
}

/// Returns `true` if `lhs` is not available or its value is not equal to `rhs`.
/// @relates maybe
template <class T, typename U>
bool operator!=(const maybe<T>& lhs, const U& rhs) {
  return !(lhs == rhs);
}

/// Returns `true` if `rhs` is not available or its value is not equal to `lhs`.
/// @relates maybe
template <class T, typename U>
bool operator!=(const T& lhs, const maybe<U>& rhs) {
  return !(lhs == rhs);
}

/// Returns `! val.available() && val.error() == err`.
/// @relates maybe
template <class T>
bool operator==(const maybe<T>& val, const std::error_condition& err) {
  return ! val.available() && val.error() == err;
}

/// Returns `! val.available() && val.error() == err`.
/// @relates maybe
template <class T>
bool operator==(const std::error_condition& err, const maybe<T>& val) {
  return val == err;
}

/// Returns `val.available() || val.error() != err`.
/// @relates maybe
template <class T>
bool operator!=(const maybe<T>& val, const std::error_condition& err) {
  return ! (val == err);
}

/// Returns `val.available() || val.error() != err`.
/// @relates maybe
template <class T>
bool operator!=(const std::error_condition& err, const maybe<T>& val) {
  return ! (val == err);
}

/// Returns `val.empty()`.
/// @relates maybe
template <class T>
bool operator==(const maybe<T>& val, const none_t&) {
  return val.empty();
}

/// Returns `val.empty()`.
/// @relates maybe
template <class T>
bool operator==(const none_t&, const maybe<T>& val) {
  return val.empty();
}

/// Returns `! val.empty()`.
/// @relates maybe
template <class T>
bool operator!=(const maybe<T>& val, const none_t&) {
  return ! val.empty();
}

/// Returns `! val.empty()`.
/// @relates maybe
template <class T>
bool operator!=(const none_t&, const maybe<T>& val) {
  return ! val.empty();
}

// Represents a computation performing side effects only and
// optionally return a `std::error_condition`.
template <>
class maybe<void> {
public:
  using type = unit_t;
  using reference = const type&;
  using const_reference = const type&;
  using pointer = const type*;
  using const_pointer = const type*;
  using error_type = std::error_condition;

  maybe() = default;

  maybe(const none_t&) {
    // nop
  }

  maybe(error_type err) : error_(std::move(err)) {
    // nop
  }

  maybe& operator=(const none_t&) {
    error_.clear();
    return *this;
  }

  maybe& operator=(error_type err) {
    error_ = std::move(err);
    return *this;
  }

  bool available() const {
    return false;
  }

  explicit operator bool() const {
    return available();
  }

  bool operator!() const {
    return ! available();
  }

  reference get() {
    CAF_ASSERT(! "should never be called");
    return unit;
  }

  const_reference get() const {
    CAF_ASSERT(! "should never be called");
    return unit;
  }

  reference operator*() {
    return get();
  }

  const_reference operator*() const {
    return get();
  }

  pointer operator->() {
    return &get();
  }

  const_pointer operator->() const {
    return &get();
  }

  bool empty() const {
    return ! error();
  }

  const error_type& error() const {
    return error_;
  }

private:
  error_type error_;
};

} // namespace caf

#endif // CAF_MAYBE_HPP
<commit_msg>Enable ADL on make_error_condition<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_MAYBE_HPP
#define CAF_MAYBE_HPP

#include <new>
#include <utility>
#include <system_error>

#include "caf/none.hpp"
#include "caf/unit.hpp"
#include "caf/config.hpp"

#include "caf/detail/safe_equal.hpp"

namespace caf {

/// Represents a computation returning either `T` or `std::error_condition`.
/// Note that the error condition might be default-constructed. In this case,
/// a `maybe` represents simply `none`. Hence, this type has three possible
/// states:
/// - A value of `T` is available
///   + `available()` returns `true`
///   + `empty()` returns `false`
///   + `error()` evaluates to `false`
/// -  No value is available but no error occurred
///   + `available()` returns `false`
///   + `empty()` returns `true`
///   + `error()` evaluates to `false`
/// - An error occurred (no value available)
///   + `available()` returns `false`
///   + `empty()` returns `false`
///   + `error()` evaluates to `true`
template <class T>
class maybe {
public:
  using type = typename std::remove_reference<T>::type;
  using reference = type&;
  using const_reference = const type&;
  using pointer = type*;
  using const_pointer = const type*;
  using error_type = std::error_condition;

  /// Type for storing values.
  using storage =
    typename std::conditional<
      std::is_reference<T>::value,
      std::reference_wrapper<type>,
      T
    >::type;

  /// Creates an instance representing an error.
  maybe(error_type err) {
    cr_error(std::move(err));
  }

  /// Creates an instance representing `value`.
  maybe(T value) {
    cr_moved_value(value);
  }

  /// Creates an instance representing an error
  /// from an error condition enum.
  template <class E,
            class = typename std::enable_if<
                      std::is_error_condition_enum<E>::value
                    >::type>
  maybe(E error_code_enum) {
    cr_error(make_error_condition(error_code_enum));
  }

  /// Creates an empty instance.
  maybe() {
    cr_error(error_type{});
  }

  /// Creates an empty instance.
  maybe(const none_t&) {
    cr_error(error_type{});
  }

  maybe(const maybe& other) {
    if (other.available_)
      cr_value(other.value_);
    else
      cr_error(other.error_);
  }

  maybe(maybe&& other) {
    if (other.available_)
      cr_moved_value(other.value_);
    else
      cr_error(std::move(other.error_));
  }

  template <class U>
  maybe(maybe<U>&& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    if (other)
      cr_moved_value(*other);
    else
      cr_error(std::move(other.error()));
  }

  template <class U>
  maybe(const maybe<U>& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    if (other)
      cr_value(*other);
    else
      cr_error(other.error());
  }

  ~maybe() {
    destroy();
  }

  maybe& operator=(const none_t&) {
    if (available_) {
      destroy();
      cr_error(error_type{});
    } else if (error_) {
      error_ = error_type{};
    }
    return *this;
  }

  maybe& operator=(T value) {
    if (! available_) {
      destroy();
      cr_moved_value(value);
    } else {
      assign_moved_value(value);
    }
    return *this;
  }

  maybe& operator=(error_type err) {
    if (available_) {
      destroy();
      cr_error(std::move(err));
    } else {
      error_ = std::move(err);
    }
    return *this;
  }

  template <class E,
            class = typename std::enable_if<
              std::is_error_condition_enum<E>::value
            >::type>
  maybe& operator=(E error_code_enum) {
    return *this = make_error_condition(error_code_enum);
  }

  maybe& operator=(maybe&& other) {
    return other ? *this = std::move(*other) : *this = std::move(other.error());
  }

  maybe& operator=(const maybe& other) {
    return other ? *this = *other : *this = other.error();
  }

  template <class U>
  maybe& operator=(maybe<U>&& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    return other ? *this = std::move(*other) : *this = std::move(other.error());
  }

  template <class U>
  maybe& operator=(const maybe<U>& other) {
    static_assert(std::is_convertible<U, T>::value, "U not convertible to T");
    return other ? *this = *other : *this = other.error();
  }

  /// Queries whether this instance holds a value.
  bool available() const {
    return available_;
  }

  /// Returns `available()`.
  explicit operator bool() const {
    return available();
  }

  /// Returns `! available()`.
  bool operator!() const {
    return ! available();
  }

  /// Returns the value.
  reference get() {
    CAF_ASSERT(available());
    return value_;
  }

  /// Returns the value.
  const_reference get() const {
    CAF_ASSERT(available());
    return value_;
  }

  /// Returns the value.
  reference operator*() {
    return get();
  }

  /// Returns the value.
  const_reference operator*() const {
    return get();
  }

  /// Returns a pointer to the value.
  pointer operator->() {
    return &get();
  }

  /// Returns a pointer to the value.
  const_pointer operator->() const {
    return &get();
  }

  /// Returns whether this objects holds neither a value nor an actual error.
  bool empty() const {
    return ! available() && ! error();
  }

  /// Returns the error.
  const error_type& error() const {
    CAF_ASSERT(! available());
    return error_;
  }

private:
  void destroy() {
    if (available_)
      value_.~storage();
    else
      error_.~error_type();
  }

  void cr_moved_value(reference x) {
    // convert to rvalue if possible
    using fwd_type =
      typename std::conditional<
        ! std::is_reference<T>::value,
        type&&,
        type&
      >::type;
    available_ = true;
    new (&value_) storage(static_cast<fwd_type>(x));
  }

  void assign_moved_value(reference x) {
    using fwd_type =
      typename std::conditional<
        ! std::is_reference<T>::value,
        type&&,
        type&
      >::type;
    value_ = static_cast<fwd_type>(x);
  }

  template <class V>
  void cr_value(V&& x) {
    available_ = true;
    new (&value_) storage(std::forward<V>(x));
  }

  void cr_error(std::error_condition ec) {
    available_ = false;
    new (&error_) error_type(std::move(ec));
  }

  bool available_;
  union {
    storage value_;
    error_type error_;
  };
};

/// Returns `true` if both objects represent either the same
/// value or the same error, `false` otherwise.
/// @relates maybe
template <class T, typename U>
bool operator==(const maybe<T>& lhs, const maybe<U>& rhs) {
  if (lhs)
    return (rhs) ? detail::safe_equal(*lhs, *rhs) : false;
  if (! rhs)
    return lhs.error() == rhs.error();
  return false;
}

/// Returns `true` if `lhs` is available and its value is equal to `rhs`.
template <class T, typename U>
bool operator==(const maybe<T>& lhs, const U& rhs) {
  return (lhs) ? *lhs == rhs : false;
}

/// Returns `true` if `rhs` is available and its value is equal to `lhs`.
/// @relates maybe
template <class T, typename U>
bool operator==(const T& lhs, const maybe<U>& rhs) {
  return rhs == lhs;
}

/// Returns `true` if the objects represent different
/// values or errors, `false` otherwise.
/// @relates maybe
template <class T, typename U>
bool operator!=(const maybe<T>& lhs, const maybe<U>& rhs) {
  return !(lhs == rhs);
}

/// Returns `true` if `lhs` is not available or its value is not equal to `rhs`.
/// @relates maybe
template <class T, typename U>
bool operator!=(const maybe<T>& lhs, const U& rhs) {
  return !(lhs == rhs);
}

/// Returns `true` if `rhs` is not available or its value is not equal to `lhs`.
/// @relates maybe
template <class T, typename U>
bool operator!=(const T& lhs, const maybe<U>& rhs) {
  return !(lhs == rhs);
}

/// Returns `! val.available() && val.error() == err`.
/// @relates maybe
template <class T>
bool operator==(const maybe<T>& val, const std::error_condition& err) {
  return ! val.available() && val.error() == err;
}

/// Returns `! val.available() && val.error() == err`.
/// @relates maybe
template <class T>
bool operator==(const std::error_condition& err, const maybe<T>& val) {
  return val == err;
}

/// Returns `val.available() || val.error() != err`.
/// @relates maybe
template <class T>
bool operator!=(const maybe<T>& val, const std::error_condition& err) {
  return ! (val == err);
}

/// Returns `val.available() || val.error() != err`.
/// @relates maybe
template <class T>
bool operator!=(const std::error_condition& err, const maybe<T>& val) {
  return ! (val == err);
}

/// Returns `val.empty()`.
/// @relates maybe
template <class T>
bool operator==(const maybe<T>& val, const none_t&) {
  return val.empty();
}

/// Returns `val.empty()`.
/// @relates maybe
template <class T>
bool operator==(const none_t&, const maybe<T>& val) {
  return val.empty();
}

/// Returns `! val.empty()`.
/// @relates maybe
template <class T>
bool operator!=(const maybe<T>& val, const none_t&) {
  return ! val.empty();
}

/// Returns `! val.empty()`.
/// @relates maybe
template <class T>
bool operator!=(const none_t&, const maybe<T>& val) {
  return ! val.empty();
}

// Represents a computation performing side effects only and
// optionally return a `std::error_condition`.
template <>
class maybe<void> {
public:
  using type = unit_t;
  using reference = const type&;
  using const_reference = const type&;
  using pointer = const type*;
  using const_pointer = const type*;
  using error_type = std::error_condition;

  maybe() = default;

  maybe(const none_t&) {
    // nop
  }

  maybe(error_type err) : error_(std::move(err)) {
    // nop
  }

  maybe& operator=(const none_t&) {
    error_.clear();
    return *this;
  }

  maybe& operator=(error_type err) {
    error_ = std::move(err);
    return *this;
  }

  bool available() const {
    return false;
  }

  explicit operator bool() const {
    return available();
  }

  bool operator!() const {
    return ! available();
  }

  reference get() {
    CAF_ASSERT(! "should never be called");
    return unit;
  }

  const_reference get() const {
    CAF_ASSERT(! "should never be called");
    return unit;
  }

  reference operator*() {
    return get();
  }

  const_reference operator*() const {
    return get();
  }

  pointer operator->() {
    return &get();
  }

  const_pointer operator->() const {
    return &get();
  }

  bool empty() const {
    return ! error();
  }

  const error_type& error() const {
    return error_;
  }

private:
  error_type error_;
};

} // namespace caf

#endif // CAF_MAYBE_HPP
<|endoftext|>


<commit_before>//===-- sanitizer_mac.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements mac-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#ifdef __APPLE__

#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"

#include <crt_externs.h>  // for _NSGetEnviron
#include <fcntl.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <libkern/OSAtomic.h>

namespace __sanitizer {

// ---------------------- sanitizer_libc.h
void *internal_mmap(void *addr, size_t length, int prot, int flags,
                    int fd, u64 offset) {
  return mmap(addr, length, prot, flags, fd, offset);
}

int internal_munmap(void *addr, uptr length) {
  return munmap(addr, length);
}

int internal_close(fd_t fd) {
  return close(fd);
}

fd_t internal_open(const char *filename, int flags) {
  return open(filename, flags);
}

fd_t internal_open(const char *filename, int flags, u32 mode) {
  return open(filename, flags, mode);
}

fd_t OpenFile(const char *filename, bool write) {
  return internal_open(filename,
      write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  return read(fd, buf, count);
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  return write(fd, buf, count);
}

int internal_stat(const char *path, void *buf) {
  return stat(path, buf);
}

int internal_lstat(const char *path, void *buf) {
  return lstat(path, buf);
}

int internal_fstat(fd_t fd, void *buf) {
  return fstat(fd, buf);
}

uptr internal_filesize(fd_t fd) {
  struct stat st;
  if (internal_fstat(fd, &st))
    return -1;
  return (uptr)st.st_size;
}

int internal_dup2(int oldfd, int newfd) {
  return dup2(oldfd, newfd);
}

uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
  return readlink(path, buf, bufsize);
}

int internal_sched_yield() {
  return sched_yield();
}

// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
  struct stat st;
  if (stat(filename, &st))
    return false;
  // Sanity check: filename is a regular file.
  return S_ISREG(st.st_mode);
}

uptr GetTid() {
  return reinterpret_cast<uptr>(pthread_self());
}

void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                uptr *stack_bottom) {
  CHECK(stack_top);
  CHECK(stack_bottom);
  uptr stacksize = pthread_get_stacksize_np(pthread_self());
  void *stackaddr = pthread_get_stackaddr_np(pthread_self());
  *stack_top = (uptr)stackaddr;
  *stack_bottom = *stack_top - stacksize;
}

const char *GetEnv(const char *name) {
  char ***env_ptr = _NSGetEnviron();
  CHECK(env_ptr);
  char **environ = *env_ptr;
  CHECK(environ);
  uptr name_len = internal_strlen(name);
  while (*environ != 0) {
    uptr len = internal_strlen(*environ);
    if (len > name_len) {
      const char *p = *environ;
      if (!internal_memcmp(p, name, name_len) &&
          p[name_len] == '=') {  // Match.
        return *environ + name_len + 1;  // String starting after =.
      }
    }
    environ++;
  }
  return 0;
}

void ReExec() {
  UNIMPLEMENTED();
}

void PrepareForSandboxing() {
  // Nothing here for now.
}

// ----------------- sanitizer_procmaps.h

MemoryMappingLayout::MemoryMappingLayout() {
  Reset();
}

MemoryMappingLayout::~MemoryMappingLayout() {
}

// More information about Mach-O headers can be found in mach-o/loader.h
// Each Mach-O image has a header (mach_header or mach_header_64) starting with
// a magic number, and a list of linker load commands directly following the
// header.
// A load command is at least two 32-bit words: the command type and the
// command size in bytes. We're interested only in segment load commands
// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
// into the task's address space.
// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
// segment_command_64 correspond to the memory address, memory size and the
// file offset of the current memory segment.
// Because these fields are taken from the images as is, one needs to add
// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.

void MemoryMappingLayout::Reset() {
  // Count down from the top.
  // TODO(glider): as per man 3 dyld, iterating over the headers with
  // _dyld_image_count is thread-unsafe. We need to register callbacks for
  // adding and removing images which will invalidate the MemoryMappingLayout
  // state.
  current_image_ = _dyld_image_count();
  current_load_cmd_count_ = -1;
  current_load_cmd_addr_ = 0;
  current_magic_ = 0;
  current_filetype_ = 0;
}

// static
void MemoryMappingLayout::CacheMemoryMappings() {
  // No-op on Mac for now.
}

void MemoryMappingLayout::LoadFromCache() {
  // No-op on Mac for now.
}

// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
// Google Perftools, http://code.google.com/p/google-perftools.

// NextSegmentLoad scans the current image for the next segment load command
// and returns the start and end addresses and file offset of the corresponding
// segment.
// Note that the segment addresses are not necessarily sorted.
template<u32 kLCSegment, typename SegmentCommand>
bool MemoryMappingLayout::NextSegmentLoad(
    uptr *start, uptr *end, uptr *offset,
    char filename[], uptr filename_size) {
  const char* lc = current_load_cmd_addr_;
  current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
  if (((const load_command *)lc)->cmd == kLCSegment) {
    const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
    const SegmentCommand* sc = (const SegmentCommand *)lc;
    if (start) *start = sc->vmaddr + dlloff;
    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
    if (offset) {
      if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
        *offset = sc->vmaddr;
      } else {
        *offset = sc->fileoff;
      }
    }
    if (filename) {
      internal_strncpy(filename, _dyld_get_image_name(current_image_),
                       filename_size);
    }
    return true;
  }
  return false;
}

bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
                               char filename[], uptr filename_size) {
  for (; current_image_ >= 0; current_image_--) {
    const mach_header* hdr = _dyld_get_image_header(current_image_);
    if (!hdr) continue;
    if (current_load_cmd_count_ < 0) {
      // Set up for this image;
      current_load_cmd_count_ = hdr->ncmds;
      current_magic_ = hdr->magic;
      current_filetype_ = hdr->filetype;
      switch (current_magic_) {
#ifdef MH_MAGIC_64
        case MH_MAGIC_64: {
          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
          break;
        }
#endif
        case MH_MAGIC: {
          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
          break;
        }
        default: {
          continue;
        }
      }
    }

    for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
      switch (current_magic_) {
        // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
#ifdef MH_MAGIC_64
        case MH_MAGIC_64: {
          if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
                  start, end, offset, filename, filename_size))
            return true;
          break;
        }
#endif
        case MH_MAGIC: {
          if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
                  start, end, offset, filename, filename_size))
            return true;
          break;
        }
      }
    }
    // If we get here, no more load_cmd's in this image talk about
    // segments.  Go on to the next image.
  }
  return false;
}

bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
                                                 char filename[],
                                                 uptr filename_size) {
  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
}

BlockingMutex::BlockingMutex(LinkerInitialized) {
  // We assume that OS_SPINLOCK_INIT is zero
}

void BlockingMutex::Lock() {
  CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
  CHECK(OS_SPINLOCK_INIT == 0);
  CHECK(owner_ != (uptr)pthread_self());
  OSSpinLockLock((OSSpinLock*)&opaque_storage_);
  CHECK(!owner_);
  owner_ = (uptr)pthread_self();
}

void BlockingMutex::Unlock() {
  CHECK(owner_ == (uptr)pthread_self());
  owner_ = 0;
  OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
}

}  // namespace __sanitizer

#endif  // __APPLE__
<commit_msg>[Sanitizer] use proper casting in *stat functions on Mac<commit_after>//===-- sanitizer_mac.cc --------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries and implements mac-specific functions from
// sanitizer_libc.h.
//===----------------------------------------------------------------------===//

#ifdef __APPLE__

#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"

#include <crt_externs.h>  // for _NSGetEnviron
#include <fcntl.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <pthread.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <libkern/OSAtomic.h>

namespace __sanitizer {

// ---------------------- sanitizer_libc.h
void *internal_mmap(void *addr, size_t length, int prot, int flags,
                    int fd, u64 offset) {
  return mmap(addr, length, prot, flags, fd, offset);
}

int internal_munmap(void *addr, uptr length) {
  return munmap(addr, length);
}

int internal_close(fd_t fd) {
  return close(fd);
}

fd_t internal_open(const char *filename, int flags) {
  return open(filename, flags);
}

fd_t internal_open(const char *filename, int flags, u32 mode) {
  return open(filename, flags, mode);
}

fd_t OpenFile(const char *filename, bool write) {
  return internal_open(filename,
      write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
}

uptr internal_read(fd_t fd, void *buf, uptr count) {
  return read(fd, buf, count);
}

uptr internal_write(fd_t fd, const void *buf, uptr count) {
  return write(fd, buf, count);
}

int internal_stat(const char *path, void *buf) {
  return stat(path, (struct stat *)buf);
}

int internal_lstat(const char *path, void *buf) {
  return lstat(path, (struct stat *)buf);
}

int internal_fstat(fd_t fd, void *buf) {
  return fstat(fd, (struct stat *)buf);
}

uptr internal_filesize(fd_t fd) {
  struct stat st;
  if (internal_fstat(fd, &st))
    return -1;
  return (uptr)st.st_size;
}

int internal_dup2(int oldfd, int newfd) {
  return dup2(oldfd, newfd);
}

uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
  return readlink(path, buf, bufsize);
}

int internal_sched_yield() {
  return sched_yield();
}

// ----------------- sanitizer_common.h
bool FileExists(const char *filename) {
  struct stat st;
  if (stat(filename, &st))
    return false;
  // Sanity check: filename is a regular file.
  return S_ISREG(st.st_mode);
}

uptr GetTid() {
  return reinterpret_cast<uptr>(pthread_self());
}

void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                uptr *stack_bottom) {
  CHECK(stack_top);
  CHECK(stack_bottom);
  uptr stacksize = pthread_get_stacksize_np(pthread_self());
  void *stackaddr = pthread_get_stackaddr_np(pthread_self());
  *stack_top = (uptr)stackaddr;
  *stack_bottom = *stack_top - stacksize;
}

const char *GetEnv(const char *name) {
  char ***env_ptr = _NSGetEnviron();
  CHECK(env_ptr);
  char **environ = *env_ptr;
  CHECK(environ);
  uptr name_len = internal_strlen(name);
  while (*environ != 0) {
    uptr len = internal_strlen(*environ);
    if (len > name_len) {
      const char *p = *environ;
      if (!internal_memcmp(p, name, name_len) &&
          p[name_len] == '=') {  // Match.
        return *environ + name_len + 1;  // String starting after =.
      }
    }
    environ++;
  }
  return 0;
}

void ReExec() {
  UNIMPLEMENTED();
}

void PrepareForSandboxing() {
  // Nothing here for now.
}

// ----------------- sanitizer_procmaps.h

MemoryMappingLayout::MemoryMappingLayout() {
  Reset();
}

MemoryMappingLayout::~MemoryMappingLayout() {
}

// More information about Mach-O headers can be found in mach-o/loader.h
// Each Mach-O image has a header (mach_header or mach_header_64) starting with
// a magic number, and a list of linker load commands directly following the
// header.
// A load command is at least two 32-bit words: the command type and the
// command size in bytes. We're interested only in segment load commands
// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
// into the task's address space.
// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
// segment_command_64 correspond to the memory address, memory size and the
// file offset of the current memory segment.
// Because these fields are taken from the images as is, one needs to add
// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.

void MemoryMappingLayout::Reset() {
  // Count down from the top.
  // TODO(glider): as per man 3 dyld, iterating over the headers with
  // _dyld_image_count is thread-unsafe. We need to register callbacks for
  // adding and removing images which will invalidate the MemoryMappingLayout
  // state.
  current_image_ = _dyld_image_count();
  current_load_cmd_count_ = -1;
  current_load_cmd_addr_ = 0;
  current_magic_ = 0;
  current_filetype_ = 0;
}

// static
void MemoryMappingLayout::CacheMemoryMappings() {
  // No-op on Mac for now.
}

void MemoryMappingLayout::LoadFromCache() {
  // No-op on Mac for now.
}

// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
// Google Perftools, http://code.google.com/p/google-perftools.

// NextSegmentLoad scans the current image for the next segment load command
// and returns the start and end addresses and file offset of the corresponding
// segment.
// Note that the segment addresses are not necessarily sorted.
template<u32 kLCSegment, typename SegmentCommand>
bool MemoryMappingLayout::NextSegmentLoad(
    uptr *start, uptr *end, uptr *offset,
    char filename[], uptr filename_size) {
  const char* lc = current_load_cmd_addr_;
  current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
  if (((const load_command *)lc)->cmd == kLCSegment) {
    const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
    const SegmentCommand* sc = (const SegmentCommand *)lc;
    if (start) *start = sc->vmaddr + dlloff;
    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
    if (offset) {
      if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
        *offset = sc->vmaddr;
      } else {
        *offset = sc->fileoff;
      }
    }
    if (filename) {
      internal_strncpy(filename, _dyld_get_image_name(current_image_),
                       filename_size);
    }
    return true;
  }
  return false;
}

bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
                               char filename[], uptr filename_size) {
  for (; current_image_ >= 0; current_image_--) {
    const mach_header* hdr = _dyld_get_image_header(current_image_);
    if (!hdr) continue;
    if (current_load_cmd_count_ < 0) {
      // Set up for this image;
      current_load_cmd_count_ = hdr->ncmds;
      current_magic_ = hdr->magic;
      current_filetype_ = hdr->filetype;
      switch (current_magic_) {
#ifdef MH_MAGIC_64
        case MH_MAGIC_64: {
          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
          break;
        }
#endif
        case MH_MAGIC: {
          current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
          break;
        }
        default: {
          continue;
        }
      }
    }

    for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
      switch (current_magic_) {
        // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
#ifdef MH_MAGIC_64
        case MH_MAGIC_64: {
          if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
                  start, end, offset, filename, filename_size))
            return true;
          break;
        }
#endif
        case MH_MAGIC: {
          if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
                  start, end, offset, filename, filename_size))
            return true;
          break;
        }
      }
    }
    // If we get here, no more load_cmd's in this image talk about
    // segments.  Go on to the next image.
  }
  return false;
}

bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
                                                 char filename[],
                                                 uptr filename_size) {
  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
}

BlockingMutex::BlockingMutex(LinkerInitialized) {
  // We assume that OS_SPINLOCK_INIT is zero
}

void BlockingMutex::Lock() {
  CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
  CHECK(OS_SPINLOCK_INIT == 0);
  CHECK(owner_ != (uptr)pthread_self());
  OSSpinLockLock((OSSpinLock*)&opaque_storage_);
  CHECK(!owner_);
  owner_ = (uptr)pthread_self();
}

void BlockingMutex::Unlock() {
  CHECK(owner_ == (uptr)pthread_self());
  owner_ = 0;
  OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
}

}  // namespace __sanitizer

#endif  // __APPLE__
<|endoftext|>


<commit_before>/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "crypto-manager.h"
#include "crypto-handlers.h"
#include "debug.h"
#include "misc.h"

#include <QFile>
#include <QDir>
#include <QMetaEnum>
#include <QSettings>

#define DEVICE_MAPPER_DIR "/dev/mapper/"
#define EXT2 "ext2"
#define EXT3 "ext3"
#define EXT4 "ext4"

namespace SignOn {

    const QString CryptoManager::keychainFilePath() const
    {
#ifdef SIGNON_AEGISFS
	  return m_aegisFSFileSystemPath + QDir::separator() + QLatin1String("keychain");
#else
	  return m_fileSystemMountPath + QDir::separator() + QLatin1String("keychain");
#endif
    }

    void CryptoManager::addKeyToKeychain(const QByteArray &key) const
    {
        //If key is already present do not add it - backwards compat. feature
        if (keychainContainsKey(key)) return;

        QSettings keychain(keychainFilePath(), QSettings::IniFormat);
        int keyCount = keychain.allKeys().count();
        keychain.setValue(QString::number(++keyCount), QVariant(key));
    }

    void CryptoManager::removeKeyFromKeychain(const QByteArray &key) const
    {
        QSettings keychain(keychainFilePath(), QSettings::IniFormat);
        foreach (QString keyIt, keychain.allKeys()) {
            if (keychain.value(keyIt).toByteArray() == key) {
                keychain.remove(keyIt);
                break;
            }
        }
    }

    bool CryptoManager::keychainContainsKey(const QByteArray &key) const
    {
        QSettings keychain(keychainFilePath(), QSettings::IniFormat);
        foreach (QString keyIt, keychain.allKeys()) {
            if (keychain.value(keyIt).toByteArray() == key)
                return true;
        }

        return false;
    }

    CryptoManager::CryptoManager(QObject *parent)
            : QObject(parent),
              m_accessCode(QByteArray()),
              m_fileSystemPath(QString()),
              m_fileSystemMapPath(QString()),
              m_fileSystemName(QString()),
              m_fileSystemMountPath(QString()),
              m_aegisFSFileSystemPath(QString()),
              m_loopDeviceName(QString()),
              m_fileSystemType(Ext2),
              m_fileSystemSize(4)
    {
        updateMountState(Unmounted);
        if (!CryptsetupHandler::loadDmMod())
            BLAME() << "Could not load `dm_mod`!";
    }

    CryptoManager::CryptoManager(const QByteArray &encryptionKey,
                                 const QString &fileSystemPath,
                                 QObject *parent)
            : QObject(parent),
              m_accessCode(encryptionKey),
              m_loopDeviceName(QString()),
              m_fileSystemType(Ext2),
              m_fileSystemSize(4)
    {
        setFileSystemPath(fileSystemPath);
        updateMountState(Unmounted);

        if (!CryptsetupHandler::loadDmMod())
            BLAME() << "Could not load `dm_mod`!";
    }

    CryptoManager::~CryptoManager()
    {
        unmountFileSystem();
    }

    void CryptoManager::setFileSystemPath(const QString &path)
    {
        m_fileSystemPath = path;

        QFileInfo fsFileInfo(path);

        m_fileSystemName = fsFileInfo.fileName();
        m_fileSystemMapPath = QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName;
        m_fileSystemMountPath = path + QLatin1String("-mnt");
    }

    void CryptoManager::setAegisFSFileSystemPath(const QString &path)
    {
    	m_aegisFSFileSystemPath = path;
    }

    bool CryptoManager::setFileSystemSize(const quint32 size)
    {
        if (size < MINUMUM_ENCRYPTED_FILE_SYSTEM_SIZE) {
            TRACE() << "Minumum encrypted file size is 4 Mb.";
            return false;
        }
        m_fileSystemSize = size;
        return true;
    }

    void CryptoManager::setEncryptionKey(const QByteArray &key)
    {
        if (fileSystemIsMounted()) {
            BLAME() << "File system already mounted";
            return;
        }

        m_accessCode = key;
    }

    bool CryptoManager::setFileSystemType(const QString &type)
    {
        QString cmpBase = type.toLower();
        if (cmpBase == QLatin1String(EXT2)) {
            m_fileSystemType = Ext2;
            return true;
        } else if (cmpBase == QLatin1String(EXT3)) {
            m_fileSystemType = Ext3;
            return true;
        } else if (cmpBase == QLatin1String(EXT4)) {
            m_fileSystemType = Ext4;
            return true;
        }
        return false;
    }

    bool CryptoManager::setupFileSystem()
    {
        if (m_mountState == Mounted) {
            TRACE() << "Ecrypyted file system already mounted.";
            return false;
        }

        if (m_accessCode.isEmpty()) {
            TRACE() << "No access code set. Stopping mount process.";
            return false;
        }

        if (!CryptsetupHandler::loadDmMod()) {
            BLAME() << "Could not load `dm_mod`!";
            return false;
        }

        clearFileSystemResources();

        m_loopDeviceName = LosetupHandler::findAvailableDevice();
        if (m_loopDeviceName.isNull()) {
            BLAME() << "No free loop device available!";
            return false;
        }

        if (!PartitionHandler::createPartitionFile(m_fileSystemPath, m_fileSystemSize)) {
            BLAME() << "Could not create partition file.";
            unmountFileSystem();
            return false;
        }

        if (!LosetupHandler::setupDevice(m_loopDeviceName,
                                         m_fileSystemPath)) {
            BLAME() << "Failed to setup loop device:" << m_loopDeviceName;
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopSet);

        if (!CryptsetupHandler::formatFile(m_accessCode, m_loopDeviceName)) {
            BLAME() << "Failed to LUKS format.";
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopLuksFormatted);

        //attempt luks close, in case of a leftover.
        if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName)) {
            TRACE() << "Filesystem exists, closing";
            CryptsetupHandler::closeFile(m_fileSystemName);
        }

        if (!CryptsetupHandler::openFile(m_accessCode,
                                         m_loopDeviceName,
                                         m_fileSystemName)) {
            BLAME() << "Failed to LUKS open";
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopLuksOpened);

        if (!PartitionHandler::formatPartitionFile(m_fileSystemMapPath,
                                                   m_fileSystemType)) {
            BLAME() << "Could not format mapped partition.";
            unmountFileSystem();
            return false;
        }

        if (!mountMappedDevice()) {
            BLAME() << "Failed to mount ecrypted file system.";
            unmountFileSystem();
            return false;
        }

        addKeyToKeychain(m_accessCode);
        updateMountState(Mounted);
        return true;
    }

    //TODO - add checking for LUKS header in case of preavious app run formatting failure
    bool CryptoManager::mountFileSystem()
    {
        if (m_mountState == Mounted) {
            TRACE() << "Ecrypyted file system already mounted.";
            return false;
        }

        if (m_accessCode.isEmpty()) {
            TRACE() << "No access code set. Stopping mount process.";
            return false;
        }

        clearFileSystemResources();

        if (!CryptsetupHandler::loadDmMod()) {
            BLAME() << "Could not load `dm_mod`!";
            return false;
        }

        m_loopDeviceName = LosetupHandler::findAvailableDevice();
        if (m_loopDeviceName.isNull()) {
            BLAME() << "No free loop device available!";
            return false;
        }

        if (!LosetupHandler::setupDevice(m_loopDeviceName, m_fileSystemPath)) {
            BLAME() << "Failed to setup loop device:" << m_loopDeviceName;
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopSet);

        //attempt luks close, in case of a leftover.
        if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName))
            CryptsetupHandler::closeFile(m_fileSystemName);

        if (!CryptsetupHandler::openFile(m_accessCode,
                                         m_loopDeviceName,
                                         m_fileSystemName)) {
            BLAME() << "Failed to LUKS open.";
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopLuksOpened);

        if (!mountMappedDevice()) {
            TRACE() << "Failed to mount ecrypted file system.";
            unmountFileSystem();
            return false;
        }

        addKeyToKeychain(m_accessCode);
        updateMountState(Mounted);
        return true;
    }

    void CryptoManager::clearFileSystemResources()
    {
        /*
            This method is a `just in case call` for the situations
            when signond closes whithout handling the unmounting of
            the secure storage.
        */

        TRACE() << "--- START clearing secure storage possibly used resources."
                   " Ignore possible errors. ---";

        if (!unmountMappedDevice())
            TRACE() << "Unmounting mapped device failed.";

        if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName)) {
            if (!CryptsetupHandler::closeFile(m_fileSystemName))
                TRACE() << "Failed to LUKS close.";
        }

        /*
         TODO - find a way to check which loop device was previously used by
                signond and close that specific one, until then this will be
                skipped as it might close devices used by different processes.

        if (!LosetupHandler::releaseDevice(m_loopDeviceName)) {
            TRACE() << "Failed to release loop device.";
        */

        TRACE() << "--- DONE clearing secure storage possibly used resources. ---";
    }

    bool CryptoManager::unmountFileSystem()
    {
        if (m_mountState == Unmounted) {
            TRACE() << "Ecrypyted file system not mounted.";
            return true;
        }

        emit fileSystemUnmounting();
        bool isOk = true;

        if ((m_mountState >= Mounted)
            && !unmountMappedDevice()) {
            TRACE() << "Failed to unmount mapped loop device.";
            isOk = false;
        } else {
            TRACE() << "Mapped loop device unmounted.";
        }

        if ((m_mountState >= LoopLuksOpened)
            && (!CryptsetupHandler::closeFile(m_fileSystemName))) {
            TRACE() << "Failed to LUKS close.";
            isOk = false;
        } else {
            TRACE() << "Luks close succeeded.";
        }

        if ((m_mountState >= LoopSet)
            && (!LosetupHandler::releaseDevice(m_loopDeviceName))) {
            TRACE() << "Failed to release loop device.";
            isOk = false;
        } else {
            TRACE() << "Loop device released.";
        }

        updateMountState(Unmounted);
        return isOk;
    }

    bool CryptoManager::deleteFileSystem()
    {
        if (m_mountState > Unmounted) {
            if (!unmountFileSystem())
                return false;
        }

        //TODO - implement effective deletion in specific handler object
        return false;
    }

    bool CryptoManager::fileSystemIsSetup() const
    {
        return QFile::exists(fileSystemPath());
    }

    //TODO - debug this method. Current test scenarios do no cover this one
    bool CryptoManager::fileSystemContainsFile(const QString &filePath)
    {
        if (!fileSystemIsMounted()) {
            TRACE() << "Ecrypyted file system not mounted.";
            return false;
        }

        QDir mountDir(m_fileSystemMountPath);
        return mountDir.exists(QDir::toNativeSeparators(filePath));
    }

    QString CryptoManager::fileSystemMountPath() const
    {
        return m_fileSystemMountPath;
    }

    void CryptoManager::updateMountState(const FileSystemMountState state)
    {
        TRACE() << "Updating mount state:" << state;
        if (state == m_mountState) return;

        m_mountState = state;
        if (state == Mounted)
            emit fileSystemMounted();
    }

    bool CryptoManager::mountMappedDevice()
    {
        //create mnt dir if not existant
        if (!QFile::exists(m_fileSystemMountPath)) {
            QDir dir;
            if (!dir.mkpath(m_fileSystemMountPath)) {
                BLAME() << "Could not create target mount dir path.";
                return false;
            }

            if (!setUserOwnership(m_fileSystemMountPath))
                TRACE() << "Failed to set User ownership for "
                           "the secure storage mount target.";
        }

        MountHandler::mount(m_fileSystemMapPath, m_fileSystemMountPath);
        return true;
    }

    bool CryptoManager::unmountMappedDevice()
    {
        return MountHandler::umount(m_fileSystemMountPath);
    }

    bool CryptoManager::addEncryptionKey(const QByteArray &key,
                                         const QByteArray &existingKey)
    {
        /*
         * TODO -- limit number of stored keys to the total available slots - 1.
         */
        if (m_mountState >= LoopLuksOpened) {
            if (CryptsetupHandler::addKeySlot(
                    m_loopDeviceName, key, existingKey)) {

                addKeyToKeychain(key);
                return true;
            }
        }
        TRACE() << "FAILED to occupy key slot on the encrypted file system header.";
        return false;
    }

    bool CryptoManager::removeEncryptionKey(const QByteArray &key,
                                            const QByteArray &remainingKey)
    {
        if (m_mountState >= LoopLuksOpened) {
            if (CryptsetupHandler::removeKeySlot(
                m_loopDeviceName, key, remainingKey))

                removeKeyFromKeychain(key);
                return true;
        }
        TRACE() << "FAILED to release key slot from the encrypted file system header.";
        return false;
    }

    bool CryptoManager::encryptionKeyInUse(const QByteArray &key)
    {
        if (fileSystemIsMounted() && (m_accessCode == key))
            return true;

        if(!fileSystemIsMounted()) {
           setEncryptionKey(key);
           return mountFileSystem();
        }

        /* Variant that tests if the key is in the LUKS keychain
         * by using a file on the encrypted storage containing the keychain.
         */
        return keychainContainsKey(key);

        /*
         * Variant that tests if the key is in the LUKS keychain
         * by directly accessing the LUKS system
         *
         * QByteArray dummyKey("dummy");
         * if (addEncryptionKey(dummyKey, key)) {
         *     if (!removeEncryptionKey(dummyKey, key))
         *         BLAME() << "Could not remove dummy auxiliary key "
         *                    "from encrypted file system header.";
         *    return true;
         * }
         *
         * return false;
         */
    }

    //TODO - remove this after stable version is achieved.
    void CryptoManager::serializeData()
    {
        TRACE() << "m_accessCode" << m_accessCode;
        TRACE() << "m_fileSystemPath" << m_fileSystemPath;
        TRACE() << "m_fileSystemMapPath" << m_fileSystemMapPath;
        TRACE() << "m_fileSystemName" << m_fileSystemName;
        TRACE() << "m_loopDeviceName" << m_loopDeviceName;
        TRACE() << "m_fileSystemType" << m_fileSystemType;
        TRACE() << "m_fileSystemSize" << m_fileSystemSize;
    }
} //namespace SignonDaemonNS
<commit_msg>making valgrind happy<commit_after>/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "crypto-manager.h"
#include "crypto-handlers.h"
#include "debug.h"
#include "misc.h"

#include <QFile>
#include <QDir>
#include <QMetaEnum>
#include <QSettings>

#define DEVICE_MAPPER_DIR "/dev/mapper/"
#define EXT2 "ext2"
#define EXT3 "ext3"
#define EXT4 "ext4"

namespace SignOn {

    const QString CryptoManager::keychainFilePath() const
    {
#ifdef SIGNON_AEGISFS
	  return m_aegisFSFileSystemPath + QDir::separator() + QLatin1String("keychain");
#else
	  return m_fileSystemMountPath + QDir::separator() + QLatin1String("keychain");
#endif
    }

    void CryptoManager::addKeyToKeychain(const QByteArray &key) const
    {
        //If key is already present do not add it - backwards compat. feature
        if (keychainContainsKey(key)) return;

        QSettings keychain(keychainFilePath(), QSettings::IniFormat);
        int keyCount = keychain.allKeys().count();
        keychain.setValue(QString::number(++keyCount), QVariant(key));
    }

    void CryptoManager::removeKeyFromKeychain(const QByteArray &key) const
    {
        QSettings keychain(keychainFilePath(), QSettings::IniFormat);
        foreach (QString keyIt, keychain.allKeys()) {
            if (keychain.value(keyIt).toByteArray() == key) {
                keychain.remove(keyIt);
                break;
            }
        }
    }

    bool CryptoManager::keychainContainsKey(const QByteArray &key) const
    {
        QSettings keychain(keychainFilePath(), QSettings::IniFormat);
        foreach (QString keyIt, keychain.allKeys()) {
            if (keychain.value(keyIt).toByteArray() == key)
                return true;
        }

        return false;
    }

    CryptoManager::CryptoManager(QObject *parent)
            : QObject(parent),
              m_accessCode(QByteArray()),
              m_fileSystemPath(QString()),
              m_fileSystemMapPath(QString()),
              m_fileSystemName(QString()),
              m_fileSystemMountPath(QString()),
              m_aegisFSFileSystemPath(QString()),
              m_loopDeviceName(QString()),
              m_mountState(Unmounted),
              m_fileSystemType(Ext2),
              m_fileSystemSize(4)
    {
        if (!CryptsetupHandler::loadDmMod())
            BLAME() << "Could not load `dm_mod`!";
    }

    CryptoManager::CryptoManager(const QByteArray &encryptionKey,
                                 const QString &fileSystemPath,
                                 QObject *parent)
            : QObject(parent),
              m_accessCode(encryptionKey),
              m_loopDeviceName(QString()),
              m_mountState(Unmounted),
              m_fileSystemType(Ext2),
              m_fileSystemSize(4)
    {
        setFileSystemPath(fileSystemPath);

        if (!CryptsetupHandler::loadDmMod())
            BLAME() << "Could not load `dm_mod`!";
    }

    CryptoManager::~CryptoManager()
    {
        unmountFileSystem();
    }

    void CryptoManager::setFileSystemPath(const QString &path)
    {
        m_fileSystemPath = path;

        QFileInfo fsFileInfo(path);

        m_fileSystemName = fsFileInfo.fileName();
        m_fileSystemMapPath = QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName;
        m_fileSystemMountPath = path + QLatin1String("-mnt");
    }

    void CryptoManager::setAegisFSFileSystemPath(const QString &path)
    {
    	m_aegisFSFileSystemPath = path;
    }

    bool CryptoManager::setFileSystemSize(const quint32 size)
    {
        if (size < MINUMUM_ENCRYPTED_FILE_SYSTEM_SIZE) {
            TRACE() << "Minumum encrypted file size is 4 Mb.";
            return false;
        }
        m_fileSystemSize = size;
        return true;
    }

    void CryptoManager::setEncryptionKey(const QByteArray &key)
    {
        if (fileSystemIsMounted()) {
            BLAME() << "File system already mounted";
            return;
        }

        m_accessCode = key;
    }

    bool CryptoManager::setFileSystemType(const QString &type)
    {
        QString cmpBase = type.toLower();
        if (cmpBase == QLatin1String(EXT2)) {
            m_fileSystemType = Ext2;
            return true;
        } else if (cmpBase == QLatin1String(EXT3)) {
            m_fileSystemType = Ext3;
            return true;
        } else if (cmpBase == QLatin1String(EXT4)) {
            m_fileSystemType = Ext4;
            return true;
        }
        return false;
    }

    bool CryptoManager::setupFileSystem()
    {
        if (m_mountState == Mounted) {
            TRACE() << "Ecrypyted file system already mounted.";
            return false;
        }

        if (m_accessCode.isEmpty()) {
            TRACE() << "No access code set. Stopping mount process.";
            return false;
        }

        if (!CryptsetupHandler::loadDmMod()) {
            BLAME() << "Could not load `dm_mod`!";
            return false;
        }

        clearFileSystemResources();

        m_loopDeviceName = LosetupHandler::findAvailableDevice();
        if (m_loopDeviceName.isNull()) {
            BLAME() << "No free loop device available!";
            return false;
        }

        if (!PartitionHandler::createPartitionFile(m_fileSystemPath, m_fileSystemSize)) {
            BLAME() << "Could not create partition file.";
            unmountFileSystem();
            return false;
        }

        if (!LosetupHandler::setupDevice(m_loopDeviceName,
                                         m_fileSystemPath)) {
            BLAME() << "Failed to setup loop device:" << m_loopDeviceName;
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopSet);

        if (!CryptsetupHandler::formatFile(m_accessCode, m_loopDeviceName)) {
            BLAME() << "Failed to LUKS format.";
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopLuksFormatted);

        //attempt luks close, in case of a leftover.
        if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName)) {
            TRACE() << "Filesystem exists, closing";
            CryptsetupHandler::closeFile(m_fileSystemName);
        }

        if (!CryptsetupHandler::openFile(m_accessCode,
                                         m_loopDeviceName,
                                         m_fileSystemName)) {
            BLAME() << "Failed to LUKS open";
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopLuksOpened);

        if (!PartitionHandler::formatPartitionFile(m_fileSystemMapPath,
                                                   m_fileSystemType)) {
            BLAME() << "Could not format mapped partition.";
            unmountFileSystem();
            return false;
        }

        if (!mountMappedDevice()) {
            BLAME() << "Failed to mount ecrypted file system.";
            unmountFileSystem();
            return false;
        }

        addKeyToKeychain(m_accessCode);
        updateMountState(Mounted);
        return true;
    }

    //TODO - add checking for LUKS header in case of preavious app run formatting failure
    bool CryptoManager::mountFileSystem()
    {
        if (m_mountState == Mounted) {
            TRACE() << "Ecrypyted file system already mounted.";
            return false;
        }

        if (m_accessCode.isEmpty()) {
            TRACE() << "No access code set. Stopping mount process.";
            return false;
        }

        clearFileSystemResources();

        if (!CryptsetupHandler::loadDmMod()) {
            BLAME() << "Could not load `dm_mod`!";
            return false;
        }

        m_loopDeviceName = LosetupHandler::findAvailableDevice();
        if (m_loopDeviceName.isNull()) {
            BLAME() << "No free loop device available!";
            return false;
        }

        if (!LosetupHandler::setupDevice(m_loopDeviceName, m_fileSystemPath)) {
            BLAME() << "Failed to setup loop device:" << m_loopDeviceName;
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopSet);

        //attempt luks close, in case of a leftover.
        if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName))
            CryptsetupHandler::closeFile(m_fileSystemName);

        if (!CryptsetupHandler::openFile(m_accessCode,
                                         m_loopDeviceName,
                                         m_fileSystemName)) {
            BLAME() << "Failed to LUKS open.";
            unmountFileSystem();
            return false;
        }
        updateMountState(LoopLuksOpened);

        if (!mountMappedDevice()) {
            TRACE() << "Failed to mount ecrypted file system.";
            unmountFileSystem();
            return false;
        }

        addKeyToKeychain(m_accessCode);
        updateMountState(Mounted);
        return true;
    }

    void CryptoManager::clearFileSystemResources()
    {
        /*
            This method is a `just in case call` for the situations
            when signond closes whithout handling the unmounting of
            the secure storage.
        */

        TRACE() << "--- START clearing secure storage possibly used resources."
                   " Ignore possible errors. ---";

        if (!unmountMappedDevice())
            TRACE() << "Unmounting mapped device failed.";

        if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName)) {
            if (!CryptsetupHandler::closeFile(m_fileSystemName))
                TRACE() << "Failed to LUKS close.";
        }

        /*
         TODO - find a way to check which loop device was previously used by
                signond and close that specific one, until then this will be
                skipped as it might close devices used by different processes.

        if (!LosetupHandler::releaseDevice(m_loopDeviceName)) {
            TRACE() << "Failed to release loop device.";
        */

        TRACE() << "--- DONE clearing secure storage possibly used resources. ---";
    }

    bool CryptoManager::unmountFileSystem()
    {
        if (m_mountState == Unmounted) {
            TRACE() << "Ecrypyted file system not mounted.";
            return true;
        }

        emit fileSystemUnmounting();
        bool isOk = true;

        if ((m_mountState >= Mounted)
            && !unmountMappedDevice()) {
            TRACE() << "Failed to unmount mapped loop device.";
            isOk = false;
        } else {
            TRACE() << "Mapped loop device unmounted.";
        }

        if ((m_mountState >= LoopLuksOpened)
            && (!CryptsetupHandler::closeFile(m_fileSystemName))) {
            TRACE() << "Failed to LUKS close.";
            isOk = false;
        } else {
            TRACE() << "Luks close succeeded.";
        }

        if ((m_mountState >= LoopSet)
            && (!LosetupHandler::releaseDevice(m_loopDeviceName))) {
            TRACE() << "Failed to release loop device.";
            isOk = false;
        } else {
            TRACE() << "Loop device released.";
        }

        updateMountState(Unmounted);
        return isOk;
    }

    bool CryptoManager::deleteFileSystem()
    {
        if (m_mountState > Unmounted) {
            if (!unmountFileSystem())
                return false;
        }

        //TODO - implement effective deletion in specific handler object
        return false;
    }

    bool CryptoManager::fileSystemIsSetup() const
    {
        return QFile::exists(fileSystemPath());
    }

    //TODO - debug this method. Current test scenarios do no cover this one
    bool CryptoManager::fileSystemContainsFile(const QString &filePath)
    {
        if (!fileSystemIsMounted()) {
            TRACE() << "Ecrypyted file system not mounted.";
            return false;
        }

        QDir mountDir(m_fileSystemMountPath);
        return mountDir.exists(QDir::toNativeSeparators(filePath));
    }

    QString CryptoManager::fileSystemMountPath() const
    {
        return m_fileSystemMountPath;
    }

    void CryptoManager::updateMountState(const FileSystemMountState state)
    {
        TRACE() << "Updating mount state:" << state;
        if (state == m_mountState) return;

        m_mountState = state;
        if (state == Mounted)
            emit fileSystemMounted();
    }

    bool CryptoManager::mountMappedDevice()
    {
        //create mnt dir if not existant
        if (!QFile::exists(m_fileSystemMountPath)) {
            QDir dir;
            if (!dir.mkpath(m_fileSystemMountPath)) {
                BLAME() << "Could not create target mount dir path.";
                return false;
            }

            if (!setUserOwnership(m_fileSystemMountPath))
                TRACE() << "Failed to set User ownership for "
                           "the secure storage mount target.";
        }

        MountHandler::mount(m_fileSystemMapPath, m_fileSystemMountPath);
        return true;
    }

    bool CryptoManager::unmountMappedDevice()
    {
        return MountHandler::umount(m_fileSystemMountPath);
    }

    bool CryptoManager::addEncryptionKey(const QByteArray &key,
                                         const QByteArray &existingKey)
    {
        /*
         * TODO -- limit number of stored keys to the total available slots - 1.
         */
        if (m_mountState >= LoopLuksOpened) {
            if (CryptsetupHandler::addKeySlot(
                    m_loopDeviceName, key, existingKey)) {

                addKeyToKeychain(key);
                return true;
            }
        }
        TRACE() << "FAILED to occupy key slot on the encrypted file system header.";
        return false;
    }

    bool CryptoManager::removeEncryptionKey(const QByteArray &key,
                                            const QByteArray &remainingKey)
    {
        if (m_mountState >= LoopLuksOpened) {
            if (CryptsetupHandler::removeKeySlot(
                m_loopDeviceName, key, remainingKey))

                removeKeyFromKeychain(key);
                return true;
        }
        TRACE() << "FAILED to release key slot from the encrypted file system header.";
        return false;
    }

    bool CryptoManager::encryptionKeyInUse(const QByteArray &key)
    {
        if (fileSystemIsMounted() && (m_accessCode == key))
            return true;

        if(!fileSystemIsMounted()) {
           setEncryptionKey(key);
           return mountFileSystem();
        }

        /* Variant that tests if the key is in the LUKS keychain
         * by using a file on the encrypted storage containing the keychain.
         */
        return keychainContainsKey(key);

        /*
         * Variant that tests if the key is in the LUKS keychain
         * by directly accessing the LUKS system
         *
         * QByteArray dummyKey("dummy");
         * if (addEncryptionKey(dummyKey, key)) {
         *     if (!removeEncryptionKey(dummyKey, key))
         *         BLAME() << "Could not remove dummy auxiliary key "
         *                    "from encrypted file system header.";
         *    return true;
         * }
         *
         * return false;
         */
    }

    //TODO - remove this after stable version is achieved.
    void CryptoManager::serializeData()
    {
        TRACE() << "m_accessCode" << m_accessCode;
        TRACE() << "m_fileSystemPath" << m_fileSystemPath;
        TRACE() << "m_fileSystemMapPath" << m_fileSystemMapPath;
        TRACE() << "m_fileSystemName" << m_fileSystemName;
        TRACE() << "m_loopDeviceName" << m_loopDeviceName;
        TRACE() << "m_fileSystemType" << m_fileSystemType;
        TRACE() << "m_fileSystemSize" << m_fileSystemSize;
    }
} //namespace SignonDaemonNS
<|endoftext|>


<commit_before>/*
 ** Author(s):
 **  - Herve Cuche <hcuche@aldebaran-robotics.com>
 **
 ** Copyright (C) 2010, 2012 Aldebaran Robotics
 */

#include <vector>
#include <iostream>
#include <string>

#include <gtest/gtest.h>

#include <qimessaging/session.hpp>
#include <qimessaging/object.hpp>
#include <qimessaging/server.hpp>
#include <qimessaging/service_directory.hpp>
#include <qimessaging/gateway.hpp>
#include <qi/os.hpp>

static std::string reply(const std::string &msg)
{
  return msg;
}

static std::string connectionAddr;

TEST(QiSession, simpleConnectionToSd)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(5000);

  EXPECT_TRUE(connected);

  EXPECT_TRUE(session.isConnected());

  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, simpleConnectionToNonReachableSd)
{
  qi::Session session;
  session.connect("tcp://127.0.1.123:1245");
  bool connected = session.waitForConnected(5000);

  EXPECT_FALSE(connected);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, simpleConnectionToInvalidAddrToSd)
{
  qi::Session session;
  session.connect("tcp://0.0.0.0:0");
  bool connected = session.waitForConnected(5000);

  EXPECT_FALSE(connected);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, simpleConnectionToInvalidSd)
{
  qi::Session session;
  session.connect("invalidAddress");
  bool connected = session.waitForConnected(5000);

  EXPECT_FALSE(connected);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, getSimpleService)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(5000);
  EXPECT_TRUE(connected);

  qi::Object obj;
  qi::Server srv;
  obj.advertiseMethod("reply", &reply);

  unsigned int servicePort = qi::os::findAvailablePort(0);
  std::stringstream serviceAddr;
  serviceAddr << "tcp://127.0.0.1:" << servicePort;

  srv.listen(&session, serviceAddr.str());
  srv.registerService("serviceTest", &obj);
  ASSERT_TRUE(session.waitForServiceReady("serviceTest"));

  qi::Object *object = session.service("serviceTest");
  EXPECT_TRUE(object);

  delete object;
  srv.close();
  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, getUnregisterService)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(5000);

  EXPECT_TRUE(connected);

  qi::Object *object = session.service("serviceTest");
  EXPECT_FALSE(object);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, getCloseService)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(5000);
  EXPECT_TRUE(connected);

  qi::Object obj;
  qi::Server srv;
  obj.advertiseMethod("reply", &reply);

  unsigned int servicePort = qi::os::findAvailablePort(0);
  std::stringstream serviceAddr;
  serviceAddr << "tcp://127.0.0.1:" << servicePort;

  srv.listen(&session, serviceAddr.str());
  srv.registerService("serviceTest", &obj);
  srv.close();

  qi::Object *object = session.service("serviceTest");
  EXPECT_FALSE(object);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(5000);

  EXPECT_TRUE(disconnected);
}
int main(int argc, char **argv)
{
#if defined(__APPLE__) || defined(__linux__)
  setsid();
#endif
  ::testing::InitGoogleTest(&argc, argv);

  qi::ServiceDirectory sd;
  unsigned int sdPort = qi::os::findAvailablePort(5555);
  std::stringstream sdAddr;
  sdAddr << "tcp://127.0.0.1:" << sdPort;
  connectionAddr = sdAddr.str();

  sd.listen(sdAddr.str());

  return RUN_ALL_TESTS();
}
<commit_msg>test_session: lower timeout<commit_after>/*
 ** Author(s):
 **  - Herve Cuche <hcuche@aldebaran-robotics.com>
 **
 ** Copyright (C) 2010, 2012 Aldebaran Robotics
 */

#include <vector>
#include <iostream>
#include <string>

#include <gtest/gtest.h>

#include <qimessaging/session.hpp>
#include <qimessaging/object.hpp>
#include <qimessaging/server.hpp>
#include <qimessaging/service_directory.hpp>
#include <qimessaging/gateway.hpp>
#include <qi/os.hpp>

static std::string reply(const std::string &msg)
{
  return msg;
}

static std::string connectionAddr;

TEST(QiSession, simpleConnectionToSd)
{
  qi::Session session;
  session.connect(connectionAddr);
  ASSERT_TRUE(session.waitForConnected(1000));

  EXPECT_TRUE(session.isConnected());

  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, simpleConnectionToNonReachableSd)
{
  qi::Session session;
  session.connect("tcp://127.0.1.123:1245");
  bool connected = session.waitForConnected(1000);

  EXPECT_FALSE(connected);
  EXPECT_FALSE(session.isConnected());

  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, simpleConnectionToInvalidAddrToSd)
{
  qi::Session session;
  session.connect("tcp://0.0.0.0:0");
  bool connected = session.waitForConnected(1000);

  EXPECT_FALSE(connected);
  EXPECT_FALSE(session.isConnected());

  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, simpleConnectionToInvalidSd)
{
  qi::Session session;
  session.connect("invalidAddress");
  bool connected = session.waitForConnected(1000);

  EXPECT_FALSE(connected);
  EXPECT_FALSE(session.isConnected());

  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, getSimpleService)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(1000);
  EXPECT_TRUE(connected);

  qi::Object obj;
  qi::Server srv;
  obj.advertiseMethod("reply", &reply);

  unsigned int servicePort = qi::os::findAvailablePort(0);
  std::stringstream serviceAddr;
  serviceAddr << "tcp://127.0.0.1:" << servicePort;

  srv.listen(&session, serviceAddr.str());
  srv.registerService("serviceTest", &obj);
  ASSERT_TRUE(session.waitForServiceReady("serviceTest"));

  qi::Object *object = session.service("serviceTest");
  EXPECT_TRUE(object);

  delete object;
  srv.close();
  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, getUnregisterService)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(1000);

  EXPECT_TRUE(connected);

  qi::Object *object = session.service("serviceTest");
  EXPECT_FALSE(object);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}

TEST(QiSession, getCloseService)
{
  qi::Session session;
  session.connect(connectionAddr);
  bool connected = session.waitForConnected(1000);
  EXPECT_TRUE(connected);

  qi::Object obj;
  qi::Server srv;
  obj.advertiseMethod("reply", &reply);

  unsigned int servicePort = qi::os::findAvailablePort(0);
  std::stringstream serviceAddr;
  serviceAddr << "tcp://127.0.0.1:" << servicePort;

  srv.listen(&session, serviceAddr.str());
  srv.registerService("serviceTest", &obj);
  srv.close();

  qi::Object *object = session.service("serviceTest");
  EXPECT_FALSE(object);

  session.disconnect();
  bool disconnected = session.waitForDisconnected(1000);

  EXPECT_TRUE(disconnected);
}
int main(int argc, char **argv)
{
#if defined(__APPLE__) || defined(__linux__)
  setsid();
#endif
  ::testing::InitGoogleTest(&argc, argv);

  qi::ServiceDirectory sd;
  unsigned int sdPort = qi::os::findAvailablePort(5555);
  std::stringstream sdAddr;
  sdAddr << "tcp://127.0.0.1:" << sdPort;
  connectionAddr = sdAddr.str();

  sd.listen(sdAddr.str());

  return RUN_ALL_TESTS();
}
<|endoftext|>


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

#include "base/platform_thread.h"

#if defined(OS_POSIX)
#include <errno.h>
#include <sched.h>
#endif

#if defined(OS_MACOSX)
#include <mach/mach.h>
#elif defined(OS_LINUX)
#include <sys/types.h>
#include <unistd.h>
#endif

// static
PlatformThread PlatformThread::Current() {
  PlatformThread thread;

#if defined(OS_WIN)
  thread.thread_ = GetCurrentThread();
#elif defined(OS_POSIX)
  thread.thread_ = pthread_self();
#endif

  return thread;
}

// static
void PlatformThread::YieldCurrentThread() {
#if defined(OS_WIN)
  ::Sleep(0);
#elif defined(OS_POSIX)
  sched_yield();
#endif
}

// static
void PlatformThread::Sleep(int duration_ms) {
#if defined(OS_WIN)
  ::Sleep(duration_ms);
#elif defined (OS_POSIX)
  struct timespec sleep_time, remaining;
  // Contains the portion of duration_ms >= 1 sec.
  sleep_time.tv_sec = duration_ms / 1000;
  duration_ms -= sleep_time.tv_sec * 1000;
  // Contains the portion of duration_ms < 1 sec.
  sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) {
    sleep_time = remaining;
  }
#endif
}

// static
int PlatformThread::CurrentId() {
#if defined(OS_WIN)
  return GetCurrentThreadId();
#elif defined(OS_MACOSX)
  return mach_thread_self();
#elif defined(OS_LINUX)
  return gettid();
#endif
}

bool PlatformThread::operator==(const PlatformThread& other_thread) {
#if defined(OS_WIN)
  return thread_ == other_thread.thread_;
#elif defined(OS_POSIX)
  return pthread_equal(thread_, other_thread.thread_);
#endif
}
<commit_msg>Use syscall instead since gettid doesn't seem to exist.<commit_after>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "base/platform_thread.h"

#if defined(OS_POSIX)
#include <errno.h>
#include <sched.h>
#endif

#if defined(OS_MACOSX)
#include <mach/mach.h>
#elif defined(OS_LINUX)
#include <sys/syscall.h>
#include <unistd.h>
#endif

// static
PlatformThread PlatformThread::Current() {
  PlatformThread thread;

#if defined(OS_WIN)
  thread.thread_ = GetCurrentThread();
#elif defined(OS_POSIX)
  thread.thread_ = pthread_self();
#endif

  return thread;
}

// static
void PlatformThread::YieldCurrentThread() {
#if defined(OS_WIN)
  ::Sleep(0);
#elif defined(OS_POSIX)
  sched_yield();
#endif
}

// static
void PlatformThread::Sleep(int duration_ms) {
#if defined(OS_WIN)
  ::Sleep(duration_ms);
#elif defined (OS_POSIX)
  struct timespec sleep_time, remaining;
  // Contains the portion of duration_ms >= 1 sec.
  sleep_time.tv_sec = duration_ms / 1000;
  duration_ms -= sleep_time.tv_sec * 1000;
  // Contains the portion of duration_ms < 1 sec.
  sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) {
    sleep_time = remaining;
  }
#endif
}

// static
int PlatformThread::CurrentId() {
#if defined(OS_WIN)
  return GetCurrentThreadId();
#elif defined(OS_MACOSX)
  return mach_thread_self();
#elif defined(OS_LINUX)
  return syscall(__NR_gettid);
#endif
}

bool PlatformThread::operator==(const PlatformThread& other_thread) {
#if defined(OS_WIN)
  return thread_ == other_thread.thread_;
#elif defined(OS_POSIX)
  return pthread_equal(thread_, other_thread.thread_);
#endif
}
<|endoftext|>


<commit_before><commit_msg>evb7: separate enable calls for A/B<commit_after><|endoftext|>


<commit_before>//Simple test for a merge

// Some Stubs
int add( int a, int b )
{
	return 0;
}

int subtract( int a, int b )
{
	return 0;
}

int multiply( int a, int b )
{
	return a * b;
}<commit_msg>changed some of hutches code to make it aweseomer<commit_after>//Simple test for a merge

// Some Stubs
int add( int a, int b )
{
	//returns a summation of a and b
	return a+b;
}

int minus( int a, int b )
{
	return b-a;
}
<|endoftext|>