<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tab_contents/native_tab_contents_container_aura.h"

#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
#include "content/browser/tab_contents/interstitial_page.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "ui/aura/window.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/views_delegate.h"

using content::WebContents;

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, public:

NativeTabContentsContainerAura::NativeTabContentsContainerAura(
    TabContentsContainer* container)
    : container_(container) {
  set_id(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW);
}

NativeTabContentsContainerAura::~NativeTabContentsContainerAura() {
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, NativeTabContentsContainer overrides:

void NativeTabContentsContainerAura::AttachContents(WebContents* contents) {
  // We need to register the tab contents window with the BrowserContainer so
  // that the BrowserContainer is the focused view when the focus is on the
  // TabContents window (for the TabContents case).
  set_focus_view(this);

  Attach(contents->GetNativeView());
}

void NativeTabContentsContainerAura::DetachContents(WebContents* contents) {
  // Detach the TabContents.  Do this before we unparent the
  // TabContentsViewViews so that the window hierarchy is intact for any
  // cleanup during Detach().
  Detach();
}

void NativeTabContentsContainerAura::SetFastResize(bool fast_resize) {
  set_fast_resize(fast_resize);
}

bool NativeTabContentsContainerAura::GetFastResize() const {
  return fast_resize();
}

bool NativeTabContentsContainerAura::FastResizeAtLastLayout() const {
  return fast_resize_at_last_layout();
}

void NativeTabContentsContainerAura::RenderViewHostChanged(
    RenderViewHost* old_host,
    RenderViewHost* new_host) {
  // If we are focused, we need to pass the focus to the new RenderViewHost.
  if (GetFocusManager()->GetFocusedView() == this)
    OnFocus();
}

views::View* NativeTabContentsContainerAura::GetView() {
  return this;
}

void NativeTabContentsContainerAura::WebContentsFocused(WebContents* contents) {
  views::FocusManager* focus_manager = GetFocusManager();
  if (!focus_manager) {
    NOTREACHED();
    return;
  }
  focus_manager->SetFocusedView(this);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, views::View overrides:

bool NativeTabContentsContainerAura::SkipDefaultKeyEventProcessing(
    const views::KeyEvent& e) {
  // Don't look-up accelerators or tab-traversal if we are showing a non-crashed
  // TabContents.
  // We'll first give the page a chance to process the key events.  If it does
  // not process them, they'll be returned to us and we'll treat them as
  // accelerators then.
  return container_->web_contents() &&
         !container_->web_contents()->IsCrashed();
}

bool NativeTabContentsContainerAura::IsFocusable() const {
  // We need to be focusable when our contents is not a view hierarchy, as
  // clicking on the contents needs to focus us.
  return container_->tab_contents() != NULL;
}

void NativeTabContentsContainerAura::OnFocus() {
  if (container_->web_contents())
    container_->web_contents()->Focus();
}

void NativeTabContentsContainerAura::RequestFocus() {
  // This is a hack to circumvent the fact that a the OnFocus() method is not
  // invoked when RequestFocus() is called on an already focused view.
  // The TabContentsContainer is the view focused when the TabContents has
  // focus.  When switching between from one tab that has focus to another tab
  // that should also have focus, RequestFocus() is invoked one the
  // TabContentsContainer.  In order to make sure OnFocus() is invoked we need
  // to clear the focus before hands.
  if (GetFocusManager()) {
    // Disable notifications.  Clear focus will assign the focus to the main
    // browser window.  Because this change of focus was not user requested,
    // don't send it to listeners.
    views::AutoNativeNotificationDisabler local_notification_disabler;
    GetFocusManager()->ClearFocus();
  }
  View::RequestFocus();
}

void NativeTabContentsContainerAura::AboutToRequestFocusFromTabTraversal(
    bool reverse) {
  container_->web_contents()->FocusThroughTabTraversal(reverse);
}

void NativeTabContentsContainerAura::GetAccessibleState(
    ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
}

gfx::NativeViewAccessible
    NativeTabContentsContainerAura::GetNativeViewAccessible() {
  // TODO(beng):
  NOTIMPLEMENTED();
  return View::GetNativeViewAccessible();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainer, public:

// static
NativeTabContentsContainer* NativeTabContentsContainer::CreateNativeContainer(
    TabContentsContainer* container) {
  return new NativeTabContentsContainerAura(container);
}
<commit_msg>Fix aura<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tab_contents/native_tab_contents_container_aura.h"

#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
#include "content/browser/tab_contents/interstitial_page.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "ui/aura/window.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/views_delegate.h"

using content::WebContents;

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, public:

NativeTabContentsContainerAura::NativeTabContentsContainerAura(
    TabContentsContainer* container)
    : container_(container) {
  set_id(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW);
}

NativeTabContentsContainerAura::~NativeTabContentsContainerAura() {
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, NativeTabContentsContainer overrides:

void NativeTabContentsContainerAura::AttachContents(WebContents* contents) {
  // We need to register the tab contents window with the BrowserContainer so
  // that the BrowserContainer is the focused view when the focus is on the
  // TabContents window (for the TabContents case).
  set_focus_view(this);

  Attach(contents->GetNativeView());
}

void NativeTabContentsContainerAura::DetachContents(WebContents* contents) {
  // Detach the TabContents.  Do this before we unparent the
  // TabContentsViewViews so that the window hierarchy is intact for any
  // cleanup during Detach().
  Detach();
}

void NativeTabContentsContainerAura::SetFastResize(bool fast_resize) {
  set_fast_resize(fast_resize);
}

bool NativeTabContentsContainerAura::GetFastResize() const {
  return fast_resize();
}

bool NativeTabContentsContainerAura::FastResizeAtLastLayout() const {
  return fast_resize_at_last_layout();
}

void NativeTabContentsContainerAura::RenderViewHostChanged(
    RenderViewHost* old_host,
    RenderViewHost* new_host) {
  // If we are focused, we need to pass the focus to the new RenderViewHost.
  if (GetFocusManager()->GetFocusedView() == this)
    OnFocus();
}

views::View* NativeTabContentsContainerAura::GetView() {
  return this;
}

void NativeTabContentsContainerAura::WebContentsFocused(WebContents* contents) {
  views::FocusManager* focus_manager = GetFocusManager();
  if (!focus_manager) {
    NOTREACHED();
    return;
  }
  focus_manager->SetFocusedView(this);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, views::View overrides:

bool NativeTabContentsContainerAura::SkipDefaultKeyEventProcessing(
    const views::KeyEvent& e) {
  // Don't look-up accelerators or tab-traversal if we are showing a non-crashed
  // TabContents.
  // We'll first give the page a chance to process the key events.  If it does
  // not process them, they'll be returned to us and we'll treat them as
  // accelerators then.
  return container_->web_contents() &&
         !container_->web_contents()->IsCrashed();
}

bool NativeTabContentsContainerAura::IsFocusable() const {
  // We need to be focusable when our contents is not a view hierarchy, as
  // clicking on the contents needs to focus us.
  return container_->web_contents() != NULL;
}

void NativeTabContentsContainerAura::OnFocus() {
  if (container_->web_contents())
    container_->web_contents()->Focus();
}

void NativeTabContentsContainerAura::RequestFocus() {
  // This is a hack to circumvent the fact that a the OnFocus() method is not
  // invoked when RequestFocus() is called on an already focused view.
  // The TabContentsContainer is the view focused when the TabContents has
  // focus.  When switching between from one tab that has focus to another tab
  // that should also have focus, RequestFocus() is invoked one the
  // TabContentsContainer.  In order to make sure OnFocus() is invoked we need
  // to clear the focus before hands.
  if (GetFocusManager()) {
    // Disable notifications.  Clear focus will assign the focus to the main
    // browser window.  Because this change of focus was not user requested,
    // don't send it to listeners.
    views::AutoNativeNotificationDisabler local_notification_disabler;
    GetFocusManager()->ClearFocus();
  }
  View::RequestFocus();
}

void NativeTabContentsContainerAura::AboutToRequestFocusFromTabTraversal(
    bool reverse) {
  container_->web_contents()->FocusThroughTabTraversal(reverse);
}

void NativeTabContentsContainerAura::GetAccessibleState(
    ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
}

gfx::NativeViewAccessible
    NativeTabContentsContainerAura::GetNativeViewAccessible() {
  // TODO(beng):
  NOTIMPLEMENTED();
  return View::GetNativeViewAccessible();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainer, public:

// static
NativeTabContentsContainer* NativeTabContentsContainer::CreateNativeContainer(
    TabContentsContainer* container) {
  return new NativeTabContentsContainerAura(container);
}
<|endoftext|>


<commit_before>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// 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 "rclcpp/executors/multi_threaded_executor.hpp"

#include <chrono>
#include <functional>
#include <vector>

#include "rclcpp/utilities.hpp"
#include "rclcpp/scope_exit.hpp"

using rclcpp::executors::multi_threaded_executor::MultiThreadedExecutor;

MultiThreadedExecutor::MultiThreadedExecutor(rclcpp::memory_strategy::MemoryStrategy::SharedPtr ms)
: executor::Executor(ms)
{
  number_of_threads_ = std::thread::hardware_concurrency();
  if (number_of_threads_ == 0) {
    number_of_threads_ = 1;
  }
}

MultiThreadedExecutor::~MultiThreadedExecutor() {}

void
MultiThreadedExecutor::spin()
{
  if (spinning.exchange(true)) {
    throw std::runtime_error("spin() called while already spinning");
  }
  RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
  std::vector<std::thread> threads;
  {
    std::lock_guard<std::mutex> wait_lock(wait_mutex_);
    size_t thread_id = 1;
    for (size_t i = number_of_threads_; i > 0; --i) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      auto func = std::bind(&MultiThreadedExecutor::run, this, thread_id++);
      threads.emplace_back(func);
    }
  }
  for (auto & thread : threads) {
    thread.join();
  }
}

size_t
MultiThreadedExecutor::get_number_of_threads()
{
  return number_of_threads_;
}

void
MultiThreadedExecutor::run(size_t this_thread_number)
{
  thread_number_by_thread_id_[std::this_thread::get_id()] = this_thread_number;
  while (rclcpp::utilities::ok() && spinning.load()) {
    executor::AnyExecutable::SharedPtr any_exec;
    {
      std::lock_guard<std::mutex> wait_lock(wait_mutex_);
      if (!rclcpp::utilities::ok() || !spinning.load()) {
        return;
      }
      any_exec = get_next_executable();
    }
    execute_any_executable(any_exec);
  }
}
<commit_msg>Get rid of idle thread in MultiThreadedExecutor<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// 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 "rclcpp/executors/multi_threaded_executor.hpp"

#include <chrono>
#include <functional>
#include <vector>

#include "rclcpp/utilities.hpp"
#include "rclcpp/scope_exit.hpp"

using rclcpp::executors::multi_threaded_executor::MultiThreadedExecutor;

MultiThreadedExecutor::MultiThreadedExecutor(rclcpp::memory_strategy::MemoryStrategy::SharedPtr ms)
: executor::Executor(ms)
{
  number_of_threads_ = std::thread::hardware_concurrency();
  if (number_of_threads_ == 0) {
    number_of_threads_ = 1;
  }
}

MultiThreadedExecutor::~MultiThreadedExecutor() {}

void
MultiThreadedExecutor::spin()
{
  if (spinning.exchange(true)) {
    throw std::runtime_error("spin() called while already spinning");
  }
  RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
  std::vector<std::thread> threads;
  size_t thread_id = 0;
  {
    std::lock_guard<std::mutex> wait_lock(wait_mutex_);
    for (; thread_id < number_of_threads_ - 1; ++thread_id) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      auto func = std::bind(&MultiThreadedExecutor::run, this, thread_id);
      threads.emplace_back(func);
    }
  }

  run(thread_id);
  for (auto & thread : threads) {
    thread.join();
  }
}

size_t
MultiThreadedExecutor::get_number_of_threads()
{
  return number_of_threads_;
}

void
MultiThreadedExecutor::run(size_t this_thread_number)
{
  thread_number_by_thread_id_[std::this_thread::get_id()] = this_thread_number;
  while (rclcpp::utilities::ok() && spinning.load()) {
    executor::AnyExecutable::SharedPtr any_exec;
    {
      std::lock_guard<std::mutex> wait_lock(wait_mutex_);
      if (!rclcpp::utilities::ok() || !spinning.load()) {
        return;
      }
      any_exec = get_next_executable();
    }
    execute_any_executable(any_exec);
  }
}
<|endoftext|>


<commit_before>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// 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 "rclcpp/executors/multi_threaded_executor.hpp"

#include <chrono>
#include <functional>
#include <vector>

#include "rclcpp/utilities.hpp"
#include "rclcpp/scope_exit.hpp"

using rclcpp::executors::multi_threaded_executor::MultiThreadedExecutor;

MultiThreadedExecutor::MultiThreadedExecutor(rclcpp::memory_strategy::MemoryStrategy::SharedPtr ms)
: executor::Executor(ms)
{
  number_of_threads_ = std::thread::hardware_concurrency();
  if (number_of_threads_ == 0) {
    number_of_threads_ = 1;
  }
}

MultiThreadedExecutor::~MultiThreadedExecutor() {}

void
MultiThreadedExecutor::spin()
{
  if (spinning.exchange(true)) {
    throw std::runtime_error("spin() called while already spinning");
  }
  RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
  std::vector<std::thread> threads;
  size_t thread_id = 0;
  {
    std::lock_guard<std::mutex> wait_lock(wait_mutex_);
    for (; thread_id < number_of_threads_ - 1; ++thread_id) {
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
      auto func = std::bind(&MultiThreadedExecutor::run, this, thread_id);
      threads.emplace_back(func);
    }
  }

  run(thread_id);
  for (auto & thread : threads) {
    thread.join();
  }
}

size_t
MultiThreadedExecutor::get_number_of_threads()
{
  return number_of_threads_;
}

void
MultiThreadedExecutor::run(size_t this_thread_number)
{
  thread_number_by_thread_id_[std::this_thread::get_id()] = this_thread_number;
  while (rclcpp::utilities::ok() && spinning.load()) {
    executor::AnyExecutable::SharedPtr any_exec;
    {
      std::lock_guard<std::mutex> wait_lock(wait_mutex_);
      if (!rclcpp::utilities::ok() || !spinning.load()) {
        return;
      }
      any_exec = get_next_executable();
    }
    execute_any_executable(any_exec);
  }
}
<commit_msg>remove excess sleep identified in #169<commit_after>// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// 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 "rclcpp/executors/multi_threaded_executor.hpp"

#include <chrono>
#include <functional>
#include <vector>

#include "rclcpp/utilities.hpp"
#include "rclcpp/scope_exit.hpp"

using rclcpp::executors::multi_threaded_executor::MultiThreadedExecutor;

MultiThreadedExecutor::MultiThreadedExecutor(rclcpp::memory_strategy::MemoryStrategy::SharedPtr ms)
: executor::Executor(ms)
{
  number_of_threads_ = std::thread::hardware_concurrency();
  if (number_of_threads_ == 0) {
    number_of_threads_ = 1;
  }
}

MultiThreadedExecutor::~MultiThreadedExecutor() {}

void
MultiThreadedExecutor::spin()
{
  if (spinning.exchange(true)) {
    throw std::runtime_error("spin() called while already spinning");
  }
  RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
  std::vector<std::thread> threads;
  size_t thread_id = 0;
  {
    std::lock_guard<std::mutex> wait_lock(wait_mutex_);
    for (; thread_id < number_of_threads_ - 1; ++thread_id) {
      auto func = std::bind(&MultiThreadedExecutor::run, this, thread_id);
      threads.emplace_back(func);
    }
  }

  run(thread_id);
  for (auto & thread : threads) {
    thread.join();
  }
}

size_t
MultiThreadedExecutor::get_number_of_threads()
{
  return number_of_threads_;
}

void
MultiThreadedExecutor::run(size_t this_thread_number)
{
  thread_number_by_thread_id_[std::this_thread::get_id()] = this_thread_number;
  while (rclcpp::utilities::ok() && spinning.load()) {
    executor::AnyExecutable::SharedPtr any_exec;
    {
      std::lock_guard<std::mutex> wait_lock(wait_mutex_);
      if (!rclcpp::utilities::ok() || !spinning.load()) {
        return;
      }
      any_exec = get_next_executable();
    }
    execute_any_executable(any_exec);
  }
}
<|endoftext|>


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

#include "display/Screen.h"

int main()
{
	Screen screen;

	//printw("Starting curses mode with multiple windows...");
	//refresh();

	//getch();

	uint32_t screen_y = screen.getHeight();
	uint32_t screen_x = screen.getWidth();

	screen_y = 40;
	screen_x = 40;

	WINDOW* top = newwin(1, screen_x, 0, 0);
	WINDOW* left = newwin(screen_y-1, 10, 1, 0);
	WINDOW* right = newwin(screen_y-1, screen_x-10, 1, 10);

	mvwprintw(top, 0, 0, "Top");
	mvwprintw(left, 0, 0, "Left");
	mvwprintw(right, 0, 0, "Right");

	wrefresh(top);
	wrefresh(left);
	wrefresh(right);

	getch();
}
<commit_msg>InterfaceTest panels have borders, labels.<commit_after>#include <ncurses.h>
#include <stdint.h>

#include "display/Screen.h"

int main()
{
	Screen screen;

	uint32_t screen_y = screen.getHeight();
	uint32_t screen_x = screen.getWidth();

	WINDOW* top = newwin(3, screen_x, 0, 0);
	WINDOW* left = newwin(screen_y-2, 20, 2, 0);
	WINDOW* right = newwin(screen_y-2, screen_x-19, 2, 19);

	wborder(top, '|', '|', '-', '-', '+', '+', '+', '+');
	wborder(left, '|', '|', '-', '-', '+', '+', '+', '+');
	wborder(right, '|', '|', '-', '-', '+', '+', '+', '+');

	mvwprintw(top, 0, 1, "Message Panel");
	mvwprintw(left, 0, 1, "Stat Panel");
	mvwprintw(right, 0, 1, "Main Panel");

	wrefresh(top);
	wrefresh(left);
	wrefresh(right);

	getch();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

#ifndef BENG_PROXY_LB_MONITOR_CONTROLLER_HXX
#define BENG_PROXY_LB_MONITOR_CONTROLLER_HXX

#include "Monitor.hxx"
#include "io/Logger.hxx"
#include "event/TimerEvent.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "net/FailureRef.hxx"
#include "util/Cancellable.hxx"

class EventLoop;
class FailureManager;
class SocketAddress;
struct LbMonitorConfig;
struct LbMonitorClass;
class LbMonitorController;

class LbMonitorController final : public LbMonitorHandler {
    EventLoop &event_loop;
    FailureRef failure;

    const LbMonitorConfig &config;
    const AllocatedSocketAddress address;
    const LbMonitorClass &class_;

    const Logger logger;

    const struct timeval interval;
    TimerEvent interval_event;

    const struct timeval timeout;
    TimerEvent timeout_event;

    CancellablePointer cancel_ptr;

    bool state = true;
    bool fade = false;

public:
    LbMonitorController(EventLoop &_event_loop,
                        FailureManager &_failure_manager,
                        const char *node_name,
                        const LbMonitorConfig &_config,
                        SocketAddress _address,
                        const LbMonitorClass &_class);

    ~LbMonitorController();

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

    const SocketAddress GetAddress() const {
        return address;
    }

private:
    void IntervalCallback();
    void TimeoutCallback();

    /* virtual methods from class LbMonitorHandler */
    virtual void Success() override;
    virtual void Fade() override;
    virtual void Timeout() override;
    virtual void Error(std::exception_ptr e) override;
};

#endif
<commit_msg>lb/MonitorStock: add reference counter<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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.
 */

#ifndef BENG_PROXY_LB_MONITOR_CONTROLLER_HXX
#define BENG_PROXY_LB_MONITOR_CONTROLLER_HXX

#include "Monitor.hxx"
#include "io/Logger.hxx"
#include "event/TimerEvent.hxx"
#include "net/AllocatedSocketAddress.hxx"
#include "net/FailureRef.hxx"
#include "util/Cancellable.hxx"

class EventLoop;
class FailureManager;
class SocketAddress;
struct LbMonitorConfig;
struct LbMonitorClass;
class LbMonitorController;

class LbMonitorController final : public LbMonitorHandler {
    EventLoop &event_loop;
    FailureRef failure;

    const LbMonitorConfig &config;
    const AllocatedSocketAddress address;
    const LbMonitorClass &class_;

    const Logger logger;

    const struct timeval interval;
    TimerEvent interval_event;

    const struct timeval timeout;
    TimerEvent timeout_event;

    CancellablePointer cancel_ptr;

    bool state = true;
    bool fade = false;

    unsigned ref = 0;

public:
    LbMonitorController(EventLoop &_event_loop,
                        FailureManager &_failure_manager,
                        const char *node_name,
                        const LbMonitorConfig &_config,
                        SocketAddress _address,
                        const LbMonitorClass &_class);

    ~LbMonitorController();

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

    void Ref() noexcept {
        ++ref;
    }

    /**
     * @return true if the reference counter has dropped to 0 (and the
     * object can be deleted)
     */
    bool Unref() noexcept {
        return --ref == 0;
    }

    const SocketAddress GetAddress() const {
        return address;
    }

private:
    void IntervalCallback();
    void TimeoutCallback();

    /* virtual methods from class LbMonitorHandler */
    virtual void Success() override;
    virtual void Fade() override;
    virtual void Timeout() override;
    virtual void Error(std::exception_ptr e) override;
};

#endif
<|endoftext|>


<commit_before>//snippet-sourcedescription:[update_table.cpp demonstrates how to update information about an Amazon DynamoDB table.]
//snippet-keyword:[AWS SDK for C++]
//snippet-keyword:[Code Sample]
//snippet-service:[Amazon DynamoDB]
//snippet-sourcetype:[full-example]
//snippet-sourcedate:[11/30/2021]
//snippet-sourceauthor:[scmacdon - aws]

/*
   Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   SPDX-License-Identifier: Apache-2.0
*/

//snippet-start:[dynamodb.cpp.update_table.inc]
#include <aws/core/Aws.h>
#include <aws/core/utils/Outcome.h>
#include <aws/dynamodb/DynamoDBClient.h>
#include <aws/dynamodb/model/ProvisionedThroughput.h>
#include <aws/dynamodb/model/UpdateTableRequest.h>
#include <iostream>
//snippet-end:[dynamodb.cpp.update_table.inc]

/**
  Update a DynamoDB table.

  Takes the name of the table to update, the read capacity and the write
  capacity to use.

  To run this C++ code example, ensure that you have setup your development environment, including your credentials.
  For information, see this documentation topic:
  https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/getting-started.html
*/
int main(int argc, char** argv)
{
    const std::string USAGE = \
        "Usage:\n"
        "    update_table <table> <read> <write>\n\n"
        "Where:\n"
        "    table - the table to put the item in.\n"
        "    read  - the new read capacity of the table.\n"
        "    write - the new write capacity of the table.\n\n"
        "Example:\n"
        "    update_table HelloTable 16 10\n";

    if (argc < 3)
    {
        std::cout << USAGE;
        return 1;
    }

    Aws::SDKOptions options;
    Aws::InitAPI(options);
    {
        const Aws::String table(argv[1]);
        const long long rc = Aws::Utils::StringUtils::ConvertToInt64(argv[2]);
        const long long wc = Aws::Utils::StringUtils::ConvertToInt64(argv[3]);

        // snippet-start:[dynamodb.cpp.update_table.code]
        Aws::Client::ClientConfiguration clientConfig;
        Aws::DynamoDB::DynamoDBClient dynamoClient(clientConfig);

        std::cout << "Updating " << table << " with new provisioned throughput values" << std::endl;
        std::cout << "Read capacity : " << rc << std::endl;
        std::cout << "Write capacity: " << wc << std::endl;

        Aws::DynamoDB::Model::UpdateTableRequest utr;
        Aws::DynamoDB::Model::ProvisionedThroughput pt;
        pt.WithReadCapacityUnits(rc).WithWriteCapacityUnits(wc);
        utr.WithProvisionedThroughput(pt).WithTableName(table);

        const Aws::DynamoDB::Model::UpdateTableOutcome& result = dynamoClient.UpdateTable(utr);
        if (!result.IsSuccess())
        {
            std::cout << result.GetError().GetMessage() << std::endl;
            return 1;
        }
        std::cout << "Done!" << std::endl;
        // snippet-end:[dynamodb.cpp.update_table.code]
    }
    Aws::ShutdownAPI(options);
    return 0;
}<commit_msg>Delete update_table.cpp<commit_after><|endoftext|>


<commit_before>/**
 * @file x_tre_split.hpp
 * @author Andrew Wells
 *
 * Defintion of the XTreeSplit class, a class that splits the nodes of an X tree, starting
 * at a leaf node and moving upwards if necessary.
 */
#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_X_TREE_SPLIT_HPP
#define __MLPACK_CORE_TREE_RECTANGLE_TREE_X_TREE_SPLIT_HPP

#include <mlpack/core.hpp>

namespace mlpack {
namespace tree /** Trees and tree-building procedures. */ {

/**
 * A Rectangle Tree has new points inserted at the bottom.  When these
 * nodes overflow, we split them, moving up the tree and splitting nodes
 * as necessary.
 */
template<typename DescentType,
	 typename StatisticType,
	 typename MatType>
class XTreeSplit
{
public:

/**
 * The X-tree paper says that a maximum allowable overlap of 20% works well.
 */
const static double MAX_OVERLAP = 0.2;

/**
 * Split a leaf node using the algorithm described in "The R*-tree: An Efficient and Robust Access method
 * for Points and Rectangles."  If necessary, this split will propagate
 * upwards through the tree.
 */
static void SplitLeafNode(RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree, std::vector<bool>& relevels);

/**
 * Split a non-leaf node using the "default" algorithm.  If this is a root node, the
 * tree increases in depth.
 */
static bool SplitNonLeafNode(RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree, std::vector<bool>& relevels);

private:
/**
 * Class to allow for faster sorting.
 */
class sortStruct {
public:
  double d;
  int n;
};

/**
 * Comparator for sorting with sortStruct.
 */
static bool structComp(const sortStruct& s1, const sortStruct& s2) {
  return s1.d < s2.d;
}

/**
  * Insert a node into another node.
  */
static void InsertNodeIntoTree(
    RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* destTree,
    RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* srcNode);

};

}; // namespace tree
}; // namespace mlpack

// Include implementation
#include "x_tree_split_impl.hpp"

#endif<commit_msg>Add comment pointing out that there is a bug.<commit_after>/**
 * @file x_tre_split.hpp
 * @author Andrew Wells
 *
 * Defintion of the XTreeSplit class, a class that splits the nodes of an X
 * tree, starting at a leaf node and moving upwards if necessary.
 *
 * This is known to have a bug: see #368.
 */
#ifndef __MLPACK_CORE_TREE_RECTANGLE_TREE_X_TREE_SPLIT_HPP
#define __MLPACK_CORE_TREE_RECTANGLE_TREE_X_TREE_SPLIT_HPP

#include <mlpack/core.hpp>

namespace mlpack {
namespace tree /** Trees and tree-building procedures. */ {

/**
 * A Rectangle Tree has new points inserted at the bottom.  When these
 * nodes overflow, we split them, moving up the tree and splitting nodes
 * as necessary.
 */
template<typename DescentType,
	 typename StatisticType,
	 typename MatType>
class XTreeSplit
{
public:

/**
 * The X-tree paper says that a maximum allowable overlap of 20% works well.
 */
const static double MAX_OVERLAP = 0.2;

/**
 * Split a leaf node using the algorithm described in "The R*-tree: An Efficient and Robust Access method
 * for Points and Rectangles."  If necessary, this split will propagate
 * upwards through the tree.
 */
static void SplitLeafNode(RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree, std::vector<bool>& relevels);

/**
 * Split a non-leaf node using the "default" algorithm.  If this is a root node, the
 * tree increases in depth.
 */
static bool SplitNonLeafNode(RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* tree, std::vector<bool>& relevels);

private:
/**
 * Class to allow for faster sorting.
 */
class sortStruct {
public:
  double d;
  int n;
};

/**
 * Comparator for sorting with sortStruct.
 */
static bool structComp(const sortStruct& s1, const sortStruct& s2) {
  return s1.d < s2.d;
}

/**
  * Insert a node into another node.
  */
static void InsertNodeIntoTree(
    RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* destTree,
    RectangleTree<XTreeSplit<DescentType, StatisticType, MatType>, DescentType, StatisticType, MatType>* srcNode);

};

}; // namespace tree
}; // namespace mlpack

// Include implementation
#include "x_tree_split_impl.hpp"

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <map>
#include <vector>
#include <sstream>
#include <string>
#include "version.h"
#include "ast.h"
#include "generator.h"

using std::stringstream;
using std::endl;

namespace ecc
{
    generator::generator()
    {

    }

    generator::~generator()
    {

    }

    void defgen::translate(const ast::elist_t& items,
	                   const std::string& fHeader,
			   const std::string& fCode,
			   std::ostream& ostr_c,
			   std::ostream& ostr_h)
    {
	ostr_h << tl_header();
	ostr_c << tl_header();

	/** c file needs to include <string>, and our header */
	ostr_c << "#include <string>" << endl;

	std::string headerLeaf;
	int pos = fHeader.rfind('/');
	if ( pos == std::string::npos )
	{
	    // File is already a leaf
	    headerLeaf = fHeader;
	}
	else
	{
	    // File is not leaf, use everything after the last '/'
	    headerLeaf = fHeader.substr(pos+1, fHeader.length()-pos);
	}

	ostr_c << "#include \"" << headerLeaf << "\"" << std::endl;

	std::string guard = headerLeaf + "_";
	for ( auto i = guard.begin(); i!=guard.end(); i++ )
	{
	    if ( (*i) == '.')
		(*i) = '_';
	    else
		(*i) = toupper(*i);
	}

	ostr_h << "#ifndef " << guard << std::endl;
	ostr_h << "#define " << guard << std::endl;

	for ( auto pEnum : items )
	{
	    ostr_h << tl_typedef(*pEnum);
	}

	ostr_c << tl_strings(items);

	for (auto pEnum : items )
	{
	    ostr_c << tl_functions(*pEnum);
	}

	ostr_h << std::endl << "#endif // " << guard << std::endl;

    }

    const std::string defgen::tl_header(void) const
    {
	stringstream ss;
	ss <<"/** Generated by " << ecc::version << "*/" << endl;
	return ss.str();
    }

    const std::string defgen::tl_typedef(const ast::enumdef& ed) const
    {
	stringstream ss;
	ss << endl << "/** typedef " << ed.get_name() << " */" << endl;
	ss << "typedef enum {";

	std::string sep = "";

	for ( auto vp : ed.getvalues() )
	{
	    ss << sep << endl << "    " << vp.first;
	    if (vp.second!=AST_DEFAULT_ENUM_VALUE)
		ss << "=" << vp.second;
	    sep = ",";
	}

	ss << endl << "} " << ed.get_name() << ";" << endl;

	return ss.str();
    }

    const std::string defgen::tl_strings(const ast::elist_t& items) const
    {
	stringstream ss;

	ss << endl << "namespace {" << endl;
	ss << "    static const std::string notfound=\"\";" << endl;

	for ( auto pItem : items )
	{
	    for ( auto vp : pItem->getvalues() )
	    {
		ss << "    static const std::string " << pItem->get_name() << "_"
		   << vp.first << " = " << "\"" << vp.first << "\";" << endl;
	    }
	}

	ss << "}" << endl;

	return ss.str();
    }

    const std::string defgen::tl_functions(const ast::enumdef& ed) const
    {
	stringstream ss;

	ss << endl << "const std::string& getstr_" << ed.get_name() << "("
	   << ed.get_name() << " v) {" << endl;

	ss << "    switch (v) {" << endl;

	for ( auto vp : ed.getvalues() )
	{
	    ss << "    case " << vp.first << ":" << endl;
	    ss << "        return " << ed.get_name() << "_" << vp.first << ";" << endl;
	}

	ss << "    default: " << endl;
	ss << "        return notfound;" << endl;

	ss << "    }" << endl;

	ss << "}" << endl;

	return ss.str();
    }
}
<commit_msg>Added prefix to guard header string<commit_after>#include <iostream>
#include <map>
#include <vector>
#include <sstream>
#include <string>
#include "version.h"
#include "ast.h"
#include "generator.h"

using std::stringstream;
using std::endl;

namespace ecc
{
    generator::generator()
    {

    }

    generator::~generator()
    {

    }

    void defgen::translate(const ast::elist_t& items,
	                   const std::string& fHeader,
			   const std::string& fCode,
			   std::ostream& ostr_c,
			   std::ostream& ostr_h)
    {
	ostr_h << tl_header();
	ostr_c << tl_header();

	/** c file needs to include <string>, and our header */
	ostr_c << "#include <string>" << endl;

	std::string headerLeaf;
	int pos = fHeader.rfind('/');
	if ( pos == std::string::npos )
	{
	    // File is already a leaf
	    headerLeaf = fHeader;
	}
	else
	{
	    // File is not leaf, use everything after the last '/'
	    headerLeaf = fHeader.substr(pos+1, fHeader.length()-pos);
	}

	ostr_c << "#include \"" << headerLeaf << "\"" << std::endl;

	std::string guard = "_HG_" + headerLeaf + "_";
	for ( auto i = guard.begin(); i!=guard.end(); i++ )
	{
	    if ( (*i) == '.')
		(*i) = '_';
	    else
		(*i) = toupper(*i);
	}

	ostr_h << "#ifndef " << guard << std::endl;
	ostr_h << "#define " << guard << std::endl;

	for ( auto pEnum : items )
	{
	    ostr_h << tl_typedef(*pEnum);
	}

	ostr_c << tl_strings(items);

	for (auto pEnum : items )
	{
	    ostr_c << tl_functions(*pEnum);
	}

	ostr_h << std::endl << "#endif // " << guard << std::endl;

    }

    const std::string defgen::tl_header(void) const
    {
	stringstream ss;
	ss <<"/** Generated by " << ecc::version << "*/" << endl;
	return ss.str();
    }

    const std::string defgen::tl_typedef(const ast::enumdef& ed) const
    {
	stringstream ss;
	ss << endl << "/** typedef " << ed.get_name() << " */" << endl;
	ss << "typedef enum {";

	std::string sep = "";

	for ( auto vp : ed.getvalues() )
	{
	    ss << sep << endl << "    " << vp.first;
	    if (vp.second!=AST_DEFAULT_ENUM_VALUE)
		ss << "=" << vp.second;
	    sep = ",";
	}

	ss << endl << "} " << ed.get_name() << ";" << endl;

	return ss.str();
    }

    const std::string defgen::tl_strings(const ast::elist_t& items) const
    {
	stringstream ss;

	ss << endl << "namespace {" << endl;
	ss << "    static const std::string notfound=\"\";" << endl;

	for ( auto pItem : items )
	{
	    for ( auto vp : pItem->getvalues() )
	    {
		ss << "    static const std::string " << pItem->get_name() << "_"
		   << vp.first << " = " << "\"" << vp.first << "\";" << endl;
	    }
	}

	ss << "}" << endl;

	return ss.str();
    }

    const std::string defgen::tl_functions(const ast::enumdef& ed) const
    {
	stringstream ss;

	ss << endl << "const std::string& getstr_" << ed.get_name() << "("
	   << ed.get_name() << " v) {" << endl;

	ss << "    switch (v) {" << endl;

	for ( auto vp : ed.getvalues() )
	{
	    ss << "    case " << vp.first << ":" << endl;
	    ss << "        return " << ed.get_name() << "_" << vp.first << ";" << endl;
	}

	ss << "    default: " << endl;
	ss << "        return notfound;" << endl;

	ss << "    }" << endl;

	ss << "}" << endl;

	return ss.str();
    }
}
<|endoftext|>


<commit_before>//
//  LFSR.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 19/01/2020.
//  Copyright © 2020 Thomas Harte. All rights reserved.
//

#ifndef LFSR_h
#define LFSR_h

#include <cstdint>
#include <cstdlib>

#include "Sizes.hpp"

namespace Numeric {

template <typename IntType> struct LSFRPolynomial {};

// The following were taken 'at random' from https://users.ece.cmu.edu/~koopman/lfsr/index.html
template <> struct LSFRPolynomial<uint64_t> {
	static constexpr uint64_t value = 0x80000000000019E2;
};

template <> struct LSFRPolynomial<uint32_t> {
	static constexpr uint32_t value = 0x80000C34;
};

template <> struct LSFRPolynomial<uint16_t> {
	static constexpr uint16_t value = 0x853E;
};

template <> struct LSFRPolynomial<uint8_t> {
	static constexpr uint8_t value = 0xAF;
};

/*!
	Provides a linear-feedback shift register with a random initial state; if no polynomial is supplied
	then one will be picked that is guaranteed to give the maximal number of LFSR states that can fit
	in the specified int type.
*/
template <typename IntType = uint64_t, IntType polynomial = LSFRPolynomial<IntType>::value> class LFSR {
	public:
		/*!
			Constructs an LFSR with a random initial value.
		*/
		constexpr LFSR() noexcept {
			// Randomise the value, ensuring it doesn't end up being 0;
			// don't set any top bits, in case this is a signed type.
			while(!value_) {
				uint8_t *value_byte = reinterpret_cast<uint8_t *>(&value_);
				for(size_t c = 0; c < sizeof(IntType); ++c) {
					*value_byte = uint8_t(uint64_t(rand()) * 127 / RAND_MAX);
					++value_byte;
				}
			}
		}

		/*!
			Constructs an LFSR with the specified initial value.

			An initial value of 0 is invalid.
		*/
		LFSR(IntType initial_value) : value_(initial_value) {}

		/*!
			Advances the LSFR, returning either an @c IntType of value @c 1 or @c 0,
			determining the bit that was just shifted out.
		*/
		IntType next() {
			const auto result = value_ & 1;
			value_ = (value_ >> 1) ^ (result * polynomial);
			return result;
		}

	private:
		IntType value_ = 0;
};

template <uint64_t polynomial> class LFSRv: public LFSR<typename MinIntTypeValue<polynomial>::type, polynomial> {};

}

#endif /* LFSR_h */
<commit_msg>Corrects for IntType != int.<commit_after>//
//  LFSR.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 19/01/2020.
//  Copyright © 2020 Thomas Harte. All rights reserved.
//

#ifndef LFSR_h
#define LFSR_h

#include <cstdint>
#include <cstdlib>

#include "Sizes.hpp"

namespace Numeric {

template <typename IntType> struct LSFRPolynomial {};

// The following were taken 'at random' from https://users.ece.cmu.edu/~koopman/lfsr/index.html
template <> struct LSFRPolynomial<uint64_t> {
	static constexpr uint64_t value = 0x80000000000019E2;
};

template <> struct LSFRPolynomial<uint32_t> {
	static constexpr uint32_t value = 0x80000C34;
};

template <> struct LSFRPolynomial<uint16_t> {
	static constexpr uint16_t value = 0x853E;
};

template <> struct LSFRPolynomial<uint8_t> {
	static constexpr uint8_t value = 0xAF;
};

/*!
	Provides a linear-feedback shift register with a random initial state; if no polynomial is supplied
	then one will be picked that is guaranteed to give the maximal number of LFSR states that can fit
	in the specified int type.
*/
template <typename IntType = uint64_t, IntType polynomial = LSFRPolynomial<IntType>::value> class LFSR {
	public:
		/*!
			Constructs an LFSR with a random initial value.
		*/
		constexpr LFSR() noexcept {
			// Randomise the value, ensuring it doesn't end up being 0;
			// don't set any top bits, in case this is a signed type.
			while(!value_) {
				uint8_t *value_byte = reinterpret_cast<uint8_t *>(&value_);
				for(size_t c = 0; c < sizeof(IntType); ++c) {
					*value_byte = uint8_t(uint64_t(rand()) * 127 / RAND_MAX);
					++value_byte;
				}
			}
		}

		/*!
			Constructs an LFSR with the specified initial value.

			An initial value of 0 is invalid.
		*/
		LFSR(IntType initial_value) : value_(initial_value) {}

		/*!
			Advances the LSFR, returning either an @c IntType of value @c 1 or @c 0,
			determining the bit that was just shifted out.
		*/
		IntType next() {
			const auto result = IntType(value_ & 1);
			value_ = IntType((value_ >> 1) ^ (result * polynomial));
			return result;
		}

	private:
		IntType value_ = 0;
};

template <uint64_t polynomial> class LFSRv: public LFSR<typename MinIntTypeValue<polynomial>::type, polynomial> {};

}

#endif /* LFSR_h */
<|endoftext|>


<commit_before>/*
 * SRT - Secure, Reliable, Transport
 * Copyright (c) 2019 Haivision Systems Inc.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Written by:
 *             Haivision Systems Inc.
 */

#include <gtest/gtest.h>
#include <future>
#include <thread>

#include "srt.h"

using namespace std;

class TestSocketOptions
    : public ::testing::Test
{
protected:
    TestSocketOptions()
    {
        // initialization code here
    }

    ~TestSocketOptions()
    {
        // cleanup any pending stuff, but no exceptions allowed
    }

protected:
    // SetUp() is run immediately before a test starts.
    void SetUp()
    {
        ASSERT_GE(srt_startup(), 0);
        const int yes = 1;

        m_caller_sock = srt_create_socket();
        ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK);
        ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect
        ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect

        m_listen_sock = srt_create_socket();
        ASSERT_NE(m_listen_sock, SRT_INVALID_SOCK);
        ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect
        ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect
    }

    void TearDown()
    {
        // Code here will be called just after the test completes.
        // OK to throw exceptions from here if needed.
        ASSERT_NE(srt_close(m_caller_sock), SRT_ERROR);
        ASSERT_NE(srt_close(m_listen_sock), SRT_ERROR);
        srt_cleanup();
    }

protected:
    // put in any custom data members that you need

    SRTSOCKET m_caller_sock = SRT_INVALID_SOCK;
    SRTSOCKET m_listen_sock = SRT_INVALID_SOCK;

    int       m_pollid = 0;
};

/// A regression test for issue #735, fixed by PR #843.
/// Checks propagation of listener's socket option SRTO_LOSSMAXTTL
/// on SRT sockets being accepted.
TEST_F(TestSocketOptions, LossMaxTTL)
{
    const int loss_max_ttl = 5;
    ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &loss_max_ttl, sizeof loss_max_ttl), SRT_SUCCESS);

    // Specify address
    sockaddr_in sa;
    memset(&sa, 0, sizeof sa);
    sa.sin_family = AF_INET;
    sa.sin_port = htons(5200);
    ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1);
    sockaddr* psa = (sockaddr*)&sa;
    ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof sa), SRT_ERROR);

    srt_listen(m_listen_sock, 1);

    auto accept_async = [](SRTSOCKET listen_sock) {
        sockaddr_in client_address;
        int length = sizeof(sockaddr_in);
        const SRTSOCKET accepted_socket = srt_accept(listen_sock, (sockaddr*)&client_address, &length);
        return accepted_socket;
    };
    auto accept_res = async(launch::async, accept_async, m_listen_sock);

    const int connect_res = srt_connect(m_caller_sock, psa, sizeof sa);
    EXPECT_EQ(connect_res, SRT_SUCCESS);

    const SRTSOCKET accepted_sock = accept_res.get();
    ASSERT_NE(accepted_sock, SRT_INVALID_SOCK);

    int opt_val = 0;
    int opt_len = 0;
    ASSERT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_LOSSMAXTTL, &opt_val, &opt_len), SRT_SUCCESS);
    EXPECT_EQ(opt_val, loss_max_ttl) << "Wrong SRTO_LOSSMAXTTL value on the accepted socket";
    EXPECT_EQ(opt_len, sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the accepted socket";

    SRT_TRACEBSTATS stats;
    EXPECT_EQ(srt_bstats(accepted_sock, &stats, 0), SRT_SUCCESS);
    EXPECT_EQ(stats.pktReorderTolerance, loss_max_ttl);

    ASSERT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &opt_val, &opt_len), SRT_SUCCESS);
    EXPECT_EQ(opt_val, loss_max_ttl) << "Wrong SRTO_LOSSMAXTTL value on the listener socket";
    EXPECT_EQ(opt_len, sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the listener socket";

    ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);
}

