<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/ReentrantMutex>

using namespace osgDB;
using namespace OpenThreads;

ReentrantMutex::ReentrantMutex():
    _threadHoldingMutex(0),
    _lockCount(0)
{
}

ReentrantMutex::~ReentrantMutex()
{
}

int ReentrantMutex::lock()
{
    if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0)
    {
        ++_lockCount;
        return 0;
    }
    else
    {
        int result = Mutex::lock();
        if (result==0)
        {
            _threadHoldingMutex = OpenThreads::Thread::CurrentThread();
            _lockCount = 1;
        }
        return result;
    }
}

int ReentrantMutex::unlock()
{
    if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0)
    {
        --_lockCount;
        if (_lockCount<=0) return Mutex::unlock();
    }
    return 0;
}

int ReentrantMutex::trylock()
{
    if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0)
    {
        ++_lockCount;
        return 0;
    }
    else
    {
        int result = Mutex::trylock();
        if (result==0)
        {
            _threadHoldingMutex = OpenThreads::Thread::CurrentThread();
            _lockCount = 1;
        }
        return result;
    }
}
<commit_msg>Added a _threadHoldingMutex = 0; to ReentrantMutex::unlock() to avoid a potential bug with the mutex being aquired by two threads.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#include <osgDB/ReentrantMutex>

using namespace osgDB;
using namespace OpenThreads;

ReentrantMutex::ReentrantMutex():
    _threadHoldingMutex(0),
    _lockCount(0)
{
}

ReentrantMutex::~ReentrantMutex()
{
}

int ReentrantMutex::lock()
{
    if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0)
    {
        ++_lockCount;
        return 0;
    }
    else
    {
        int result = Mutex::lock();
        if (result==0)
        {
            _threadHoldingMutex = OpenThreads::Thread::CurrentThread();
            _lockCount = 1;
        }
        return result;
    }
}

int ReentrantMutex::unlock()
{
    if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0)
    {
        --_lockCount;
        if (_lockCount<=0)
        {
            _threadHoldingMutex = 0;
            return Mutex::unlock();
        }
    }
    return 0;
}

int ReentrantMutex::trylock()
{
    if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0)
    {
        ++_lockCount;
        return 0;
    }
    else
    {
        int result = Mutex::trylock();
        if (result==0)
        {
            _threadHoldingMutex = OpenThreads::Thread::CurrentThread();
            _lockCount = 1;
        }
        return result;
    }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2012 - 2021 Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"

/*!
 * \file commandQueue.cpp
 * \brief  Definitions for HostQueue object.
 *
 * \author Laurent Morichetti
 * \date   October 2008
 */

namespace amd {

HostQueue::HostQueue(Context& context, Device& device, cl_command_queue_properties props,
                     uint queueRTCUs, Priority priority, const std::vector<uint32_t>& cuMask)
    : CommandQueue(context, device, props, device.info().queueProperties_, queueRTCUs,
                   priority, cuMask),
      lastEnqueueCommand_(nullptr),
      head_(nullptr),
      tail_(nullptr),
      isActive_(false),
      markerTsCount_(0) {
  if (AMD_DIRECT_DISPATCH) {
    // Initialize the queue
    thread_.Init(this);
  } else {
    if (thread_.state() >= Thread::INITIALIZED) {
      ScopedLock sl(queueLock_);
      thread_.start(this);
      queueLock_.wait();
    }
  }

  if (GPU_FORCE_QUEUE_PROFILING) {
    properties().set(CL_QUEUE_PROFILING_ENABLE);
  }
}

bool HostQueue::terminate() {
  if (AMD_DIRECT_DISPATCH) {
    Command* marker = new Marker(*this, true);
    if (marker != nullptr) {
      marker->enqueue();
      marker->awaitCompletion();
      marker->release();
    }
    thread_.acceptingCommands_ = false;
    thread_.Release();
  } else {
    if (Os::isThreadAlive(thread_)) {
      Command* marker = nullptr;

      // Send a finish if the queue is still accepting commands.
      {
        ScopedLock sl(queueLock_);
        if (thread_.acceptingCommands_) {
          marker = new Marker(*this, false);
          if (marker != nullptr) {
            append(*marker);
            queueLock_.notify();
          }
        }
      }
      if (marker != nullptr) {
        marker->awaitCompletion();
        marker->release();
      }

      // Wake-up the command loop, so it can exit
      {
        ScopedLock sl(queueLock_);
        thread_.acceptingCommands_ = false;
        queueLock_.notify();
      }

      // FIXME_lmoriche: fix termination handshake
      while (thread_.state() < Thread::FINISHED) {
        Os::yield();
      }
    }
  }

  if (Agent::shouldPostCommandQueueEvents()) {
    Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
  }

  return true;
}

void HostQueue::finish() {
  Command* command = nullptr;
  if (IS_HIP) {
    command = getLastQueuedCommand(true);
    if (AMD_DIRECT_DISPATCH && command == nullptr) {
      return;
    }
  }
  if (nullptr == command || vdev()->isHandlerPending()) {
    if (nullptr != command) {
      command->release();
    }
    // Send a finish to make sure we finished all commands
    command = new Marker(*this, false);
    if (command == NULL) {
      return;
    }
    ClPrint(LOG_DEBUG, LOG_CMD, "Marker queued to ensure finish");
    command->enqueue();
  }
  // Check HW status of the ROCcrl event. Note: not all ROCclr modes support HW status
  static constexpr bool kWaitCompletion = true;
  if (!device().IsHwEventReady(command->event(), kWaitCompletion)) {
    ClPrint(LOG_DEBUG, LOG_CMD, "HW Event not ready, awaiting completion instead");
    command->awaitCompletion();
  }
  if (IS_HIP) {
    ScopedLock sl(vdev()->execution());
    ScopedLock l(lastCmdLock_);
    // Runtime can clear the last command only if no other submissions occured during finish()
    if (command == lastEnqueueCommand_) {
      lastEnqueueCommand_->release();
      lastEnqueueCommand_ = nullptr;
    }
  }
  command->release();
  ClPrint(LOG_DEBUG, LOG_CMD, "All commands finished");
}

void HostQueue::loop(device::VirtualDevice* virtualDevice) {
  // Notify the caller that the queue is ready to accept commands.
  {
    ScopedLock sl(queueLock_);
    thread_.acceptingCommands_ = true;
    queueLock_.notify();
  }
  // Create a command batch with all the commands present in the queue.
  Command* head = NULL;
  Command* tail = NULL;
  while (true) {
    // Get one command from the queue
    Command* command = queue_.dequeue();
    if (command == NULL) {
      ScopedLock sl(queueLock_);
      while ((command = queue_.dequeue()) == NULL) {
        if (!thread_.acceptingCommands_) {
          return;
        }
        queueLock_.wait();
      }
    }

    command->retain();

    // Process the command's event wait list.
    const Command::EventWaitList& events = command->eventWaitList();
    bool dependencyFailed = false;
    ClPrint(LOG_DEBUG, LOG_CMD, "Command (%s) processing: %p ,events.size(): %d",
            getOclCommandKindString(command->type()), command, events.size());
    for (const auto& it : events) {
      // Only wait if the command is enqueued into another queue.
      if (it->command().queue() != this) {
        // Runtime has to flush the current batch only if the dependent wait is blocking
        if (it->command().status() != CL_COMPLETE) {
          ClPrint(LOG_DEBUG, LOG_CMD, "Command (%s) %p awaiting event: %p", getOclCommandKindString(command->type()), command, it);
          virtualDevice->flush(head, true);
          tail = head = NULL;
          dependencyFailed |= !it->awaitCompletion();
        }
      }
    }

    // Insert the command to the linked list.
    if (NULL == head) {  // if the list is empty
      head = tail = command;
    } else {
      tail->setNext(command);
      tail = command;
    }

    if (dependencyFailed) {
      command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
      continue;
    }

    ClPrint(LOG_DEBUG, LOG_CMD, "Command (%s) submitted: %p", getOclCommandKindString(command->type()), command);

    command->setStatus(CL_SUBMITTED);

    // Submit to the device queue.
    command->submit(*virtualDevice);

    // if this is a user invisible marker command, then flush
    if (0 == command->type()) {
      virtualDevice->flush(head);
      tail = head = NULL;
    }
  }  // while (true) {
}

void HostQueue::append(Command& command) {
  // We retain the command here. It will be released when its status
  // changes to CL_COMPLETE
  if ((command.getWaitBits() & 0x1) != 0) {
    finish();
  }
  command.retain();
  command.setStatus(CL_QUEUED);
  queue_.enqueue(&command);
  if (!IS_HIP) {
    return;
  }

  // Set last submitted command
  Command* prevLastEnqueueCommand;
  command.retain();
  {
    // lastCmdLock_ ensures that lastEnqueueCommand() can retain the command before it is swapped
    // out. We want to keep this critical section as short as possible, so the command should be
    // released outside this section.
    ScopedLock l(lastCmdLock_);

    prevLastEnqueueCommand = lastEnqueueCommand_;
    lastEnqueueCommand_ = &command;
  }

  if (prevLastEnqueueCommand != nullptr) {
    prevLastEnqueueCommand->release();
  }
}

bool HostQueue::isEmpty() {
  // Get a snapshot of queue size
  return queue_.empty();
}

Command* HostQueue::getLastQueuedCommand(bool retain) {
  if (AMD_DIRECT_DISPATCH) {
    // The batch update must be lock protected to avoid a race condition
    // when multiple threads submit/flush/update the batch at the same time
    ScopedLock sl(vdev()->execution());
    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
    return lastEnqueueCommand_;
  } else {
    // Get last submitted command
    ScopedLock l(lastCmdLock_);

    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
    return lastEnqueueCommand_;
  }
}

DeviceQueue::~DeviceQueue() {
  delete virtualDevice_;
  ScopedLock lock(context().lock());
  context().removeDeviceQueue(device(), this);
}

bool DeviceQueue::create() {
  const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
  bool result = false;

  virtualDevice_ = device().createVirtualDevice(this);
  if (virtualDevice_ != NULL) {
    result = true;
    context().addDeviceQueue(device(), this, defaultDeviceQueue);
  }

  return result;
}

}  // namespace amd
<commit_msg>SWDEV-352487 - Don't add notifications as the last command<commit_after>/* Copyright (c) 2012 - 2021 Advanced Micro Devices, Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE. */

