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

#define MAX_TRANSPARENCY (unsigned char)255
#define DEFAULT_TRANSPARENCY (unsigned char)127

IMPLEMENT_DYNAMIC(MessageDlg, CDialog)

/**
 * \brief the constructor
 * \see CDialog::CDialog
 */
MessageDlg::MessageDlg()
  : CDialog(MessageDlg::IDD, nullptr),
    FadeWnd(),
    _elapseMiliSecondsBeforeFadeOut(0),
    _totalMilisecondsToShowMessage(0)
{
}

/**
 * Todo
 * \see CDialog::DoDataExchange
 * \param pDX the data exchange being processed.
 * \return void
 */
void MessageDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(MessageDlg, CDialog)
  ON_WM_PAINT()
  ON_WM_CLOSE()
END_MESSAGE_MAP()

/**
 * \brief the dialog is about to destroy itself.
 * \see CDialog::PostNcDestroy
 */
void MessageDlg::PostNcDestroy()
{
  delete this;
}

/**
 * \brief called when the window is being created, we can then set our own values.
 * \see CDialog::Create
 * \param sText the text we want to display
 * \param elapseMiliSecondsBeforeFadeOut how long we want to display the message for before we fade out.
 * \param totalMilisecondsToShowMessage how long we want the message to be displayed before fading out.
 */
void MessageDlg::Create(const std::wstring& sText, const long elapseMiliSecondsBeforeFadeOut, const long totalMilisecondsToShowMessage)
{
  //  save the value
  _totalMilisecondsToShowMessage = totalMilisecondsToShowMessage;
  _mStdMessage = sText;
  _elapseMiliSecondsBeforeFadeOut = elapseMiliSecondsBeforeFadeOut;

  __super::Create( MessageDlg::IDD );
}

/**
 * \brief Initialise the fading window.
 */
void MessageDlg::InitWindowPos()
{
  //  get the size of the windows
  const auto hdc = ::GetDC( m_hWnd );

  //  get the font that we will be using for display
  //  because of the XML config this is only really used for size.
  const auto pOldFont = SelDisplayFont( hdc );

  RECT r = {0,0,0,0};
  myodd::html::html(hdc, _mStdMessage.c_str() , _mStdMessage.length(), &r, DT_DEFAULT | DT_CALCRECT );

  //  clean up old fonts
  if ( pOldFont != nullptr )
  {
    SelectObject( hdc, pOldFont );
  }

  ::ReleaseDC( nullptr, hdc );

  const auto width   = GetSystemMetrics( SM_CXFULLSCREEN ) / 2;
  const auto height  = GetSystemMetrics( SM_CYFULLSCREEN ) / 2;

  int widthM   = abs( r.right - r.left);
  int heightM  = abs( r.bottom - r.top);

  //  pad a little
  widthM  += 2 * static_cast<int>(::myodd::config::Get(L"commands\\pad.x", 2));
  heightM += 2 * static_cast<int>(::myodd::config::Get(L"commands\\pad.y", 2));

  //  move the window to the top left hand corner
  SetWindowPos( &wndTopMost,
                (width - widthM/2),
                (height - heightM/2),
                (widthM),
                (heightM),
                SWP_HIDEWINDOW );
}

/**
 * \brief set the font we will be using to display the message
 * \param hdc the device context handle
 * \param fontSize the size of the font.
 * \return the created font.
 */
HGDIOBJ MessageDlg::SelDisplayFont(const HDC hdc, UINT fontSize )
{
  // TODO replace magic number.
  return __super::SelDisplayFont( hdc, 35 );
}

/**
 * \brief Check if anything is running
 * \return if we are still busy
 */
bool MessageDlg::IsRunning() const
{
  return _worker.Running();
}

/**
 * \brief the timer to fade the window from time to time.
 * \param owner the timer event number
 */
void MessageDlg::Fade(MessageDlg* owner )
{
  // make it thread safe
  try
  {
    owner->DoFade();
  }
  catch ( ... )
  {
    // ignore the errors.
    // something broke ... somewhere.
  }

  // close it
  owner->CloseFromThread();
}

/**
 * \brief do the actual fading.
 */
void MessageDlg::DoFade()
{
  // if we do not want to show the message, we might as well hide it right away.
  if ((_totalMilisecondsToShowMessage+_elapseMiliSecondsBeforeFadeOut) <= 0)
  {
    return;
  }

  // where we want the transparancy to start from, (we will end at zero)
  const auto startTransparency = GetStartTransparency();

  // if we want to show the message for a total of _totalMilisecondsToShowMessage
  // but we want to wait for _elapseMiliSecondsBeforeFadeOut before we go
  // how many milliseconds do we have before we need to fade out.
  const auto timeLeftForFadeOutMilliseconds = _totalMilisecondsToShowMessage - _elapseMiliSecondsBeforeFadeOut;

  // and given that we have 'startTransparency' steps to fade out in
  // the number of milliseconds between each steps is ...
  // the sleep time _could_ be zero
  const auto waitTimeBetweenFadeStepsInMilliseconds = (long)((double)timeLeftForFadeOutMilliseconds / (double)startTransparency);

  // show the message without any fadding.
  for (auto timeToSleptInMilliseconds = 0;
    timeToSleptInMilliseconds < _elapseMiliSecondsBeforeFadeOut;
    timeToSleptInMilliseconds += (waitTimeBetweenFadeStepsInMilliseconds <= 0 ? 1 : waitTimeBetweenFadeStepsInMilliseconds)
    )
  {
    // if we have been asked to stop ... then stop right away.
    if (Stopped())
    {
      return;
    }

    // then show the window a little.
    ShowMessageWithNoFadding(_elapseMiliSecondsBeforeFadeOut);
  }

  // we can now start fading down toward 'hidden' so the total time
  // should be near our target time of '_totalMilisecondsToShowMessage'
  for (auto currentTransparancy = startTransparency;
       currentTransparancy > 0;
       --currentTransparancy)
  {
    // if we have been asked to stop ... then stop right away.
    if (Stopped())
    {
      return;
    }

    // set the transparancy
    SetTransparency(currentTransparancy);

    // show the message a little bit more.
    ShowMessageWithNoFadding(waitTimeBetweenFadeStepsInMilliseconds);
  }
}

void MessageDlg::ShowMessageWithNoFadding(long milliseconds)
{
  if (milliseconds <= 0)
  {
    return;
  }

  // sleep a little.
  std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));

  // is the window still visible?
  // if not, then there is no point in going any further.
  if (0 == ::GetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT))
  {
    return;
  }

  // pump the message
  MessagePump(m_hWnd);
}

/**
 * \brief we cannot close the window from inside a thread
 *        so we post a message here, so the owning thread can call destroy window.
 */
void MessageDlg::CloseFromThread()
{
  // call the complete function.
  // so we can tell all that we are done here.
  _onComplete(this);

  // close it
  PostMessage(WM_CLOSE);

  // complete whatever needs to be done
  MessagePump(m_hWnd);

  // wait a little.
  std::this_thread::sleep_for(std::chrono::milliseconds(100));

  // and let the other threads process their messages.
  MessagePump(nullptr);
}

/**
 * \brief called when the dialog is closing, (this is the main app).
 * \see CTrayDialog::OnClose
 */
void MessageDlg::OnClose()
{
  DestroyWindow();
}

/**
 * \brief function called every time we are repainting the window.
 * \see CDialog::OnPaint
 */
void MessageDlg::OnPaint()
{
  CPaintDC dc(this); // device context for painting

  const auto hdc = dc.GetSafeHdc();
  //  get the font that we will be using for display
  //  because of the XML config this is only really used for size.
  const auto pOldFont = SelDisplayFont( hdc );

  RECT r = {0,0,0,0};
  myodd::html::html(hdc, _mStdMessage.c_str() , _mStdMessage.length(), &r, DT_DEFAULT | DT_CALCRECT );

  //  pad a little
  r.left += static_cast<int>(::myodd::config::Get(L"commands\\pad.x", 2));
  r.top  += static_cast<int>(::myodd::config::Get(L"commands\\pad.y", 2));

  SetBkMode( hdc, TRANSPARENT );
  myodd::html::html(hdc, _mStdMessage.c_str() , _mStdMessage.length(), &r, DT_DEFAULT );

  //  clean up old fonts
  if ( pOldFont != nullptr )
  {
    SelectObject( hdc, pOldFont );
  }
}

/**
 * \brief initialise the dialog.
 * \see CDialog::OnInitDialog
 */
BOOL MessageDlg::OnInitDialog()
{
  __super::OnInitDialog();

  SetFadeParent( m_hWnd );

  ModifyStyleEx(WS_EX_APPWINDOW,0); //  no taskbar!

  // move the window at the right place/size
  InitWindowPos();

  // fade the window a little.
  ShowWindow( SW_HIDE );

  return TRUE;
}

/**
 * \brief start the thread to fade the window.
 * \param onComplete the callback function we want to call when the window is complete
 */
void MessageDlg::Show(std::function<void(CWnd*)> onComplete)
{
  // fade the window a little.
  ShowWindow(SW_SHOW);
  SetTransparency( GetStartTransparency() );

  // save the complete callback function
  _onComplete = onComplete;

  // start the worker.
  _worker.QueueWorker(&MessageDlg::Fade, this);
}

/**
 * \brief get the start transparency and make sure that it falls within range.
 * \return safe start transparency
 */
unsigned char MessageDlg::GetStartTransparency() const
{
  const auto transparency = ::myodd::config::Get(L"commands\\transparency", DEFAULT_TRANSPARENCY);
  if( transparency < 0 )
  {
    return DEFAULT_TRANSPARENCY;
  }
  return transparency > MAX_TRANSPARENCY ? DEFAULT_TRANSPARENCY : transparency;
}

/**
 * \brief kill the window and wait for it to complete.
 *        this is a static function so we can call it with workers.
 * \param owner the owner of the window we are closing.
 */
void MessageDlg::Close(MessageDlg* owner)
{
  owner->FadeCloseWindow();
}

/**
 * \brief kill the window and wait for it to complete.
 */
void MessageDlg::FadeCloseWindow()
{
  // are we done already?
  if ( !IsRunning() )
  {
    // close the window.
    CloseFromThread();
    return;
  }

  // stop all
  Stop();

  // pump the remaining messages
  MessagePump( m_hWnd );
  MessagePump( nullptr );

  // then wait for everything to finish.
  _worker.WaitForAllWorkers();
}<commit_msg>... and fixed a bug<commit_after>//This file is part of Myoddweb.Piger.
//
//    Myoddweb.Piger is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    Myoddweb.Piger is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with Myoddweb.Piger.  If not, see<https://www.gnu.org/licenses/gpl-3.0.en.html>.
#include "stdafx.h"
#include "MessageDlg.h"

#define MAX_TRANSPARENCY (unsigned char)255
#define DEFAULT_TRANSPARENCY (unsigned char)127

IMPLEMENT_DYNAMIC(MessageDlg, CDialog)

/**
 * \brief the constructor
 * \see CDialog::CDialog
 */
MessageDlg::MessageDlg()
  : CDialog(MessageDlg::IDD, nullptr),
    FadeWnd(),
    _elapseMiliSecondsBeforeFadeOut(0),
    _totalMilisecondsToShowMessage(0)
{
}

/**
 * Todo
 * \see CDialog::DoDataExchange
 * \param pDX the data exchange being processed.
 * \return void
 */
void MessageDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(MessageDlg, CDialog)
  ON_WM_PAINT()
  ON_WM_CLOSE()
END_MESSAGE_MAP()

/**
 * \brief the dialog is about to destroy itself.
 * \see CDialog::PostNcDestroy
 */
void MessageDlg::PostNcDestroy()
{
  delete this;
}

/**
 * \brief called when the window is being created, we can then set our own values.
 * \see CDialog::Create
 * \param sText the text we want to display
 * \param elapseMiliSecondsBeforeFadeOut how long we want to display the message for before we fade out.
 * \param totalMilisecondsToShowMessage how long we want the message to be displayed before fading out.
 */