<commit_msg>[tests] Added tests for SRTO_MININPUTBW<commit_after>/*
 * SRT - Secure, Reliable, Transport
 * Copyright (c) 2019 Haivision Systems Inc.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Written by:
 *             Haivision Systems Inc.
 */

#include <gtest/gtest.h>
#include <future>
#include <thread>

#include "srt.h"

using namespace std;

class TestSocketOptions
    : public ::testing::Test
{
protected:
    TestSocketOptions()
    {
        // initialization code here
    }

    ~TestSocketOptions()
    {
        // cleanup any pending stuff, but no exceptions allowed
    }

public:
    void StartListener()
    {
        // Specify address of the listener
        sockaddr* psa = (sockaddr*)&m_sa;
        ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof m_sa), SRT_ERROR);

        srt_listen(m_listen_sock, 1);
    }

    SRTSOCKET EstablishConnection()
    {
        auto accept_async = [](SRTSOCKET listen_sock) {
            sockaddr_in client_address;
            int length = sizeof(sockaddr_in);
            const SRTSOCKET accepted_socket = srt_accept(listen_sock, (sockaddr*)&client_address, &length);
            return accepted_socket;
        };
        auto accept_res = async(launch::async, accept_async, m_listen_sock);

        sockaddr* psa = (sockaddr*)&m_sa;
        const int connect_res = srt_connect(m_caller_sock, psa, sizeof m_sa);
        EXPECT_EQ(connect_res, SRT_SUCCESS);

        const SRTSOCKET accepted_sock = accept_res.get();
        EXPECT_NE(accepted_sock, SRT_INVALID_SOCK);

        return accepted_sock;
    }