#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"

/*!
 * \file commandQueue.cpp
 * \brief  Definitions for HostQueue object.
 *
 * \author Laurent Morichetti
 * \date   October 2008
 */

namespace amd {

HostQueue::HostQueue(Context& context, Device& device, cl_command_queue_properties props,
                     uint queueRTCUs, Priority priority, const std::vector<uint32_t>& cuMask)
    : CommandQueue(context, device, props, device.info().queueProperties_, queueRTCUs,
                   priority, cuMask),
      lastEnqueueCommand_(nullptr),
      head_(nullptr),
      tail_(nullptr),
      isActive_(false),
      markerTsCount_(0) {
  if (AMD_DIRECT_DISPATCH) {
    // Initialize the queue
    thread_.Init(this);
  } else {
    if (thread_.state() >= Thread::INITIALIZED) {
      ScopedLock sl(queueLock_);
      thread_.start(this);
      queueLock_.wait();
    }
  }

  if (GPU_FORCE_QUEUE_PROFILING) {
    properties().set(CL_QUEUE_PROFILING_ENABLE);
  }
}

bool HostQueue::terminate() {
  if (AMD_DIRECT_DISPATCH) {
    Command* marker = new Marker(*this, true);
    if (marker != nullptr) {
      marker->enqueue();
      marker->awaitCompletion();
      marker->release();
    }
    thread_.acceptingCommands_ = false;
    thread_.Release();
  } else {
    if (Os::isThreadAlive(thread_)) {
      Command* marker = nullptr;

      // Send a finish if the queue is still accepting commands.
      {
        ScopedLock sl(queueLock_);
        if (thread_.acceptingCommands_) {
          marker = new Marker(*this, false);
          if (marker != nullptr) {
            append(*marker);
            queueLock_.notify();
          }
        }
      }
      if (marker != nullptr) {
        marker->awaitCompletion();
        marker->release();
      }

      // Wake-up the command loop, so it can exit
      {
        ScopedLock sl(queueLock_);
        thread_.acceptingCommands_ = false;
        queueLock_.notify();
      }

      // FIXME_lmoriche: fix termination handshake
      while (thread_.state() < Thread::FINISHED) {
        Os::yield();
      }
    }
  }

  if (Agent::shouldPostCommandQueueEvents()) {
    Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
  }

  return true;
}

void HostQueue::finish() {
  Command* command = nullptr;
  if (IS_HIP) {
    command = getLastQueuedCommand(true);
    if (command == nullptr) {
      return;
    }
  }
  if (nullptr == command || vdev()->isHandlerPending()) {
    if (nullptr != command) {
      command->release();
    }
    // Send a finish to make sure we finished all commands
    command = new Marker(*this, false);
    if (command == NULL) {
      return;
    }
    ClPrint(LOG_DEBUG, LOG_CMD, "Marker queued to ensure finish");
    command->enqueue();
  }
  // Check HW status of the ROCcrl event. Note: not all ROCclr modes support HW status
  static constexpr bool kWaitCompletion = true;
  if (!device().IsHwEventReady(command->event(), kWaitCompletion)) {
    ClPrint(LOG_DEBUG, LOG_CMD, "HW Event not ready, awaiting completion instead");
    command->awaitCompletion();
  }
  if (IS_HIP) {
    ScopedLock sl(vdev()->execution());
    ScopedLock l(lastCmdLock_);
    // Runtime can clear the last command only if no other submissions occured during finish()
    if (command == lastEnqueueCommand_) {
      lastEnqueueCommand_->release();
      lastEnqueueCommand_ = nullptr;
    }
  }
  command->release();
  ClPrint(LOG_DEBUG, LOG_CMD, "All commands finished");
}

void HostQueue::loop(device::VirtualDevice* virtualDevice) {
  // Notify the caller that the queue is ready to accept commands.
  {
    ScopedLock sl(queueLock_);
    thread_.acceptingCommands_ = true;
    queueLock_.notify();
  }
  // Create a command batch with all the commands present in the queue.
  Command* head = NULL;
  Command* tail = NULL;
  while (true) {
    // Get one command from the queue
    Command* command = queue_.dequeue();
    if (command == NULL) {
      ScopedLock sl(queueLock_);
      while ((command = queue_.dequeue()) == NULL) {
        if (!thread_.acceptingCommands_) {
          return;
        }
        queueLock_.wait();
      }
    }

    command->retain();

    // Process the command's event wait list.
    const Command::EventWaitList& events = command->eventWaitList();
    bool dependencyFailed = false;
    ClPrint(LOG_DEBUG, LOG_CMD, "Command (%s) processing: %p ,events.size(): %d",
            getOclCommandKindString(command->type()), command, events.size());
    for (const auto& it : events) {
      // Only wait if the command is enqueued into another queue.
      if (it->command().queue() != this) {
        // Runtime has to flush the current batch only if the dependent wait is blocking
        if (it->command().status() != CL_COMPLETE) {
          ClPrint(LOG_DEBUG, LOG_CMD, "Command (%s) %p awaiting event: %p", getOclCommandKindString(command->type()), command, it);
          virtualDevice->flush(head, true);
          tail = head = NULL;
          dependencyFailed |= !it->awaitCompletion();
        }
      }
    }

    // Insert the command to the linked list.
    if (NULL == head) {  // if the list is empty
      head = tail = command;
    } else {
      tail->setNext(command);
      tail = command;
    }

    if (dependencyFailed) {
      command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
      continue;
    }

    ClPrint(LOG_DEBUG, LOG_CMD, "Command (%s) submitted: %p", getOclCommandKindString(command->type()), command);

    command->setStatus(CL_SUBMITTED);

    // Submit to the device queue.
    command->submit(*virtualDevice);

    // if this is a user invisible marker command, then flush
    if (0 == command->type()) {
      virtualDevice->flush(head);
      tail = head = NULL;
    }
  }  // while (true) {
}

void HostQueue::append(Command& command) {
  // We retain the command here. It will be released when its status
  // changes to CL_COMPLETE
  if ((command.getWaitBits() & 0x1) != 0) {
    finish();
  }
  command.retain();
  command.setStatus(CL_QUEUED);
  queue_.enqueue(&command);
  if (!IS_HIP) {
    return;
  }

  // Set last submitted command
  Command* prevLastEnqueueCommand = nullptr;

  // Attach only real commands and skip internal notifications for CPU queue
  if (command.waitingEvent() == nullptr) {
    command.retain();

    // lastCmdLock_ ensures that lastEnqueueCommand() can retain the command before it is swapped
    // out. We want to keep this critical section as short as possible, so the command should be
    // released outside this section.
    ScopedLock l(lastCmdLock_);

    prevLastEnqueueCommand = lastEnqueueCommand_;
    lastEnqueueCommand_ = &command;
  }

  if (prevLastEnqueueCommand != nullptr) {
    prevLastEnqueueCommand->release();
  }
}

bool HostQueue::isEmpty() {
  // Get a snapshot of queue size
  return queue_.empty();
}

Command* HostQueue::getLastQueuedCommand(bool retain) {
  if (AMD_DIRECT_DISPATCH) {
    // The batch update must be lock protected to avoid a race condition
    // when multiple threads submit/flush/update the batch at the same time
    ScopedLock sl(vdev()->execution());
    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
    return lastEnqueueCommand_;
  } else {
    // Get last submitted command
    ScopedLock l(lastCmdLock_);

    // Since the lastCmdLock_ is acquired, it is safe to read and retain the lastEnqueueCommand.
    // It is guaranteed that the pointer will not change.
    if (retain && lastEnqueueCommand_ != nullptr) {
      lastEnqueueCommand_->retain();
    }
    return lastEnqueueCommand_;
  }
}

DeviceQueue::~DeviceQueue() {
  delete virtualDevice_;
  ScopedLock lock(context().lock());
  context().removeDeviceQueue(device(), this);
}

bool DeviceQueue::create() {
  const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
  bool result = false;

  virtualDevice_ = device().createVirtualDevice(this);
  if (virtualDevice_ != NULL) {
    result = true;
    context().addDeviceQueue(device(), this, defaultDeviceQueue);
  }

  return result;
}

}  // namespace amd
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision: 17495 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "QmitkImageNavigatorView.h"

#include "mitkNodePredicateDataType.h"

#include "QmitkDataStorageComboBox.h"
#include "QmitkStdMultiWidget.h"

#include "mitkDataStorageEditorInput.h"

// berry Includes
#include <berryPlatform.h>
#include <berryIWorkbenchPage.h>
#include <berryConstants.h>

#include <QMessageBox>

const std::string QmitkImageNavigatorView::VIEW_ID = "org.mitk.views.imagenavigator";

class ImageNavigatorPartListener : public berry::IPartListener
{
public:

  ImageNavigatorPartListener(QmitkImageNavigatorView* view)
    : m_View(view)
  {}

  berry::IPartListener::Events::Types GetPartEventTypes() const
  {
    return berry::IPartListener::Events::OPENED |
        berry::IPartListener::Events::CLOSED;
  }

  void PartClosed(berry::IWorkbenchPartReference::Pointer partRef)
  {
    m_View->SetMultiWidget(0);
  }

  void PartOpened(berry::IWorkbenchPartReference::Pointer partRef)
  {
    if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID)
    {
      if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID)
      {
        if (QmitkStdMultiWidgetEditor::Pointer multiWidgetPart =
            partRef->GetPart(false).Cast<QmitkStdMultiWidgetEditor>())
        {
          m_View->SetMultiWidget(multiWidgetPart->GetStdMultiWidget());
        }
        else
        {
          m_View->SetMultiWidget(0);
        }
      }
    }
  }

private:

  QmitkImageNavigatorView* m_View;
};

QmitkImageNavigatorView::QmitkImageNavigatorView()
: m_MultiWidget(NULL)
{
  multiWidgetListener = new ImageNavigatorPartListener(this);
}

QmitkImageNavigatorView::~QmitkImageNavigatorView()
{
  this->GetSite()->GetPage()->RemovePartListener(multiWidgetListener);
  //delete m_TransversalStepper;
  //delete m_SagittalStepper;
  //delete m_FrontalStepper;
  //delete m_TimeStepper;
}