void MessageDlg::Create(const std::wstring& sText, const long elapseMiliSecondsBeforeFadeOut, const long totalMilisecondsToShowMessage)
{
  //  save the value
  _totalMilisecondsToShowMessage = totalMilisecondsToShowMessage;
  _mStdMessage = sText;
  _elapseMiliSecondsBeforeFadeOut = elapseMiliSecondsBeforeFadeOut;

  __super::Create( MessageDlg::IDD );
}

/**
 * \brief Initialise the fading window.
 */
void MessageDlg::InitWindowPos()
{
  //  get the size of the windows
  const auto hdc = ::GetDC( m_hWnd );

  //  get the font that we will be using for display
  //  because of the XML config this is only really used for size.
  const auto pOldFont = SelDisplayFont( hdc );

  RECT r = {0,0,0,0};
  myodd::html::html(hdc, _mStdMessage.c_str() , _mStdMessage.length(), &r, DT_DEFAULT | DT_CALCRECT );

  //  clean up old fonts
  if ( pOldFont != nullptr )
  {
    SelectObject( hdc, pOldFont );
  }

  ::ReleaseDC( nullptr, hdc );

  const auto width   = GetSystemMetrics( SM_CXFULLSCREEN ) / 2;
  const auto height  = GetSystemMetrics( SM_CYFULLSCREEN ) / 2;

  int widthM   = abs( r.right - r.left);
  int heightM  = abs( r.bottom - r.top);

  //  pad a little
  widthM  += 2 * static_cast<int>(::myodd::config::Get(L"commands\\pad.x", 2));
  heightM += 2 * static_cast<int>(::myodd::config::Get(L"commands\\pad.y", 2));

  //  move the window to the top left hand corner
  SetWindowPos( &wndTopMost,
                (width - widthM/2),
                (height - heightM/2),
                (widthM),
                (heightM),
                SWP_HIDEWINDOW );
}

/**
 * \brief set the font we will be using to display the message
 * \param hdc the device context handle
 * \param fontSize the size of the font.
 * \return the created font.
 */
HGDIOBJ MessageDlg::SelDisplayFont(const HDC hdc, UINT fontSize )
{
  // TODO replace magic number.
  return __super::SelDisplayFont( hdc, 35 );
}

/**
 * \brief Check if anything is running
 * \return if we are still busy
 */
bool MessageDlg::IsRunning() const
{
  return _worker.Running();
}

/**
 * \brief the timer to fade the window from time to time.
 * \param owner the timer event number
 */
void MessageDlg::Fade(MessageDlg* owner )
{
  // make it thread safe
  try
  {
    owner->DoFade();
  }
  catch ( ... )
  {
    // ignore the errors.
    // something broke ... somewhere.
  }

  // close it
  owner->CloseFromThread();
}

/**
 * \brief do the actual fading.
 */
void MessageDlg::DoFade()
{
  // if we do not want to show the message, we might as well hide it right away.
  if ((_totalMilisecondsToShowMessage+_elapseMiliSecondsBeforeFadeOut) <= 0)
  {
    return;
  }

  // where we want the transparancy to start from, (we will end at zero)
  const auto startTransparency = GetStartTransparency();

  // if we want to show the message for a total of _totalMilisecondsToShowMessage
  // but we want to wait for _elapseMiliSecondsBeforeFadeOut before we go
  // how many milliseconds do we have before we need to fade out.
  const auto timeLeftForFadeOutMilliseconds = _totalMilisecondsToShowMessage - _elapseMiliSecondsBeforeFadeOut;

  // and given that we have 'startTransparency' steps to fade out in
  // the number of milliseconds between each steps is ...
  // the sleep time _could_ be zero
  const auto waitTimeBetweenFadeStepsInMilliseconds = (long)((double)timeLeftForFadeOutMilliseconds / (double)startTransparency);

  // show the message without any fadding.
  for (auto timeToSleptInMilliseconds = 0;
    timeToSleptInMilliseconds < _elapseMiliSecondsBeforeFadeOut;
    timeToSleptInMilliseconds += (waitTimeBetweenFadeStepsInMilliseconds <= 0 ? 1 : waitTimeBetweenFadeStepsInMilliseconds)
    )
  {
    // if we have been asked to stop ... then stop right away.
    if (Stopped())
    {
      return;
    }

    // then show the window a little.
    ShowMessageWithNoFadding(waitTimeBetweenFadeStepsInMilliseconds);
  }

  // we can now start fading down toward 'hidden' so the total time
  // should be near our target time of '_totalMilisecondsToShowMessage'
  for (auto currentTransparancy = startTransparency;
       currentTransparancy > 0;
       --currentTransparancy)
  {
    // if we have been asked to stop ... then stop right away.
    if (Stopped())
    {
      return;
    }

    // set the transparancy
    SetTransparency(currentTransparancy);

    // show the message a little bit more.
    ShowMessageWithNoFadding(waitTimeBetweenFadeStepsInMilliseconds);
  }
}

void MessageDlg::ShowMessageWithNoFadding(long milliseconds)
{
  if (milliseconds <= 0)
  {
    return;
  }

  // sleep a little.
  std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));

  // is the window still visible?
  // if not, then there is no point in going any further.
  if (0 == ::GetWindowLongPtr(m_hWnd, GWLP_HWNDPARENT))
  {
    return;
  }

  // pump the message
  MessagePump(m_hWnd);
}

/**
 * \brief we cannot close the window from inside a thread
 *        so we post a message here, so the owning thread can call destroy window.
 */
void MessageDlg::CloseFromThread()
{
  // call the complete function.
  // so we can tell all that we are done here.
  _onComplete(this);

  // close it
  PostMessage(WM_CLOSE);

  // complete whatever needs to be done
  MessagePump(m_hWnd);

  // wait a little.
  std::this_thread::sleep_for(std::chrono::milliseconds(100));

  // and let the other threads process their messages.
  MessagePump(nullptr);
}

/**
 * \brief called when the dialog is closing, (this is the main app).
 * \see CTrayDialog::OnClose
 */
void MessageDlg::OnClose()
{
  DestroyWindow();
}

/**
 * \brief function called every time we are repainting the window.
 * \see CDialog::OnPaint
 */
void MessageDlg::OnPaint()
{
  CPaintDC dc(this); // device context for painting

  const auto hdc = dc.GetSafeHdc();
  //  get the font that we will be using for display
  //  because of the XML config this is only really used for size.
  const auto pOldFont = SelDisplayFont( hdc );

  RECT r = {0,0,0,0};
  myodd::html::html(hdc, _mStdMessage.c_str() , _mStdMessage.length(), &r, DT_DEFAULT | DT_CALCRECT );

  //  pad a little
  r.left += static_cast<int>(::myodd::config::Get(L"commands\\pad.x", 2));
  r.top  += static_cast<int>(::myodd::config::Get(L"commands\\pad.y", 2));

  SetBkMode( hdc, TRANSPARENT );
  myodd::html::html(hdc, _mStdMessage.c_str() , _mStdMessage.length(), &r, DT_DEFAULT );

  //  clean up old fonts
  if ( pOldFont != nullptr )
  {
    SelectObject( hdc, pOldFont );
  }
}

/**
 * \brief initialise the dialog.
 * \see CDialog::OnInitDialog
 */
BOOL MessageDlg::OnInitDialog()
{
  __super::OnInitDialog();

  SetFadeParent( m_hWnd );

  ModifyStyleEx(WS_EX_APPWINDOW,0); //  no taskbar!

  // move the window at the right place/size
  InitWindowPos();

  // fade the window a little.
  ShowWindow( SW_HIDE );

  return TRUE;
}

/**
 * \brief start the thread to fade the window.
 * \param onComplete the callback function we want to call when the window is complete
 */
void MessageDlg::Show(std::function<void(CWnd*)> onComplete)
{
  // fade the window a little.
  ShowWindow(SW_SHOW);
  SetTransparency( GetStartTransparency() );

  // save the complete callback function
  _onComplete = onComplete;

  // start the worker.
  _worker.QueueWorker(&MessageDlg::Fade, this);
}

/**
 * \brief get the start transparency and make sure that it falls within range.
 * \return safe start transparency
 */
unsigned char MessageDlg::GetStartTransparency() const
{
  const auto transparency = ::myodd::config::Get(L"commands\\transparency", DEFAULT_TRANSPARENCY);
  if( transparency < 0 )
  {
    return DEFAULT_TRANSPARENCY;
  }
  return transparency > MAX_TRANSPARENCY ? DEFAULT_TRANSPARENCY : transparency;
}

/**
 * \brief kill the window and wait for it to complete.
 *        this is a static function so we can call it with workers.
 * \param owner the owner of the window we are closing.
 */
void MessageDlg::Close(MessageDlg* owner)
{
  owner->FadeCloseWindow();
}

/**
 * \brief kill the window and wait for it to complete.
 */
void MessageDlg::FadeCloseWindow()
{
  // are we done already?
  if ( !IsRunning() )
  {
    // close the window.
    CloseFromThread();
    return;
  }

  // stop all
  Stop();

  // pump the remaining messages
  MessagePump( m_hWnd );
  MessagePump( nullptr );

  // then wait for everything to finish.
  _worker.WaitForAllWorkers();
}<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 *
 * This is a simple test program to test the facilities of the libcvmfs C
 * (not C++) library, which is used by Parrot and some other tools.
 *
 * The goal here is not so much to build the ultimate testing tool, but to
 * provide a simple build target which can verify that libcvmfs is exporting the
 * proper set of symbols to be used by a C program.
 */

#define __STDC_FORMAT_MACROS

#include "cvmfs_config.h"

#include <errno.h>
#include <inttypes.h>

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
#include <string>

#include "libcvmfs.h"

#define TEST_LINE_MAX 1024

typedef std::map<std::string, cvmfs_context*> RepoMap;
static RepoMap attached_repos;

void cvmfs_test_help()
{
  printf("commands are:\n");
  printf("   attach <repo name (without .cern.ch)>\n");
  printf("   detach <repo name (without .cern.ch)>\n");
  printf("   list <path>\n");
  printf("   cat  <path>\n");
  printf("   quit\n");
}

int cvmfs_test_list(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char filepath[TEST_LINE_MAX];
  struct stat info;

  char **buffer = 0;
  size_t length = 0;
  int i;

  int result = cvmfs_listdir(ctx, path, &buffer, &length);
  if (result < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return -1;
  }

  for (i = 0; buffer[i]; i++) {
    snprintf(filepath, TEST_LINE_MAX, "%s/%s", path, buffer[i]);
    cvmfs_stat(ctx, filepath, &info);
    printf("%10"PRIu64" %s\n", static_cast<uint64_t>(info.st_size), buffer[i]);
  }

  free(buffer);

  return 0;
}

int cvmfs_test_cat(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char buffer[TEST_LINE_MAX];

  int fd = cvmfs_open(ctx, path);
  if (fd < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return fd;
  }

  while (1) {
    int length = read(fd, buffer, sizeof(buffer));
    if (length <= 0) break;
    int retval = write(1, buffer, length);
    assert(retval == length);
  }

  cvmfs_close(ctx, fd);

  return 0;
}

cvmfs_context* cvmfs_test_attach(const char *repo_name)
{
  cvmfs_context *ctx = NULL;

  RepoMap::const_iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    const char *repo_options =
      "repo_name=%s.cern.ch,url=http://cvmfs-stratum-one.cern.ch/opt/%s;"
      "http://cernvmfs.gridpp.rl.ac.uk/opt/%s;http://cvmfs.racf.bnl.gov/opt/%s,"
      "pubkey=/etc/cvmfs/keys/cern.ch.pub";
    char options[TEST_LINE_MAX];
    snprintf(options, TEST_LINE_MAX, repo_options, repo_name, repo_name,
             repo_name, repo_name);

    printf("attaching repo with options: %s\n", options);
    ctx = cvmfs_attach_repo(options);
    if (ctx == NULL) {
      fprintf(stderr, "couldn't initialize cvmfs!\n");
    } else {
      attached_repos[repo_name] = ctx;
    }
  } else {
    printf("switching to previously attached repo: %s\n", repo_name);
    ctx = i->second;
  }

  return ctx;
}