protected:
    // SetUp() is run immediately before a test starts.
    void SetUp()
    {
        ASSERT_GE(srt_startup(), 0);
        const int yes = 1;

        memset(&m_sa, 0, sizeof m_sa);
        m_sa.sin_family = AF_INET;
        m_sa.sin_port = htons(5200);
        ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &m_sa.sin_addr), 1);

        m_caller_sock = srt_create_socket();
        ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK);
        ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect
        ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect

        m_listen_sock = srt_create_socket();
        ASSERT_NE(m_listen_sock, SRT_INVALID_SOCK);
        ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect
        ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect
    }

    void TearDown()
    {
        // Code here will be called just after the test completes.
        // OK to throw exceptions from here if needed.
        ASSERT_NE(srt_close(m_caller_sock), SRT_ERROR);
        ASSERT_NE(srt_close(m_listen_sock), SRT_ERROR);
        srt_cleanup();
    }

protected:
    // put in any custom data members that you need

    sockaddr_in m_sa;
    SRTSOCKET m_caller_sock = SRT_INVALID_SOCK;
    SRTSOCKET m_listen_sock = SRT_INVALID_SOCK;

    int       m_pollid = 0;
};

/// A regression test for issue #735, fixed by PR #843.
/// Checks propagation of listener's socket option SRTO_LOSSMAXTTL
/// on SRT sockets being accepted.
TEST_F(TestSocketOptions, LossMaxTTL)
{
    const int loss_max_ttl = 5;
    ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &loss_max_ttl, sizeof loss_max_ttl), SRT_SUCCESS);

    StartListener();
    const SRTSOCKET accepted_sock = EstablishConnection();

    int opt_val = 0;
    int opt_len = 0;
    ASSERT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_LOSSMAXTTL, &opt_val, &opt_len), SRT_SUCCESS);
    EXPECT_EQ(opt_val, loss_max_ttl) << "Wrong SRTO_LOSSMAXTTL value on the accepted socket";
    EXPECT_EQ(opt_len, sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the accepted socket";

    SRT_TRACEBSTATS stats;
    EXPECT_EQ(srt_bstats(accepted_sock, &stats, 0), SRT_SUCCESS);
    EXPECT_EQ(stats.pktReorderTolerance, loss_max_ttl);

    ASSERT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &opt_val, &opt_len), SRT_SUCCESS);
    EXPECT_EQ(opt_val, loss_max_ttl) << "Wrong SRTO_LOSSMAXTTL value on the listener socket";
    EXPECT_EQ(opt_len, sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the listener socket";

    ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);
}