void QmitkImageNavigatorView::CreateQtPartControl(QWidget *parent)
{

  // create GUI widgets
  m_Controls.setupUi(parent);
  m_MultiWidget = this->GetActiveStdMultiWidget();
  m_Controls.m_SliceNavigatorTransversal->SetInverseDirection(true);
  m_TransversalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTransversal, m_MultiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice() , "sliceNavigatorTransversalFromSimpleExample");
  m_SagittalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorSagittal, m_MultiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample");
  m_FrontalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorFrontal, m_MultiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample");
  m_TimeStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTime, m_MultiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample");

  this->GetSite()->GetPage()->AddPartListener(multiWidgetListener);
}

void QmitkImageNavigatorView::SetFocus ()
{

}

void QmitkImageNavigatorView::SetMultiWidget(QmitkStdMultiWidget* multiWidget)
{
  m_MultiWidget = multiWidget;
  if (m_MultiWidget)
  {
    m_TransversalStepper->SetStepper(m_MultiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice());
    m_SagittalStepper->SetStepper(m_MultiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice());
    m_FrontalStepper->SetStepper(m_MultiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice());
    m_TimeStepper->SetStepper(m_MultiWidget->GetTimeNavigationController()->GetTime());
  }
  else
  {
    m_TransversalStepper->SetStepper(0);
    m_SagittalStepper->SetStepper(0);
    m_FrontalStepper->SetStepper(0);
    m_TimeStepper->SetStepper(0);
  }
}

QmitkStdMultiWidget* QmitkImageNavigatorView::GetActiveStdMultiWidget()
{
  QmitkStdMultiWidget* activeStdMultiWidget = 0;
  berry::IEditorPart::Pointer editor =
    this->GetSite()->GetPage()->GetActiveEditor();

  if (editor.Cast<QmitkStdMultiWidgetEditor>().IsNotNull())
  {
    activeStdMultiWidget = editor.Cast<QmitkStdMultiWidgetEditor>()->GetStdMultiWidget();
  }
  else
  {
    mitk::DataStorageEditorInput::Pointer editorInput;
    editorInput = new mitk::DataStorageEditorInput();
    berry::IEditorPart::Pointer editor = this->GetSite()->GetPage()->OpenEditor(editorInput, QmitkStdMultiWidgetEditor::EDITOR_ID, false);
    activeStdMultiWidget = editor.Cast<QmitkStdMultiWidgetEditor>()->GetStdMultiWidget();
  }

  return activeStdMultiWidget;
}

int QmitkImageNavigatorView::GetSizeFlags(bool width)
{
  if(!width)
  {
    return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL;
  }
  else
  {
    return 0;
  }
}

int QmitkImageNavigatorView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult)
{
  if(width==false)
  {
    return 160;
  }
  else
  {
    return preferredResult;
  }
}