void cvmfs_test_detach(const char *repo_name, const cvmfs_context *active_ctx) {
  RepoMap::iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    printf("Did not find '%s' to detach\n", repo_name);
    return;
  }

  cvmfs_context *ctx = i->second;
  if (ctx == active_ctx) {
    printf("'%s' is currently active and cannot be detached.\n", repo_name);
    return;
  }

  attached_repos.erase(i);
  cvmfs_detach_repo(ctx);
}

int main(int argc, char *argv[])
{
  char line[TEST_LINE_MAX];
  char path[TEST_LINE_MAX];
  char repo_name[TEST_LINE_MAX];

  const char *global_options = "cache_directory=/tmp/test-libcvmfs-cache";

  printf("%s: initializing with options: %s\n", argv[0], global_options);
  int retval = cvmfs_init(global_options);
  if (retval != 0) {
    fprintf(stderr, "couldn't initialize libcvmfs!\n");
    return -1;
  }

  cvmfs_context *ctx = NULL;

  while (1) {
    printf("cvmfs> ");
    fflush(stdout);

    if (!fgets(line, sizeof(line), stdin)) break;

    line[strlen(line)-1] = 0;

    if (sscanf(line, "list %s", path) == 1) {
      cvmfs_test_list(ctx, path);
    } else if (sscanf(line, "cat %s", path) == 1) {
      cvmfs_test_cat(ctx, path);
    } else if (sscanf(line, "attach %s", repo_name) == 1) {
      ctx = cvmfs_test_attach(repo_name);
    } else if (sscanf(line, "detach %s", repo_name) == 1) {
      cvmfs_test_detach(repo_name, ctx);
    } else if (!strcmp(line, "quit")) {
      break;
    } else {
      cvmfs_test_help();
    }
  }

  cvmfs_fini();

  return 0;
}

<commit_msg>FIX: test_libcvmfs initialization options<commit_after>/**
 * This file is part of the CernVM File System.
 *
 * This is a simple test program to test the facilities of the libcvmfs C
 * (not C++) library, which is used by Parrot and some other tools.
 *
 * The goal here is not so much to build the ultimate testing tool, but to
 * provide a simple build target which can verify that libcvmfs is exporting the
 * proper set of symbols to be used by a C program.
 */

#define __STDC_FORMAT_MACROS

#include "cvmfs_config.h"

#include <errno.h>
#include <inttypes.h>

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <map>
#include <string>

#include "libcvmfs.h"

#define TEST_LINE_MAX 1024

typedef std::map<std::string, cvmfs_context*> RepoMap;
static RepoMap attached_repos;

void cvmfs_test_help()
{
  printf("commands are:\n");
  printf("   attach <repo name (without .cern.ch)>\n");
  printf("   detach <repo name (without .cern.ch)>\n");
  printf("   list <path>\n");
  printf("   cat  <path>\n");
  printf("   quit\n");
}

int cvmfs_test_list(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char filepath[TEST_LINE_MAX];
  struct stat info;

  char **buffer = 0;
  size_t length = 0;
  int i;

  int result = cvmfs_listdir(ctx, path, &buffer, &length);
  if (result < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return -1;
  }

  for (i = 0; buffer[i]; i++) {
    snprintf(filepath, TEST_LINE_MAX, "%s/%s", path, buffer[i]);
    cvmfs_stat(ctx, filepath, &info);
    printf("%10"PRIu64" %s\n", static_cast<uint64_t>(info.st_size), buffer[i]);
  }

  free(buffer);

  return 0;
}

int cvmfs_test_cat(cvmfs_context *ctx, const char *path)
{
  if (ctx == NULL) {
    fprintf(stderr, "%s\n", "please attach a repo first!");
    return -1;
  }

  char buffer[TEST_LINE_MAX];

  int fd = cvmfs_open(ctx, path);
  if (fd < 0) {
    fprintf(stderr, "%s: %s\n", path, strerror(errno));
    return fd;
  }

  while (1) {
    int length = read(fd, buffer, sizeof(buffer));
    if (length <= 0) break;
    int retval = write(1, buffer, length);
    assert(retval == length);
  }

  cvmfs_close(ctx, fd);

  return 0;
}

cvmfs_context* cvmfs_test_attach(const char *repo_name)
{
  cvmfs_context *ctx = NULL;

  RepoMap::const_iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    const char *repo_options =
      "repo_name=%s.cern.ch,url=http://cvmfs-stratum-one.cern.ch/opt/%s;"
      "http://cernvmfs.gridpp.rl.ac.uk/opt/%s;http://cvmfs.racf.bnl.gov/opt/%s,"
      "pubkey=/etc/cvmfs/keys/cern.ch/cern.ch.pub,"
      "proxies=http://ca-proxy.cern.ch:3128";
    char options[TEST_LINE_MAX];
    snprintf(options, TEST_LINE_MAX, repo_options, repo_name, repo_name,
             repo_name, repo_name);

    printf("attaching repo with options: %s\n", options);
    ctx = cvmfs_attach_repo(options);
    if (ctx == NULL) {
      fprintf(stderr, "couldn't initialize cvmfs!\n");
    } else {
      attached_repos[repo_name] = ctx;
    }
  } else {
    printf("switching to previously attached repo: %s\n", repo_name);
    ctx = i->second;
  }

  return ctx;
}

void cvmfs_test_detach(const char *repo_name, const cvmfs_context *active_ctx) {
  RepoMap::iterator i = attached_repos.find(repo_name);
  if (i == attached_repos.end()) {
    printf("Did not find '%s' to detach\n", repo_name);
    return;
  }

  cvmfs_context *ctx = i->second;
  if (ctx == active_ctx) {
    printf("'%s' is currently active and cannot be detached.\n", repo_name);
    return;
  }

  attached_repos.erase(i);
  cvmfs_detach_repo(ctx);
}

int main(int argc, char *argv[])
{
  char line[TEST_LINE_MAX];
  char path[TEST_LINE_MAX];
  char repo_name[TEST_LINE_MAX];

  const char *global_options = "cache_directory=/tmp/test-libcvmfs-cache";

  printf("%s: initializing with options: %s\n", argv[0], global_options);
  int retval = cvmfs_init(global_options);
  if (retval != 0) {
    fprintf(stderr, "couldn't initialize libcvmfs!\n");
    return -1;
  }

  cvmfs_context *ctx = NULL;

  while (1) {
    printf("cvmfs> ");
    fflush(stdout);

    if (!fgets(line, sizeof(line), stdin)) break;

    line[strlen(line)-1] = 0;

    if (sscanf(line, "list %s", path) == 1) {
      cvmfs_test_list(ctx, path);
    } else if (sscanf(line, "cat %s", path) == 1) {
      cvmfs_test_cat(ctx, path);
    } else if (sscanf(line, "attach %s", repo_name) == 1) {
      ctx = cvmfs_test_attach(repo_name);
    } else if (sscanf(line, "detach %s", repo_name) == 1) {
      cvmfs_test_detach(repo_name, ctx);
    } else if (!strcmp(line, "quit")) {
      break;
    } else {
      cvmfs_test_help();
    }
  }

  cvmfs_fini();

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copy parameters from a request to the widget object.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "widget.hxx"
#include "widget-quark.h"
#include "widget.hxx"
#include "widget_class.hxx"
#include "widget_ref.hxx"
#include "session.hxx"
#include "penv.hxx"
#include "uri/uri_parser.hxx"
#include "puri_relative.hxx"
#include "pool.hxx"
#include "shm/dpool.hxx"

#include <string.h>
#include <assert.h>

void
Widget::SaveToSession(WidgetSession &ws) const
try {
    assert(cls != nullptr);
    assert(cls->stateful); /* cannot save state for stateless widgets */

    auto &p = ws.session.parent.pool;

    if (ws.path_info != nullptr)
        d_free(p, ws.path_info);

    ws.path_info.Set(p, from_request.path_info);

    if (ws.query_string != nullptr)
        d_free(p, ws.query_string);

    if (from_request.query_string.IsEmpty())
        ws.query_string.Clear(p);
    else
        ws.query_string.Set(p, from_request.query_string);
} catch (std::bad_alloc) {
}

void
Widget::LoadFromSession(const WidgetSession &ws)
{
    assert(cls != nullptr);
    assert(cls->stateful); /* cannot load state from stateless widgets */
    assert(lazy.address == nullptr);

    from_request.path_info = ws.path_info;

    if (ws.query_string != nullptr)
        from_request.query_string = ws.query_string;
}

bool
Widget::HasFocus() const
{
    assert(parent != nullptr);

    return id != nullptr &&
        parent->from_request.focus_ref != nullptr &&
        strcmp(id, parent->from_request.focus_ref->id) == 0 &&
        parent->from_request.focus_ref->next == nullptr;
}

bool
Widget::DescendantHasFocus() const
{
    assert(parent != nullptr);

    return id != nullptr &&
        parent->from_request.focus_ref != nullptr &&
        strcmp(id, parent->from_request.focus_ref->id) == 0 &&
        parent->from_request.focus_ref->next != nullptr;
}

bool
Widget::CopyFromRequest(struct processor_env &env, GError **error_r)
{
    assert(parent != nullptr);
    assert(lazy.address == nullptr);
    assert(from_request.path_info == nullptr);
    assert(from_request.query_string.IsEmpty());
    assert(from_request.focus_ref == nullptr);
    assert(from_request.method == HTTP_METHOD_GET);
    assert(from_request.body == nullptr);

    if (id == nullptr)
        return true;

    /* are we focused? */

    if (HasFocus()) {
        /* we're in focus.  forward query string and request body. */
        from_request.path_info = env.path_info;
        if (from_request.path_info != nullptr) {
            from_request.path_info =
                uri_compress(env.pool, from_request.path_info);
            if (from_request.path_info == nullptr) {
                g_set_error(error_r, widget_quark(), WIDGET_ERROR_FORBIDDEN,
                            "path compression failed");
                return false;
            }
        }

        from_request.query_string = env.external_uri->query;

        from_request.method = env.method;
        from_request.body = parent->for_focused.body;
        parent->for_focused.body = nullptr;
    } else if (DescendantHasFocus()) {
        /* we are the parent (or grant-parent) of the focused widget.
           store the relative focus_ref. */

        from_request.focus_ref = parent->from_request.focus_ref->next;
        parent->from_request.focus_ref = nullptr;

        for_focused = parent->for_focused;
        parent->for_focused.body = nullptr;
    }

    return true;
}

void
Widget::LoadFromSession(RealmSession &session)
{
    assert(parent != nullptr);
    assert(lazy.address == nullptr);
    assert(cls != nullptr);
    assert(cls->stateful);
    assert(session_sync_pending);
    assert(!session_save_pending);

    session_sync_pending = false;

    if (!ShouldSyncSession())
        /* not stateful in this request */
        return;

    /* are we focused? */

    if (HasFocus()) {
        /* postpone until we have the widget's response; we do not
           know yet which view will be used until we have checked the
           response headers */

        session_save_pending = true;
    } else {
        /* get query string from session */

        WidgetSession *ws = widget_get_session(this, &session, false);
        if (ws != nullptr)
            LoadFromSession(*ws);
    }
}

void
Widget::SaveToSession(RealmSession &session)
{
    assert(parent != nullptr);
    assert(cls != nullptr);
    assert(cls->stateful);
    assert(!session_sync_pending);
    assert(session_save_pending);

    session_save_pending = false;

    if (!ShouldSyncSession())
        /* not stateful in this request */
        return;

    WidgetSession *ws = widget_get_session(this, &session, true);
    if (ws != nullptr)
        SaveToSession(*ws);
}

void
Widget::CopyFromRedirectLocation(StringView location, RealmSession *session)
{
    assert(cls != nullptr);

    from_request.method = HTTP_METHOD_GET;
    from_request.body = nullptr;

    const char *qmark = location.Find('?');
    if (qmark == nullptr) {
        from_request.path_info = p_strdup(pool, location);
        from_request.query_string = nullptr;
    } else {
        from_request.path_info = p_strdup(pool,
                                          StringView(location.data, qmark));
        from_request.query_string = { qmark + 1,
                                      size_t(location.end() - (qmark + 1)) };
    }

    lazy.address = nullptr;

    if (session != nullptr) {
        assert(cls->stateful);

        auto *ws = widget_get_session(this, session, true);
        if (ws != nullptr)
            SaveToSession(*ws);
    }
}
<commit_msg>widget_request: fix two double free bugs<commit_after>/*
 * Copy parameters from a request to the widget object.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "widget.hxx"
#include "widget-quark.h"
#include "widget.hxx"
#include "widget_class.hxx"
#include "widget_ref.hxx"
#include "session.hxx"
#include "penv.hxx"
#include "uri/uri_parser.hxx"
#include "puri_relative.hxx"
#include "pool.hxx"
#include "shm/dpool.hxx"

#include <string.h>
#include <assert.h>

void
Widget::SaveToSession(WidgetSession &ws) const
try {
    assert(cls != nullptr);
    assert(cls->stateful); /* cannot save state for stateless widgets */

    auto &p = ws.session.parent.pool;

    ws.path_info.Set(p, from_request.path_info);

    if (from_request.query_string.IsEmpty())
        ws.query_string.Clear(p);
    else
        ws.query_string.Set(p, from_request.query_string);
} catch (std::bad_alloc) {
}