// Try to set/get SRTO_MININPUTBW with wrong optlen
TEST_F(TestSocketOptions, MinInputBWWrongLen)
{
    int64_t mininputbw = 0;
    int optlen = (int)(sizeof mininputbw) - 1;
    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_ERROR);
    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);
    optlen += 2;
    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS) << "Bigger storage is allowed";
    EXPECT_EQ(optlen, (int)(sizeof mininputbw));

    EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, sizeof mininputbw - 1), SRT_ERROR);
    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);
    EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, sizeof mininputbw + 1), SRT_ERROR);
    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);
}

// Check the default SRTO_MININPUTBW is SRT_PACING_MAXBW_DEFAULT
TEST_F(TestSocketOptions, MinInputBWDefault)
{
    const int mininputbw_expected = 0;
    int64_t mininputbw = 1;
    int optlen = (int)(sizeof mininputbw);
    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(optlen, (int)(sizeof mininputbw));
    EXPECT_EQ(mininputbw, mininputbw_expected);

    StartListener();
    const SRTSOCKET accepted_sock = EstablishConnection();

    // Check both listener and accepted socket have default values
    for (SRTSOCKET sock : { m_listen_sock, accepted_sock })
    {
        optlen = (int)(sizeof mininputbw);
        EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS);
        EXPECT_EQ(optlen, (int)(sizeof mininputbw));
        EXPECT_EQ(mininputbw, mininputbw_expected);
    }

    ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);
}