<commit_msg>The image navigator now checks which bundle is closed and only deletes its stdMultiWidget if the navigator itself or the stdMultiWidget tab is closed. Furthermore, new steppers are created in the SetMultiWidget method to reconnect to the view when it is reopened after pressing reinit.<commit_after>/*=========================================================================
Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "QmitkImageNavigatorView.h"

#include "mitkNodePredicateDataType.h"

#include "QmitkDataStorageComboBox.h"
#include "QmitkStdMultiWidget.h"

#include "mitkDataStorageEditorInput.h"

// berry Includes
#include <berryPlatform.h>
#include <berryIWorkbenchPage.h>
#include <berryConstants.h>

#include <QMessageBox>

const std::string QmitkImageNavigatorView::VIEW_ID = "org.mitk.views.imagenavigator";

class ImageNavigatorPartListener : public berry::IPartListener
{
public:

  ImageNavigatorPartListener(QmitkImageNavigatorView* view)
    : m_View(view)
  {}

  berry::IPartListener::Events::Types GetPartEventTypes() const
  {
    return berry::IPartListener::Events::OPENED |
        berry::IPartListener::Events::CLOSED;
  }

  void PartClosed(berry::IWorkbenchPartReference::Pointer partRef)
  {
    if((partRef->GetId() == QmitkImageNavigatorView::VIEW_ID) || (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID))
    {
      m_View->SetMultiWidget(0);
    }
  }

  void PartOpened(berry::IWorkbenchPartReference::Pointer partRef)
  {
    if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID)
    {
      if (QmitkStdMultiWidgetEditor::Pointer multiWidgetPart =
          partRef->GetPart(false).Cast<QmitkStdMultiWidgetEditor>())
      {
        m_View->SetMultiWidget(multiWidgetPart->GetStdMultiWidget());
      }
      else
      {
        m_View->SetMultiWidget(0);
      }
    }
  }

private:

  QmitkImageNavigatorView* m_View;
};

QmitkImageNavigatorView::QmitkImageNavigatorView()
  : m_MultiWidget(NULL)
{
  multiWidgetListener = new ImageNavigatorPartListener(this);
}

QmitkImageNavigatorView::~QmitkImageNavigatorView()
{
  this->GetSite()->GetPage()->RemovePartListener(multiWidgetListener);
}

void QmitkImageNavigatorView::CreateQtPartControl(QWidget *parent)
{

  // create GUI widgets
  m_Controls.setupUi(parent);
  m_MultiWidget = this->GetActiveStdMultiWidget();
  m_Controls.m_SliceNavigatorTransversal->SetInverseDirection(true);
  m_TransversalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTransversal, m_MultiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice() , "sliceNavigatorTransversalFromSimpleExample");
  m_SagittalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorSagittal, m_MultiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample");
  m_FrontalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorFrontal, m_MultiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample");
  m_TimeStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTime, m_MultiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample");

  this->GetSite()->GetPage()->AddPartListener(multiWidgetListener);
}

void QmitkImageNavigatorView::SetFocus ()
{

}

void QmitkImageNavigatorView::SetMultiWidget(QmitkStdMultiWidget* multiWidget)
{
  m_MultiWidget = multiWidget;
  if (m_MultiWidget)
  {
    m_TransversalStepper->deleteLater();
    m_SagittalStepper->deleteLater();
    m_FrontalStepper->deleteLater();
    m_TimeStepper->deleteLater();

    m_TransversalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTransversal, m_MultiWidget->mitkWidget1->GetSliceNavigationController()->GetSlice() , "sliceNavigatorTransversalFromSimpleExample");
    m_SagittalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorSagittal, m_MultiWidget->mitkWidget2->GetSliceNavigationController()->GetSlice(), "sliceNavigatorSagittalFromSimpleExample");
    m_FrontalStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorFrontal, m_MultiWidget->mitkWidget3->GetSliceNavigationController()->GetSlice(), "sliceNavigatorFrontalFromSimpleExample");
    m_TimeStepper = new QmitkStepperAdapter(m_Controls.m_SliceNavigatorTime, m_MultiWidget->GetTimeNavigationController()->GetTime(), "sliceNavigatorTimeFromSimpleExample");
  }
  else
  {
    m_TransversalStepper->SetStepper(0);
    m_SagittalStepper->SetStepper(0);
    m_FrontalStepper->SetStepper(0);
    m_TimeStepper->SetStepper(0);
  }
}

QmitkStdMultiWidget* QmitkImageNavigatorView::GetActiveStdMultiWidget()
{
  QmitkStdMultiWidget* activeStdMultiWidget = 0;
  berry::IEditorPart::Pointer editor =
      this->GetSite()->GetPage()->GetActiveEditor();

  if (editor.Cast<QmitkStdMultiWidgetEditor>().IsNotNull())
  {
    activeStdMultiWidget = editor.Cast<QmitkStdMultiWidgetEditor>()->GetStdMultiWidget();
  }
  else
  {
    mitk::DataStorageEditorInput::Pointer editorInput;
    editorInput = new mitk::DataStorageEditorInput();
    berry::IEditorPart::Pointer editor = this->GetSite()->GetPage()->OpenEditor(editorInput, QmitkStdMultiWidgetEditor::EDITOR_ID, false);
    activeStdMultiWidget = editor.Cast<QmitkStdMultiWidgetEditor>()->GetStdMultiWidget();
  }

  return activeStdMultiWidget;
}

int QmitkImageNavigatorView::GetSizeFlags(bool width)
{
  if(!width)
  {
    return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL;
  }
  else
  {
    return 0;
  }
}

int QmitkImageNavigatorView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult)
{
  if(width==false)
  {
    return 160;
  }
  else
  {
    return preferredResult;
  }
}

<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Ingo Kloecker <kloecker@kde.org>                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include "create.h"

#include <QtCore/QDebug>
#include <QtCore/QStringList>

#include "akonadi.h"
#include "akonadiconnection.h"
#include "storage/datastore.h"
#include "storage/entity.h"
#include "storage/transaction.h"
#include "handlerhelper.h"
#include "storage/selectquerybuilder.h"

#include "response.h"
#include "libs/imapparser_p.h"
#include "imapstreamparser.h"

using namespace Akonadi;

Create::Create( Scope::SelectionScope scope ) :
  Handler(),
  m_scope( scope )
{
}

bool Create::parseStream()
{
  QString name = m_streamParser->readUtf8String();
  if ( name.isEmpty() ) {
    return failureResponse( "Invalid collection name" );
  }

  bool ok = false;
  Collection parent;

  if ( m_scope == Scope::Uid || m_scope == Scope::None ) {
    qint64 parentId = m_streamParser->readNumber( &ok );
    if ( !ok ) { // RFC 3501 compat
      QString parentPath;
      int index = name.lastIndexOf( QLatin1Char('/') );
      if ( index > 0 ) {
        parentPath = name.left( index );
        name = name.mid( index + 1 );
        parent = HandlerHelper::collectionFromIdOrName( parentPath.toUtf8() );
      } else {
        parentId = 0;
      }
    } else {
      if ( parentId > 0 ) {
        parent = Collection::retrieveById( parentId );
      }
    }

    if ( parentId != 0 && !parent.isValid() ) {
      return failureResponse( "Parent collection not found" );
    }
  } else if ( m_scope == Scope::Rid ) {
    const QString rid = m_streamParser->readUtf8String();
    if ( rid.isEmpty() ) {
      throw HandlerException( "Empty parent remote identifier" );
    }
    if ( !connection()->resourceContext().isValid() ) {
      throw HandlerException( "Invalid resource context" );
    }
    SelectQueryBuilder<Collection> qb;
    qb.addValueCondition( Collection::remoteIdColumn(), Query::Equals, rid );
    qb.addValueCondition( Collection::resourceIdColumn(), Query::Equals, connection()->resourceContext().id() );
    if ( !qb.exec() ) {
      throw HandlerException( "Unable to execute collection query" );
    }
    const Collection::List cols = qb.result();
    if ( cols.size() == 0 ) {
      throw HandlerException( "Parent collection not found" );
    } else if ( cols.size() > 1 ) {
      throw HandlerException( "Parent collection is not unique" );
    }
    parent = cols.first();
  }

  qint64 resourceId = 0;
  bool forceVirtual = false;
  MimeType::List parentContentTypes;
  if ( parent.isValid() ) {
    // check if parent can contain a sub-folder
    parentContentTypes = parent.mimeTypes();
    bool found = false, foundVirtual = false;
    Q_FOREACH ( const MimeType &mt, parentContentTypes ) {
      if ( mt.name() == QLatin1String( "inode/directory" ) ) {
        found = true;
        if ( foundVirtual ) {
          break;
        }
      } else if ( mt.name() == QLatin1String( "application/x-vnd.akonadi.collection.virtual" ) ) {
        foundVirtual = true;
        if ( found ) {
          break;
        }
      }
    }
    if ( !found && !foundVirtual ) {
      return failureResponse( "Parent collection can not contain sub-collections" );
    }

    // If only virtual collections are supported, force every new collection to
    // be virtual. Otherwise depend on VIRTUAL attribute in the command
    if ( foundVirtual && !found ) {
      forceVirtual = true;
    }

    // inherit resource
    resourceId = parent.resourceId();
  } else {
    // deduce owning resource from current session id
    QString sessionId = QString::fromUtf8( connection()->sessionId() );
    Resource res = Resource::retrieveByName( sessionId );
    if ( !res.isValid() ) {
      return failureResponse( "Cannot create top-level collection" );
    }
    resourceId = res.id();
  }

  Collection collection;
  if ( parent.isValid() ) {
    collection.setParentId( parent.id() );
  }
  collection.setName( name );
  collection.setResourceId( resourceId );

  // attributes
  QList<QByteArray> attributes;
  QList<QByteArray> mimeTypes;
  QVector< QPair<QByteArray, QByteArray> > userDefAttrs;
  bool mimeTypesSet = false;
  attributes = m_streamParser->readParenthesizedList();
  for ( int i = 0; i < attributes.count() - 1; i += 2 ) {
    const QByteArray key = attributes.at( i );
    const QByteArray value = attributes.at( i + 1 );
    if ( key == AKONADI_PARAM_REMOTEID ) {
      collection.setRemoteId( QString::fromUtf8( value ) );
    } else if ( key == AKONADI_PARAM_REMOTEREVISION ) {
      collection.setRemoteRevision( QString::fromUtf8( value ) );
    } else if ( key == AKONADI_PARAM_MIMETYPE ) {
      ImapParser::parseParenthesizedList( value, mimeTypes );
      mimeTypesSet = true;
    } else if ( key == AKONADI_PARAM_CACHEPOLICY ) {
      HandlerHelper::parseCachePolicy( value, collection );
    } else if ( key == AKONADI_PARAM_VIRTUAL ) {
      collection.setIsVirtual( value.toUInt() != 0 );
    } else {
      userDefAttrs << qMakePair( key, value );
    }
  }

  if ( forceVirtual ) {
    collection.setIsVirtual( true );
  }

  DataStore *db = connection()->storageBackend();
  Transaction transaction( db );

  if ( !db->appendCollection( collection ) ) {
    return failureResponse( "Could not create collection " + name.toLocal8Bit() + " resourceId: " + QByteArray::number(resourceId));
  }

  QStringList effectiveMimeTypes;
  if ( mimeTypesSet ) {
    Q_FOREACH ( const QByteArray &b, mimeTypes )
      effectiveMimeTypes << QString::fromUtf8( b );
  } else {
    Q_FOREACH ( const MimeType &mt, parentContentTypes )
      effectiveMimeTypes << mt.name();
  }
  if ( !db->appendMimeTypeForCollection( collection.id(), effectiveMimeTypes ) ) {
    return failureResponse( "Unable to append mimetype for collection " + name.toLocal8Bit() + " resourceId: " + QByteArray::number(resourceId) );
  }

  // store user defined attributes
  typedef QPair<QByteArray,QByteArray> QByteArrayPair;
  Q_FOREACH ( const QByteArrayPair &attr, userDefAttrs ) {
    if ( !db->addCollectionAttribute( collection, attr.first, attr.second ) ) {
      return failureResponse( "Unable to add collection attribute." );
    }
  }

  Response response;
  response.setUntagged();

   // write out collection details
  db->activeCachePolicy( collection );
  const QByteArray b = HandlerHelper::collectionToByteArray( collection );
  response.setString( b );
  Q_EMIT responseAvailable( response );

  if ( !transaction.commit() ) {
    return failureResponse( "Unable to commit transaction." );
  }

  return successResponse( "CREATE completed" );
}
<commit_msg>Fix build<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Ingo Kloecker <kloecker@kde.org>                *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include "create.h"

#include <QtCore/QDebug>
#include <QtCore/QStringList>

#include "akonadi.h"
#include "akonadiconnection.h"
#include "storage/datastore.h"
#include "storage/entity.h"
#include "storage/transaction.h"
#include "handlerhelper.h"
#include "storage/selectquerybuilder.h"
#include "libs/protocol_p.h"

#include "response.h"
#include "libs/imapparser_p.h"
#include "imapstreamparser.h"

using namespace Akonadi;

Create::Create( Scope::SelectionScope scope ) :
  Handler(),
  m_scope( scope )
{
}

bool Create::parseStream()
{
  QString name = m_streamParser->readUtf8String();
  if ( name.isEmpty() ) {
    return failureResponse( "Invalid collection name" );
  }

  bool ok = false;
  Collection parent;

  if ( m_scope == Scope::Uid || m_scope == Scope::None ) {
    qint64 parentId = m_streamParser->readNumber( &ok );
    if ( !ok ) { // RFC 3501 compat
      QString parentPath;
      int index = name.lastIndexOf( QLatin1Char('/') );
      if ( index > 0 ) {
        parentPath = name.left( index );
        name = name.mid( index + 1 );
        parent = HandlerHelper::collectionFromIdOrName( parentPath.toUtf8() );
      } else {
        parentId = 0;
      }
    } else {
      if ( parentId > 0 ) {
        parent = Collection::retrieveById( parentId );
      }
    }

    if ( parentId != 0 && !parent.isValid() ) {
      return failureResponse( "Parent collection not found" );
    }
  } else if ( m_scope == Scope::Rid ) {
    const QString rid = m_streamParser->readUtf8String();
    if ( rid.isEmpty() ) {
      throw HandlerException( "Empty parent remote identifier" );
    }
    if ( !connection()->resourceContext().isValid() ) {
      throw HandlerException( "Invalid resource context" );
    }
    SelectQueryBuilder<Collection> qb;
    qb.addValueCondition( Collection::remoteIdColumn(), Query::Equals, rid );
    qb.addValueCondition( Collection::resourceIdColumn(), Query::Equals, connection()->resourceContext().id() );
    if ( !qb.exec() ) {
      throw HandlerException( "Unable to execute collection query" );
    }
    const Collection::List cols = qb.result();
    if ( cols.size() == 0 ) {
      throw HandlerException( "Parent collection not found" );
    } else if ( cols.size() > 1 ) {
      throw HandlerException( "Parent collection is not unique" );
    }
    parent = cols.first();
  }

  qint64 resourceId = 0;
  bool forceVirtual = false;
  MimeType::List parentContentTypes;
  if ( parent.isValid() ) {
    // check if parent can contain a sub-folder
    parentContentTypes = parent.mimeTypes();
    bool found = false, foundVirtual = false;
    Q_FOREACH ( const MimeType &mt, parentContentTypes ) {
      if ( mt.name() == QLatin1String( "inode/directory" ) ) {
        found = true;
        if ( foundVirtual ) {
          break;
        }
      } else if ( mt.name() == QLatin1String( "application/x-vnd.akonadi.collection.virtual" ) ) {
        foundVirtual = true;
        if ( found ) {
          break;
        }
      }
    }
    if ( !found && !foundVirtual ) {
      return failureResponse( "Parent collection can not contain sub-collections" );
    }

    // If only virtual collections are supported, force every new collection to
    // be virtual. Otherwise depend on VIRTUAL attribute in the command
    if ( foundVirtual && !found ) {
      forceVirtual = true;
    }

    // inherit resource
    resourceId = parent.resourceId();
  } else {
    // deduce owning resource from current session id
    QString sessionId = QString::fromUtf8( connection()->sessionId() );
    Resource res = Resource::retrieveByName( sessionId );
    if ( !res.isValid() ) {
      return failureResponse( "Cannot create top-level collection" );
    }
    resourceId = res.id();
  }

  Collection collection;
  if ( parent.isValid() ) {
    collection.setParentId( parent.id() );
  }
  collection.setName( name );
  collection.setResourceId( resourceId );

  // attributes
  QList<QByteArray> attributes;
  QList<QByteArray> mimeTypes;
  QVector< QPair<QByteArray, QByteArray> > userDefAttrs;
  bool mimeTypesSet = false;
  attributes = m_streamParser->readParenthesizedList();
  for ( int i = 0; i < attributes.count() - 1; i += 2 ) {
    const QByteArray key = attributes.at( i );
    const QByteArray value = attributes.at( i + 1 );
    if ( key == AKONADI_PARAM_REMOTEID ) {
      collection.setRemoteId( QString::fromUtf8( value ) );
    } else if ( key == AKONADI_PARAM_REMOTEREVISION ) {
      collection.setRemoteRevision( QString::fromUtf8( value ) );
    } else if ( key == AKONADI_PARAM_MIMETYPE ) {
      ImapParser::parseParenthesizedList( value, mimeTypes );
      mimeTypesSet = true;
    } else if ( key == AKONADI_PARAM_CACHEPOLICY ) {
      HandlerHelper::parseCachePolicy( value, collection );
    } else if ( key == AKONADI_PARAM_VIRTUAL ) {
      collection.setIsVirtual( value.toUInt() != 0 );
    } else {
      userDefAttrs << qMakePair( key, value );
    }
  }

  if ( forceVirtual ) {
    collection.setIsVirtual( true );
  }

  DataStore *db = connection()->storageBackend();
  Transaction transaction( db );

  if ( !db->appendCollection( collection ) ) {
    return failureResponse( "Could not create collection " + name.toLocal8Bit() + " resourceId: " + QByteArray::number(resourceId));
  }

  QStringList effectiveMimeTypes;
  if ( mimeTypesSet ) {
    Q_FOREACH ( const QByteArray &b, mimeTypes )
      effectiveMimeTypes << QString::fromUtf8( b );
  } else {
    Q_FOREACH ( const MimeType &mt, parentContentTypes )
      effectiveMimeTypes << mt.name();
  }
  if ( !db->appendMimeTypeForCollection( collection.id(), effectiveMimeTypes ) ) {
    return failureResponse( "Unable to append mimetype for collection " + name.toLocal8Bit() + " resourceId: " + QByteArray::number(resourceId) );
  }

  // store user defined attributes
  typedef QPair<QByteArray,QByteArray> QByteArrayPair;
  Q_FOREACH ( const QByteArrayPair &attr, userDefAttrs ) {
    if ( !db->addCollectionAttribute( collection, attr.first, attr.second ) ) {
      return failureResponse( "Unable to add collection attribute." );
    }
  }

  Response response;
  response.setUntagged();

   // write out collection details
  db->activeCachePolicy( collection );
  const QByteArray b = HandlerHelper::collectionToByteArray( collection );
  response.setString( b );
  Q_EMIT responseAvailable( response );

  if ( !transaction.commit() ) {
    return failureResponse( "Unable to commit transaction." );
  }

  return successResponse( "CREATE completed" );
}
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE trace_data_extraction
#include <boost/test/included/unit_test.hpp>

#include <eosio/chain/trace.hpp>
#include <eosio/chain/transaction.hpp>
#include <eosio/chain/block.hpp>
#include <eosio/chain/block_state.hpp>

#include <eosio/trace_api_plugin/test_common.hpp>
#include <eosio/trace_api_plugin/chain_extraction.hpp>

using namespace eosio;
using namespace eosio::trace_api_plugin;
using namespace eosio::trace_api_plugin::test_common;
using eosio::chain::name;
using eosio::chain::digest_type;

namespace {
   chain::transaction_trace_ptr make_transaction_trace( chain::transaction_id_type&& id, uint32_t block_number, uint32_t slot, chain::transaction_receipt_header::status_enum status, std::vector<chain::action_trace> && actions ) {
      return std::make_shared<chain::transaction_trace>(chain::transaction_trace{
         std::move(id),
         block_number,
         chain::block_timestamp_type(slot),
         {},
         chain::transaction_receipt_header{status},
         fc::microseconds(0),
         0,
         false,
         std::move(actions),
         {},
         {},
         {},
         {},
         {}
      });
   }

   chain::action_trace make_action_trace(uint64_t global_sequence, chain::name receiver, chain::name account, chain::name action, std::vector<chain::permission_level>&& authorizations, chain::bytes&& data ) {
      chain::action_trace result;
      // don't think we need any information other than receiver and global sequence
      result.receipt.emplace(chain::action_receipt{
         receiver,
         "0000000000000000000000000000000000000000000000000000000000000000"_h,
         global_sequence,
         0,
         {},
         0,
         0
      });
      result.receiver = receiver;
      result.act = chain::action( std::move(authorizations), account, action, std::move(data) );
      return result;
   }

   chain::bytes make_transfer_data( chain::name from, chain::name to, chain::asset quantity, std::string&& memo) {
      fc::datastream<size_t> ps;
      fc::raw::pack(ps, from, to, quantity, memo);
      chain::bytes result(ps.tellp());

      if( result.size() ) {
         fc::datastream<char*>  ds( result.data(), size_t(result.size()) );
         fc::raw::pack(ds, from, to, quantity, memo);
      }
      return result;
   }

   auto get_private_key( name keyname, std::string role = "owner" ) {
      auto secret = fc::sha256::hash( keyname.to_string() + role );
      return chain::private_key_type::regenerate<fc::ecc::private_key_shim>( secret );
   }

   auto get_public_key( name keyname, std::string role = "owner" ) {
      return get_private_key( keyname, role ).get_public_key();
   }

   auto create_test_block_state( std::vector<chain::transaction_metadata_ptr> trx_metas ) {
      chain::signed_block_ptr block = std::make_shared<chain::signed_block>();
      for( auto& trx_meta : trx_metas ) {
         block->transactions.emplace_back( *trx_meta->packed_trx());
      }

      block->producer = eosio::chain::config::system_account_name;

      auto priv_key = get_private_key( block->producer, "active" );
      auto pub_key = get_public_key( block->producer, "active" );

      auto prev = std::make_shared<chain::block_state>();
      auto header_bmroot = digest_type::hash( std::make_pair( block->digest(), prev->blockroot_merkle.get_root()));
      auto sig_digest = digest_type::hash( std::make_pair( header_bmroot, prev->pending_schedule.schedule_hash ));
      block->producer_signature = priv_key.sign( sig_digest );

      std::vector<chain::private_key_type> signing_keys;
      signing_keys.emplace_back( std::move( priv_key ));

      auto signer = [&]( digest_type d ) {
         std::vector<chain::signature_type> result;
         result.reserve( signing_keys.size());
         for( const auto& k: signing_keys )
            result.emplace_back( k.sign( d ));
         return result;
      };
      chain::pending_block_header_state pbhs;
      pbhs.producer = block->producer;
      chain::producer_authority_schedule schedule = {0, {chain::producer_authority{block->producer,
                                                                     chain::block_signing_authority_v0{1, {{pub_key, 1}}}}}};
      pbhs.active_schedule = schedule;
      pbhs.valid_block_signing_authority = chain::block_signing_authority_v0{1, {{pub_key, 1}}};
      auto bsp = std::make_shared<chain::block_state>(
            std::move( pbhs ),
            std::move( block ),
            std::move( trx_metas ),
            chain::protocol_feature_set(),
            []( chain::block_timestamp_type timestamp,
                const fc::flat_set<digest_type>& cur_features,
                const std::vector<digest_type>& new_features ) {},
            signer
      );

      return bsp;
   }

   chain::block_state_ptr make_block_state( chain::block_id_type id, chain::block_id_type previous, uint32_t height,
         uint32_t slot, chain::name producer,
         std::vector<std::tuple<chain::transaction_id_type, chain::transaction_receipt_header::status_enum>> transactions ) {
      // TODO: it was going to be very complicated to produce a proper block_state_ptr, this can probably be changed
      // to some sort of intermediate form that a shim interface can extract from a block_state_ptr to make testing
      // and refactoring easier.
      return {};
   }
}

struct extraction_test_fixture {
   /**
    * MOCK implementation of the logfile input API
    */
   struct mock_logfile_provider_type {
      mock_logfile_provider_type(extraction_test_fixture& fixture)
      :fixture(fixture)
      {}

      /**
       * append an entry to the end of the data log
       *
       * @param entry : the entry to append
       * @return the offset in the log where that entry is written
       */
      uint64_t append_data_log( const data_log_entry& entry ) {
         fixture.data_log.emplace_back(entry);
         return fixture.data_log.size() - 1;
      }

      /**
       * Append an entry to the metadata log
       *
       * @param entry
       * @return
       */
      uint64_t append_metadata_log( const metadata_log_entry& entry ) {
         if (entry.contains<block_entry_v0>()) {
            const auto& b = entry.get<block_entry_v0>();
            fixture.block_entry_for_height[b.number] = b;
         } else if (entry.contains<lib_entry_v0>()) {
            const auto& lib = entry.get<lib_entry_v0>();
            fixture.max_lib = std::max(fixture.max_lib, lib.lib);
         } else {
            BOOST_FAIL("Unknown metadata log entry emitted");
         }
         return fixture.metadata_offset++;
      }

      extraction_test_fixture& fixture;
   };

   /**
    * TODO: initialize extraction implementation here with `mock_logfile_provider` as template param
    */
   extraction_test_fixture()
   : extraction_impl(mock_logfile_provider_type(*this), [](std::exception_ptr eptr) {})
   {
   }

   void signal_applied_transaction( const chain::transaction_trace_ptr& trace, const chain::signed_transaction& strx ) {
      extraction_impl.signal_applied_transaction(trace, strx);
   }

   void signal_accepted_block( const chain::block_state_ptr& bsp ) {
      extraction_impl.signal_accepted_block(bsp);
   }

   // fixture data and methods
   std::map<uint64_t, block_entry_v0> block_entry_for_height = {};
   uint64_t metadata_offset = 0;
   uint64_t max_lib = 0;
   std::vector<data_log_entry> data_log = {};

   chain_extraction_impl_type<mock_logfile_provider_type> extraction_impl;

};