void
Widget::LoadFromSession(const WidgetSession &ws)
{
    assert(cls != nullptr);
    assert(cls->stateful); /* cannot load state from stateless widgets */
    assert(lazy.address == nullptr);

    from_request.path_info = ws.path_info;

    if (ws.query_string != nullptr)
        from_request.query_string = ws.query_string;
}

bool
Widget::HasFocus() const
{
    assert(parent != nullptr);

    return id != nullptr &&
        parent->from_request.focus_ref != nullptr &&
        strcmp(id, parent->from_request.focus_ref->id) == 0 &&
        parent->from_request.focus_ref->next == nullptr;
}

bool
Widget::DescendantHasFocus() const
{
    assert(parent != nullptr);

    return id != nullptr &&
        parent->from_request.focus_ref != nullptr &&
        strcmp(id, parent->from_request.focus_ref->id) == 0 &&
        parent->from_request.focus_ref->next != nullptr;
}

bool
Widget::CopyFromRequest(struct processor_env &env, GError **error_r)
{
    assert(parent != nullptr);
    assert(lazy.address == nullptr);
    assert(from_request.path_info == nullptr);
    assert(from_request.query_string.IsEmpty());
    assert(from_request.focus_ref == nullptr);
    assert(from_request.method == HTTP_METHOD_GET);
    assert(from_request.body == nullptr);

    if (id == nullptr)
        return true;

    /* are we focused? */

    if (HasFocus()) {
        /* we're in focus.  forward query string and request body. */
        from_request.path_info = env.path_info;
        if (from_request.path_info != nullptr) {
            from_request.path_info =
                uri_compress(env.pool, from_request.path_info);
            if (from_request.path_info == nullptr) {
                g_set_error(error_r, widget_quark(), WIDGET_ERROR_FORBIDDEN,
                            "path compression failed");
                return false;
            }
        }

        from_request.query_string = env.external_uri->query;

        from_request.method = env.method;
        from_request.body = parent->for_focused.body;
        parent->for_focused.body = nullptr;
    } else if (DescendantHasFocus()) {
        /* we are the parent (or grant-parent) of the focused widget.
           store the relative focus_ref. */

        from_request.focus_ref = parent->from_request.focus_ref->next;
        parent->from_request.focus_ref = nullptr;

        for_focused = parent->for_focused;
        parent->for_focused.body = nullptr;
    }

    return true;
}

void
Widget::LoadFromSession(RealmSession &session)
{
    assert(parent != nullptr);
    assert(lazy.address == nullptr);
    assert(cls != nullptr);
    assert(cls->stateful);
    assert(session_sync_pending);
    assert(!session_save_pending);

    session_sync_pending = false;

    if (!ShouldSyncSession())
        /* not stateful in this request */
        return;

    /* are we focused? */

    if (HasFocus()) {
        /* postpone until we have the widget's response; we do not
           know yet which view will be used until we have checked the
           response headers */

        session_save_pending = true;
    } else {
        /* get query string from session */

        WidgetSession *ws = widget_get_session(this, &session, false);
        if (ws != nullptr)
            LoadFromSession(*ws);
    }
}

void
Widget::SaveToSession(RealmSession &session)
{
    assert(parent != nullptr);
    assert(cls != nullptr);
    assert(cls->stateful);
    assert(!session_sync_pending);
    assert(session_save_pending);

    session_save_pending = false;

    if (!ShouldSyncSession())
        /* not stateful in this request */
        return;

    WidgetSession *ws = widget_get_session(this, &session, true);
    if (ws != nullptr)
        SaveToSession(*ws);
}

void
Widget::CopyFromRedirectLocation(StringView location, RealmSession *session)
{
    assert(cls != nullptr);

    from_request.method = HTTP_METHOD_GET;
    from_request.body = nullptr;

    const char *qmark = location.Find('?');
    if (qmark == nullptr) {
        from_request.path_info = p_strdup(pool, location);
        from_request.query_string = nullptr;
    } else {
        from_request.path_info = p_strdup(pool,
                                          StringView(location.data, qmark));
        from_request.query_string = { qmark + 1,
                                      size_t(location.end() - (qmark + 1)) };
    }

    lazy.address = nullptr;

    if (session != nullptr) {
        assert(cls->stateful);

        auto *ws = widget_get_session(this, session, true);
        if (ws != nullptr)
            SaveToSession(*ws);
    }
}
<|endoftext|>


<commit_before>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "Overlay.h"
#include "MainWindow.h"
#include "ServerHandler.h"
#include "AudioInput.h"
#include "AudioOutput.h"
#include "AudioWizard.h"
#include "Database.h"
#include "Log.h"
#include "Plugins.h"
#include "Global.h"
#ifndef Q_OS_MAC
#include "DBus.h"
#endif
#include "VersionCheck.h"
#include "NetworkConfig.h"

#ifdef BOOST_NO_EXCEPTIONS
namespace boost {
void throw_exception(std::exception const &) {
	qFatal("Boost exception caught!");
}
}
#endif

extern void os_init();