// Check setting and getting SRT_MININPUTBW
TEST_F(TestSocketOptions, MinInputBWSet)
{
    const int64_t mininputbw_dflt = 0;
    const int64_t mininputbw = 50000000;
    int optlen = (int)(sizeof mininputbw);

    int64_t bw = -100;
    EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_ERROR) << "Has to be a non-negative number";
    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, mininputbw_dflt);

    bw = mininputbw;
    EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS);
    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, mininputbw);

    StartListener();
    const SRTSOCKET accepted_sock = EstablishConnection();

    // Check accepted socket inherits values
    for (SRTSOCKET sock : { m_listen_sock, accepted_sock })
    {
        optlen = (int)(sizeof bw);
        EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS);
        EXPECT_EQ(optlen, (int)(sizeof bw));
        EXPECT_EQ(bw, mininputbw);
    }

    ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);
}

// Check setting and getting SRTO_MININPUTBW in runtime
TEST_F(TestSocketOptions, MinInputBWRuntime)
{
    const int64_t mininputbw = 50000000;

    // Establish a connection
    StartListener();
    const SRTSOCKET accepted_sock = EstablishConnection();

    // Test a connected socket
    int64_t bw = mininputbw;
    int optlen = (int)(sizeof bw);
    EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS);
    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, mininputbw);

    bw = 0;
    EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_INPUTBW, &bw, sizeof bw), SRT_SUCCESS);
    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_INPUTBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, 0);

    EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MAXBW, &bw, sizeof bw), SRT_SUCCESS);
    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MAXBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, 0);

    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, mininputbw);

    const int64_t new_mininputbw = 20000000;
    bw = new_mininputbw;
    EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS);
    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS);
    EXPECT_EQ(bw, new_mininputbw);

    ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);
}