BOOST_AUTO_TEST_SUITE(block_extraction)
   BOOST_FIXTURE_TEST_CASE(basic_single_transaction_block, extraction_test_fixture)
   {
      // apply a basic transfer
      //
      signal_applied_transaction(
         make_transaction_trace(
            "0000000000000000000000000000000000000000000000000000000000000001"_h,
            1,
            1,
            chain::transaction_receipt_header::executed,
            {
                  make_action_trace(0, "eosio.token"_n, "eosio.token"_n, "transfer"_n, {{ "alice"_n, "active"_n }}, make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" ) ),
                  make_action_trace(1, "alice"_n, "eosio.token"_n, "transfer"_n, {{ "alice"_n, "active"_n }}, make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" ) ),
                  make_action_trace(2, "bob"_n, "eosio.token"_n, "transfer"_n, {{ "alice"_n, "active"_n }}, make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" ) )
            }
         ),
         {
               // I don't think we will need any data from here?
         }
      );

      // accept the block with one transaction
      //

      signal_accepted_block(
         make_block_state(
            "b000000000000000000000000000000000000000000000000000000000000001"_h,
            "0000000000000000000000000000000000000000000000000000000000000000"_h,
            1,
            1,
            "bp.one"_n,
            {
               { "0000000000000000000000000000000000000000000000000000000000000001"_h, chain::transaction_receipt_header::executed }
            }
         )
      );

      // Verify that the blockheight and LIB are correct
      //
      const uint64_t expected_lib = 0;
      const block_entry_v0 expected_entry {
        "b000000000000000000000000000000000000000000000000000000000000001"_h,
        1,
        0
      };

      const block_trace_v0 expected_trace {
         "b000000000000000000000000000000000000000000000000000000000000001"_h,
         1,
         "0000000000000000000000000000000000000000000000000000000000000000"_h,
         chain::block_timestamp_type(1),
         "bp.one"_n,
         {
            {
               "0000000000000000000000000000000000000000000000000000000000000001"_h,
               chain::transaction_receipt_header::executed,
               {
                  {
                     0,
                     "eosio.token"_n, "eosio.token"_n, "transfer"_n,
                     {{ "alice"_n, "active"_n }},
                     make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" )
                  },
                  {
                     1,
                     "alice"_n, "eosio.token"_n, "transfer"_n,
                     {{ "alice"_n, "active"_n }},
                     make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" )
                  },
                  {
                     2,
                     "bob"_n, "eosio.token"_n, "transfer"_n,
                     {{ "alice"_n, "active"_n }},
                     make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" )
                  }
               }
            }
         }
      };
      BOOST_REQUIRE_EQUAL(max_lib, 0);
      BOOST_REQUIRE(block_entry_for_height.count(1) > 0);
      BOOST_REQUIRE_EQUAL(block_entry_for_height.at(1), expected_entry);
      BOOST_REQUIRE(data_log.size() >= expected_entry.offset);
      BOOST_REQUIRE(data_log.at(expected_entry.offset).contains<block_trace_v0>());
      BOOST_REQUIRE_EQUAL(data_log.at(expected_entry.offset).get<block_trace_v0>(), expected_trace);
   }

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>First test passing<commit_after>#define BOOST_TEST_MODULE trace_data_extraction
#include <boost/test/included/unit_test.hpp>

#include <eosio/chain/trace.hpp>
#include <eosio/chain/transaction.hpp>
#include <eosio/chain/block.hpp>
#include <eosio/chain/block_state.hpp>

#include <eosio/trace_api_plugin/test_common.hpp>
#include <eosio/trace_api_plugin/chain_extraction.hpp>

#include <fc/bitutil.hpp>

using namespace eosio;
using namespace eosio::trace_api_plugin;
using namespace eosio::trace_api_plugin::test_common;
using eosio::chain::name;
using eosio::chain::digest_type;

namespace {
   chain::transaction_trace_ptr make_transaction_trace( const chain::transaction_id_type& id, uint32_t block_number,
         uint32_t slot, chain::transaction_receipt_header::status_enum status, std::vector<chain::action_trace>&& actions ) {
      return std::make_shared<chain::transaction_trace>(chain::transaction_trace{
         id,
         block_number,
         chain::block_timestamp_type(slot),
         {},
         chain::transaction_receipt_header{status},
         fc::microseconds(0),
         0,
         false,
         std::move(actions),
         {},
         {},
         {},
         {},
         {}
      });
   }

   chain::bytes make_transfer_data( chain::name from, chain::name to, chain::asset quantity, std::string&& memo ) {
      fc::datastream<size_t> ps;
      fc::raw::pack(ps, from, to, quantity, memo);
      chain::bytes result(ps.tellp());

      if( result.size() ) {
         fc::datastream<char*>  ds( result.data(), size_t(result.size()) );
         fc::raw::pack(ds, from, to, quantity, memo);
      }
      return result;
   }

   auto get_private_key( name keyname, std::string role = "owner" ) {
      auto secret = fc::sha256::hash( keyname.to_string() + role );
      return chain::private_key_type::regenerate<fc::ecc::private_key_shim>( secret );
   }

   auto get_public_key( name keyname, std::string role = "owner" ) {
      return get_private_key( keyname, role ).get_public_key();
   }

   auto make_transfer_action( chain::name from, chain::name to, chain::asset quantity, std::string memo ) {
      return chain::action( std::vector<chain::permission_level> {{from, chain::config::active_name}},
                            "eosio.token"_n, "transfer"_n, make_transfer_data( from, to, quantity, std::move(memo) ) );
   }

   auto make_packed_trx( std::vector<chain::action> actions ) {
      chain::signed_transaction trx;
      trx.actions = std::move( actions );
      return packed_transaction( trx );
   }

   chain::action_trace make_action_trace( uint64_t global_sequence, chain::action act, chain::name receiver ) {
      chain::action_trace result;
      // don't think we need any information other than receiver and global sequence
      result.receipt.emplace(chain::action_receipt{
         receiver,
         digest_type::hash(act),
         global_sequence,
         0,
         {},
         0,
         0
      });
      result.receiver = receiver;
      result.act = std::move(act);
      return result;
   }

   auto make_block_state( chain::block_id_type previous, uint32_t height, uint32_t slot, chain::name producer,
                          std::vector<chain::packed_transaction> trxs ) {
      chain::signed_block_ptr block = std::make_shared<chain::signed_block>();
      for( auto& trx : trxs ) {
         block->transactions.emplace_back( trx );
      }
      block->producer = producer;
      block->timestamp = chain::block_timestamp_type(slot);
      // make sure previous contains correct block # so block_header::block_num() returns correct value
      if( previous == chain::block_id_type() ) {
         previous._hash[0] &= 0xffffffff00000000;
         previous._hash[0] += fc::endian_reverse_u32(height - 1);
      }
      block->previous = previous;

      auto priv_key = get_private_key( block->producer, "active" );
      auto pub_key = get_public_key( block->producer, "active" );

      auto prev = std::make_shared<chain::block_state>();
      auto header_bmroot = digest_type::hash( std::make_pair( block->digest(), prev->blockroot_merkle.get_root()));
      auto sig_digest = digest_type::hash( std::make_pair( header_bmroot, prev->pending_schedule.schedule_hash ));
      block->producer_signature = priv_key.sign( sig_digest );

      std::vector<chain::private_key_type> signing_keys;
      signing_keys.emplace_back( std::move( priv_key ));
      auto signer = [&]( digest_type d ) {
         std::vector<chain::signature_type> result;
         result.reserve( signing_keys.size());
         for( const auto& k: signing_keys )
            result.emplace_back( k.sign( d ));
         return result;
      };
      chain::pending_block_header_state pbhs;
      pbhs.producer = block->producer;
      pbhs.timestamp = block->timestamp;
      chain::producer_authority_schedule schedule = {0, {chain::producer_authority{block->producer,
                                                                     chain::block_signing_authority_v0{1, {{pub_key, 1}}}}}};
      pbhs.active_schedule = schedule;
      pbhs.valid_block_signing_authority = chain::block_signing_authority_v0{1, {{pub_key, 1}}};
      auto bsp = std::make_shared<chain::block_state>(
            std::move( pbhs ),
            std::move( block ),
            std::vector<chain::transaction_metadata_ptr>(),
            chain::protocol_feature_set(),
            []( chain::block_timestamp_type timestamp,
                const fc::flat_set<digest_type>& cur_features,
                const std::vector<digest_type>& new_features ) {},
            signer
      );
      bsp->block_num = height;

      return bsp;
   }

}

struct extraction_test_fixture {
   /**
    * MOCK implementation of the logfile input API
    */
   struct mock_logfile_provider_type {
      mock_logfile_provider_type(extraction_test_fixture& fixture)
      :fixture(fixture)
      {}

      /**
       * append an entry to the end of the data log
       *
       * @param entry : the entry to append
       * @return the offset in the log where that entry is written
       */
      uint64_t append_data_log( const data_log_entry& entry ) {
         fixture.data_log.emplace_back(entry);
         return fixture.data_log.size() - 1;
      }

      /**
       * Append an entry to the metadata log
       *
       * @param entry
       * @return
       */
      uint64_t append_metadata_log( const metadata_log_entry& entry ) {
         if (entry.contains<block_entry_v0>()) {
            const auto& b = entry.get<block_entry_v0>();
            fixture.block_entry_for_height[b.number] = b;
         } else if (entry.contains<lib_entry_v0>()) {
            const auto& lib = entry.get<lib_entry_v0>();
            fixture.max_lib = std::max(fixture.max_lib, lib.lib);
         } else {
            BOOST_FAIL("Unknown metadata log entry emitted");
         }
         return fixture.metadata_offset++;
      }

      extraction_test_fixture& fixture;
   };

   extraction_test_fixture()
   : extraction_impl(mock_logfile_provider_type(*this), [](std::exception_ptr eptr) {})
   {
   }

   void signal_applied_transaction( const chain::transaction_trace_ptr& trace, const chain::signed_transaction& strx ) {
      extraction_impl.signal_applied_transaction(trace, strx);
   }

   void signal_accepted_block( const chain::block_state_ptr& bsp ) {
      extraction_impl.signal_accepted_block(bsp);
   }

   // fixture data and methods
   std::map<uint64_t, block_entry_v0> block_entry_for_height = {};
   uint64_t metadata_offset = 0;
   uint64_t max_lib = 0;
   std::vector<data_log_entry> data_log = {};

   chain_extraction_impl_type<mock_logfile_provider_type> extraction_impl;
};

BOOST_AUTO_TEST_SUITE(block_extraction)
   BOOST_FIXTURE_TEST_CASE(basic_single_transaction_block, extraction_test_fixture)
   {
      auto act1 = make_transfer_action( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" );
      auto act2 = make_transfer_action( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" );
      auto act3 = make_transfer_action( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" );
      auto actt1 = make_action_trace( 0, act1, "eosio.token"_n );
      auto actt2 = make_action_trace( 1, act1, "alice"_n );
      auto actt3 = make_action_trace( 2, act1, "bob"_n );
      auto ptrx1 = make_packed_trx( { act1, act2, act3 } );

      // apply a basic transfer
      //
      signal_applied_transaction(
            make_transaction_trace(
                  ptrx1.id(),
                  1,
                  1,
                  chain::transaction_receipt_header::executed,
                  { actt1, actt2, actt3 }
                  ),
                  {
                    // I don't think we will need any data from here?
                  }
      );

      // accept the block with one transaction

      auto bsp1 = make_block_state(
            chain::block_id_type(),
            1,
            1,
            "bp.one"_n,
            { chain::packed_transaction(ptrx1) } );
      signal_accepted_block( bsp1 );

      // Verify that the blockheight and LIB are correct
      //
      const uint64_t expected_lib = 0;
      const block_entry_v0 expected_entry {
         bsp1->id,
         1,
         0
      };

      const block_trace_v0 expected_trace {
         bsp1->id,
         1,
         bsp1->prev(),
         chain::block_timestamp_type(1),
         "bp.one"_n,
         {
            {
               ptrx1.id(),
               chain::transaction_receipt_header::executed,
               {
                  {
                     0,
                     "eosio.token"_n, "eosio.token"_n, "transfer"_n,
                     {{ "alice"_n, "active"_n }},
                     make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" )
                  },
                  {
                     1,
                     "alice"_n, "eosio.token"_n, "transfer"_n,
                     {{ "alice"_n, "active"_n }},
                     make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" )
                  },
                  {
                     2,
                     "bob"_n, "eosio.token"_n, "transfer"_n,
                     {{ "alice"_n, "active"_n }},
                     make_transfer_data( "alice"_n, "bob"_n, "0.0001 SYS"_t, "Memo!" )
                  }
               }
            }
         }
      };

      BOOST_REQUIRE_EQUAL(max_lib, 0);
      BOOST_REQUIRE(block_entry_for_height.count(1) > 0);
      BOOST_REQUIRE_EQUAL(block_entry_for_height.at(1), expected_entry);
      BOOST_REQUIRE(data_log.size() >= expected_entry.offset);
      BOOST_REQUIRE(data_log.at(expected_entry.offset).contains<block_trace_v0>());
      BOOST_REQUIRE_EQUAL(data_log.at(expected_entry.offset).get<block_trace_v0>(), expected_trace);
   }

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Copyright 2008, Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.

// The file contains the implementation of the File methods specific to
// the win32 platform.

// TODO: likely there are better ways to accomplish Delete and
// CreateNewTempFile.

#include "kml/base/file.h"
#include <windows.h>
#include <tchar.h>
#include <xstring>
#include <algorithm>

namespace kmlbase {

// Internal to the win32 file class. We need a conversion from string to
// LPCWSTR.
static std::wstring Str2Wstr(const string& str) {
  std::wstring wstr(str.length(), L'');
  std::copy(str.begin(), str.end(), wstr.begin());
  return wstr;
}

// Internal to the win32 file class. We need a conversion from std::wstring to
// string.
string Wstr2Str(const std::wstring& wstr) {
  size_t s = wstr.size();
  string str(static_cast<int>(s+1), 0);
  WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(s), &str[0],
                      static_cast<int>(s), NULL, NULL);
  return str;
}

bool File::Exists(const string& full_path) {
  if (full_path.empty()) {
    return false;
  }
  std::wstring wstr = Str2Wstr(full_path);
  DWORD attrs = ::GetFileAttributes(wstr.c_str());
  return (attrs != INVALID_FILE_ATTRIBUTES) &&
    ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0);
}

bool File::Delete(const string& filepath) {
  if (filepath.empty()) {
    return false;
  }
  std::wstring wstr = Str2Wstr(filepath);
  return ::DeleteFile(wstr.c_str()) ? true : false;
}

static const unsigned int BUFSIZE = 1024;
DWORD dwBufSize = BUFSIZE;
DWORD dwRetVal;
TCHAR lpPathBuffer[BUFSIZE];
UINT uRetVal;
TCHAR szTempName[BUFSIZE];

// http://msdn.microsoft.com/en-us/library/aa363875(VS.85).aspx
bool File::CreateNewTempFile(string* path) {
  if (!path) {
    return false;
  }
  // Get the temp path.
  dwRetVal = ::GetTempPath(dwBufSize, lpPathBuffer);
  if (dwRetVal > dwBufSize || (dwRetVal == 0)) {
    return false;
  }
  // Create a temporary file.
  uRetVal = ::GetTempFileName(lpPathBuffer, TEXT("libkml"), 0, szTempName);
  if (uRetVal == 0) {
    return false;
  }
  string str = Wstr2Str(szTempName);
  path->assign(str.c_str(), strlen(str.c_str()));
  return true;
}

}  // end namespace kmlbase
<commit_msg>_WIN32 guard for including windows headers<commit_after>// Copyright 2008, Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//  1. Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//  3. Neither the name of Google Inc. nor the names of its contributors may be
//     used to endorse or promote products derived from this software without
//     specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.

// The file contains the implementation of the File methods specific to
// the win32 platform.

// TODO: likely there are better ways to accomplish Delete and
// CreateNewTempFile.

#ifdef _WIN32

#include "kml/base/file.h"
#include <windows.h>
#include <tchar.h>
#include <xstring>
#include <algorithm>

namespace kmlbase {

// Internal to the win32 file class. We need a conversion from string to
// LPCWSTR.
static std::wstring Str2Wstr(const string& str) {
  std::wstring wstr(str.length(), L'');
  std::copy(str.begin(), str.end(), wstr.begin());
  return wstr;
}

// Internal to the win32 file class. We need a conversion from std::wstring to
// string.
string Wstr2Str(const std::wstring& wstr) {
  size_t s = wstr.size();
  string str(static_cast<int>(s+1), 0);
  WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(s), &str[0],
                      static_cast<int>(s), NULL, NULL);
  return str;
}

bool File::Exists(const string& full_path) {
  if (full_path.empty()) {
    return false;
  }
  std::wstring wstr = Str2Wstr(full_path);
  DWORD attrs = ::GetFileAttributes(wstr.c_str());
  return (attrs != INVALID_FILE_ATTRIBUTES) &&
    ((attrs & FILE_ATTRIBUTE_DIRECTORY) == 0);
}

bool File::Delete(const string& filepath) {
  if (filepath.empty()) {
    return false;
  }
  std::wstring wstr = Str2Wstr(filepath);
  return ::DeleteFile(wstr.c_str()) ? true : false;
}

static const unsigned int BUFSIZE = 1024;
DWORD dwBufSize = BUFSIZE;
DWORD dwRetVal;
TCHAR lpPathBuffer[BUFSIZE];
UINT uRetVal;
TCHAR szTempName[BUFSIZE];

// http://msdn.microsoft.com/en-us/library/aa363875(VS.85).aspx
bool File::CreateNewTempFile(string* path) {
  if (!path) {
    return false;
  }
  // Get the temp path.
  dwRetVal = ::GetTempPath(dwBufSize, lpPathBuffer);
  if (dwRetVal > dwBufSize || (dwRetVal == 0)) {
    return false;
  }
  // Create a temporary file.
  uRetVal = ::GetTempFileName(lpPathBuffer, TEXT("libkml"), 0, szTempName);
  if (uRetVal == 0) {
    return false;
  }
  string str = Wstr2Str(szTempName);
  path->assign(str.c_str(), strlen(str.c_str()));
  return true;
}

}  // end namespace kmlbase

#endif
<|endoftext|>


<commit_before>#include "ofdpa_bridge.hpp"

#include "roflibs/netlink/clogging.hpp"

#include <cassert>
#include <map>

#include <rofl/common/openflow/cofport.h>

namespace basebox {

ofdpa_bridge::ofdpa_bridge(rofl::rofl_ofdpa_fm_driver &fm_driver)
    : fm_driver(fm_driver) {}

ofdpa_bridge::~ofdpa_bridge() {}

void ofdpa_bridge::set_bridge_interface(const rofcore::crtlink &rtl) {
  if (AF_BRIDGE != rtl.get_family() || 0 != rtl.get_master()) {
    rofcore::logging::error << __PRETTY_FUNCTION__
                            << " not a bridge master: " << rtl << std::endl;
    return;
  }

  this->bridge = rtl;
  fm_driver.enable_policy_arp(1,1);
}

static int find_next_bit(int i, uint32_t x) {
  int j;

  if (i >= 32)
    return -1;

  /* find first bit */
  if (i < 0)
    return __builtin_ffs(x);

  /* mask off prior finds to get next */
  j = __builtin_ffs(x >> i);
  return j ? j + i : 0;
}

void ofdpa_bridge::add_interface(const rofcore::crtlink &rtl) {

  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot attach interface without bridge: " << rtl
                   << std::endl;
    return;
  }
  if (AF_BRIDGE != rtl.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a bridge interface " << std::endl;
    return;
  }
  if (bridge.get_ifindex() != rtl.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a slave of this bridge interface " << std::endl;
    return;
  }

  const struct rtnl_link_bridge_vlan *br_vlan = rtl.get_br_vlan();

  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = br_vlan->vlan_bitmap[k];

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, a);
      if (j > 0) {
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;
        }

        uint32_t group = fm_driver.enable_port_vid_egress(rtl.get_devname(),
                                                          vid, egress_untagged);
        assert(group && "invalid group identifier");
        if (rofl::openflow::OFPG_MAX == group) {
          logging::error << __PRETTY_FUNCTION__
                         << " failed to set vid on egress " << std::endl;
          i = j;
          continue;
        }
        l2_domain[vid].push_back(group);

        if (br_vlan->pvid == vid) {
          fm_driver.enable_port_pvid_ingress(rtl.get_devname(), vid);
        } else {
          fm_driver.enable_port_vid_ingress(rtl.get_devname(), vid);
        }

//        // todo check if vid is okay as an id as well
//        group = fm_driver.enable_group_l2_multicast(vid, vid, l2_domain[vid],
//                                                    1 != l2_domain[vid].size());
//
//        if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
//          fm_driver.enable_policy_arp(vid, group);
//        }

        i = j;
      } else {
        done = 1;
      }
    }
  }
}