int main(int argc, char **argv) {
	// Check for SSE and MMX, but only in the windows binaries

	int res;
#ifdef Q_OS_WIN
	os_init();
#endif

	QT_REQUIRE_VERSION(argc, argv, "4.3.0");

	// Initialize application object.
	QApplication a(argc, argv);
	a.setApplicationName(QLatin1String("Mumble"));
	a.setOrganizationName(QLatin1String("Mumble"));
	a.setOrganizationDomain(QLatin1String("mumble.sourceforge.net"));
	a.setQuitOnLastWindowClosed(false);

	Global::g_global_struct = new Global();

#ifdef USE_DBUS
#ifdef Q_OS_WIN
	// By default, windbus expects the path to dbus-daemon to be in PATH, and the path
	// should contain bin\\, and the path to the config is hardcoded as ..\etc

	{
		size_t reqSize;
		_wgetenv_s(&reqSize, NULL, 0, L"PATH");
		STACKVAR(wchar_t, buff, reqSize+1);
		_wgetenv_s(&reqSize, buff, reqSize, L"PATH");
		QString path = QString::fromLatin1("%1\\bin;%1;%2").arg(QDir::toNativeSeparators(a.applicationDirPath())).arg(QString::fromWCharArray(buff));
		STACKVAR(wchar_t, buffout, path.length() + 1);
		path.toWCharArray(buffout);
		_wputenv_s(L"PATH", buffout);
	}
#endif

	QDBusInterface qdbi(QLatin1String("net.sourceforge.mumble.mumble"), QLatin1String("/"));
	QDBusMessage reply=qdbi.call(QLatin1String("focus"));
	if (reply.type() == QDBusMessage::ReplyMessage) {
		if (a.arguments().count() > 1) {
			qdbi.call(QLatin1String("openUrl"), a.arguments().last());
		}
		return 0;
	}
#endif

	QFile inifile(QString::fromLatin1("%1/mumble.ini").arg(a.applicationDirPath()));
	if (inifile.exists() && inifile.permissions().testFlag(QFile::WriteUser))
		g.qs = new QSettings(inifile.fileName(), QSettings::IniFormat);
	else
		g.qs = new QSettings();

	// Load preferences
	g.s.load();

	DeferInit::run_initializers();

	if (! g.s.qsStyle.isEmpty()) {
		a.setStyle(g.s.qsStyle);
	}

	if (! g.s.qsSkin.isEmpty()) {
		QFile file(g.s.qsSkin);
		file.open(QFile::ReadOnly);
		QString styleSheet=QLatin1String(file.readAll());
		if (! styleSheet.isEmpty()) {
			QFileInfo fi(g.s.qsSkin);
			QDir::addSearchPath(QLatin1String("skin"), fi.path());
			a.setStyleSheet(styleSheet);
		}
	}

	QDir::addSearchPath(QLatin1String("skin"),QLatin1String(":/"));
	QDir::addSearchPath(QLatin1String("translation"), a.applicationDirPath());
	QDir::addSearchPath(QLatin1String("translation"), QLatin1String(":/"));

	qWarning("Locale is %s", qPrintable(QLocale::system().name()));

	QString locale = g.s.qsLanguage.isEmpty() ? QLocale::system().name() : g.s.qsLanguage;

	QTranslator translator;
	translator.load(QLatin1String("translation:mumble_") + locale);
	a.installTranslator(&translator);

	QTranslator qttranslator;
	qttranslator.load(QLatin1String("translation:qt_") + locale);
	a.installTranslator(&qttranslator);

	// Initialize proxy settings
	NetworkConfig::SetupProxy();

	// Initialize logger
	g.l = new Log();

	// Initialize database
	g.db = new Database();

	// Initialize the serverhandler
	g.sh = new ServerHandler();
	g.sh->moveToThread(g.sh);

	g.o = new Overlay();
	g.o->setActive(g.s.bOverlayEnable);

	// Main Window
	g.mw=new MainWindow(NULL);
	g.mw->show();

#ifdef USE_DBUS
	new MumbleDBus(g.mw);
	QDBusConnection::sessionBus().registerObject(QLatin1String("/"), g.mw);
	QDBusConnection::sessionBus().registerService(QLatin1String("net.sourceforge.mumble.mumble"));
#endif

	g.l->log(Log::Information, MainWindow::tr("Welcome to Mumble."));

	// Plugins
	g.p = new Plugins(NULL);
	g.p->rescanPlugins();

	// And the start the last chosen audio system.
	g.ai = AudioInputRegistrar::newFromChoice();
	if (g.ai)
		g.ai->start(QThread::HighestPriority);
	g.ao = AudioOutputRegistrar::newFromChoice();
	if (g.ao)
		g.ao->start(QThread::HighPriority);

	a.setQuitOnLastWindowClosed(false);

	if (g.s.bFirstTime) {
		g.s.bFirstTime = false;
		if (QMessageBox::question(g.mw, MainWindow::tr("Mumble"), MainWindow::tr("This is the first time you're starting Mumble.
Would you like to go through the Audio Wizard to configure your soundcard?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) {
			AudioWizard *aw = new AudioWizard(g.mw);
			aw->exec();
			delete aw;
		}
	}

	if (g.s.bUpdateCheck)
		new VersionCheck(true, g.mw);

	if (a.arguments().count() > 1) {
		g.mw->openUrl(QUrl(a.arguments().last()));
	} else {
		g.mw->on_qaServerConnect_triggered();
	}
	res=a.exec();

	g.s.save();

	g.ao.reset();
	g.ai.reset();

	g.sh->disconnect();

	// This causes QT to complain. Fatally. It's either a bug in
	// my code or the QT code.
	// delete g.sh;
	delete g.mw;

	delete g.db;
	delete g.l;

	delete g.o;

	delete g.qs;

	DeferInit::run_destroyers();

	return res;
}
<commit_msg>Avoid loading system Qt plugins on Mac OS X.<commit_after>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "Overlay.h"
#include "MainWindow.h"
#include "ServerHandler.h"
#include "AudioInput.h"
#include "AudioOutput.h"
#include "AudioWizard.h"
#include "Database.h"
#include "Log.h"
#include "Plugins.h"
#include "Global.h"
#ifndef Q_OS_MAC
#include "DBus.h"
#endif
#include "VersionCheck.h"
#include "NetworkConfig.h"

#ifdef BOOST_NO_EXCEPTIONS
namespace boost {
void throw_exception(std::exception const &) {
	qFatal("Boost exception caught!");
}
}
#endif

extern void os_init();

int main(int argc, char **argv) {
	// Check for SSE and MMX, but only in the windows binaries

	int res;
#ifdef Q_OS_WIN
	os_init();
#endif

	QT_REQUIRE_VERSION(argc, argv, "4.3.0");

	// Initialize application object.
	QApplication a(argc, argv);
	a.setApplicationName(QLatin1String("Mumble"));
	a.setOrganizationName(QLatin1String("Mumble"));
	a.setOrganizationDomain(QLatin1String("mumble.sourceforge.net"));
	a.setQuitOnLastWindowClosed(false);

#ifdef Q_OS_MAC
	// Avoid auto-loading system Qt plugins. This could potentially make
	// us load two different Qt libraries into our process. Not good.
	a.setLibraryPaths(QStringList());
#endif

	Global::g_global_struct = new Global();

#ifdef USE_DBUS
#ifdef Q_OS_WIN
	// By default, windbus expects the path to dbus-daemon to be in PATH, and the path
	// should contain bin\\, and the path to the config is hardcoded as ..\etc

	{
		size_t reqSize;
		_wgetenv_s(&reqSize, NULL, 0, L"PATH");
		STACKVAR(wchar_t, buff, reqSize+1);
		_wgetenv_s(&reqSize, buff, reqSize, L"PATH");
		QString path = QString::fromLatin1("%1\\bin;%1;%2").arg(QDir::toNativeSeparators(a.applicationDirPath())).arg(QString::fromWCharArray(buff));
		STACKVAR(wchar_t, buffout, path.length() + 1);
		path.toWCharArray(buffout);
		_wputenv_s(L"PATH", buffout);
	}
#endif

	QDBusInterface qdbi(QLatin1String("net.sourceforge.mumble.mumble"), QLatin1String("/"));
	QDBusMessage reply=qdbi.call(QLatin1String("focus"));
	if (reply.type() == QDBusMessage::ReplyMessage) {
		if (a.arguments().count() > 1) {
			qdbi.call(QLatin1String("openUrl"), a.arguments().last());
		}
		return 0;
	}
#endif

	QFile inifile(QString::fromLatin1("%1/mumble.ini").arg(a.applicationDirPath()));
	if (inifile.exists() && inifile.permissions().testFlag(QFile::WriteUser))
		g.qs = new QSettings(inifile.fileName(), QSettings::IniFormat);
	else
		g.qs = new QSettings();

	// Load preferences
	g.s.load();

	DeferInit::run_initializers();

	if (! g.s.qsStyle.isEmpty()) {
		a.setStyle(g.s.qsStyle);
	}

	if (! g.s.qsSkin.isEmpty()) {
		QFile file(g.s.qsSkin);
		file.open(QFile::ReadOnly);
		QString styleSheet=QLatin1String(file.readAll());
		if (! styleSheet.isEmpty()) {
			QFileInfo fi(g.s.qsSkin);
			QDir::addSearchPath(QLatin1String("skin"), fi.path());
			a.setStyleSheet(styleSheet);
		}
	}

	QDir::addSearchPath(QLatin1String("skin"),QLatin1String(":/"));
	QDir::addSearchPath(QLatin1String("translation"), a.applicationDirPath());
	QDir::addSearchPath(QLatin1String("translation"), QLatin1String(":/"));

	qWarning("Locale is %s", qPrintable(QLocale::system().name()));

	QString locale = g.s.qsLanguage.isEmpty() ? QLocale::system().name() : g.s.qsLanguage;

	QTranslator translator;
	translator.load(QLatin1String("translation:mumble_") + locale);
	a.installTranslator(&translator);

	QTranslator qttranslator;
	qttranslator.load(QLatin1String("translation:qt_") + locale);
	a.installTranslator(&qttranslator);

	// Initialize proxy settings
	NetworkConfig::SetupProxy();

	// Initialize logger
	g.l = new Log();

	// Initialize database
	g.db = new Database();

	// Initialize the serverhandler
	g.sh = new ServerHandler();
	g.sh->moveToThread(g.sh);

	g.o = new Overlay();
	g.o->setActive(g.s.bOverlayEnable);

	// Main Window
	g.mw=new MainWindow(NULL);
	g.mw->show();

#ifdef USE_DBUS
	new MumbleDBus(g.mw);
	QDBusConnection::sessionBus().registerObject(QLatin1String("/"), g.mw);
	QDBusConnection::sessionBus().registerService(QLatin1String("net.sourceforge.mumble.mumble"));
#endif

	g.l->log(Log::Information, MainWindow::tr("Welcome to Mumble."));

	// Plugins
	g.p = new Plugins(NULL);
	g.p->rescanPlugins();

	// And the start the last chosen audio system.
	g.ai = AudioInputRegistrar::newFromChoice();
	if (g.ai)
		g.ai->start(QThread::HighestPriority);
	g.ao = AudioOutputRegistrar::newFromChoice();
	if (g.ao)
		g.ao->start(QThread::HighPriority);

	a.setQuitOnLastWindowClosed(false);

	if (g.s.bFirstTime) {
		g.s.bFirstTime = false;
		if (QMessageBox::question(g.mw, MainWindow::tr("Mumble"), MainWindow::tr("This is the first time you're starting Mumble.
Would you like to go through the Audio Wizard to configure your soundcard?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) {
			AudioWizard *aw = new AudioWizard(g.mw);
			aw->exec();
			delete aw;
		}
	}

	if (g.s.bUpdateCheck)
		new VersionCheck(true, g.mw);

	if (a.arguments().count() > 1) {
		g.mw->openUrl(QUrl(a.arguments().last()));
	} else {
		g.mw->on_qaServerConnect_triggered();
	}
	res=a.exec();

	g.s.save();

	g.ao.reset();
	g.ai.reset();

	g.sh->disconnect();

	// This causes QT to complain. Fatally. It's either a bug in
	// my code or the QT code.
	// delete g.sh;
	delete g.mw;

	delete g.db;
	delete g.l;

	delete g.o;

	delete g.qs;

	DeferInit::run_destroyers();

	return res;
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2006 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "LagInfo.h"

float LagInfo::adminlagannouncetresh = 0.0;
float LagInfo::lagannouncetresh = 0.0;
float LagInfo::threshold = 0.0;
float LagInfo::jitterthreshold = 0.0;
float LagInfo::lossthreshold = 0.0;
float LagInfo::max       = 0.0;
float LagInfo::jittermax       = 0.0;
float LagInfo::lossmax       = 0.0;

LagInfo::LagInfo(PlayerInfo *_info)
  : info(_info), lagavg(0), jitteravg(0), lostavg(0), lagalpha(1),
    jitteralpha(1), lostalpha(1), lagcount(0), laglastwarn(0), lagwarncount(0),
    jittercount(0), jitterlastwarn(0), jitterwarncount(0), losscount(0),
    losslastwarn(0), losswarncount(0), pingpending(false), pingseqno(0),
    pingssent(0), lasttimestamp(0.0f), alagannouncecount(0), lagannouncecount(0) {
}

void LagInfo::reset()
{
  nextping       = info->now;
  nextping      += 10.0;
  lastupdate     = info->now;
}

int LagInfo::getLag() const
{
  return int(lagavg * 1000);
}

int LagInfo::getJitter() const
{
  return int(jitteravg * 1000);
}

int LagInfo::getLoss() const
{
	return int(lostavg * 100);
}

float LagInfo::getLagAvg() const
{
  return lagavg;
}

void LagInfo::getLagStats(char* msg, bool isAdmin) const
{
  msg[0] = 0;
  if (!info->isPlaying() || !info->isHuman())
    return;

  // don't wait for ping to come back
  int lag = int(lagavg * 1000);
  if (pingpending) {
    float timepassed = (float)(info->now - lastping);
    int lastLag = int((lagavg * (1 - lagalpha) + lagalpha * timepassed) * 1000);
    if (lastLag > lag)
      lag = lastLag;
  }

  int numchars;
  if (isAdmin)
    numchars = sprintf(msg, "[%3d] %-24.24s: %3d", info->getPlayerIndex(),
          TextUtils::str_trunc_continued (info->getCallSign(), 22).c_str(), lag);
  else
    numchars = sprintf(msg, "%-24.24s: %3d",
          TextUtils::str_trunc_continued (info->getCallSign(), 22).c_str(), lag);

  if (info->isObserver()) {
    sprintf(msg+numchars, "ms");
  } else {
    numchars += sprintf(msg + numchars, " +- %2dms", int(jitteravg * 1000));
    if (lostavg >= 0.01f)
      sprintf(msg + numchars, " %d%% lost/ooo", int(lostavg * 100));
  }
}

// update absolute latency based on LagPing messages
void LagInfo::updatePingLag(void *buf, bool &warn, bool &kick, bool &jittwarn,
			    bool &jittkick, bool &plosswarn, bool &plosskick,
			    bool &alagannouncewarn, bool &lagannouncewarn) {
  uint16_t _pingseqno;
  nboUnpackUShort(buf, _pingseqno);
  if (pingseqno == _pingseqno) {
    float timepassed = float(info->now - lastping);
    // time is smoothed exponentially using a dynamic smoothing factor
    lagavg   = lagavg * (1 - lagalpha) + lagalpha * timepassed;
    lagalpha = lagalpha / (0.9f + lagalpha);
    alagcount++;
    lagcount++;
    jittercount++;
    losscount++;

    // if lag has been good for some time, forget old warnings
    if (lagavg < threshold && lagcount - laglastwarn >= 20)
      lagwarncount = 0;
    if (lagavg < adminlagannouncetresh && alagcount - alaglastannounce >= 20)
      alagannouncecount = 0;
    if (lagavg < lagannouncetresh && ((TimeKeeper::getCurrent() - laglastannounce) > 2.0f))
      lagannouncecount = 0;

    // if jitter has been good for some time, forget old warnings
    if (jitteravg < jitterthreshold && jittercount - jitterlastwarn >= 20)
      jitterwarncount = 0;

    // if loss has been good for some time, forget old warnings
    if (lostavg < lossthreshold && losscount - losslastwarn >=20)
      losswarncount = 0;

    // announce players from time to time whose lag is > threshold (-lagwarn)
    if (!info->isObserver() && (adminlagannouncetresh > 0) && lagavg > adminlagannouncetresh
	&& alagcount - alaglastannounce > 2 * alagannouncecount) {
      alaglastannounce = alagcount;
      alagannouncewarn = true;
    } else {
      alagannouncewarn = false;
    }

    if (!info->isObserver() && (lagannouncetresh > 0) && lagavg > lagannouncetresh
	&& (
	(lagannouncecount == 0) ||
	(lagannouncecount == 1 && ((TimeKeeper::getCurrent() - laglastannounce) > 5.0f)) ||
	(lagannouncecount == 2 && ((TimeKeeper::getCurrent() - laglastannounce) > 10.0f)))) {
        laglastannounce = TimeKeeper::getCurrent();
	lagannouncecount++;
        lagannouncewarn = true;
    } else {
      lagannouncewarn = false;
    }

    // warn players from time to time whose lag is > threshold (-lagwarn)
    if (!info->isObserver() && (threshold > 0) && lagavg > threshold
	&& lagcount - laglastwarn > 2 * lagwarncount) {
      laglastwarn = lagcount;
      warn = true;
      kick = (lagwarncount++ > max);
    } else {
      warn = false;
      kick = false;
    }

    // warn players from time to time whose jitter is > jitterthreshold
    if (!info->isObserver() && (jitterthreshold > 0)
	&& jitteravg > jitterthreshold
	&& jittercount - jitterlastwarn > 2 * jitterwarncount) {
      jitterlastwarn = jittercount;
      jittwarn = true;
      jittkick = (jitterwarncount++ > jittermax);
    } else {
      jittwarn = false;
      jittkick = false;
    }

    // warn players from time to time whose packetloss is > lossthreshold (-packetlosswarn)
    if (!info->isObserver() && (lossthreshold > 0)
	&& lostavg > lossthreshold
	&& losscount - losslastwarn > 2 * losswarncount) {
      losslastwarn = losscount;
      plosswarn = true;
      plosskick = (++losswarncount > lossmax);
    } else {
      plosswarn = false;
      plosskick = false;
    }

    lostavg     = lostavg * (1 - lostalpha);
    lostalpha   = lostalpha / (0.99f + lostalpha);
    pingpending = false;
  } else {
    warn = false;
    kick = false;
    jittwarn = false;
    jittkick = false;
    plosswarn = false;
    plosskick = false;
    alagannouncewarn = false;
    lagannouncewarn = false;
  }
}

void LagInfo::updateLag(float timestamp, bool ooo) {
  if (!info->isPlaying())
    return;
  if (ooo) {
    lostavg   = lostavg * (1 - lostalpha) + lostalpha;
    lostalpha = lostalpha / (0.99f + lostalpha);
  }
  // don't calc jitter if more than 2 seconds between packets
  if (lasttimestamp > 0.0f && timestamp - lasttimestamp < 2.0f) {
    const float jitter = fabs((float)(info->now - lastupdate)
			      - (timestamp - lasttimestamp));
    // time is smoothed exponentially using a dynamic smoothing factor
    jitteravg   = jitteravg * (1 - jitteralpha) + jitteralpha * fabs(jitter);
    jitteralpha = jitteralpha / (0.99f + jitteralpha);
    lostavg     = lostavg * (1 - lostalpha);
    lostalpha   = lostalpha / (0.99f + lostalpha);
  }
  lasttimestamp = timestamp;
  lastupdate    = info->now;
}

int LagInfo::getNextPingSeqno(bool &warn, bool &kick) {

  warn = false;
  kick = false;

  if (!info->isPlaying() || !info->isHuman())
    return -1;

  if (info->now <= nextping)
    // no time for pinging
    return -1;

  pingseqno = (pingseqno + 1) % 10000;
  if (pingpending) {
    // ping lost
    lostavg   = lostavg * (1 - lostalpha) + lostalpha;
    lostalpha = lostalpha / (0.99f + lostalpha);
  }

  pingpending = true;
  lastping    = info->now;
  nextping    = info->now;
  nextping   += 10.0f;
  pingssent++;
  return pingseqno;
}

// update absolute latency based on LagPing messages
void LagInfo::updateLatency(float &waitTime) {
  if (!info->isPlaying() || !info->isHuman())
    return;
  float delta = (float)(nextping - info->now);
  if (delta < waitTime)
    waitTime  = delta;
}

void LagInfo::setAdminLagAnnounceThreshold(float _adminlagannouncetresh) {
  adminlagannouncetresh = _adminlagannouncetresh;
}

void LagInfo::setLagAnnounceThreshold(float _lagannouncetresh) {
  lagannouncetresh = _lagannouncetresh;
}

void LagInfo::setThreshold(float _threshold, float _max) {
  threshold = _threshold;
  max       = _max;
}

void LagInfo::setJitterThreshold(float _jitterthreshold, float _jittermax) {
  jitterthreshold = _jitterthreshold;
  jittermax       = _jittermax;
}

void LagInfo::setPacketLossThreshold(float _lossthreshold, float _lossmax) {
  lossthreshold = _lossthreshold * 10;
  lossmax       = _lossmax;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Hopefully lagannounce now ok, list -adminlagannounce and -lagannounce in ChangeLog<commit_after>/* bzflag
 * Copyright (c) 1993 - 2006 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "LagInfo.h"

float LagInfo::adminlagannouncetresh = 0.0;
float LagInfo::lagannouncetresh = 0.0;
float LagInfo::threshold = 0.0;
float LagInfo::jitterthreshold = 0.0;
float LagInfo::lossthreshold = 0.0;
float LagInfo::max       = 0.0;
float LagInfo::jittermax       = 0.0;
float LagInfo::lossmax       = 0.0;

LagInfo::LagInfo(PlayerInfo *_info)
  : info(_info), lagavg(0), jitteravg(0), lostavg(0), lagalpha(1),
    jitteralpha(1), lostalpha(1), lagcount(0), laglastwarn(0), lagwarncount(0),
    jittercount(0), jitterlastwarn(0), jitterwarncount(0), losscount(0),
    losslastwarn(0), losswarncount(0), pingpending(false), pingseqno(0),
    pingssent(0), lasttimestamp(0.0f), alagannouncecount(0), lagannouncecount(0) {
}

void LagInfo::reset()
{
  nextping       = info->now;
  nextping      += 10.0;
  lastupdate     = info->now;
}

int LagInfo::getLag() const
{
  return int(lagavg * 1000);
}

int LagInfo::getJitter() const
{
  return int(jitteravg * 1000);
}

int LagInfo::getLoss() const
{
	return int(lostavg * 100);
}

float LagInfo::getLagAvg() const
{
  return lagavg;
}

void LagInfo::getLagStats(char* msg, bool isAdmin) const
{
  msg[0] = 0;
  if (!info->isPlaying() || !info->isHuman())
    return;

  // don't wait for ping to come back
  int lag = int(lagavg * 1000);
  if (pingpending) {
    float timepassed = (float)(info->now - lastping);
    int lastLag = int((lagavg * (1 - lagalpha) + lagalpha * timepassed) * 1000);
    if (lastLag > lag)
      lag = lastLag;
  }

  int numchars;
  if (isAdmin)
    numchars = sprintf(msg, "[%3d] %-24.24s: %3d", info->getPlayerIndex(),
          TextUtils::str_trunc_continued (info->getCallSign(), 22).c_str(), lag);
  else
    numchars = sprintf(msg, "%-24.24s: %3d",
          TextUtils::str_trunc_continued (info->getCallSign(), 22).c_str(), lag);

  if (info->isObserver()) {
    sprintf(msg+numchars, "ms");
  } else {
    numchars += sprintf(msg + numchars, " +- %2dms", int(jitteravg * 1000));
    if (lostavg >= 0.01f)
      sprintf(msg + numchars, " %d%% lost/ooo", int(lostavg * 100));
  }
}

// update absolute latency based on LagPing messages
void LagInfo::updatePingLag(void *buf, bool &warn, bool &kick, bool &jittwarn,
			    bool &jittkick, bool &plosswarn, bool &plosskick,
			    bool &alagannouncewarn, bool &lagannouncewarn) {
  uint16_t _pingseqno;
  nboUnpackUShort(buf, _pingseqno);
  if (pingseqno == _pingseqno) {
    float timepassed = float(info->now - lastping);
    // time is smoothed exponentially using a dynamic smoothing factor
    lagavg   = lagavg * (1 - lagalpha) + lagalpha * timepassed;
    lagalpha = lagalpha / (0.9f + lagalpha);
    alagcount++;
    lagcount++;
    jittercount++;
    losscount++;

    // if lag has been good for some time, forget old warnings
    if (lagavg < threshold && lagcount - laglastwarn >= 20)
      lagwarncount = 0;
    if (lagavg < adminlagannouncetresh && alagcount - alaglastannounce >= 20)
      alagannouncecount = 0;
    if (lagavg < lagannouncetresh && ((TimeKeeper::getCurrent() - laglastannounce) > 10.0f))
      lagannouncecount = 0;

    // if jitter has been good for some time, forget old warnings
    if (jitteravg < jitterthreshold && jittercount - jitterlastwarn >= 20)
      jitterwarncount = 0;

    // if loss has been good for some time, forget old warnings
    if (lostavg < lossthreshold && losscount - losslastwarn >=20)
      losswarncount = 0;

    // announce players from time to time whose lag is > threshold (-lagwarn)
    if (!info->isObserver() && (adminlagannouncetresh > 0) && lagavg > adminlagannouncetresh
	&& alagcount - alaglastannounce > 2 * alagannouncecount) {
      alaglastannounce = alagcount;
      alagannouncewarn = true;
    } else {
      alagannouncewarn = false;
    }

    if (!info->isObserver() && (lagannouncetresh > 0) && lagavg > lagannouncetresh
	&& (
	(lagannouncecount == 0) ||
	(lagannouncecount == 1 && ((TimeKeeper::getCurrent() - laglastannounce) > 5.0f)) ||
	(lagannouncecount == 2 && ((TimeKeeper::getCurrent() - laglastannounce) > 10.0f)) ||
	(lagannouncecount > 2 && ((TimeKeeper::getCurrent() - laglastannounce) > 180.0f)))) {
        laglastannounce = TimeKeeper::getCurrent();
	lagannouncecount++;
        lagannouncewarn = true;
    } else {
      lagannouncewarn = false;
    }

    // warn players from time to time whose lag is > threshold (-lagwarn)
    if (!info->isObserver() && (threshold > 0) && lagavg > threshold
	&& lagcount - laglastwarn > 2 * lagwarncount) {
      laglastwarn = lagcount;
      warn = true;
      kick = (lagwarncount++ > max);
    } else {
      warn = false;
      kick = false;
    }

    // warn players from time to time whose jitter is > jitterthreshold
    if (!info->isObserver() && (jitterthreshold > 0)
	&& jitteravg > jitterthreshold
	&& jittercount - jitterlastwarn > 2 * jitterwarncount) {
      jitterlastwarn = jittercount;
      jittwarn = true;
      jittkick = (jitterwarncount++ > jittermax);
    } else {
      jittwarn = false;
      jittkick = false;
    }

    // warn players from time to time whose packetloss is > lossthreshold (-packetlosswarn)
    if (!info->isObserver() && (lossthreshold > 0)
	&& lostavg > lossthreshold
	&& losscount - losslastwarn > 2 * losswarncount) {
      losslastwarn = losscount;
      plosswarn = true;
      plosskick = (++losswarncount > lossmax);
    } else {
      plosswarn = false;
      plosskick = false;
    }

    lostavg     = lostavg * (1 - lostalpha);
    lostalpha   = lostalpha / (0.99f + lostalpha);
    pingpending = false;
  } else {
    warn = false;
    kick = false;
    jittwarn = false;
    jittkick = false;
    plosswarn = false;
    plosskick = false;
    alagannouncewarn = false;
    lagannouncewarn = false;
  }
}

void LagInfo::updateLag(float timestamp, bool ooo) {
  if (!info->isPlaying())
    return;
  if (ooo) {
    lostavg   = lostavg * (1 - lostalpha) + lostalpha;
    lostalpha = lostalpha / (0.99f + lostalpha);
  }
  // don't calc jitter if more than 2 seconds between packets
  if (lasttimestamp > 0.0f && timestamp - lasttimestamp < 2.0f) {
    const float jitter = fabs((float)(info->now - lastupdate)
			      - (timestamp - lasttimestamp));
    // time is smoothed exponentially using a dynamic smoothing factor
    jitteravg   = jitteravg * (1 - jitteralpha) + jitteralpha * fabs(jitter);
    jitteralpha = jitteralpha / (0.99f + jitteralpha);
    lostavg     = lostavg * (1 - lostalpha);
    lostalpha   = lostalpha / (0.99f + lostalpha);
  }
  lasttimestamp = timestamp;
  lastupdate    = info->now;
}

int LagInfo::getNextPingSeqno(bool &warn, bool &kick) {

  warn = false;
  kick = false;

  if (!info->isPlaying() || !info->isHuman())
    return -1;

  if (info->now <= nextping)
    // no time for pinging
    return -1;

  pingseqno = (pingseqno + 1) % 10000;
  if (pingpending) {
    // ping lost
    lostavg   = lostavg * (1 - lostalpha) + lostalpha;
    lostalpha = lostalpha / (0.99f + lostalpha);
  }

  pingpending = true;
  lastping    = info->now;
  nextping    = info->now;
  nextping   += 10.0f;
  pingssent++;
  return pingseqno;
}

// update absolute latency based on LagPing messages
void LagInfo::updateLatency(float &waitTime) {
  if (!info->isPlaying() || !info->isHuman())
    return;
  float delta = (float)(nextping - info->now);
  if (delta < waitTime)
    waitTime  = delta;
}

void LagInfo::setAdminLagAnnounceThreshold(float _adminlagannouncetresh) {
  adminlagannouncetresh = _adminlagannouncetresh;
}

void LagInfo::setLagAnnounceThreshold(float _lagannouncetresh) {
  lagannouncetresh = _lagannouncetresh;
}

void LagInfo::setThreshold(float _threshold, float _max) {
  threshold = _threshold;
  max       = _max;
}

void LagInfo::setJitterThreshold(float _jitterthreshold, float _jittermax) {
  jitterthreshold = _jitterthreshold;
  jittermax       = _jittermax;
}

void LagInfo::setPacketLossThreshold(float _lossthreshold, float _lossmax) {
  lossthreshold = _lossthreshold * 10;
  lossmax       = _lossmax;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include <i2p/netdb.h>
#include <i2p/memory.hpp>
#include <i2p/datatypes/router_info.h>
#include <experimental/filesystem>
#include <cassert>
#include <iostream>
#include <fstream>

namespace fs = std::experimental::filesystem;

struct i2p_netdb
{
  mem::allocator mem;
  fs::path rootdir;

  bool Init()
  {
    fs::create_directories(rootdir);
    for (const char ch : "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890-~")
      if(!fs::create_directory(rootdir / fs::path("r"+std::to_string(ch)))) return false;
    return fs::exists(rootdir);
  }

  bool Iterate(struct i2p_netdb_iterator * iter)
  {
    bool found = false;
    iter->netdb = this;
    for(auto & path : fs::recursive_directory_iterator(rootdir))
    {
      if(path.path().filename().string().find("routerInfo-") == 0)
      {
        std::ifstream i;
        i.open(path.path());
        if(i.is_open())
        {
          i.seekg(0, std::ios_base::end);
          size_t sz = i.tellg();
          i.seekg(0);
          {
            mem::buffer ribuf = mem.Alloc<uint8_t>(sz);
            uint8_t * buf = ribuf.data();
            i.read(reinterpret_cast<char*>(buf), sz);
            struct i2p_router_info * ri = nullptr;
            if(i2p_router_info_parse(&ri, &buf, sz))
            {
              if(iter->filter(iter, ri)) iter->visit(iter, ri);
              i2p_router_info_free(&ri);
            }
          }
        }
      }
    }
    iter->netdb = nullptr;
    return found;
  }
};

bool i2p_netdb_new(struct i2p_netdb ** n, struct i2p_allocator * mem)
{
  (*n) = (i2p_netdb*) i2p_alloc(mem, sizeof(i2p_netdb));
  (*n)->mem = mem;
  return true;
}

bool i2p_netdb_free(struct i2p_netdb ** n)
{
  if(*n)
  {
    i2p_free((*n)->mem, n);
    *n = nullptr;
    return true;
  }
  return false;
}

void i2p_netdb_set_root(struct i2p_netdb * netdb, const char * rootdir)
{
  netdb->rootdir = fs::path(rootdir);
}

bool i2p_netdb_init_skiplist(struct i2p_netdb * netdb)
{
  return netdb->Init();
}

bool i2p_netdb_iterate_local(struct i2p_netdb * netdb, struct i2p_netdb_iterator * iter)
{
  return netdb->Iterate(iter);
}
<commit_msg>fix netdb skiplist creation<commit_after>#include <i2p/netdb.h>
#include <i2p/memory.hpp>
#include <i2p/datatypes/router_info.h>
#include <experimental/filesystem>
#include <cassert>
#include <iostream>
#include <fstream>

namespace fs = std::experimental::filesystem;

struct i2p_netdb
{
  mem::allocator mem;
  fs::path rootdir;

  bool Init()
  {
    fs::create_directories(rootdir);
    for (const char ch : "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890-~")
      if(!fs::create_directory(rootdir / fs::path("r"+std::string(&ch,1)))) return false;
    return fs::exists(rootdir);
  }

  bool Iterate(struct i2p_netdb_iterator * iter)
  {
    bool found = false;
    iter->netdb = this;
    for(auto & path : fs::recursive_directory_iterator(rootdir))
    {
      if(path.path().filename().string().find("routerInfo-") == 0)
      {
        std::ifstream i;
        i.open(path.path());
        if(i.is_open())
        {
          i.seekg(0, std::ios_base::end);
          size_t sz = i.tellg();
          i.seekg(0);
          {
            mem::buffer ribuf = mem.Alloc<uint8_t>(sz);
            uint8_t * buf = ribuf.data();
            i.read(reinterpret_cast<char*>(buf), sz);
            struct i2p_router_info * ri = nullptr;
            if(i2p_router_info_parse(&ri, &buf, sz))
            {
              if(iter->filter(iter, ri)) iter->visit(iter, ri);
              i2p_router_info_free(&ri);
            }
          }
        }
      }
    }
    iter->netdb = nullptr;
    return found;
  }
};

bool i2p_netdb_new(struct i2p_netdb ** n, struct i2p_allocator * mem)
{
  (*n) = (i2p_netdb*) i2p_alloc(mem, sizeof(i2p_netdb));
  (*n)->mem = mem;
  return true;
}

bool i2p_netdb_free(struct i2p_netdb ** n)
{
  if(*n)
  {
    i2p_free((*n)->mem, n);
    *n = nullptr;
    return true;
  }
  return false;
}

void i2p_netdb_set_root(struct i2p_netdb * netdb, const char * rootdir)
{
  netdb->rootdir = fs::path(rootdir);
}

bool i2p_netdb_init_skiplist(struct i2p_netdb * netdb)
{
  return netdb->Init();
}

bool i2p_netdb_iterate_local(struct i2p_netdb * netdb, struct i2p_netdb_iterator * iter)
{
  return netdb->Iterate(iter);
}
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>
#include <openssl/evp.h>

namespace node_aes_ccm {

using v8::FunctionCallbackInfo;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Exception;
using v8::Boolean;
using namespace node;

// Perform GCM mode AES-128 encryption using the provided key, IV, plaintext
// and auth_data buffers, and return an object containing "ciphertext"
// and "auth_tag" buffers.

void CcmEncrypt(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  // We want 5 arguments
  // key
  // iv
  // plaintext
  // aad
  // auth tag length
  if (args.Length() < 4 || !Buffer::HasInstance(args[0]) ||
      !Buffer::HasInstance(args[1]) || !Buffer::HasInstance(args[2]) ||
      !Buffer::HasInstance(args[3]) || !args[4]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "encrypt requires a key Buffer, a " \
                      "IV Buffer, a plaintext Buffer, an auth_data " \
                      "Buffer parameter, and the length of the auth tag")));
    return;
  }

  // Make a buffer for the ciphertext that is the same size as the
  // plaintext, but padded to 16 byte increments
  size_t plaintext_len = Buffer::Length(args[2]);
  size_t ciphertext_len = (((plaintext_len - 1) / 16) + 1) * 16;
  unsigned char *ciphertext = new unsigned char[ciphertext_len];
  // Make a authentication tag buffer
  int auth_tag_len = args[4]->NumberValue();
  unsigned char *auth_tag = new unsigned char[auth_tag_len];

  // Init OpenSSL interace with 128-bit AES GCM cipher and give it the
  // key and IV
  int outl;
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL);

  size_t iv_len = Buffer::Length(args[1]);

  // set iv and auth tag length
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL);
  // EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, 3, NULL);
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, auth_tag_len, NULL);

  EVP_EncryptInit_ex(ctx, NULL, NULL,
                    (unsigned char *)Buffer::Data(args[0]),
                    (unsigned char *)Buffer::Data(args[1]));

  int aad_len = Buffer::Length(args[3]);
  EVP_EncryptUpdate(ctx, NULL, &outl, NULL, plaintext_len);
  // Pass additional authenticated data
  // There is some extra complication here because Buffer::Data seems to
  // return NULL for empty buffers, and NULL makes update not work as we
  // expect it to.  So we force a valid non-NULL pointer for empty buffers.

  EVP_EncryptUpdate(ctx, NULL, &outl, aad_len ?
                    (unsigned char *)Buffer::Data(args[3]) : auth_tag,
                    aad_len);
  // Encrypt plaintext
  EVP_EncryptUpdate(ctx, ciphertext, &outl,
                    (unsigned char *)Buffer::Data(args[2]),
                    plaintext_len);
  // Finalize
  EVP_EncryptFinal_ex(ctx, ciphertext + outl, &outl);
  // Get the authentication tag
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, auth_tag_len, auth_tag);
  // Free the OpenSSL interface structure
  EVP_CIPHER_CTX_free(ctx);

  // Create the return buffers and object
  // We strip padding from the ciphertext
  MaybeLocal<Object> ciphertext_buf = Buffer::New(isolate, (char*)ciphertext, plaintext_len);
  MaybeLocal<Object> auth_tag_buf = Buffer::New(isolate, (char*)auth_tag, auth_tag_len);
  Local<Object> return_obj = Object::New(isolate);
  return_obj->Set(String::NewFromUtf8(isolate, "ciphertext"), ciphertext_buf.FromMaybe(Local<Object>()));
  return_obj->Set(String::NewFromUtf8(isolate, "auth_tag"), auth_tag_buf.FromMaybe(Local<Object>()));

  // Return it
  args.GetReturnValue().Set(return_obj);
}

// Perform GCM mode AES-128 decryption using the provided key, IV, ciphertext,
// auth_data and auth_tag buffers, and return an object containing a "plaintext"
// buffer and an "auth_ok" boolean.

void CcmDecrypt(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  // We want 5 buffer arguments
  // key
  // IV
  // ciphertext
  // aad
  // auth_tag
  if (args.Length() < 5 || !Buffer::HasInstance(args[0]) ||
      !Buffer::HasInstance(args[1]) || !Buffer::HasInstance(args[2]) ||
      !Buffer::HasInstance(args[3]) || !Buffer::HasInstance(args[4])
     ) {
    isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "decrypt requires a key Buffer, a " \
                      "IV Buffer, a ciphertext Buffer, an auth_data " \
                      "Buffer and an auth_tag Buffer parameter")));
  }

  // Make a buffer for the plaintext that is the same size as the
  // ciphertext, but padded to 16 byte increments
  size_t ciphertext_len = Buffer::Length(args[2]);
  size_t plaintext_len = (((ciphertext_len - 1) / 16) + 1) * 16;
  int aad_len = Buffer::Length(args[3]);
  unsigned char *plaintext = new unsigned char[plaintext_len];

  // Init OpenSSL interace with 128-bit AES GCM cipher and give it the
  // key and IV
  int outl;
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL);

  size_t iv_len = Buffer::Length(args[1]);
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, 0);

  // Set the input reference authentication tag
  size_t auth_tag_len = Buffer::Length(args[4]);
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, auth_tag_len,
                    Buffer::Data(args[4]));
  // Example showed we needed to do init again
  EVP_DecryptInit_ex(ctx, NULL, NULL,
                    (unsigned char *)Buffer::Data(args[0]),
                    (unsigned char *)Buffer::Data(args[1]));

  EVP_DecryptUpdate(ctx, NULL, &outl, NULL, ciphertext_len);
  // Pass additional authenticated data
  // There is some extra complication here because Buffer::Data seems to
  // return NULL for empty buffers, and NULL makes update not work as we
  // expect it to.  So we force a valid non-NULL pointer for empty buffers.
  EVP_DecryptUpdate(ctx, NULL, &outl, Buffer::Length(args[3]) ?
                    (unsigned char *)Buffer::Data(args[3]) : plaintext,
                    aad_len);
  // Decrypt ciphertext
  bool auth_ok = EVP_DecryptUpdate(ctx, plaintext, &outl,
                    (unsigned char *)Buffer::Data(args[2]),
                    ciphertext_len);
  // Finalize
  //bool auth_ok = EVP_DecryptFinal_ex(ctx, plaintext + outl, &outl);
  // Free the OpenSSL interface structure
  EVP_CIPHER_CTX_free(ctx);

  // Create the return buffer and object
  // We strip padding from the plaintext
  MaybeLocal<Object> plaintext_buf = Buffer::New(isolate, (char*)plaintext, ciphertext_len);
  Local<Object> return_obj = Object::New(isolate);
  return_obj->Set(String::NewFromUtf8(isolate, "plaintext"), plaintext_buf.FromMaybe(Local<Object>()));
  return_obj->Set(String::NewFromUtf8(isolate, "auth_ok"), Boolean::New(isolate, auth_ok));

  // Return it
  args.GetReturnValue().Set(return_obj);
}

void init(Local<Object> exports) {
  NODE_SET_METHOD(exports, "encrypt", CcmEncrypt);
  NODE_SET_METHOD(exports, "decrypt", CcmDecrypt);
}

NODE_MODULE(node_aes_ccm, init)

} // namespace node_aes_ccm<commit_msg>Remove unused HandleScope<commit_after>#include <node.h>
#include <node_buffer.h>
#include <openssl/evp.h>

namespace node_aes_ccm {

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Exception;
using v8::Boolean;
using namespace node;

// Perform GCM mode AES-128 encryption using the provided key, IV, plaintext
// and auth_data buffers, and return an object containing "ciphertext"
// and "auth_tag" buffers.

void CcmEncrypt(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  // We want 5 arguments
  // key
  // iv
  // plaintext
  // aad
  // auth tag length
  if (args.Length() < 4 || !Buffer::HasInstance(args[0]) ||
      !Buffer::HasInstance(args[1]) || !Buffer::HasInstance(args[2]) ||
      !Buffer::HasInstance(args[3]) || !args[4]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "encrypt requires a key Buffer, a " \
                      "IV Buffer, a plaintext Buffer, an auth_data " \
                      "Buffer parameter, and the length of the auth tag")));
    return;
  }

  // Make a buffer for the ciphertext that is the same size as the
  // plaintext, but padded to 16 byte increments
  size_t plaintext_len = Buffer::Length(args[2]);
  size_t ciphertext_len = (((plaintext_len - 1) / 16) + 1) * 16;
  unsigned char *ciphertext = new unsigned char[ciphertext_len];
  // Make a authentication tag buffer
  int auth_tag_len = args[4]->NumberValue();
  unsigned char *auth_tag = new unsigned char[auth_tag_len];

  // Init OpenSSL interace with 128-bit AES GCM cipher and give it the
  // key and IV
  int outl;
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  EVP_EncryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL);

  size_t iv_len = Buffer::Length(args[1]);

  // set iv and auth tag length
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, NULL);
  // EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, 3, NULL);
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, auth_tag_len, NULL);

  EVP_EncryptInit_ex(ctx, NULL, NULL,
                    (unsigned char *)Buffer::Data(args[0]),
                    (unsigned char *)Buffer::Data(args[1]));

  int aad_len = Buffer::Length(args[3]);
  EVP_EncryptUpdate(ctx, NULL, &outl, NULL, plaintext_len);
  // Pass additional authenticated data
  // There is some extra complication here because Buffer::Data seems to
  // return NULL for empty buffers, and NULL makes update not work as we
  // expect it to.  So we force a valid non-NULL pointer for empty buffers.

  EVP_EncryptUpdate(ctx, NULL, &outl, aad_len ?
                    (unsigned char *)Buffer::Data(args[3]) : auth_tag,
                    aad_len);
  // Encrypt plaintext
  EVP_EncryptUpdate(ctx, ciphertext, &outl,
                    (unsigned char *)Buffer::Data(args[2]),
                    plaintext_len);
  // Finalize
  EVP_EncryptFinal_ex(ctx, ciphertext + outl, &outl);
  // Get the authentication tag
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, auth_tag_len, auth_tag);
  // Free the OpenSSL interface structure
  EVP_CIPHER_CTX_free(ctx);

  // Create the return buffers and object
  // We strip padding from the ciphertext
  MaybeLocal<Object> ciphertext_buf = Buffer::New(isolate, (char*)ciphertext, plaintext_len);
  MaybeLocal<Object> auth_tag_buf = Buffer::New(isolate, (char*)auth_tag, auth_tag_len);
  Local<Object> return_obj = Object::New(isolate);
  return_obj->Set(String::NewFromUtf8(isolate, "ciphertext"), ciphertext_buf.FromMaybe(Local<Object>()));
  return_obj->Set(String::NewFromUtf8(isolate, "auth_tag"), auth_tag_buf.FromMaybe(Local<Object>()));

  // Return it
  args.GetReturnValue().Set(return_obj);
}

// Perform GCM mode AES-128 decryption using the provided key, IV, ciphertext,
// auth_data and auth_tag buffers, and return an object containing a "plaintext"
// buffer and an "auth_ok" boolean.

void CcmDecrypt(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();

  // We want 5 buffer arguments
  // key
  // IV
  // ciphertext
  // aad
  // auth_tag
  if (args.Length() < 5 || !Buffer::HasInstance(args[0]) ||
      !Buffer::HasInstance(args[1]) || !Buffer::HasInstance(args[2]) ||
      !Buffer::HasInstance(args[3]) || !Buffer::HasInstance(args[4])
     ) {
    isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "decrypt requires a key Buffer, a " \
                      "IV Buffer, a ciphertext Buffer, an auth_data " \
                      "Buffer and an auth_tag Buffer parameter")));
  }

  // Make a buffer for the plaintext that is the same size as the
  // ciphertext, but padded to 16 byte increments
  size_t ciphertext_len = Buffer::Length(args[2]);
  size_t plaintext_len = (((ciphertext_len - 1) / 16) + 1) * 16;
  int aad_len = Buffer::Length(args[3]);
  unsigned char *plaintext = new unsigned char[plaintext_len];

  // Init OpenSSL interace with 128-bit AES GCM cipher and give it the
  // key and IV
  int outl;
  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
  EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL);

  size_t iv_len = Buffer::Length(args[1]);
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_len, 0);

  // Set the input reference authentication tag
  size_t auth_tag_len = Buffer::Length(args[4]);
  EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, auth_tag_len,
                    Buffer::Data(args[4]));
  // Example showed we needed to do init again
  EVP_DecryptInit_ex(ctx, NULL, NULL,
                    (unsigned char *)Buffer::Data(args[0]),
                    (unsigned char *)Buffer::Data(args[1]));

  EVP_DecryptUpdate(ctx, NULL, &outl, NULL, ciphertext_len);
  // Pass additional authenticated data
  // There is some extra complication here because Buffer::Data seems to
  // return NULL for empty buffers, and NULL makes update not work as we
  // expect it to.  So we force a valid non-NULL pointer for empty buffers.
  EVP_DecryptUpdate(ctx, NULL, &outl, Buffer::Length(args[3]) ?
                    (unsigned char *)Buffer::Data(args[3]) : plaintext,
                    aad_len);
  // Decrypt ciphertext
  bool auth_ok = EVP_DecryptUpdate(ctx, plaintext, &outl,
                    (unsigned char *)Buffer::Data(args[2]),
                    ciphertext_len);
  // Finalize
  //bool auth_ok = EVP_DecryptFinal_ex(ctx, plaintext + outl, &outl);
  // Free the OpenSSL interface structure
  EVP_CIPHER_CTX_free(ctx);

  // Create the return buffer and object
  // We strip padding from the plaintext
  MaybeLocal<Object> plaintext_buf = Buffer::New(isolate, (char*)plaintext, ciphertext_len);
  Local<Object> return_obj = Object::New(isolate);
  return_obj->Set(String::NewFromUtf8(isolate, "plaintext"), plaintext_buf.FromMaybe(Local<Object>()));
  return_obj->Set(String::NewFromUtf8(isolate, "auth_ok"), Boolean::New(isolate, auth_ok));

  // Return it
  args.GetReturnValue().Set(return_obj);
}

void init(Local<Object> exports) {
  NODE_SET_METHOD(exports, "encrypt", CcmEncrypt);
  NODE_SET_METHOD(exports, "decrypt", CcmDecrypt);
}

NODE_MODULE(node_aes_ccm, init)

} // namespace node_aes_ccm<|endoftext|>


<commit_before>#include "graphi.hpp"
#include <algorithm>
#include <queue>

bool GraphI::find_path(int node1, int node2, std::vector<int> *path) const
{
    int vnum = vertex_num();
    std::vector<bool> visited(vnum, false);
    std::vector<int> prev(vnum, -1);
    std::vector<int> dist(vnum, vnum + 1);
    for (auto i = 0; i < vnum; ++i) {
        visited[i] = false;
        prev[i] = -1;
        dist[i] = vnum + 1;
    }

    std::queue<int> queue;

    bool path_found = false;

    queue.push(node1);
    dist[node1] = 0;

    while (!path_found && !queue.empty()) {
        int u = queue.front();
        queue.pop();
        visited[u] = true;

        for (auto v = 0; v < vnum; ++v) {
            if (is_edge(u, v) && !visited[v]) {
                int alt = dist[u] + 1;
                if (alt < dist[v]) {
                    dist[v] = alt;
                    prev[v] = u;
                }

                queue.push(v);
                if (v == node2) {
                    path_found = true;
                    break;
                }
            }
        }
    }

    if (path_found) {
        int v = node2;
        do {
            path->push_back(v);
            v = prev[v];
        } while (v != -1);
        // FIXME
        std::reverse(path->begin(), path->end());
    }

    return path_found;
}
<commit_msg>Fix segfault on search on empty graph<commit_after>#include "graphi.hpp"
#include <algorithm>
#include <queue>

bool GraphI::find_path(int node1, int node2, std::vector<int> *path) const
{
    int vnum = vertex_num();
    if (std::max(node1, node2) > vnum) {
        return false;
    }

    std::vector<bool> visited(vnum, false);
    std::vector<int> prev(vnum, -1);
    std::vector<int> dist(vnum, vnum + 1);
    for (auto i = 0; i < vnum; ++i) {
        visited[i] = false;
        prev[i] = -1;
        dist[i] = vnum + 1;
    }

    std::queue<int> queue;

    bool path_found = false;

    queue.push(node1);
    dist[node1] = 0;

    while (!path_found && !queue.empty()) {
        int u = queue.front();
        queue.pop();
        visited[u] = true;

        for (auto v = 0; v < vnum; ++v) {
            if (is_edge(u, v) && !visited[v]) {
                int alt = dist[u] + 1;
                if (alt < dist[v]) {
                    dist[v] = alt;
                    prev[v] = u;
                }

                queue.push(v);
                if (v == node2) {
                    path_found = true;
                    break;
                }
            }
        }
    }

    if (path_found) {
        int v = node2;
        do {
            path->push_back(v);
            v = prev[v];
        } while (v != -1);
        // FIXME
        std::reverse(path->begin(), path->end());
    }

    return path_found;
}
<|endoftext|>