<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* 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 Hobu, Inc. or Flaxen Geo Consulting 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 <boost/test/unit_test.hpp>
#include <boost/cstdint.hpp>

#include <libpc/drivers/faux/Reader.hpp>

using namespace libpc;

BOOST_AUTO_TEST_SUITE(FauxReaderTest)

BOOST_AUTO_TEST_CASE(test_constant)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Constant);
    BOOST_CHECK(reader.getName() == "Faux Reader");

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointData data(layout, 750);

    boost::uint32_t numRead = reader.read(data);

    BOOST_CHECK(numRead == 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        float x = data.getField<float>(i, offsetX);
        float y = data.getField<float>(i, offsetY);
        float z = data.getField<float>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK(x == 1.0);
        BOOST_CHECK(y == 2.0);
        BOOST_CHECK(z == 3.0);
        BOOST_CHECK(t == i);
    }

    return;
}

BOOST_AUTO_TEST_CASE(test_random)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointData data(layout, 750);

    boost::uint32_t numRead = reader.read(data);

    BOOST_CHECK(numRead == 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        float x = data.getField<float>(i, offsetX);
        float y = data.getField<float>(i, offsetY);
        float z = data.getField<float>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK(x >= 1.0 && x <= 101.0);
        BOOST_CHECK(y >= 2.0 && y <= 102.0);
        BOOST_CHECK(z >= 3.0 && z <= 103.0);
        BOOST_CHECK(t == i);
    }

    return;
}

BOOST_AUTO_TEST_CASE(test_custom_fields)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);

    Dimension dimY(Dimension::Field_Y, Dimension::Uint8);
    Dimension dimX(Dimension::Field_X, Dimension::Uint8);
    std::vector<Dimension> dims;
    dims.push_back(dimY);
    dims.push_back(dimX);

    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random, dims);

    const Schema& schema = reader.getHeader().getSchema();
    BOOST_CHECK(schema.getDimensions().size() == 2);
    BOOST_CHECK(schema.getDimension(0).getField() == Dimension::Field_Y);
    BOOST_CHECK(schema.getDimension(1).getField() == Dimension::Field_X);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>more epsilon compares<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* 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 Hobu, Inc. or Flaxen Geo Consulting 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 <boost/test/unit_test.hpp>
#include <boost/cstdint.hpp>

#include <libpc/drivers/faux/Reader.hpp>

using namespace libpc;

BOOST_AUTO_TEST_SUITE(FauxReaderTest)

BOOST_AUTO_TEST_CASE(test_constant)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Constant);
    BOOST_CHECK(reader.getName() == "Faux Reader");

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointData data(layout, 750);

    boost::uint32_t numRead = reader.read(data);

    BOOST_CHECK(numRead == 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        float x = data.getField<float>(i, offsetX);
        float y = data.getField<float>(i, offsetY);
        float z = data.getField<float>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK( Utils::compare_approx( (double)x, 1.0, (std::numeric_limits<double>::min)()) == true);
        BOOST_CHECK(Utils::compare_approx( (double)y, 2.0, (std::numeric_limits<double>::min)()) == true);
        BOOST_CHECK(Utils::compare_approx( (double)z, 3.0, (std::numeric_limits<double>::min)()) == true);
        BOOST_CHECK(Utils::compare_approx( (double)t, (double) i, (std::numeric_limits<double>::min)()) == true);
    }

    return;
}

BOOST_AUTO_TEST_CASE(test_random)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);
    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random);

    const Schema& schema = reader.getHeader().getSchema();
    SchemaLayout layout(schema);

    PointData data(layout, 750);

    boost::uint32_t numRead = reader.read(data);

    BOOST_CHECK(numRead == 750);

    int offsetX = schema.getDimensionIndex(Dimension::Field_X);
    int offsetY = schema.getDimensionIndex(Dimension::Field_Y);
    int offsetZ = schema.getDimensionIndex(Dimension::Field_Z);
    int offsetT = schema.getDimensionIndex(Dimension::Field_Time);

    for (boost::uint32_t i=0; i<numRead; i++)
    {
        float x = data.getField<float>(i, offsetX);
        float y = data.getField<float>(i, offsetY);
        float z = data.getField<float>(i, offsetZ);
        boost::uint64_t t = data.getField<boost::uint64_t>(i, offsetT);

        BOOST_CHECK(x >= 1.0 && x <= 101.0);
        BOOST_CHECK(y >= 2.0 && y <= 102.0);
        BOOST_CHECK(z >= 3.0 && z <= 103.0);
        BOOST_CHECK(t == i);
    }

    return;
}

BOOST_AUTO_TEST_CASE(test_custom_fields)
{
    Bounds<double> bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0);

    Dimension dimY(Dimension::Field_Y, Dimension::Uint8);
    Dimension dimX(Dimension::Field_X, Dimension::Uint8);
    std::vector<Dimension> dims;
    dims.push_back(dimY);
    dims.push_back(dimX);

    libpc::drivers::faux::Reader reader(bounds, 1000, libpc::drivers::faux::Reader::Random, dims);

    const Schema& schema = reader.getHeader().getSchema();
    BOOST_CHECK(schema.getDimensions().size() == 2);
    BOOST_CHECK(schema.getDimension(0).getField() == Dimension::Field_Y);
    BOOST_CHECK(schema.getDimension(1).getField() == Dimension::Field_X);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#pragma once
#include <mutex>
//#include <shared_mutex>
#include <boost/parameter.hpp>
#include <boost/mpl/arg.hpp>
#include <boost/parameter/name.hpp>
#include <boost/parameter/binding.hpp>
namespace fox {
  using boost::mpl::_;
  BOOST_PARAMETER_TEMPLATE_KEYWORD(RecursiveType)
    BOOST_PARAMETER_TEMPLATE_KEYWORD(TimedType)
    BOOST_PARAMETER_TEMPLATE_KEYWORD(SharedType)

    class SharedWay
  {
  };
  class NotShared :public SharedWay {

  };
  class Shared :public SharedWay {

  };
  class TimedWay
  {
  };
  class NotTimed :public TimedWay {

  };
  class Timed :public TimedWay {

  };
  class RecursiveWay
  {
  };
  class NotRecursive :public RecursiveWay {

  };
  class Recursive :public RecursiveWay {

  };
  template<class T, class U, class V>
  class Mutex;
  template<>
  class Mutex<NotRecursive, NotTimed, NotShared> : public std::mutex {
  };

  template<>
  class Mutex<Recursive, NotTimed, NotShared> : public std::recursive_mutex {
  };

  template<>
  class Mutex<NotRecursive, Timed, NotShared> : public std::timed_mutex {
  };
  template<>
  class Mutex<Recursive, Timed, NotShared> : public std::recursive_timed_mutex {
  };
  //template<>
  //class Mutex<NotRecursive, NotTimed, Shared> : public std::shared_mutex {
  //};
  //template<>
  //class Mutex<NotRecursive, Timed, Shared> : public std::shared_timed_mutex {
  //};
  namespace parameter = boost::parameter;
  typedef parameter::parameters<
    parameter::optional<parameter::deduced<tag::RecursiveType>, boost::is_base_and_derived<RecursiveWay, _>>
    , parameter::optional<parameter::deduced<tag::TimedType>, boost::is_base_and_derived<TimedWay, _>>
    , parameter::optional<parameter::deduced<tag::SharedType>, boost::is_base_and_derived<SharedWay, _>>
  > class_signature;
  template <
    class A0 = parameter::void_
    , class A1 = parameter::void_
    , class A2 = parameter::void_
  >
    struct MyMutexImpl
  {
    typedef typename
      class_signature::bind<A0, A1, A2>::type
      args;