void ofdpa_bridge::update_vlans(const std::string &devname,
                                const rtnl_link_bridge_vlan *old_br_vlan,
                                const rtnl_link_bridge_vlan *new_br_vlan) {
  using rofcore::logging;
  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = old_br_vlan->vlan_bitmap[k];
    uint32_t b = new_br_vlan->vlan_bitmap[k];

    uint32_t c = old_br_vlan->untagged_bitmap[k];
    uint32_t d = new_br_vlan->untagged_bitmap[k];

    uint32_t vlan_diff = a ^ b;
    uint32_t untagged_diff = c ^ d;

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, vlan_diff);
      if (j > 0) {
        // vlan added or removed
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (new_br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;

          // clear untagged_diff bit
          untagged_diff &= ~((uint32_t)1 << (j - 1));
        }

        if (new_br_vlan->vlan_bitmap[k] & 1 << (j - 1)) {
          // vlan added

          uint32_t group =
              fm_driver.enable_port_vid_egress(devname, vid, egress_untagged);
          assert(group && "invalid group identifier");
          if (rofl::openflow::OFPG_MAX == group) {
            logging::error << __PRETTY_FUNCTION__
                           << " failed to set vid on egress " << std::endl;
            i = j;
            continue;
          }
          l2_domain[vid].push_back(group);

          if (new_br_vlan->pvid == vid) {
            // todo check for existing pvid?
            fm_driver.enable_port_pvid_ingress(devname, vid);
          } else {
            fm_driver.enable_port_vid_ingress(devname, vid);
          }

          // todo check if vid is okay as an id as well
//          group = fm_driver.enable_group_l2_multicast(
//              vid, vid, l2_domain[vid], 1 != l2_domain[vid].size());
//// enable arp flooding as well
//#if DISABLED_TO_TEST
//          if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
//            fm_driver.enable_policy_arp(vid, group);
//          }
//#endif
        } else {
          // vlan removed
        }

        i = j;
      } else {
        done = 1;
      }
    }

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// XXX implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);

				i = j;
			} else {
				done = 1;
			}
		}