    // Extract first logical parameter.
    typedef typename parameter::value_type<
      args, tag::RecursiveType, NotRecursive >::type RecursiveType;

    typedef typename parameter::value_type<
      args, tag::TimedType, NotTimed >::type TimedType;

    typedef typename parameter::value_type<
      args, tag::SharedType, NotShared >::type SharedType;
    typedef Mutex<RecursiveType, TimedType, SharedType> MutexType;
  };

  template <
    class A0 = parameter::void_
    , class A1 = parameter::void_
    , class A2 = parameter::void_
  >
    using GeneralMutex = typename MyMutexImpl<A0, A1, A2>::MutexType;
}
<commit_msg>shared mutex<commit_after>#pragma once
#include <mutex>
#include <shared_mutex>
#include <boost/parameter.hpp>
#include <boost/mpl/arg.hpp>
#include <boost/parameter/name.hpp>
#include <boost/parameter/binding.hpp>
namespace fox {
  using boost::mpl::_;
  BOOST_PARAMETER_TEMPLATE_KEYWORD(RecursiveType)
    BOOST_PARAMETER_TEMPLATE_KEYWORD(TimedType)
    BOOST_PARAMETER_TEMPLATE_KEYWORD(SharedType)

    class SharedWay
  {
  };
  class NotShared :public SharedWay {

  };
  class Shared :public SharedWay {

  };
  class TimedWay
  {
  };
  class NotTimed :public TimedWay {

  };
  class Timed :public TimedWay {

  };
  class RecursiveWay
  {
  };
  class NotRecursive :public RecursiveWay {

  };
  class Recursive :public RecursiveWay {

  };
  template<class T, class U, class V>
  class Mutex;
  template<>
  class Mutex<NotRecursive, NotTimed, NotShared> : public std::mutex {
  };

  template<>
  class Mutex<Recursive, NotTimed, NotShared> : public std::recursive_mutex {
  };

  template<>
  class Mutex<NotRecursive, Timed, NotShared> : public std::timed_mutex {
  };
  template<>
  class Mutex<Recursive, Timed, NotShared> : public std::recursive_timed_mutex {
  };
  template<>
  class Mutex<NotRecursive, NotTimed, Shared> : public std::shared_mutex {
  };
  template<>
  class Mutex<NotRecursive, Timed, Shared> : public std::shared_timed_mutex {
  };
  namespace parameter = boost::parameter;
  typedef parameter::parameters<
    parameter::optional<parameter::deduced<tag::RecursiveType>, boost::is_base_and_derived<RecursiveWay, _>>
    , parameter::optional<parameter::deduced<tag::TimedType>, boost::is_base_and_derived<TimedWay, _>>
    , parameter::optional<parameter::deduced<tag::SharedType>, boost::is_base_and_derived<SharedWay, _>>
  > class_signature;
  template <
    class A0 = parameter::void_
    , class A1 = parameter::void_
    , class A2 = parameter::void_
  >
    struct MyMutexImpl
  {
    typedef typename
      class_signature::bind<A0, A1, A2>::type
      args;

    typedef typename parameter::value_type<
      args, tag::RecursiveType, NotRecursive >::type RecursiveType;

    typedef typename parameter::value_type<
      args, tag::TimedType, NotTimed >::type TimedType;

    typedef typename parameter::value_type<
      args, tag::SharedType, NotShared >::type SharedType;
    typedef Mutex<RecursiveType, TimedType, SharedType> MutexType;
  };

  template <
    class A0 = parameter::void_
    , class A1 = parameter::void_
    , class A2 = parameter::void_
  >
    using GeneralMutex = typename MyMutexImpl<A0, A1, A2>::MutexType;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of dirtsand.                                             *
 *                                                                            *
 * dirtsand is free software: you can redistribute it and/or modify           *
 * it under the terms of the GNU Affero General Public License as             *
 * published by the Free Software Foundation, either version 3 of the         *
 * License, or (at your option) any later version.                            *
 *                                                                            *
 * dirtsand is distributed in the hope that it will be useful,                *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 * GNU Affero General Public License for more details.                        *
 *                                                                            *
 * You should have received a copy of the GNU Affero General Public License   *
 * along with dirtsand.  If not, see <http://www.gnu.org/licenses/>.          *
 ******************************************************************************/

#include "SockIO.h"
#include "errors.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <mutex>

static const int SOCK_YES = 1;

struct SocketHandle_Private
{
    int m_sockfd;
    union {
        sockaddr         m_addr;
        sockaddr_in      m_in4addr;
        sockaddr_in6     m_in6addr;
        sockaddr_storage m_addrMax;
    };
    socklen_t m_addrLen;
    std::mutex m_sendLock;

    SocketHandle_Private() : m_addrLen(sizeof(m_addrMax)) { }
};

static void* get_in_addr(SocketHandle_Private* sock)
{
    if (sock->m_addr.sa_family == AF_INET)
        return &sock->m_in4addr.sin_addr;
    return &sock->m_in6addr.sin6_addr;
}

static uint16_t get_in_port(SocketHandle_Private* sock)
{
    if (sock->m_addr.sa_family == AF_INET)
        return ntohs(sock->m_in4addr.sin_port);
    return ntohs(sock->m_in6addr.sin6_port);
}

DS::SocketHandle DS::BindSocket(const char* address, const char* port)
{
    int result;
    int sockfd;

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

    addrinfo* addrList;
    result = getaddrinfo(address, port, &info, &addrList);
    DS_PASSERT(result == 0);

    addrinfo* addr_iter;
    for (addr_iter = addrList; addr_iter != 0; addr_iter = addr_iter->ai_next) {
        sockfd = socket(addr_iter->ai_family, addr_iter->ai_socktype,
                        addr_iter->ai_protocol);
        if (sockfd == -1)
            continue;

        // Avoid annoying "Address already in use" messages when restarting
        // the server.
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &SOCK_YES, sizeof(SOCK_YES));
        if (bind(sockfd, addr_iter->ai_addr, addr_iter->ai_addrlen) == 0)
            break;
        fprintf(stderr, "[Bind] %s\n", strerror(errno));

        // Couldn't bind, try the next one
        close(sockfd);
    }
    freeaddrinfo(addrList);

    // Die if we didn't get a successful socket
    DS_PASSERT(addr_iter);

    SocketHandle_Private* sockinfo = new SocketHandle_Private();
    sockinfo->m_sockfd = sockfd;
    result = getsockname(sockfd, &sockinfo->m_addr, &sockinfo->m_addrLen);
    if (result != 0) {
        delete sockinfo;
        DS_PASSERT(0);
    }
    return reinterpret_cast<SocketHandle>(sockinfo);
}

void DS::ListenSock(const DS::SocketHandle sock, int backlog)
{
    DS_DASSERT(sock);
    int result = listen(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd, backlog);
    DS_PASSERT(result == 0);
}

DS::SocketHandle DS::AcceptSock(const DS::SocketHandle sock)
{
    DS_DASSERT(sock);
    SocketHandle_Private* sockp = reinterpret_cast<SocketHandle_Private*>(sock);

    SocketHandle_Private* client = new SocketHandle_Private();
    client->m_sockfd = accept(sockp->m_sockfd, &client->m_addr, &client->m_addrLen);
    if (client->m_sockfd < 0) {
        delete client;
        if (errno == EINVAL) {
            throw DS::SockHup();
        } else if (errno == ECONNABORTED) {
            return 0;
        } else {
            fprintf(stderr, "Socket closed: %s\n", strerror(errno));
            DS_DASSERT(0);
        }
    }
    timeval tv;
    // Client pings us every 30 seconds. A timeout of 45 gives us some wiggle room
    // so networks can suck without kicking a client off.
    tv.tv_sec = 45;
    tv.tv_usec = 0;
    setsockopt(client->m_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    // Allow 50ms on blocking sends to account for net suckiness
    tv.tv_sec = 0;
    tv.tv_usec = (50 * 1000);
    setsockopt(client->m_sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
    // eap-tastic protocols require Nagle's algo be disabled
    setsockopt(client->m_sockfd, IPPROTO_TCP, TCP_NODELAY, &SOCK_YES, sizeof(SOCK_YES));
    return reinterpret_cast<SocketHandle>(client);
}

void DS::CloseSock(DS::SocketHandle sock)
{
    DS_DASSERT(sock);
    shutdown(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd, SHUT_RDWR);
    close(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd);
}

void DS::FreeSock(DS::SocketHandle sock)
{
    CloseSock(sock);
    delete reinterpret_cast<SocketHandle_Private*>(sock);
}

DS::String DS::SockIpAddress(const DS::SocketHandle sock)
{
    char addrbuf[256];
    SocketHandle_Private* sockp = reinterpret_cast<SocketHandle_Private*>(sock);
    inet_ntop(sockp->m_addr.sa_family, get_in_addr(sockp), addrbuf, 256);
    return String::Format("%s/%u", addrbuf, get_in_port(sockp));
}

uint32_t DS::GetAddress4(const char* lookup)
{
    addrinfo info;
    memset(&info, 0, sizeof(info));
    info.ai_family = AF_INET;
    info.ai_socktype = SOCK_STREAM;
    info.ai_flags = 0;

    addrinfo* addrList;
    int result = getaddrinfo(lookup, 0, &info, &addrList);
    DS_PASSERT(result == 0);
    DS_PASSERT(addrList != 0);
    uint32_t addr = reinterpret_cast<sockaddr_in*>(addrList->ai_addr)->sin_addr.s_addr;
    freeaddrinfo(addrList);

    return ntohl(addr);
}

void DS::SendBuffer(const DS::SocketHandle sock, const void* buffer, size_t size, SendFlag mode)
{
    int32_t flags = (mode & DS::e_SendNonBlocking) ? MSG_DONTWAIT : 0;
    bool retry = !(mode & DS::e_SendNoRetry);
    std::lock_guard<std::mutex> guard(reinterpret_cast<SocketHandle_Private*>(sock)->m_sendLock);
    do {
        ssize_t bytes = send(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd,
                             buffer, size, flags);
        if (bytes < 0) {
            if (errno == EPIPE || errno == ECONNRESET) {
                throw DS::SockHup();
            } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                if (retry)
                    continue;
                else {
                    CloseSock(sock);
                    throw DS::SockHup();
                }
            }
        } else if (bytes == 0)
            throw DS::SockHup();
        DS_PASSERT(bytes > 0);

        size -= bytes;
        buffer = reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(buffer) + bytes);
    } while ((size > 0) && retry);

    if (size > 0) {
        CloseSock(sock);
        throw DS::SockHup();
    }
}

void DS::RecvBuffer(const DS::SocketHandle sock, void* buffer, size_t size)
{
    while (size > 0) {
        ssize_t bytes = recv(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd,
                             buffer, size, 0);
        if (bytes < 0 && (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK))
            throw DS::SockHup();
        if (bytes < 0 && errno == EINTR)
            continue;
        else if (bytes == 0)
            throw DS::SockHup();
        DS_PASSERT(bytes > 0);

        size -= bytes;
        buffer = reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(buffer) + bytes);
    }
}

size_t DS::PeekSize(const SocketHandle sock)
{
    uint8_t buffer[256];
    ssize_t bytes = recv(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd,
                         buffer, 256, MSG_PEEK | MSG_TRUNC);

    if (bytes < 0 && (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK))
        throw DS::SockHup();
    else if (bytes == 0)
        throw DS::SockHup();
    DS_PASSERT(bytes > 0);

    return static_cast<size_t>(bytes);
}
<commit_msg>more EPIPE handling == less assertions<commit_after>/******************************************************************************
 * This file is part of dirtsand.                                             *
 *                                                                            *
 * dirtsand is free software: you can redistribute it and/or modify           *
 * it under the terms of the GNU Affero General Public License as             *
 * published by the Free Software Foundation, either version 3 of the         *
 * License, or (at your option) any later version.                            *
 *                                                                            *
 * dirtsand is distributed in the hope that it will be useful,                *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 * GNU Affero General Public License for more details.                        *
 *                                                                            *
 * You should have received a copy of the GNU Affero General Public License   *
 * along with dirtsand.  If not, see <http://www.gnu.org/licenses/>.          *
 ******************************************************************************/

#include "SockIO.h"
#include "errors.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <mutex>

static const int SOCK_YES = 1;

struct SocketHandle_Private
{
    int m_sockfd;
    union {
        sockaddr         m_addr;
        sockaddr_in      m_in4addr;
        sockaddr_in6     m_in6addr;
        sockaddr_storage m_addrMax;
    };
    socklen_t m_addrLen;
    std::mutex m_sendLock;

    SocketHandle_Private() : m_addrLen(sizeof(m_addrMax)) { }
};

static void* get_in_addr(SocketHandle_Private* sock)
{
    if (sock->m_addr.sa_family == AF_INET)
        return &sock->m_in4addr.sin_addr;
    return &sock->m_in6addr.sin6_addr;
}

static uint16_t get_in_port(SocketHandle_Private* sock)
{
    if (sock->m_addr.sa_family == AF_INET)
        return ntohs(sock->m_in4addr.sin_port);
    return ntohs(sock->m_in6addr.sin6_port);
}

DS::SocketHandle DS::BindSocket(const char* address, const char* port)
{
    int result;
    int sockfd;

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

    addrinfo* addrList;
    result = getaddrinfo(address, port, &info, &addrList);
    DS_PASSERT(result == 0);

    addrinfo* addr_iter;
    for (addr_iter = addrList; addr_iter != 0; addr_iter = addr_iter->ai_next) {
        sockfd = socket(addr_iter->ai_family, addr_iter->ai_socktype,
                        addr_iter->ai_protocol);
        if (sockfd == -1)
            continue;

        // Avoid annoying "Address already in use" messages when restarting
        // the server.
        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &SOCK_YES, sizeof(SOCK_YES));
        if (bind(sockfd, addr_iter->ai_addr, addr_iter->ai_addrlen) == 0)
            break;
        fprintf(stderr, "[Bind] %s\n", strerror(errno));

        // Couldn't bind, try the next one
        close(sockfd);
    }
    freeaddrinfo(addrList);

    // Die if we didn't get a successful socket
    DS_PASSERT(addr_iter);

    SocketHandle_Private* sockinfo = new SocketHandle_Private();
    sockinfo->m_sockfd = sockfd;
    result = getsockname(sockfd, &sockinfo->m_addr, &sockinfo->m_addrLen);
    if (result != 0) {
        delete sockinfo;
        DS_PASSERT(0);
    }
    return reinterpret_cast<SocketHandle>(sockinfo);
}

void DS::ListenSock(const DS::SocketHandle sock, int backlog)
{
    DS_DASSERT(sock);
    int result = listen(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd, backlog);
    DS_PASSERT(result == 0);
}

DS::SocketHandle DS::AcceptSock(const DS::SocketHandle sock)
{
    DS_DASSERT(sock);
    SocketHandle_Private* sockp = reinterpret_cast<SocketHandle_Private*>(sock);

    SocketHandle_Private* client = new SocketHandle_Private();
    client->m_sockfd = accept(sockp->m_sockfd, &client->m_addr, &client->m_addrLen);
    if (client->m_sockfd < 0) {
        delete client;
        if (errno == EINVAL) {
            throw DS::SockHup();
        } else if (errno == ECONNABORTED) {
            return 0;
        } else {
            fprintf(stderr, "Socket closed: %s\n", strerror(errno));
            DS_DASSERT(0);
        }
    }
    timeval tv;
    // Client pings us every 30 seconds. A timeout of 45 gives us some wiggle room
    // so networks can suck without kicking a client off.
    tv.tv_sec = 45;
    tv.tv_usec = 0;
    setsockopt(client->m_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    // Allow 50ms on blocking sends to account for net suckiness
    tv.tv_sec = 0;
    tv.tv_usec = (50 * 1000);
    setsockopt(client->m_sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
    // eap-tastic protocols require Nagle's algo be disabled
    setsockopt(client->m_sockfd, IPPROTO_TCP, TCP_NODELAY, &SOCK_YES, sizeof(SOCK_YES));
    return reinterpret_cast<SocketHandle>(client);
}

void DS::CloseSock(DS::SocketHandle sock)
{
    DS_DASSERT(sock);
    shutdown(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd, SHUT_RDWR);
    close(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd);
}

void DS::FreeSock(DS::SocketHandle sock)
{
    CloseSock(sock);
    delete reinterpret_cast<SocketHandle_Private*>(sock);
}

DS::String DS::SockIpAddress(const DS::SocketHandle sock)
{
    char addrbuf[256];
    SocketHandle_Private* sockp = reinterpret_cast<SocketHandle_Private*>(sock);
    inet_ntop(sockp->m_addr.sa_family, get_in_addr(sockp), addrbuf, 256);
    return String::Format("%s/%u", addrbuf, get_in_port(sockp));
}

uint32_t DS::GetAddress4(const char* lookup)
{
    addrinfo info;
    memset(&info, 0, sizeof(info));
    info.ai_family = AF_INET;
    info.ai_socktype = SOCK_STREAM;
    info.ai_flags = 0;

    addrinfo* addrList;
    int result = getaddrinfo(lookup, 0, &info, &addrList);
    DS_PASSERT(result == 0);
    DS_PASSERT(addrList != 0);
    uint32_t addr = reinterpret_cast<sockaddr_in*>(addrList->ai_addr)->sin_addr.s_addr;
    freeaddrinfo(addrList);

    return ntohl(addr);
}

void DS::SendBuffer(const DS::SocketHandle sock, const void* buffer, size_t size, SendFlag mode)
{
    int32_t flags = (mode & DS::e_SendNonBlocking) ? MSG_DONTWAIT : 0;
    bool retry = !(mode & DS::e_SendNoRetry);
    std::lock_guard<std::mutex> guard(reinterpret_cast<SocketHandle_Private*>(sock)->m_sendLock);
    do {
        ssize_t bytes = send(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd,
                             buffer, size, flags);
        if (bytes < 0) {
            if (errno == EPIPE || errno == ECONNRESET) {
                throw DS::SockHup();
            } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                if (retry)
                    continue;
                else {
                    CloseSock(sock);
                    throw DS::SockHup();
                }
            }
        } else if (bytes == 0)
            throw DS::SockHup();
        DS_PASSERT(bytes > 0);

        size -= bytes;
        buffer = reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(buffer) + bytes);
    } while ((size > 0) && retry);

    if (size > 0) {
        CloseSock(sock);
        throw DS::SockHup();
    }
}

void DS::RecvBuffer(const DS::SocketHandle sock, void* buffer, size_t size)
{
    while (size > 0) {
        ssize_t bytes = recv(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd,
                             buffer, size, 0);
        if (bytes < 0 && (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK || errno == EPIPE))
            throw DS::SockHup();
        if (bytes < 0 && errno == EINTR)
            continue;
        else if (bytes == 0)
            throw DS::SockHup();
        DS_PASSERT(bytes > 0);

        size -= bytes;
        buffer = reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(buffer) + bytes);
    }
}

size_t DS::PeekSize(const SocketHandle sock)
{
    uint8_t buffer[256];
    ssize_t bytes = recv(reinterpret_cast<SocketHandle_Private*>(sock)->m_sockfd,
                         buffer, 256, MSG_PEEK | MSG_TRUNC);

    if (bytes < 0 && (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK))
        throw DS::SockHup();
    else if (bytes == 0)
        throw DS::SockHup();
    DS_PASSERT(bytes > 0);

    return static_cast<size_t>(bytes);
}
<|endoftext|>