#endif
  }
}

void ofdpa_bridge::update_interface(const rofcore::crtlink &oldlink,
                                    const rofcore::crtlink &newlink) {
  using rofcore::crtlink;
  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot update interface without bridge" << std::endl;
    return;
  }
  if (AF_BRIDGE != newlink.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a bridge interface" << std::endl;
    return;
  }
  //	if (AF_BRIDGE != oldlink.get_family()) {
  //		logging::error << __PRETTY_FUNCTION__ << oldlink << " is
  // not a bridge interface" << std::endl;
  //		return;
  //	}
  if (bridge.get_ifindex() != newlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }
  if (bridge.get_ifindex() != oldlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }

  if (newlink.get_devname().compare(oldlink.get_devname())) {
    logging::info << __PRETTY_FUNCTION__
                  << " interface rename currently ignored " << std::endl;
    // FIXME this has to be handled differently
    return;
  }

  if (not crtlink::are_br_vlan_equal(newlink.get_br_vlan(),
                                     oldlink.get_br_vlan())) {
    // vlan updated
    update_vlans(oldlink.get_devname(), oldlink.get_br_vlan(),
                 newlink.get_br_vlan());
  }
}

void ofdpa_bridge::delete_interface(const rofcore::crtlink &rtl) {
  // XXX update L2 Multicast Group

  // get group id

  // remove id from l2_domain

  // update enable_group_l2_multicast
}

void ofdpa_bridge::add_mac_to_fdb(const uint32_t of_port_no,
                                  const uint16_t vlan,
                                  const rofl::cmacaddr &mac, bool permanent) {
  fm_driver.add_bridging_unicast_vlan(mac, vlan, of_port_no, permanent);
}

void ofdpa_bridge::remove_mac_from_fdb(const uint32_t of_port_no, uint16_t vid,
                                       const rofl::cmacaddr &mac) {
  fm_driver.remove_bridging_unicast_vlan(mac, vid, of_port_no);
}

} /* namespace basebox */
<commit_msg>catch errors in case of congestion<commit_after>#include "ofdpa_bridge.hpp"

#include "roflibs/netlink/clogging.hpp"

#include <cassert>
#include <map>

#include <rofl/common/openflow/cofport.h>

namespace basebox {

ofdpa_bridge::ofdpa_bridge(rofl::rofl_ofdpa_fm_driver &fm_driver)
    : fm_driver(fm_driver) {}

ofdpa_bridge::~ofdpa_bridge() {}

void ofdpa_bridge::set_bridge_interface(const rofcore::crtlink &rtl) {
  if (AF_BRIDGE != rtl.get_family() || 0 != rtl.get_master()) {
    rofcore::logging::error << __PRETTY_FUNCTION__
                            << " not a bridge master: " << rtl << std::endl;
    return;
  }

  this->bridge = rtl;
  fm_driver.enable_policy_arp(1,1);
}

static int find_next_bit(int i, uint32_t x) {
  int j;

  if (i >= 32)
    return -1;

  /* find first bit */
  if (i < 0)
    return __builtin_ffs(x);

  /* mask off prior finds to get next */
  j = __builtin_ffs(x >> i);
  return j ? j + i : 0;
}

void ofdpa_bridge::add_interface(const rofcore::crtlink &rtl) {

  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot attach interface without bridge: " << rtl
                   << std::endl;
    return;
  }
  if (AF_BRIDGE != rtl.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a bridge interface " << std::endl;
    return;
  }
  if (bridge.get_ifindex() != rtl.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a slave of this bridge interface " << std::endl;
    return;
  }

  const struct rtnl_link_bridge_vlan *br_vlan = rtl.get_br_vlan();

  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = br_vlan->vlan_bitmap[k];

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, a);
      if (j > 0) {
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;
        }

        uint32_t group = fm_driver.enable_port_vid_egress(rtl.get_devname(),
                                                          vid, egress_untagged);
        assert(group && "invalid group identifier");
        if (rofl::openflow::OFPG_MAX == group) {
          logging::error << __PRETTY_FUNCTION__
                         << " failed to set vid on egress " << std::endl;
          i = j;
          continue;
        }
        l2_domain[vid].push_back(group);

        if (br_vlan->pvid == vid) {
          fm_driver.enable_port_pvid_ingress(rtl.get_devname(), vid);
        } else {
          fm_driver.enable_port_vid_ingress(rtl.get_devname(), vid);
        }

//        // todo check if vid is okay as an id as well
//        group = fm_driver.enable_group_l2_multicast(vid, vid, l2_domain[vid],
//                                                    1 != l2_domain[vid].size());
//
//        if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
//          fm_driver.enable_policy_arp(vid, group);
//        }

        i = j;
      } else {
        done = 1;
      }
    }
  }
}

void ofdpa_bridge::update_vlans(const std::string &devname,
                                const rtnl_link_bridge_vlan *old_br_vlan,
                                const rtnl_link_bridge_vlan *new_br_vlan) {
  using rofcore::logging;
  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = old_br_vlan->vlan_bitmap[k];
    uint32_t b = new_br_vlan->vlan_bitmap[k];

    uint32_t c = old_br_vlan->untagged_bitmap[k];
    uint32_t d = new_br_vlan->untagged_bitmap[k];

    uint32_t vlan_diff = a ^ b;
    uint32_t untagged_diff = c ^ d;

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, vlan_diff);
      if (j > 0) {
        // vlan added or removed
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (new_br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;

          // clear untagged_diff bit
          untagged_diff &= ~((uint32_t)1 << (j - 1));
        }

        if (new_br_vlan->vlan_bitmap[k] & 1 << (j - 1)) {
          // vlan added

          try {
            uint32_t group =
                fm_driver.enable_port_vid_egress(devname, vid, egress_untagged);
            assert(group && "invalid group identifier");
            if (rofl::openflow::OFPG_MAX == group) {
              logging::error << __PRETTY_FUNCTION__
                  << " failed to set vid on egress " << std::endl;
              i = j;
              continue;
            }
            l2_domain[vid].push_back(group);
          } catch (std::exception &e) {
            logging::error << __PRETTY_FUNCTION__ << " caught error1:"
                << e.what() << std::endl;
          }

          try {
            if (new_br_vlan->pvid == vid) {
              // todo check for existing pvid?
              fm_driver.enable_port_pvid_ingress(devname, vid);
            } else {
              fm_driver.enable_port_vid_ingress(devname, vid);
            }
          } catch (std::exception &e) {
            logging::error << __PRETTY_FUNCTION__ << " caught error2:"
                           << e.what() << std::endl;
          }

          // todo check if vid is okay as an id as well
//          group = fm_driver.enable_group_l2_multicast(
//              vid, vid, l2_domain[vid], 1 != l2_domain[vid].size());
//// enable arp flooding as well
//#if DISABLED_TO_TEST
//          if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
//            fm_driver.enable_policy_arp(vid, group);
//          }
//#endif
        } else {
          // vlan removed
        }

        i = j;
      } else {
        done = 1;
      }
    }

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// XXX implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);

				i = j;
			} else {
				done = 1;
			}
		}
#endif
  }
}

void ofdpa_bridge::update_interface(const rofcore::crtlink &oldlink,
                                    const rofcore::crtlink &newlink) {
  using rofcore::crtlink;
  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot update interface without bridge" << std::endl;
    return;
  }
  if (AF_BRIDGE != newlink.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a bridge interface" << std::endl;
    return;
  }
  //	if (AF_BRIDGE != oldlink.get_family()) {
  //		logging::error << __PRETTY_FUNCTION__ << oldlink << " is
  // not a bridge interface" << std::endl;
  //		return;
  //	}
  if (bridge.get_ifindex() != newlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }
  if (bridge.get_ifindex() != oldlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }

  if (newlink.get_devname().compare(oldlink.get_devname())) {
    logging::info << __PRETTY_FUNCTION__
                  << " interface rename currently ignored " << std::endl;
    // FIXME this has to be handled differently
    return;
  }

  if (not crtlink::are_br_vlan_equal(newlink.get_br_vlan(),
                                     oldlink.get_br_vlan())) {
    // vlan updated
    update_vlans(oldlink.get_devname(), oldlink.get_br_vlan(),
                 newlink.get_br_vlan());
  }
}

void ofdpa_bridge::delete_interface(const rofcore::crtlink &rtl) {
  // XXX update L2 Multicast Group

  // get group id

  // remove id from l2_domain

  // update enable_group_l2_multicast
}

void ofdpa_bridge::add_mac_to_fdb(const uint32_t of_port_no,
                                  const uint16_t vlan,
                                  const rofl::cmacaddr &mac, bool permanent) {
  fm_driver.add_bridging_unicast_vlan(mac, vlan, of_port_no, permanent);
}

void ofdpa_bridge::remove_mac_from_fdb(const uint32_t of_port_no, uint16_t vid,
                                       const rofl::cmacaddr &mac) {
  fm_driver.remove_bridging_unicast_vlan(mac, vid, of_port_no);
}

} /* namespace basebox */
<|endoftext|>