<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "formeditorfactory.h"
#include "formeditorw.h"
#include "formwindoweditor.h"
#include "editordata.h"
#include "designerxmleditorwidget.h"

#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/infobar.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/modemanager.h>

#include <QCoreApplication>
#include <QDebug>

using namespace Designer::Constants;

namespace Designer {
namespace Internal {

FormEditorFactory::FormEditorFactory()
  : Core::IEditorFactory(Core::ICore::instance())
{
    setId(K_DESIGNER_XML_EDITOR_ID);
    setDisplayName(qApp->translate("Designer", C_DESIGNER_XML_DISPLAY_NAME));
    addMimeType(FORM_MIMETYPE);

    Core::FileIconProvider::registerIconOverlayForSuffix(":/formeditor/images/qt_ui.png", "ui");
}

Core::IEditor *FormEditorFactory::createEditor()
{
    const EditorData data = FormEditorW::instance()->createEditor();
    if (data.formWindowEditor) {
        Core::InfoBarEntry info(Core::Id(Constants::INFO_READ_ONLY),
                                tr("This file can only be edited in Design mode."));
        info.setCustomButtonInfo(tr("Switch mode"), this, SLOT(designerModeClicked()));
        data.formWindowEditor->document()->infoBar()->addInfo(info);
    }
    return data.formWindowEditor;
}

void FormEditorFactory::designerModeClicked()
{
    Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN);
}

} // namespace Internal
} // namespace Designer
<commit_msg>Designer: fix capitalization of UI text<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "formeditorfactory.h"
#include "formeditorw.h"
#include "formwindoweditor.h"
#include "editordata.h"
#include "designerxmleditorwidget.h"

#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/infobar.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/modemanager.h>

#include <QCoreApplication>
#include <QDebug>

using namespace Designer::Constants;

namespace Designer {
namespace Internal {

FormEditorFactory::FormEditorFactory()
  : Core::IEditorFactory(Core::ICore::instance())
{
    setId(K_DESIGNER_XML_EDITOR_ID);
    setDisplayName(qApp->translate("Designer", C_DESIGNER_XML_DISPLAY_NAME));
    addMimeType(FORM_MIMETYPE);

    Core::FileIconProvider::registerIconOverlayForSuffix(":/formeditor/images/qt_ui.png", "ui");
}

Core::IEditor *FormEditorFactory::createEditor()
{
    const EditorData data = FormEditorW::instance()->createEditor();
    if (data.formWindowEditor) {
        Core::InfoBarEntry info(Core::Id(Constants::INFO_READ_ONLY),
                                tr("This file can only be edited in Design mode."));
        info.setCustomButtonInfo(tr("Switch Mode"), this, SLOT(designerModeClicked()));
        data.formWindowEditor->document()->infoBar()->addInfo(info);
    }
    return data.formWindowEditor;
}

void FormEditorFactory::designerModeClicked()
{
    Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN);
}

} // namespace Internal
} // namespace Designer
<|endoftext|>


<commit_before>//
// LocalDatabuf.cpp: a wrapper for the Databuf class which is found either in
//  in vtdata or libMini.
//
// Copyright (c) 2008 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "LocalDatabuf.h"

/////////////////////////////////////////////////////

#ifdef _MSC_VER
  #if _MSC_VER >= 1400 // vc8
	  #pragma message( "Adding link with libMini-vc8.lib" )
	  #pragma comment( lib, "libMini-vc8.lib" )
  #else // vc71
	  #pragma message( "Adding link with libMini-vc7.lib" )
	  #pragma comment( lib, "libMini-vc7.lib" )
  #endif
  #pragma comment( lib, "glu32.lib" )
#endif

/////////////////////////////////////////////////////

#if USE_LIBMINI_DATABUF

// A useful method to set the extents (in local CRS) and the corners
//  (in Geo WGS84) at the same time.
bool vtMiniDatabuf::SetBounds(const vtProjection &proj, const DRECT &extents)
{
	// First, set the extent rectangle
	set_extents((float)extents.left, (float)extents.right, (float)extents.bottom, (float)extents.top);

	// Create transform from local to Geo-WGS84
	vtProjection geo;
	geo.SetWellKnownGeogCS("WGS84");
	OCT *trans = CreateCoordTransform(&proj, &geo);

	if (!trans)
		return false;

	// Convert each corner as a point
	DPoint2 sw_corner, se_corner, nw_corner, ne_corner;

	sw_corner.Set(extents.left, extents.bottom);
	trans->Transform(1, &sw_corner.x, &sw_corner.y);

	se_corner.Set(extents.right, extents.bottom);
	trans->Transform(1, &se_corner.x, &se_corner.y);

	nw_corner.Set(extents.left, extents.top);
	trans->Transform(1, &nw_corner.x, &nw_corner.y);

	ne_corner.Set(extents.right, extents.top);
	trans->Transform(1, &ne_corner.x, &ne_corner.y);

	set_LLWGS84corners((float)sw_corner.x, (float)sw_corner.y,
                       (float)se_corner.x, (float)se_corner.y,
                       (float)nw_corner.x, (float)nw_corner.y,
                       (float)ne_corner.x, (float)ne_corner.y);
	delete trans;
	return true;
}

//! get rgb[a] color
void vtMiniDatabuf::getrgb(const unsigned int i,const unsigned int j,const unsigned int k, float *value)
{
	if (type==3)
	{
		unsigned char *ptr=&((unsigned char *)data)[3*(i+(j+k*ysize)*xsize)];

		value[0] = ptr[0];
		value[1] = ptr[1];
		value[2] = ptr[2];
	}
}

void vtMiniDatabuf::getrgba(const unsigned int i,const unsigned int j,const unsigned int k, float *value)
{
	if (type==4)
	{
		unsigned char *ptr=&((unsigned char *)data)[4*(i+(j+k*ysize)*xsize)];

		value[0] = ptr[0];
		value[1] = ptr[1];
		value[2] = ptr[2];
		value[3] = ptr[3];
	}
}

#endif
<commit_msg>previously reported warning goes away with libMini -r 1052<commit_after>//
// LocalDatabuf.cpp: a wrapper for the Databuf class which is found either in
//  in vtdata or libMini.
//
// Copyright (c) 2008 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "LocalDatabuf.h"

/////////////////////////////////////////////////////

#ifdef _MSC_VER
  #if _MSC_VER >= 1400 // vc8
	  #pragma message( "Adding link with libMini-vc8.lib" )
	  #pragma comment( lib, "libMini-vc8.lib" )
  #else // vc71
	  #pragma message( "Adding link with libMini-vc7.lib" )
	  #pragma comment( lib, "libMini-vc7.lib" )
  #endif
  #pragma comment( lib, "glu32.lib" )
#endif

/////////////////////////////////////////////////////

#if USE_LIBMINI_DATABUF

// A useful method to set the extents (in local CRS) and the corners
//  (in Geo WGS84) at the same time.
bool vtMiniDatabuf::SetBounds(const vtProjection &proj, const DRECT &extents)
{
	// First, set the extent rectangle
	set_extents(extents.left, extents.right, extents.bottom, extents.top);

	// Create transform from local to Geo-WGS84
	vtProjection geo;
	geo.SetWellKnownGeogCS("WGS84");
	OCT *trans = CreateCoordTransform(&proj, &geo);

	if (!trans)
		return false;

	// Convert each corner as a point
	DPoint2 sw_corner, se_corner, nw_corner, ne_corner;

	sw_corner.Set(extents.left, extents.bottom);
	trans->Transform(1, &sw_corner.x, &sw_corner.y);

	se_corner.Set(extents.right, extents.bottom);
	trans->Transform(1, &se_corner.x, &se_corner.y);

	nw_corner.Set(extents.left, extents.top);
	trans->Transform(1, &nw_corner.x, &nw_corner.y);

	ne_corner.Set(extents.right, extents.top);
	trans->Transform(1, &ne_corner.x, &ne_corner.y);

	set_LLWGS84corners(sw_corner.x, sw_corner.y,
                       se_corner.x, se_corner.y,
                       nw_corner.x, nw_corner.y,
                       ne_corner.x, ne_corner.y);
	delete trans;
	return true;
}

//! get rgb[a] color
void vtMiniDatabuf::getrgb(const unsigned int i,const unsigned int j,const unsigned int k, float *value)
{
	if (type==3)
	{
		unsigned char *ptr=&((unsigned char *)data)[3*(i+(j+k*ysize)*xsize)];

		value[0] = ptr[0];
		value[1] = ptr[1];
		value[2] = ptr[2];
	}
}

void vtMiniDatabuf::getrgba(const unsigned int i,const unsigned int j,const unsigned int k, float *value)
{
	if (type==4)
	{
		unsigned char *ptr=&((unsigned char *)data)[4*(i+(j+k*ysize)*xsize)];

		value[0] = ptr[0];
		value[1] = ptr[1];
		value[2] = ptr[2];
		value[3] = ptr[3];
	}
}

#endif
<|endoftext|>


<commit_before>#include <string>
#include <stdlib.h>
#include "string_cast.h"

using namespace std;

template <>
string string_cast<string>(const wchar_t* src)
{
	unsigned int maxCharSize = MB_CUR_MAX;

	size_t srcSize = wcslen(src);
	char* dst = reinterpret_cast<char*>(alloca((srcSize * maxCharSize) + 1));
	char* dstPtr = dst;
	for(unsigned int i = 0; i < srcSize; i++)
	{
		int charSize = wctomb(dstPtr, src[i]);
		if(charSize < 0)
		{
			(*dstPtr) = '?';
			dstPtr++;
		}
		else
		{
			dstPtr += charSize;
		}
	}
	(*dstPtr) = 0;

	return string(dst);
}

template <>
wstring string_cast<wstring>(const char* sSource)
{
	size_t nSize;
	wchar_t* sConvert;

	nSize = strlen(sSource) + 1;
	sConvert = (wchar_t*)alloca(nSize * sizeof(wchar_t));

	mbstowcs(sConvert, sSource, nSize);

	return wstring(sConvert);
}

template <>
wstring string_cast<wstring>(const wchar_t* sSource)
{
	return wstring(sSource);
}

template <>
string string_cast<string>(const wstring& sSource)
{
	return string_cast<string, wchar_t>(sSource.c_str());
}

template <>
wstring string_cast<wstring>(const string& sSource)
{
	return string_cast<wstring, char>(sSource.c_str());
}

template <>
wstring string_cast<wstring>(const wstring& sSource)
{
	return sSource;
}
<commit_msg>Added an additional template specialization for string_cast.<commit_after>#include <string>
#include <stdlib.h>
#include "string_cast.h"

using namespace std;

template <>
string string_cast<string>(const wchar_t* src)
{
	unsigned int maxCharSize = MB_CUR_MAX;

	size_t srcSize = wcslen(src);
	char* dst = reinterpret_cast<char*>(alloca((srcSize * maxCharSize) + 1));
	char* dstPtr = dst;
	for(unsigned int i = 0; i < srcSize; i++)
	{
		int charSize = wctomb(dstPtr, src[i]);
		if(charSize < 0)
		{
			(*dstPtr) = '?';
			dstPtr++;
		}
		else
		{
			dstPtr += charSize;
		}
	}
	(*dstPtr) = 0;

	return string(dst);
}

template <>
wstring string_cast<wstring>(const char* sSource)
{
	size_t nSize;
	wchar_t* sConvert;

	nSize = strlen(sSource) + 1;
	sConvert = (wchar_t*)alloca(nSize * sizeof(wchar_t));

	mbstowcs(sConvert, sSource, nSize);

	return wstring(sConvert);
}

template <>
wstring string_cast<wstring>(const wchar_t* sSource)
{
	return wstring(sSource);
}

template <>
string string_cast<string>(const wstring& sSource)
{
	return string_cast<string, wchar_t>(sSource.c_str());
}

template <>
string string_cast<string>(wchar_t* const& source)
{
	return string_cast<string, wchar_t>(source);
}

template <>
wstring string_cast<wstring>(const string& sSource)
{
	return string_cast<wstring, char>(sSource.c_str());
}

template <>
wstring string_cast<wstring>(const wstring& sSource)
{
	return sSource;
}
<|endoftext|>


<commit_before>#include <dhash.h>
#include <route.h>
#include <chord.h>
#include <chord_prot.h>
#include "sfsmisc.h"
#include "arpc.h"
#include "crypt.h"
#include <sys/time.h>
#include "chord_util.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif

unsigned int MTU = (getenv ("DHASH_MTU") ?
		   atoi (getenv ("DHASH_MTU")) :
		   1024);

static int gnonce;

#define LOOKUP_TIMEOUT 30

// ---------------------------------------------------------------------------
// dhash_retrieve

class dhash_retrieve {
private:
  ptr<vnode> clntnode;
  uint npending;
  bool error;
  chordID sourceID;
  chordID blockID;
  cbretrieve_t cb;
  bool askforlease;

  ptr<dhash_block> block;
  int nextblock;
  int numblocks;
  vec<long> seqnos;

  dhash_retrieve (ptr<vnode> clntnode, chordID sourceID, chordID blockID,
		  char *data, u_int len, u_int totsz, int cookie, int lease,
		  bool askforlease, cbretrieve_t cb)
    : clntnode (clntnode),
      sourceID (sourceID),
      blockID (blockID),
      cb (cb),
      askforlease (askforlease)
  {
    block            = New refcounted<dhash_block> ((char *)NULL, totsz);
    block->source    = sourceID;
    block->hops      = 0;
    block->errors    = 0;
    block->lease     = 0;

    if (askforlease)
      block->lease = lease;

    npending = 0;
    error = false;
    nextblock = 1;
    numblocks = 1;
    seqnos.push_back (0);

    if (data) {
      get_remaining_chunks (len, totsz, cookie);
      add_data (data, len, 0);
    } else {
      ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg>;
      arg->v     = sourceID;
      arg->key   = blockID;
      arg->start = 0;
      arg->len   = MTU;
      arg->cookie = 0;
      arg->lease = askforlease;

      ptr<dhash_fetchiter_res> res = New refcounted<dhash_fetchiter_res> ();
      long seqno = clntnode->doRPC (sourceID, dhash_program_1,
				    DHASHPROC_FETCHITER,
				    arg, res,
				    wrap (this,&dhash_retrieve::first_chunk_cb,
					  res, numblocks++));
      seqnos.push_back (seqno);
    }
  }

  void
  get_remaining_chunks (size_t nread, size_t totsz, int cookie)
  {
    //issue the RPCs to get the other chunks
    while (nread < totsz) {
      int length = MIN (MTU, totsz - nread);
      npending++;

      ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg>;
      arg->v     = sourceID;
      arg->key   = blockID;
      arg->start = nread;
      arg->len   = length;
      arg->cookie = cookie;
      arg->lease = askforlease;

      ptr<dhash_fetchiter_res> res = New refcounted<dhash_fetchiter_res> ();
      long seqno = clntnode->doRPC (sourceID, dhash_program_1,
				    DHASHPROC_FETCHITER,
				    arg, res,
				    wrap (this,&dhash_retrieve::finish_block_fetch,
					  res, numblocks++));

      seqnos.push_back (seqno);
      nread += length;
    }
  }

  void
  first_chunk_cb  (ptr<dhash_fetchiter_res> res, int blocknum,
		   clnt_stat err)
  {
    if (err || (res && res->status != DHASH_COMPLETE))
      fail (dhasherr2str (res->status));
    else {
      int cookie     = res->compl_res->cookie;
      size_t totsz   = res->compl_res->attr.size;
      size_t datalen = res->compl_res->res.size ();
      char  *data    = res->compl_res->res.base ();
      size_t dataoff = res->compl_res->offset;

      get_remaining_chunks (datalen, totsz, cookie);
      add_data (data, datalen, dataoff);
      check_finish ();
    }
  }

  void
  add_data (char *data, int len, int off)
  {
    if ((unsigned)(off + len) > block->len)
      fail (strbuf ("bad fragment: off %d, len %d, block %d",
		    off, len, block->len));
    else
      memcpy (&block->data[off], data, len);
  }

  void
  check_finish ()
  {
    if (npending == 0) {
      /* got all chunks */
      if (error)
	block = NULL;
      (*cb) (block);
      delete this;
    }
  }

  void
  finish_block_fetch (ptr<dhash_fetchiter_res> res, int blocknum,
		      clnt_stat err)
  {
    npending--;

    if (err || (res && res->status != DHASH_COMPLETE))
      fail (dhasherr2str (res->status));
    else {
      if (askforlease && block->lease > res->compl_res->lease)
	block->lease = res->compl_res->lease;

      if ((blocknum > nextblock) && (numblocks - blocknum > 1)) {
	warn << "FAST retransmit: " << blockID << " chunk " << nextblock << " being retransmitted\n";

	clntnode->resendRPC(seqnos[nextblock]);
	//only one per fetch; finding more is too much bookkeeping
	numblocks = 0;
      }

      nextblock++;
      add_data (res->compl_res->res.base (), res->compl_res->res.size (),
		res->compl_res->offset);
    }
    check_finish ();
  }

  void
  fail (str errstr)
  {
    warn << "dhash_store failed: " << blockID << ": " << errstr << "\n";
    error = true;
  }

public:
  static void execute (ptr<vnode> clntnode, chordID sourceID, chordID blockID,
		       char *data, u_int len, u_int totsz, int cookie, int lease,
		       bool askforlease, cbretrieve_t cb)
  {
    vNew dhash_retrieve (clntnode, sourceID, blockID, data, len, totsz, cookie, lease, askforlease, cb);
  }
};

// ---------------------------------------------------------------------------
// route_dhash

route_dhash::route_dhash (ptr<route_factory> f,
			  chordID blockID,
			  dhash *dh,
			  bool lease,
			  bool ucs)

  : dh (dh),
    ask_for_lease (lease),
    use_cached_succ (ucs),
    npending (0), fetch_error (false),
    blockID (blockID),
    f (f),
    ignore_block (false)
{

  last_hop = false;
  ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg> ();
  arg->key = blockID;
  f->get_node (&arg->from);
  arg->start = 0;
  arg->len = MTU;
  arg->cookie = 0;
  arg->nonce = gnonce++;
  arg->lease = ask_for_lease;

  // XXX on timeout this never gets unregistered !!!
  dh->register_block_cb (arg->nonce, wrap (mkref(this), &route_dhash::block_cb));

  // Along the chord lookup path, 'arg' will get upcalled to each dhash server (dhash::do_upcall).
  // The dhash server will respond back by sending an RPC *request* to us.  We'll associate the
  // incoming RPC request with 'arg' via gnonce.  We'll field the RPC request in
  // route_dhash::block_cb. Our RPC response is essentially ignored.
  chord_iterator = f->produce_iterator_ptr (blockID, dhash_program_1, DHASHPROC_FETCHITER, arg);
}

route_dhash::~route_dhash ()
{
  delete chord_iterator;
}

void
route_dhash::reexecute ()
{
  // XXX ugly code... duplicates the constructor
  delete chord_iterator;

  timecb_remove (dcb);
  dcb = NULL;

  last_hop = false;
  ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg> ();
  arg->key = blockID;
  f->get_node (&arg->from);
  arg->start = 0;
  arg->len = MTU;
  arg->cookie = 0;
  arg->nonce = gnonce++;
  arg->lease = ask_for_lease;

  // XXX on timeout this never gets unregistered !!!
  dh->register_block_cb (arg->nonce, wrap (mkref(this), &route_dhash::block_cb));

  // Along the chord lookup path, 'arg' will get upcalled to each dhash server (dhash::do_upcall).
  // The dhash server will respond back by sending an RPC *request* to us.  We'll associate the
  // incoming RPC request with 'arg' via gnonce.  We'll field the RPC request in
  // route_dhash::block_cb. Our RPC response is essentially ignored.
  chord_iterator = f->produce_iterator_ptr (blockID, dhash_program_1, DHASHPROC_FETCHITER, arg);

  dcb = delaycb (LOOKUP_TIMEOUT, wrap (mkref(this), &route_dhash::timed_out));
  chord_iterator->send (use_cached_succ);
}

void
route_dhash::execute (cb_ret cbi, chordID first_hop)
{
  cb = cbi;
  dcb = delaycb (LOOKUP_TIMEOUT, wrap (mkref(this), &route_dhash::timed_out));
  chord_iterator->send (first_hop);
}

void
route_dhash::execute (cb_ret cbi)
{
  cb = cbi;
  dcb = delaycb (LOOKUP_TIMEOUT, wrap (mkref(this), &route_dhash::timed_out));
  chord_iterator->send (use_cached_succ);
}

void
route_dhash::timed_out ()
{
  warn << "lookup TIMED OUT\n";
  // give the network a bit to heal, then retry the block fetch
  delaycb (5, wrap (mkref(this), &route_dhash::timed_out_after_wait));

#if 0
 (*cb)(DHASH_TIMEDOUT, NULL, path ());
  //XXX what happens if the request comes back
  //    after we've given up on it?
  // gotta do something, the timecb_remove below is causing a panic
  // once the block comes in after the timer has timed_out. ignore it?
  ignore_block = true;
#endif
}

void
route_dhash::timed_out_after_wait ()
{
  // retry the block fetch
  execute (cb);
}

void
route_dhash::walk (vec<chord_node> succs)
{
  if (succs.size() == 0) {
    warn << "walk: No luck walking successors, retrying..\n";
    delaycb (5, wrap (mkref(this), &route_dhash::reexecute));
  } else {
    chord_node s = succs.pop_front ();
    cbchallengeID_t cb = wrap (mkref(this), &route_dhash::walk_cachedloc, succs);
    f->get_vnode ()->locations->cacheloc (s.x, s.r, cb);
  }
}

void
route_dhash::walk_cachedloc (vec<chord_node> succs, chordID id, bool ok, chordstat stat)
{
  if (!ok || stat) {
    warn << "walk: challenge of " << id << " failed\n";
    walk (succs);
  } else {
    warn << "walk: challenge of " << id << " succeeded\n";
    dhash_retrieve::execute (f->get_vnode (),
			     id,
			     blockID,
			     NULL,
			     0,
			     0,
			     0,
			     0,
			     ask_for_lease,
			     wrap (mkref(this), &route_dhash::walk_gotblock, succs));
    // cb (DHASH_OK, block, path ());
    // assert (0);
    // try_fetch_block (id, wrap (mkref<>));
  }
}

void
route_dhash::walk_gotblock (vec<chord_node> succs, ptr<dhash_block> block)
{
  if (block)
    cb (DHASH_OK, block, path ());
  else {
    warn << "walk_gotblock failed\n";
    walk (succs);
  }
}

//  A node along the lookup path will send an RPC (request!) to us
//  if it has (or should have) the block we request.  This request
//  is dispatched from dhash::dispatch DHASHPROC_BLOCK to here.
void
route_dhash::block_cb (s_dhash_block_arg *arg)
{
  if (ignore_block)
    return;
  timecb_remove (dcb);
  dcb = NULL;
  if (arg->offset == -1) {
    vec<chord_node> succs;
    for (u_int i = 0; i < arg->nodelist.size (); i++)
      succs.push_back (arg->nodelist[i]);
    warn << "Responsible node did not have block.  Walking\n";
    walk (succs);
    return;
  }

  dhash_retrieve::execute (f->get_vnode (),
			   arg->source,
			   blockID,
			   arg->res.base (),
			   arg->res.size (),
			   arg->attr.size,
			   arg->cookie,
			   arg->lease,
			   ask_for_lease,
			   wrap (mkref(this), &route_dhash::gotblock));
}

void
route_dhash::gotblock (ptr<dhash_block> block)
{
  // XXX fix the path, we might have got the block off a replica
  if (block)
    cb (DHASH_OK, block, path ());
  else
    (*cb) (DHASH_NOENT, NULL, path ());
}

route
route_dhash::path ()
{
  route p = chord_iterator->path ();
  return p;
}
<commit_msg>forgot to set the hop count after fetching the block<commit_after>#include <dhash.h>
#include <route.h>
#include <chord.h>
#include <chord_prot.h>
#include "sfsmisc.h"
#include "arpc.h"
#include "crypt.h"
#include <sys/time.h>
#include "chord_util.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif

unsigned int MTU = (getenv ("DHASH_MTU") ?
		   atoi (getenv ("DHASH_MTU")) :
		   1024);

static int gnonce;

#define LOOKUP_TIMEOUT 30

// ---------------------------------------------------------------------------
// dhash_retrieve

class dhash_retrieve {
private:
  ptr<vnode> clntnode;
  uint npending;
  bool error;
  chordID sourceID;
  chordID blockID;
  cbretrieve_t cb;
  bool askforlease;

  ptr<dhash_block> block;
  int nextblock;
  int numblocks;
  vec<long> seqnos;

  dhash_retrieve (ptr<vnode> clntnode, chordID sourceID, chordID blockID,
		  char *data, u_int len, u_int totsz, int cookie, int lease,
		  bool askforlease, cbretrieve_t cb)
    : clntnode (clntnode),
      sourceID (sourceID),
      blockID (blockID),
      cb (cb),
      askforlease (askforlease)
  {
    block            = New refcounted<dhash_block> ((char *)NULL, totsz);
    block->source    = sourceID;
    block->hops      = 0;
    block->errors    = 0;
    block->lease     = 0;

    if (askforlease)
      block->lease = lease;

    npending = 0;
    error = false;
    nextblock = 1;
    numblocks = 1;
    seqnos.push_back (0);

    if (data) {
      get_remaining_chunks (len, totsz, cookie);
      add_data (data, len, 0);
    } else {
      ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg>;
      arg->v     = sourceID;
      arg->key   = blockID;
      arg->start = 0;
      arg->len   = MTU;
      arg->cookie = 0;
      arg->lease = askforlease;

      ptr<dhash_fetchiter_res> res = New refcounted<dhash_fetchiter_res> ();
      long seqno = clntnode->doRPC (sourceID, dhash_program_1,
				    DHASHPROC_FETCHITER,
				    arg, res,
				    wrap (this,&dhash_retrieve::first_chunk_cb,
					  res, numblocks++));
      seqnos.push_back (seqno);
    }
  }

  void
  get_remaining_chunks (size_t nread, size_t totsz, int cookie)
  {
    //issue the RPCs to get the other chunks
    while (nread < totsz) {
      int length = MIN (MTU, totsz - nread);
      npending++;

      ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg>;
      arg->v     = sourceID;
      arg->key   = blockID;
      arg->start = nread;
      arg->len   = length;
      arg->cookie = cookie;
      arg->lease = askforlease;

      ptr<dhash_fetchiter_res> res = New refcounted<dhash_fetchiter_res> ();
      long seqno = clntnode->doRPC (sourceID, dhash_program_1,
				    DHASHPROC_FETCHITER,
				    arg, res,
				    wrap (this,&dhash_retrieve::finish_block_fetch,
					  res, numblocks++));

      seqnos.push_back (seqno);
      nread += length;
    }
  }

  void
  first_chunk_cb  (ptr<dhash_fetchiter_res> res, int blocknum,
		   clnt_stat err)
  {
    if (err || (res && res->status != DHASH_COMPLETE))
      fail (dhasherr2str (res->status));
    else {
      int cookie     = res->compl_res->cookie;
      size_t totsz   = res->compl_res->attr.size;
      size_t datalen = res->compl_res->res.size ();
      char  *data    = res->compl_res->res.base ();
      size_t dataoff = res->compl_res->offset;

      get_remaining_chunks (datalen, totsz, cookie);
      add_data (data, datalen, dataoff);
      check_finish ();
    }
  }

  void
  add_data (char *data, int len, int off)
  {
    if ((unsigned)(off + len) > block->len)
      fail (strbuf ("bad fragment: off %d, len %d, block %d",
		    off, len, block->len));
    else
      memcpy (&block->data[off], data, len);
  }

  void
  check_finish ()
  {
    if (npending == 0) {
      /* got all chunks */
      if (error)
	block = NULL;
      (*cb) (block);
      delete this;
    }
  }

  void
  finish_block_fetch (ptr<dhash_fetchiter_res> res, int blocknum,
		      clnt_stat err)
  {
    npending--;

    if (err || (res && res->status != DHASH_COMPLETE))
      fail (dhasherr2str (res->status));
    else {
      if (askforlease && block->lease > res->compl_res->lease)
	block->lease = res->compl_res->lease;

      if ((blocknum > nextblock) && (numblocks - blocknum > 1)) {
	warn << "FAST retransmit: " << blockID << " chunk " << nextblock << " being retransmitted\n";

	clntnode->resendRPC(seqnos[nextblock]);
	//only one per fetch; finding more is too much bookkeeping
	numblocks = 0;
      }

      nextblock++;
      add_data (res->compl_res->res.base (), res->compl_res->res.size (),
		res->compl_res->offset);
    }
    check_finish ();
  }

  void
  fail (str errstr)
  {
    warn << "dhash_store failed: " << blockID << ": " << errstr << "\n";
    error = true;
  }

public:
  static void execute (ptr<vnode> clntnode, chordID sourceID, chordID blockID,
		       char *data, u_int len, u_int totsz, int cookie, int lease,
		       bool askforlease, cbretrieve_t cb)
  {
    vNew dhash_retrieve (clntnode, sourceID, blockID, data, len, totsz, cookie, lease, askforlease, cb);
  }
};

// ---------------------------------------------------------------------------
// route_dhash

route_dhash::route_dhash (ptr<route_factory> f,
			  chordID blockID,
			  dhash *dh,
			  bool lease,
			  bool ucs)

  : dh (dh),
    ask_for_lease (lease),
    use_cached_succ (ucs),
    npending (0), fetch_error (false),
    blockID (blockID),
    f (f),
    ignore_block (false)
{

  last_hop = false;
  ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg> ();
  arg->key = blockID;
  f->get_node (&arg->from);
  arg->start = 0;
  arg->len = MTU;
  arg->cookie = 0;
  arg->nonce = gnonce++;
  arg->lease = ask_for_lease;

  // XXX on timeout this never gets unregistered !!!
  dh->register_block_cb (arg->nonce, wrap (mkref(this), &route_dhash::block_cb));

  // Along the chord lookup path, 'arg' will get upcalled to each dhash server (dhash::do_upcall).
  // The dhash server will respond back by sending an RPC *request* to us.  We'll associate the
  // incoming RPC request with 'arg' via gnonce.  We'll field the RPC request in
  // route_dhash::block_cb. Our RPC response is essentially ignored.
  chord_iterator = f->produce_iterator_ptr (blockID, dhash_program_1, DHASHPROC_FETCHITER, arg);
}

route_dhash::~route_dhash ()
{
  delete chord_iterator;
}

void
route_dhash::reexecute ()
{
  // XXX ugly code... duplicates the constructor
  delete chord_iterator;

  timecb_remove (dcb);
  dcb = NULL;

  last_hop = false;
  ptr<s_dhash_fetch_arg> arg = New refcounted<s_dhash_fetch_arg> ();
  arg->key = blockID;
  f->get_node (&arg->from);
  arg->start = 0;
  arg->len = MTU;
  arg->cookie = 0;
  arg->nonce = gnonce++;
  arg->lease = ask_for_lease;

  // XXX on timeout this never gets unregistered !!!
  dh->register_block_cb (arg->nonce, wrap (mkref(this), &route_dhash::block_cb));

  // Along the chord lookup path, 'arg' will get upcalled to each dhash server (dhash::do_upcall).
  // The dhash server will respond back by sending an RPC *request* to us.  We'll associate the
  // incoming RPC request with 'arg' via gnonce.  We'll field the RPC request in
  // route_dhash::block_cb. Our RPC response is essentially ignored.
  chord_iterator = f->produce_iterator_ptr (blockID, dhash_program_1, DHASHPROC_FETCHITER, arg);

  dcb = delaycb (LOOKUP_TIMEOUT, wrap (mkref(this), &route_dhash::timed_out));
  chord_iterator->send (use_cached_succ);
}

void
route_dhash::execute (cb_ret cbi, chordID first_hop)
{
  cb = cbi;
  dcb = delaycb (LOOKUP_TIMEOUT, wrap (mkref(this), &route_dhash::timed_out));
  chord_iterator->send (first_hop);
}

void
route_dhash::execute (cb_ret cbi)
{
  cb = cbi;
  dcb = delaycb (LOOKUP_TIMEOUT, wrap (mkref(this), &route_dhash::timed_out));
  chord_iterator->send (use_cached_succ);
}

void
route_dhash::timed_out ()
{
  warn << "lookup TIMED OUT\n";
  // give the network a bit to heal, then retry the block fetch
  delaycb (5, wrap (mkref(this), &route_dhash::timed_out_after_wait));

#if 0
 (*cb)(DHASH_TIMEDOUT, NULL, path ());
  //XXX what happens if the request comes back
  //    after we've given up on it?
  // gotta do something, the timecb_remove below is causing a panic
  // once the block comes in after the timer has timed_out. ignore it?
  ignore_block = true;
#endif
}

void
route_dhash::timed_out_after_wait ()
{
  // retry the block fetch
  execute (cb);
}

void
route_dhash::walk (vec<chord_node> succs)
{
  if (succs.size() == 0) {
    warn << "walk: No luck walking successors, retrying..\n";
    delaycb (5, wrap (mkref(this), &route_dhash::reexecute));
  } else {
    chord_node s = succs.pop_front ();
    cbchallengeID_t cb = wrap (mkref(this), &route_dhash::walk_cachedloc, succs);
    f->get_vnode ()->locations->cacheloc (s.x, s.r, cb);
  }
}

void
route_dhash::walk_cachedloc (vec<chord_node> succs, chordID id, bool ok, chordstat stat)
{
  if (!ok || stat) {
    warn << "walk: challenge of " << id << " failed\n";
    walk (succs);
  } else {
    warn << "walk: challenge of " << id << " succeeded\n";
    dhash_retrieve::execute (f->get_vnode (),
			     id,
			     blockID,
			     NULL,
			     0,
			     0,
			     0,
			     0,
			     ask_for_lease,
			     wrap (mkref(this), &route_dhash::walk_gotblock, succs));
    // cb (DHASH_OK, block, path ());
    // assert (0);
    // try_fetch_block (id, wrap (mkref<>));
  }
}

void
route_dhash::walk_gotblock (vec<chord_node> succs, ptr<dhash_block> block)
{
  if (block)
    cb (DHASH_OK, block, path ());
  else {
    warn << "walk_gotblock failed\n";
    walk (succs);
  }
}

//  A node along the lookup path will send an RPC (request!) to us
//  if it has (or should have) the block we request.  This request
//  is dispatched from dhash::dispatch DHASHPROC_BLOCK to here.
void
route_dhash::block_cb (s_dhash_block_arg *arg)
{
  if (ignore_block)
    return;
  timecb_remove (dcb);
  dcb = NULL;
  if (arg->offset == -1) {
    vec<chord_node> succs;
    for (u_int i = 0; i < arg->nodelist.size (); i++)
      succs.push_back (arg->nodelist[i]);
    warn << "Responsible node did not have block.  Walking\n";
    walk (succs);
    return;
  }

  dhash_retrieve::execute (f->get_vnode (),
			   arg->source,
			   blockID,
			   arg->res.base (),
			   arg->res.size (),
			   arg->attr.size,
			   arg->cookie,
			   arg->lease,
			   ask_for_lease,
			   wrap (mkref(this), &route_dhash::gotblock));
}

void
route_dhash::gotblock (ptr<dhash_block> block)
{
  // XXX fix the path, we might have got the block off a replica
  block->hops = path ().size ();

  if (block)
    cb (DHASH_OK, block, path ());
  else
    (*cb) (DHASH_NOENT, NULL, path ());
}

route
route_dhash::path ()
{
  route p = chord_iterator->path ();
  return p;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "PlatformKeyboardEvent.h"
#include <windows.h>

#define REPEAT_COUNT_MASK           0x0000FFFF
#define NEW_RELEASE_STATE_MASK      0x80000000
#define PREVIOUS_DOWN_STATE_MASK    0x40000000
#define ALT_KEY_DOWN_MASK           0x20000000

#define HIGH_BIT_MASK_SHORT         0x8000

namespace WebCore {

// FIXME: This is incomplete. We could change this to mirror
// more like what Firefox does, and generate these switch statements
// at build time.
static String keyIdentifierForWindowsKeyCode(short keyCode)
{
    switch (keyCode) {
        case VK_MENU:
            return "Alt";
        case VK_CLEAR:
            return "Clear";
        case VK_DOWN:
            return "Down";
        // "End"
        case VK_END:
            return "End";
        // "Enter"
        case VK_RETURN:
            return "Enter";
        case VK_EXECUTE:
            return "Execute";
        case VK_F1:
            return "F1";
        case VK_F2:
            return "F2";
        case VK_F3:
            return "F3";
        case VK_F4:
            return "F4";
        case VK_F5:
            return "F5";
        case VK_F6:
            return "F6";
        case VK_F7:
            return "F7";
        case VK_F8:
            return "F8";
        case VK_F9:
            return "F9";
        case VK_F10:
            return "F11";
        case VK_F12:
            return "F12";
        case VK_F13:
            return "F13";
        case VK_F14:
            return "F14";
        case VK_F15:
            return "F15";
        case VK_F16:
            return "F16";
        case VK_F17:
            return "F17";
        case VK_F18:
            return "F18";
        case VK_F19:
            return "F19";
        case VK_F20:
            return "F20";
        case VK_F21:
            return "F21";
        case VK_F22:
            return "F22";
        case VK_F23:
            return "F23";
        case VK_F24:
            return "F24";
        case VK_HELP:
            return "Help";
        case VK_HOME:
            return "Home";
        case VK_INSERT:
            return "Insert";
        case VK_LEFT:
            return "Left";
        case VK_NEXT:
            return "PageDown";
        case VK_PRIOR:
            return "PageUp";
        case VK_PAUSE:
            return "Pause";
        case VK_SNAPSHOT:
            return "PrintScreen";
        case VK_RIGHT:
            return "Right";
        case VK_SCROLL:
            return "Scroll";
        case VK_SELECT:
            return "Select";
        case VK_UP:
            return "Up";
        // Standard says that DEL becomes U+007F.
        case VK_DELETE:
            return "U+007F";
        default:
            return String::format("U+%04X", toupper(keyCode));
    }
}

static inline String singleCharacterString(UChar c) { return String(&c, 1); }

PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM virtualKeyCode, LPARAM keyData, UChar characterCode)
    : m_text(singleCharacterString(characterCode))
    , m_unmodifiedText(singleCharacterString(characterCode))
    , m_keyIdentifier(keyIdentifierForWindowsKeyCode(virtualKeyCode))
    , m_isKeyUp((keyData & NEW_RELEASE_STATE_MASK))
    , m_autoRepeat((keyData & REPEAT_COUNT_MASK) > 1)
    , m_WindowsKeyCode(virtualKeyCode)
    , m_isKeypad(false) // FIXME: Need to implement this.
    , m_shiftKey(GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
    , m_ctrlKey(GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
    , m_altKey(keyData & ALT_KEY_DOWN_MASK)
    , m_metaKey(keyData & ALT_KEY_DOWN_MASK) // FIXME: This is not right!
{
}

}
<commit_msg>LAnd piece of alt patch I forgot to.<commit_after>/*
 * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "PlatformKeyboardEvent.h"
#include <windows.h>

#define REPEAT_COUNT_MASK           0x0000FFFF
#define NEW_RELEASE_STATE_MASK      0x80000000
#define PREVIOUS_DOWN_STATE_MASK    0x40000000

#define HIGH_BIT_MASK_SHORT         0x8000

namespace WebCore {

// FIXME: This is incomplete. We could change this to mirror
// more like what Firefox does, and generate these switch statements
// at build time.
static String keyIdentifierForWindowsKeyCode(short keyCode)
{
    switch (keyCode) {
        case VK_MENU:
            return "Alt";
        case VK_CLEAR:
            return "Clear";
        case VK_DOWN:
            return "Down";
        // "End"
        case VK_END:
            return "End";
        // "Enter"
        case VK_RETURN:
            return "Enter";
        case VK_EXECUTE:
            return "Execute";
        case VK_F1:
            return "F1";
        case VK_F2:
            return "F2";
        case VK_F3:
            return "F3";
        case VK_F4:
            return "F4";
        case VK_F5:
            return "F5";
        case VK_F6:
            return "F6";
        case VK_F7:
            return "F7";
        case VK_F8:
            return "F8";
        case VK_F9:
            return "F9";
        case VK_F10:
            return "F11";
        case VK_F12:
            return "F12";
        case VK_F13:
            return "F13";
        case VK_F14:
            return "F14";
        case VK_F15:
            return "F15";
        case VK_F16:
            return "F16";
        case VK_F17:
            return "F17";
        case VK_F18:
            return "F18";
        case VK_F19:
            return "F19";
        case VK_F20:
            return "F20";
        case VK_F21:
            return "F21";
        case VK_F22:
            return "F22";
        case VK_F23:
            return "F23";
        case VK_F24:
            return "F24";
        case VK_HELP:
            return "Help";
        case VK_HOME:
            return "Home";
        case VK_INSERT:
            return "Insert";
        case VK_LEFT:
            return "Left";
        case VK_NEXT:
            return "PageDown";
        case VK_PRIOR:
            return "PageUp";
        case VK_PAUSE:
            return "Pause";
        case VK_SNAPSHOT:
            return "PrintScreen";
        case VK_RIGHT:
            return "Right";
        case VK_SCROLL:
            return "Scroll";
        case VK_SELECT:
            return "Select";
        case VK_UP:
            return "Up";
        // Standard says that DEL becomes U+007F.
        case VK_DELETE:
            return "U+007F";
        default:
            return String::format("U+%04X", toupper(keyCode));
    }
}

static inline String singleCharacterString(UChar c) { return String(&c, 1); }

PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM virtualKeyCode, LPARAM keyData, UChar characterCode)
    : m_text(singleCharacterString(characterCode))
    , m_unmodifiedText(singleCharacterString(characterCode))
    , m_keyIdentifier(keyIdentifierForWindowsKeyCode(virtualKeyCode))
    , m_isKeyUp((keyData & NEW_RELEASE_STATE_MASK))
    , m_autoRepeat((keyData & REPEAT_COUNT_MASK) > 1)
    , m_WindowsKeyCode(virtualKeyCode)
    , m_isKeypad(false) // FIXME: Need to implement this.
    , m_shiftKey(GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
    , m_ctrlKey(GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
    , m_altKey(GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
    , m_metaKey(m_altKey)
{
}

}
<|endoftext|>


<commit_before>#include <GarrysMod/Lua/Interface.h>
#include <GarrysMod/Lua/LuaInterface.h>
#include <SymbolFinder.hpp>
#include <MologieDetours/detours.h>
#include <stdexcept>
#include <string>
#include <stdint.h>
#include <stdio.h>
#include <sha1.h>

#define HASHER_METATABLE "SHA1"
#define HASHER_TYPE 31

#define THROW_ERROR( error ) ( LUA->ThrowError( error ), 0 )
#define LUA_ERROR( ) THROW_ERROR( LUA->GetString( ) )

#define GET_USERDATA( index ) reinterpret_cast<GarrysMod::Lua::UserData *>( LUA->GetUserdata( index ) )
#define GET_HASHER( index ) reinterpret_cast<sha1_context *>( GET_USERDATA( index )->data )
#define VALIDATE_HASHER( hasher ) if( hasher == 0 ) return THROW_ERROR( HASHER_METATABLE " object is not valid" )

#if defined _WIN32

#define snprintf _snprintf

#define FASTCALL __fastcall
#define THISCALL __thiscall

#define SERVER_BINARY "server.dll"

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( "\x55\x8B\xEC\x83\xEC\x18\x53\x56\x8B\x75\x08\x83\xC6\x04\x83\x7E" )
#define ADDORUPDATEFILE_SYMLEN 16

#elif defined __linux || defined __APPLE__

#define CDECL __attribute__((cdecl))

#if defined __linux

#define SERVER_BINARY "garrysmod/bin/server_srv.so"

#define SYMBOL_PREFIX "@"

#else

#define SERVER_BINARY "garrysmod/bin/server.dylib"

#define SYMBOL_PREFIX "@_"

#endif

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( SYMBOL_PREFIX "_ZN12GModDataPack15AddOrUpdateFileEP7LuaFileb" )
#define ADDORUPDATEFILE_SYMLEN 0

#endif

GarrysMod::Lua::ILuaInterface *lua = NULL;

class GModDataPack;

struct LuaFile
{
	uint32_t skip;
	const char *path;
};

#if defined _WIN32

typedef void ( THISCALL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#elif defined __linux || defined __APPLE__

typedef void ( CDECL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#endif

AddOrUpdateFile_t AddOrUpdateFile = NULL;
MologieDetours::Detour<AddOrUpdateFile_t> *AddOrUpdateFile_d = NULL;

#if defined _WIN32

void FASTCALL AddOrUpdateFile_h( GModDataPack *self, void *, LuaFile *file, bool b )

#elif defined __linux || defined __APPLE__

void CDECL AddOrUpdateFile_h( GModDataPack *self, LuaFile *file, bool b )

#endif

{
	lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );
	if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
	{
		lua->GetField( -1, "hook" );
		if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
		{
			lua->GetField( -1, "Run" );
			if( lua->IsType( -1, GarrysMod::Lua::Type::FUNCTION ) )
			{
				lua->PushString( "AddOrUpdateCSLuaFile" );

				lua->PushString( file->path );
				lua->PushBool( b );

				if( lua->PCall( 3, 1, 0 ) != 0 )
				{
					lua->Msg( "[luapack_internal] %s\n", lua->GetString( ) );
					lua->Pop( 3 );
					return AddOrUpdateFile( self, file, b );
				}

				if( lua->IsType( -1, GarrysMod::Lua::Type::BOOL ) && lua->GetBool( ) )
				{
					lua->Pop( 3 );
					return;
				}

				lua->Pop( 1 );
			}
			else
			{
				lua->Pop( 1 );
			}
		}

		lua->Pop( 1 );
	}

	lua->Pop( 1 );
	return AddOrUpdateFile( self, file, b );
}

LUA_FUNCTION_STATIC( hasher__new )
{
	try
	{
		sha1_context *context = new sha1_context;
		sha1_starts( context );

		void *luadata = LUA->NewUserdata( sizeof( GarrysMod::Lua::UserData ) );
		GarrysMod::Lua::UserData *userdata = reinterpret_cast<GarrysMod::Lua::UserData *>( luadata );
		userdata->data = context;
		userdata->type = HASHER_TYPE;

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );
		LUA->SetMetaTable( -2 );

		return 1;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

LUA_FUNCTION_STATIC( hasher__gc )
{
	LUA->CheckType( 1, HASHER_TYPE );

	GarrysMod::Lua::UserData *userdata = GET_USERDATA( 1 );
	sha1_context *hasher = reinterpret_cast<sha1_context *>( userdata->data );
	VALIDATE_HASHER( hasher );

	userdata->data = 0;

	delete hasher;
	return 0;
}

LUA_FUNCTION_STATIC( hasher_update )
{
	LUA->CheckType( 1, HASHER_TYPE );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint32_t len = 0;
	const uint8_t *data = reinterpret_cast<const uint8_t *>( LUA->GetString( 2, &len ) );

	sha1_update( hasher, data, len );

	return 0;
}

LUA_FUNCTION_STATIC( hasher_final )
{
	LUA->CheckType( 1, HASHER_TYPE );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint8_t digest[20];
	sha1_finish( hasher, digest );

	LUA->PushString( reinterpret_cast<const char *>( digest ), sizeof( digest ) );
	return 1;
}

static void SubstituteChar( std::string &path, char part, char sub )
{
	size_t pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, 1 );
		path.insert( pos, 1, sub );
		pos = path.find( part, pos + 1 );
	}
}

static void RemovePart( std::string &path, const char *part )
{
	size_t len = strlen( part ), pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, len );
		pos = path.find( part, pos );
	}
}

static bool HasWhitelistedExtension( const std::string &path )
{
	size_t extstart = path.rfind( '.' );
	if( extstart != path.npos )
	{
		size_t lastslash = path.rfind( '/' );
		if( lastslash != path.npos && lastslash > extstart )
			return false;

		std::string ext = path.substr( extstart + 1 );
		return ext == "txt" || ext == "dat" || ext == "lua";
	}

	return false;
}

static bool Rename( const char *f, const char *t )
{
	std::string from = "garrysmod/";
	from += f;
	if( !HasWhitelistedExtension( from ) )
		return false;

	std::string to = "garrysmod/";
	to += t;
	if( !HasWhitelistedExtension( to ) )
		return false;

	SubstituteChar( from, '\\', '/' );
	RemovePart( from, "../" );
	RemovePart( from, "./" );

	SubstituteChar( to, '\\', '/' );
	RemovePart( to, "../" );
	RemovePart( to, "./" );

	return rename( from.c_str( ), to.c_str( ) ) == 0;
}

LUA_FUNCTION_STATIC( luapack_rename )
{
	LUA->CheckType( 1, GarrysMod::Lua::Type::STRING );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	LUA->PushBool( Rename( LUA->GetString( 1 ), LUA->GetString( 2 ) ) );
	return 1;
}

GMOD_MODULE_OPEN( )
{
	lua = reinterpret_cast<GarrysMod::Lua::ILuaInterface *>( LUA );

	try
	{
		lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );

		lua->GetField( -1, "luapack" );
		if( !lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
			throw std::runtime_error( "luapack table not found" );

		lua->PushCFunction( luapack_rename );
		lua->SetField( -2, "Rename" );

		lua->PushCFunction( hasher__new );
		lua->SetField( -2, HASHER_METATABLE );

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );

		LUA->Push( -1 );
		LUA->SetField( -2, "__index" );

		LUA->PushCFunction( hasher__gc );
		LUA->SetField( -2, "__gc" );

		LUA->PushCFunction( hasher_update );
		LUA->SetField( -2, "Update" );

		LUA->PushCFunction( hasher_final );
		LUA->SetField( -2, "Final" );

		SymbolFinder symfinder;

		AddOrUpdateFile = reinterpret_cast<AddOrUpdateFile_t>( symfinder.ResolveOnBinary( SERVER_BINARY, ADDORUPDATEFILE_SYM, ADDORUPDATEFILE_SYMLEN ) );
		if( AddOrUpdateFile == NULL )
			throw std::runtime_error( "GModDataPack::AddOrUpdateFile detour failed" );

		AddOrUpdateFile_d = new MologieDetours::Detour<AddOrUpdateFile_t>( AddOrUpdateFile, reinterpret_cast<AddOrUpdateFile_t>( AddOrUpdateFile_h ) );

		AddOrUpdateFile = AddOrUpdateFile_d->GetOriginalFunction( );

		lua->Msg( "[luapack_internal] GModDataPack::AddOrUpdateFile detoured.\n" );

		return 0;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

GMOD_MODULE_CLOSE( )
{
	(void)state;
	delete AddOrUpdateFile_d;
	return 0;
}<commit_msg>Correct path separators for each OS.<commit_after>#include <GarrysMod/Lua/Interface.h>
#include <GarrysMod/Lua/LuaInterface.h>
#include <SymbolFinder.hpp>
#include <MologieDetours/detours.h>
#include <stdexcept>
#include <string>
#include <stdint.h>
#include <stdio.h>
#include <sha1.h>

#define HASHER_METATABLE "SHA1"
#define HASHER_TYPE 31

#define THROW_ERROR( error ) ( LUA->ThrowError( error ), 0 )
#define LUA_ERROR( ) THROW_ERROR( LUA->GetString( ) )

#define GET_USERDATA( index ) reinterpret_cast<GarrysMod::Lua::UserData *>( LUA->GetUserdata( index ) )
#define GET_HASHER( index ) reinterpret_cast<sha1_context *>( GET_USERDATA( index )->data )
#define VALIDATE_HASHER( hasher ) if( hasher == 0 ) return THROW_ERROR( HASHER_METATABLE " object is not valid" )

#if defined _WIN32

#define GOOD_SEPARATOR '\\'
#define BAD_SEPARATOR '/'

#define PARENT_DIRECTORY "..\\"
#define CURRENT_DIRECTORY ".\\"

#define snprintf _snprintf

#define FASTCALL __fastcall
#define THISCALL __thiscall

#define SERVER_BINARY "server.dll"

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( "\x55\x8B\xEC\x83\xEC\x18\x53\x56\x8B\x75\x08\x83\xC6\x04\x83\x7E" )
#define ADDORUPDATEFILE_SYMLEN 16

#elif defined __linux || defined __APPLE__

#define GOOD_SEPARATOR '/'
#define BAD_SEPARATOR '\\'

#define PARENT_DIRECTORY "../"
#define CURRENT_DIRECTORY "./"

#define CDECL __attribute__((cdecl))

#if defined __linux

#define SERVER_BINARY "garrysmod/bin/server_srv.so"

#define SYMBOL_PREFIX "@"

#else

#define SERVER_BINARY "garrysmod/bin/server.dylib"

#define SYMBOL_PREFIX "@_"

#endif

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( SYMBOL_PREFIX "_ZN12GModDataPack15AddOrUpdateFileEP7LuaFileb" )
#define ADDORUPDATEFILE_SYMLEN 0

#endif

GarrysMod::Lua::ILuaInterface *lua = NULL;

class GModDataPack;

struct LuaFile
{
	uint32_t skip;
	const char *path;
};

#if defined _WIN32

typedef void ( THISCALL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#elif defined __linux || defined __APPLE__

typedef void ( CDECL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#endif

AddOrUpdateFile_t AddOrUpdateFile = NULL;
MologieDetours::Detour<AddOrUpdateFile_t> *AddOrUpdateFile_d = NULL;

#if defined _WIN32

void FASTCALL AddOrUpdateFile_h( GModDataPack *self, void *, LuaFile *file, bool b )

#elif defined __linux || defined __APPLE__

void CDECL AddOrUpdateFile_h( GModDataPack *self, LuaFile *file, bool b )

#endif

{
	lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );
	if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
	{
		lua->GetField( -1, "hook" );
		if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
		{
			lua->GetField( -1, "Run" );
			if( lua->IsType( -1, GarrysMod::Lua::Type::FUNCTION ) )
			{
				lua->PushString( "AddOrUpdateCSLuaFile" );

				lua->PushString( file->path );
				lua->PushBool( b );

				if( lua->PCall( 3, 1, 0 ) != 0 )
				{
					lua->Msg( "[luapack_internal] %s\n", lua->GetString( ) );
					lua->Pop( 3 );
					return AddOrUpdateFile( self, file, b );
				}

				if( lua->IsType( -1, GarrysMod::Lua::Type::BOOL ) && lua->GetBool( ) )
				{
					lua->Pop( 3 );
					return;
				}

				lua->Pop( 1 );
			}
			else
			{
				lua->Pop( 1 );
			}
		}

		lua->Pop( 1 );
	}

	lua->Pop( 1 );
	return AddOrUpdateFile( self, file, b );
}

LUA_FUNCTION_STATIC( hasher__new )
{
	try
	{
		sha1_context *context = new sha1_context;
		sha1_starts( context );

		void *luadata = LUA->NewUserdata( sizeof( GarrysMod::Lua::UserData ) );
		GarrysMod::Lua::UserData *userdata = reinterpret_cast<GarrysMod::Lua::UserData *>( luadata );
		userdata->data = context;
		userdata->type = HASHER_TYPE;

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );
		LUA->SetMetaTable( -2 );

		return 1;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

LUA_FUNCTION_STATIC( hasher__gc )
{
	LUA->CheckType( 1, HASHER_TYPE );

	GarrysMod::Lua::UserData *userdata = GET_USERDATA( 1 );
	sha1_context *hasher = reinterpret_cast<sha1_context *>( userdata->data );
	VALIDATE_HASHER( hasher );

	userdata->data = 0;

	delete hasher;
	return 0;
}

LUA_FUNCTION_STATIC( hasher_update )
{
	LUA->CheckType( 1, HASHER_TYPE );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint32_t len = 0;
	const uint8_t *data = reinterpret_cast<const uint8_t *>( LUA->GetString( 2, &len ) );

	sha1_update( hasher, data, len );

	return 0;
}

LUA_FUNCTION_STATIC( hasher_final )
{
	LUA->CheckType( 1, HASHER_TYPE );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint8_t digest[20];
	sha1_finish( hasher, digest );

	LUA->PushString( reinterpret_cast<const char *>( digest ), sizeof( digest ) );
	return 1;
}

static void SubstituteChar( std::string &path, char part, char sub )
{
	size_t pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, 1 );
		path.insert( pos, 1, sub );
		pos = path.find( part, pos + 1 );
	}
}

static void RemovePart( std::string &path, const char *part )
{
	size_t len = strlen( part ), pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, len );
		pos = path.find( part, pos );
	}
}

static bool HasWhitelistedExtension( const std::string &path )
{
	size_t extstart = path.rfind( '.' );
	if( extstart != path.npos )
	{
		size_t lastslash = path.rfind( GOOD_SEPARATOR );
		if( lastslash != path.npos && lastslash > extstart )
			return false;

		std::string ext = path.substr( extstart + 1 );
		return ext == "txt" || ext == "dat" || ext == "lua";
	}

	return false;
}

static bool Rename( const char *f, const char *t )
{
	std::string from = "garrysmod";
	from += GOOD_SEPARATOR;
	from += f;

	SubstituteChar( from, BAD_SEPARATOR, GOOD_SEPARATOR );
	if( !HasWhitelistedExtension( from ) )
		return false;

	std::string to = "garrysmod";
	to += GOOD_SEPARATOR;
	to += t;

	SubstituteChar( to, BAD_SEPARATOR, GOOD_SEPARATOR );
	if( !HasWhitelistedExtension( to ) )
		return false;

	RemovePart( from, PARENT_DIRECTORY );
	RemovePart( from, CURRENT_DIRECTORY );

	RemovePart( to, PARENT_DIRECTORY );
	RemovePart( to, CURRENT_DIRECTORY );

	return rename( from.c_str( ), to.c_str( ) ) == 0;
}

LUA_FUNCTION_STATIC( luapack_rename )
{
	LUA->CheckType( 1, GarrysMod::Lua::Type::STRING );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	LUA->PushBool( Rename( LUA->GetString( 1 ), LUA->GetString( 2 ) ) );
	return 1;
}

GMOD_MODULE_OPEN( )
{
	lua = reinterpret_cast<GarrysMod::Lua::ILuaInterface *>( LUA );

	try
	{
		lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );

		lua->GetField( -1, "luapack" );
		if( !lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
			throw std::runtime_error( "luapack table not found" );

		lua->PushCFunction( luapack_rename );
		lua->SetField( -2, "Rename" );

		lua->PushCFunction( hasher__new );
		lua->SetField( -2, HASHER_METATABLE );

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );

		LUA->Push( -1 );
		LUA->SetField( -2, "__index" );

		LUA->PushCFunction( hasher__gc );
		LUA->SetField( -2, "__gc" );

		LUA->PushCFunction( hasher_update );
		LUA->SetField( -2, "Update" );

		LUA->PushCFunction( hasher_final );
		LUA->SetField( -2, "Final" );

		SymbolFinder symfinder;

		AddOrUpdateFile = reinterpret_cast<AddOrUpdateFile_t>( symfinder.ResolveOnBinary( SERVER_BINARY, ADDORUPDATEFILE_SYM, ADDORUPDATEFILE_SYMLEN ) );
		if( AddOrUpdateFile == NULL )
			throw std::runtime_error( "GModDataPack::AddOrUpdateFile detour failed" );

		AddOrUpdateFile_d = new MologieDetours::Detour<AddOrUpdateFile_t>( AddOrUpdateFile, reinterpret_cast<AddOrUpdateFile_t>( AddOrUpdateFile_h ) );

		AddOrUpdateFile = AddOrUpdateFile_d->GetOriginalFunction( );

		lua->Msg( "[luapack_internal] GModDataPack::AddOrUpdateFile detoured.\n" );

		return 0;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

GMOD_MODULE_CLOSE( )
{
	(void)state;
	delete AddOrUpdateFile_d;
	return 0;
}<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.hh"
#include "pushnotification/applepush.hh"
#include "pushnotification/googlepush.hh"
#include "pushnotification/microsoftpush.hh"
#include "pushnotification/firebasepush.hh"
#include "pushnotification/pushnotificationservice.hh"

#include <unistd.h>
#include <string>

#include <ortp/ortp.h>
#include <sofia-sip/url.h>
#include <sofia-sip/base64.h>

static const int MAX_QUEUE_SIZE = 3000;
// static const int PRINT_STATS_TIMEOUT = 3000;	/* In milliseconds. */

struct PusherArgs {
	string prefix;
	string pntype;
	bool debug;
	string appid;
	vector<string> pntok;
	string apikey;
	string packageSID;
	void usage(const char *app) {
		cout << app
			 << " --pntype google|firebase|wp|w10|apple --appid id --key apikey(secretkey) --sid ms-app://value --prefix dir --debug --pntok id1 (id2 id3 ...)"
			 << endl;
	}

	const char *parseUrlParams(const char *params) {
		char tmp[64];
		if (url_param(params, "pn-type", tmp, sizeof(tmp)) == 0) {
			return "no pn-type";
		} else
			pntype = tmp;

		if (url_param(params, "app-id", tmp, sizeof(tmp)) == 0) {
			return "no app-id";
		} else
			appid = tmp;

		if (url_param(params, "pn-tok", tmp, sizeof(tmp)) == 0) {
			return "no pn-tok";
		} else
			pntok.push_back(tmp);

		return NULL;
	}

	void parse(int argc, char *argv[]) {
		prefix = "/etc/flexisip";
		pntype = "";
#define EQ0(i, name) (strcmp(name, argv[i]) == 0)
#define EQ1(i, name) (strcmp(name, argv[i]) == 0 && argc > i)
		for (int i = 1; i < argc; ++i) {
			if (EQ1(i, "--prefix")) {
				prefix = argv[++i];
			} else if (EQ1(i, "--pntype")) {
				pntype = argv[++i];
			} else if (EQ1(i, "--appid")) {
				appid = argv[++i];
			} else if (EQ1(i, "--sid")) {
				packageSID = argv[++i];
			} else if (EQ0(i, "--debug")) {
				debug = true;
			} else if (EQ1(i, "--pntok")) {
				while (i+1 < argc && strncmp(argv[i+1], "--", 2) != 0) {
					i++;
					pntok.push_back(argv[i]);
				}
			} else if (EQ1(i, "--key")) {
				apikey = argv[++i];
			} else if (EQ1(i, "--raw")) {
				const char *res = parseUrlParams(argv[++i]);
				if (res) {
					cerr << "? raw " << res << endl;
					exit(-1);
				}
			} else if (EQ0(i, "--help") || EQ0(i, "-h")) {
				usage(*argv);
				exit(0);
			} else {
				cerr << "? arg" << i << " " << argv[i] << endl;
				usage(*argv);
				exit(-1);
			}
		}
	}
};

static vector<shared_ptr<PushNotificationRequest>> createRequestFromArgs(const PusherArgs &args) {
	vector<shared_ptr<PushNotificationRequest>> result;
	for (auto it = args.pntok.begin(); it != args.pntok.end(); it++) {
		auto pntok = *it;
		PushInfo pinfo;
		pinfo.mType = args.pntype;
		pinfo.mFromName = "Pusher";
		pinfo.mFromUri = "sip:toto@sip.linphone.org";
		if (args.pntype == "google") {
			pinfo.mCallId = "fb14b5fe-a9ab-1231-9485-7d582244ba3d";
			pinfo.mFromName = "+33681741738";
			pinfo.mDeviceToken = pntok;
			pinfo.mAppId = args.appid;
			pinfo.mApiKey = args.apikey;
			result.push_back(make_shared<GooglePushNotificationRequest>(pinfo));
		} else if (args.pntype == "firebase") {
			pinfo.mCallId = "fb14b5fe-a9ab-1231-9485-7d582244ba3d";
			pinfo.mFromName = "+33681741738";
			pinfo.mDeviceToken = pntok;
			pinfo.mAppId = args.appid;
			pinfo.mApiKey = args.apikey;
			result.push_back(make_shared<FirebasePushNotificationRequest>(pinfo));
		} else if (args.pntype == "wp") {
			pinfo.mAppId = args.appid;
			pinfo.mDeviceToken = pntok;
			pinfo.mEvent = PushInfo::Message;
			pinfo.mText = "Hi here!";
			result.push_back(make_shared<WindowsPhonePushNotificationRequest>(pinfo));
		} else if (args.pntype == "w10") {
			pinfo.mAppId = args.appid;
			pinfo.mEvent = PushInfo::Message;
			pinfo.mDeviceToken = pntok;
			pinfo.mText = "Hi here!";
			result.push_back(make_shared<WindowsPhonePushNotificationRequest>(pinfo));
		} else if (args.pntype == "apple") {
			pinfo.mAlertMsgId = "IM_MSG";
			pinfo.mAlertSound = "msg.caf";
			pinfo.mAppId = args.appid;
			pinfo.mDeviceToken = pntok;
			pinfo.mTtl = 2592000;
			//pinfo.mTtl = 60;
			result.push_back(make_shared<ApplePushNotificationRequest>(pinfo));
		} else {
			cerr << "? push pntype " << args.pntype << endl;
			exit(-1);
		}
	}
	return result;
}

int main(int argc, char *argv[]) {
	int ret = 0;
	PusherArgs args;
	args.parse(argc, argv);

	flexisip::log::preinit(sUseSyslog, args.debug);
	flexisip::log::initLogs(sUseSyslog, "debug", false);
	flexisip::log::updateFilter("%Severity% >= debug");

	{
		PushNotificationService service(MAX_QUEUE_SIZE);

		if (args.pntype == "apple") {
			service.setupiOSClient(args.prefix + "/apn", "");
		} else if (args.pntype == "google") {
			map<string, string> googleKey;
			googleKey.insert(make_pair(args.appid, args.apikey));
			service.setupAndroidClient(googleKey);
		} else if (args.pntype == "firebase") {
			map<string, string> firebaseKey;
			firebaseKey.insert(make_pair(args.appid, args.apikey));
			service.setupFirebaseClient(firebaseKey);
		} else if (args.pntype == "wp" || args.pntype == "w10") {
			service.setupWindowsPhoneClient(args.packageSID, args.apikey);
		}

		auto pn = createRequestFromArgs(args);
		for (auto it = pn.begin(); it != pn.end(); it++) {
			auto push = *it;
			ret += service.sendPush(push);
		}
		if (ret == 0) {
			while (!service.isIdle()) {
				sleep(1);
			}
		} else {
			cerr << "fail to send request, aborting" << endl;
		}
	}
	cerr << "job is done, thanks for using " << argv[0] << ". Bye!" << endl;
	return ret;
}
<commit_msg>Fix compilation issue<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.hh"
#include "pushnotification/applepush.hh"
#include "pushnotification/googlepush.hh"
#include "pushnotification/microsoftpush.hh"
#include "pushnotification/firebasepush.hh"
#include "pushnotification/pushnotificationservice.hh"

#include <unistd.h>
#include <string>

#include <ortp/ortp.h>
#include <sofia-sip/url.h>
#include <sofia-sip/base64.h>

static const int MAX_QUEUE_SIZE = 3000;
// static const int PRINT_STATS_TIMEOUT = 3000;	/* In milliseconds. */

struct PusherArgs {
	string prefix;
	string pntype;
	bool debug;
	string appid;
	vector<string> pntok;
	string apikey;
	string packageSID;
	void usage(const char *app) {
		cout << app
			 << " --pntype google|firebase|wp|w10|apple --appid id --key apikey(secretkey) --sid ms-app://value --prefix dir --debug --pntok id1 (id2 id3 ...)"
			 << endl;
	}

	const char *parseUrlParams(const char *params) {
		char tmp[64];
		if (url_param(params, "pn-type", tmp, sizeof(tmp)) == 0) {
			return "no pn-type";
		} else
			pntype = tmp;

		if (url_param(params, "app-id", tmp, sizeof(tmp)) == 0) {
			return "no app-id";
		} else
			appid = tmp;

		if (url_param(params, "pn-tok", tmp, sizeof(tmp)) == 0) {
			return "no pn-tok";
		} else
			pntok.push_back(tmp);

		return NULL;
	}

	void parse(int argc, char *argv[]) {
		prefix = "/etc/flexisip";
		pntype = "";
#define EQ0(i, name) (strcmp(name, argv[i]) == 0)
#define EQ1(i, name) (strcmp(name, argv[i]) == 0 && argc > i)
		for (int i = 1; i < argc; ++i) {
			if (EQ1(i, "--prefix")) {
				prefix = argv[++i];
			} else if (EQ1(i, "--pntype")) {
				pntype = argv[++i];
			} else if (EQ1(i, "--appid")) {
				appid = argv[++i];
			} else if (EQ1(i, "--sid")) {
				packageSID = argv[++i];
			} else if (EQ0(i, "--debug")) {
				debug = true;
			} else if (EQ1(i, "--pntok")) {
				while (i+1 < argc && strncmp(argv[i+1], "--", 2) != 0) {
					i++;
					pntok.push_back(argv[i]);
				}
			} else if (EQ1(i, "--key")) {
				apikey = argv[++i];
			} else if (EQ1(i, "--raw")) {
				const char *res = parseUrlParams(argv[++i]);
				if (res) {
					cerr << "? raw " << res << endl;
					exit(-1);
				}
			} else if (EQ0(i, "--help") || EQ0(i, "-h")) {
				usage(*argv);
				exit(0);
			} else {
				cerr << "? arg" << i << " " << argv[i] << endl;
				usage(*argv);
				exit(-1);
			}
		}
	}
};

static vector<shared_ptr<PushNotificationRequest>> createRequestFromArgs(const PusherArgs &args) {
	vector<shared_ptr<PushNotificationRequest>> result;
	for (auto it = args.pntok.begin(); it != args.pntok.end(); it++) {
		auto pntok = *it;
		PushInfo pinfo;
		pinfo.mType = args.pntype;
		pinfo.mFromName = "Pusher";
		pinfo.mFromUri = "sip:toto@sip.linphone.org";
		if (args.pntype == "google") {
			pinfo.mCallId = "fb14b5fe-a9ab-1231-9485-7d582244ba3d";
			pinfo.mFromName = "+33681741738";
			pinfo.mDeviceToken = pntok;
			pinfo.mAppId = args.appid;
			pinfo.mApiKey = args.apikey;
			result.push_back(make_shared<GooglePushNotificationRequest>(pinfo));
		} else if (args.pntype == "firebase") {
			pinfo.mCallId = "fb14b5fe-a9ab-1231-9485-7d582244ba3d";
			pinfo.mFromName = "+33681741738";
			pinfo.mDeviceToken = pntok;
			pinfo.mAppId = args.appid;
			pinfo.mApiKey = args.apikey;
			result.push_back(make_shared<FirebasePushNotificationRequest>(pinfo));
		} else if (args.pntype == "wp") {
			pinfo.mAppId = args.appid;
			pinfo.mDeviceToken = pntok;
			pinfo.mEvent = PushInfo::Message;
			pinfo.mText = "Hi here!";
			result.push_back(make_shared<WindowsPhonePushNotificationRequest>(pinfo));
		} else if (args.pntype == "w10") {
			pinfo.mAppId = args.appid;
			pinfo.mEvent = PushInfo::Message;
			pinfo.mDeviceToken = pntok;
			pinfo.mText = "Hi here!";
			result.push_back(make_shared<WindowsPhonePushNotificationRequest>(pinfo));
		} else if (args.pntype == "apple") {
			pinfo.mAlertMsgId = "IM_MSG";
			pinfo.mAlertSound = "msg.caf";
			pinfo.mAppId = args.appid;
			pinfo.mDeviceToken = pntok;
			pinfo.mTtl = 2592000;
			//pinfo.mTtl = 60;
			result.push_back(make_shared<ApplePushNotificationRequest>(pinfo));
		} else {
			cerr << "? push pntype " << args.pntype << endl;
			exit(-1);
		}
	}
	return result;
}

int main(int argc, char *argv[]) {
	int ret = 0;
	PusherArgs args;
	args.parse(argc, argv);

	flexisip::log::preinit(sUseSyslog, args.debug);
	flexisip::log::initLogs(sUseSyslog, "debug", "error", false);
	flexisip::log::updateFilter("%Severity% >= debug");

	{
		PushNotificationService service(MAX_QUEUE_SIZE);

		if (args.pntype == "apple") {
			service.setupiOSClient(args.prefix + "/apn", "");
		} else if (args.pntype == "google") {
			map<string, string> googleKey;
			googleKey.insert(make_pair(args.appid, args.apikey));
			service.setupAndroidClient(googleKey);
		} else if (args.pntype == "firebase") {
			map<string, string> firebaseKey;
			firebaseKey.insert(make_pair(args.appid, args.apikey));
			service.setupFirebaseClient(firebaseKey);
		} else if (args.pntype == "wp" || args.pntype == "w10") {
			service.setupWindowsPhoneClient(args.packageSID, args.apikey);
		}

		auto pn = createRequestFromArgs(args);
		for (auto it = pn.begin(); it != pn.end(); it++) {
			auto push = *it;
			ret += service.sendPush(push);
		}
		if (ret == 0) {
			while (!service.isIdle()) {
				sleep(1);
			}
		} else {
			cerr << "fail to send request, aborting" << endl;
		}
	}
	cerr << "job is done, thanks for using " << argv[0] << ". Bye!" << endl;
	return ret;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Tom van Dijk, Johannes Kepler University Linz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <csignal>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sys/time.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include "cxxopts.hpp"
#include "game.hpp"
#include "oink.hpp"
#include "solvers.hpp"
#include "verifier.hpp"
#include "tools/getrss.h"

using namespace pg;

/*------------------------------------------------------------------------*/

static double
wctime()
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return time.tv_sec + 1E-6 * time.tv_usec;
}

static double t_start;

/*------------------------------------------------------------------------*/

// timestamp_filter adds a timestamp at the beginning of every line.
namespace io = boost::iostreams;
class timestamp_filter : public io::output_filter
{
public:
    timestamp_filter() {}
    struct category : io::output_filter::category, io::flushable_tag { };

    template<typename Sink> bool put(Sink& snk, char c);
    template<typename Device> void close(Device&);
    template<typename Sink> bool flush(Sink& snk);

private:
    bool is_start = true;
    char sz[16];
    const char* pos = NULL;
    const char* end = NULL;
};

template<typename Sink>
bool timestamp_filter::put(Sink& dest, char c)
{
    if (is_start) {
        if (c == '\n') return true;  // ignore consecutive endl
        is_start = false;
        pos = sz;
        end = sz + snprintf(sz, 16, "[% 8.2f] ", wctime() - t_start);
    }

    while (pos != end) {
        if (!io::put(dest, *pos)) return false;
        pos++;
    }

    if (!io::put(dest, c)) return false;
    if (c == '\n') is_start = true;

    return true;
}

template<typename Sink>
bool timestamp_filter::flush(Sink& dest)
{
    while (pos != end) {
        if (!io::put(dest, *pos)) return false;
        pos++;
    }

    return io::flush(dest);
}

template<typename Device>
void timestamp_filter::close(Device&)
{
    is_start = true;
    pos = end = NULL;
}

// global variable so signal handlers can work with it
io::filtering_ostream out;

/*------------------------------------------------------------------------*/

static void (*sig_int_handler)(int);
static void (*sig_segv_handler)(int);
static void (*sig_abrt_handler)(int);
static void (*sig_term_handler)(int);
static void (*sig_alrm_handler)(int);

static void
resetsighandlers(void)
{
    (void)signal(SIGINT, sig_int_handler);
    (void)signal(SIGSEGV, sig_segv_handler);
    (void)signal(SIGABRT, sig_abrt_handler);
    (void)signal(SIGTERM, sig_term_handler);
    (void)signal(SIGALRM, sig_alrm_handler);
}

static void
catchsig(int sig)
{
    // note: this can actually deadlock because we are writing to stdout...

    if (sig == SIGALRM) {
        resetsighandlers();
        out << std::endl << "terminated due to timeout" << std::endl;
        out.flush();
        exit(-1);
    } else if (sig == SIGINT) {
        // CTRL-C
        resetsighandlers();
        out << std::endl << "received INT signal" << std::endl;
        out.flush();
        exit(-SIGINT);
    } else if (sig == SIGABRT) {
        // really bad
        resetsighandlers();
        out << std::endl << "terminated due to ABORT signal" << std::endl;
        out.flush();
        exit(-SIGABRT);
        raise(sig);
    } else {
        resetsighandlers();
        out << std::endl << "terminated due to signal " << sig << std::endl;
        out.flush();
        exit(-sig);
    }
}

static void
setsighandlers(void)
{
    sig_int_handler = signal(SIGINT, catchsig);
    sig_segv_handler = signal(SIGSEGV, catchsig);
    sig_abrt_handler = signal(SIGABRT, catchsig);
    sig_term_handler = signal(SIGTERM, catchsig);
    sig_alrm_handler = signal(SIGALRM, catchsig);
}

/*------------------------------------------------------------------------*/

static char*
to_h(double size, char *buf)
{
    const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
    int i = 0;
    for (;size>1024;size/=1024) i++;
    sprintf(buf, "%.*f %s", i, size, units[i]);
    return buf;
}

/*------------------------------------------------------------------------*/

int main(int argc, char **argv)
{
    t_start = wctime();

    setsighandlers();

    cxxopts::Options opts(argv[0], "Parity game solver");
    opts.add_options()
        ("help", "Print help")
        ("t,trace", "Generate trace (with increasing verbosity)")
        ("v,verify", "Verify solution")
        ("p,print", "Print solution to stdout")
        ("i,input", "Input parity game", cxxopts::value<std::string>())
        ("sol", "Input (partial) solution", cxxopts::value<std::string>())
        ("o,output", "Output game or solution", cxxopts::value<std::string>())
        ("dot", "Write .dot file (before preprocessing)", cxxopts::value<std::string>())
        /* Preprocessing */
        ("inflate", "Inflate game")
        ("compress", "Compress game")
        ("no-single", "Do not solve single-parity games during preprocessing")
        ("no-loops", "Do not remove self-loops during preprocessing (default behavior)")
        ("no-wcwc", "Do not solve winner-controlled winning cycles during preprocessing")
        ("no", "Do not touch the game at all")
        /* Solving */
        ("scc", "Iteratively solve bottom SCCs")
        ("s,solver", "Use given solver (--solvers for info)", cxxopts::value<std::string>())
        ("solvers", "List available solvers")
        ("w,workers", "Number of workers for parallel code", cxxopts::value<int>())
        ("z,timeout", "Number of seconds for timeout", cxxopts::value<int>())
        ;

    /* Add solvers */
    Solvers solvers;
    for (unsigned id=0; id<solvers.count(); id++) {
        opts.add_options()(solvers.label(id), solvers.desc(id));
    }

    /* Parse command line */
    opts.parse_positional(std::vector<std::string>({"input", "output"}));
    auto options = opts.parse(argc, argv);

    if (options.count("help")) {
        std::cout << opts.help() << std::endl;
        return 0;
    }

    if (options.count("solvers")) {
        solvers.list(std::cout);
        return 0;
    }

    /* Setup timestamp filter */

    out.push(timestamp_filter());
    out.push(std::cout);

    /**
     * STEP 1
     * Read the game that must be solved.
     * (Supports bz2 and gz compression.)
     */

    Game pg;

    try {
        if (options.count("input")) {
            std::string filename = options["input"].as<std::string>();
            io::filtering_istream in;
            if (boost::algorithm::ends_with(filename, ".bz2")) in.push(io::bzip2_decompressor());
            if (boost::algorithm::ends_with(filename, ".gz")) in.push(io::gzip_decompressor());
            std::ifstream file(filename, std::ios_base::binary);
            in.push(file);
            pg.parse_pgsolver(in, options.count("no-loops") == 0 and options.count("no") == 0);
            file.close();
        } else {
            pg.parse_pgsolver(std::cin, options.count("no-loops") == 0);
        }
        out << "parity game with " << pg.nodecount() << " nodes and " << pg.edgecount() << " edges." << std::endl;
    } catch (const char *err) {
        out << "parsing error: " << err << std::endl;
        return -1;
    }

    /**
     * STEP 2
     * Parse the (partial) solution.
     */

    try {
        if (options.count("sol")) {
            std::ifstream file(options["sol"].as<std::string>());
            pg.parse_solution(file);
            file.close();
            out << "solution parsed." << std::endl;
        }
    } catch (const char *err) {
        out << "parsing error: " << err << std::endl;
        return -1;
    }

    /**
     * STEP 3
     * If requested, write .dot file
     */

    if (options.count("dot")) {
        std::ofstream file(options["dot"].as<std::string>());
        pg.write_dot(file);
        file.close();
        out << "dot file written." << std::endl;
    }

    /**
     * STEP 4
     * Reindex the game so all nodes are in order of priority.
     * (Remember the mapping to reverse the reindex later.)
     */

    int *mapping = new int[pg.nodecount()];
    pg.sort(mapping);
    out << "parity game reindexed" << std::endl;

    /**
     * STEP 5
     * Configure the solver.
     */

    Oink en(pg, out);
    en.setTrace(options.count("t"));

    // preprocessing options
    bool no = options.count("no");
    if (options.count("inflate")) en.setInflate();
    else if (options.count("compress")) en.setCompress();
    else if (!no) en.setRenumber();
    if (no or options.count("no-single")) en.setSolveSingle(false);
    if (no or options.count("no-loops")) en.setRemoveLoops(false);
    if (no or options.count("no-wcwc")) en.setRemoveWCWC(false);

    // solver
    if (options.count("solver")) {
        en.setSolver(solvers.id(options["solver"].as<std::string>()));
    } else {
        en.setSolver("tl"); // default solver
        for (unsigned id=0; id<solvers.count(); id++) {
            if (options.count(solvers.label(id))) en.setSolver(id);
        }
    }

    // solving options
    if (options.count("scc")) en.setBottomSCC(true);
    if (options.count("workers")) en.setWorkers(options["workers"].as<int>());

    /**
     * STEP 6
     * Run the solver and report the time.
     */

    if (options.count("timeout")) alarm(options["timeout"].as<int>());

    try {
        double begin = wctime();
        en.run();
        double end = wctime();
        out << "total solving time: " << std::fixed << (end-begin) << " sec." << std::endl;
    } catch (pg::Error &err) {
        out << "solving error: " << err.what() << std::endl;
        return -1;
    }

    /**
     * STEP 7
     * Verify the solution.
     */

    if (options.count("v")) {
        try {
            out << "verifying solution..." << std::endl;
            Verifier v(&pg, out);
            double vbegin = wctime();
            v.verify(true, true, true);
            double vend = wctime();
            out << "solution verified (" << v.n_strategies << " strategies)." << std::endl;
            out << "verification took " << std::fixed << (vend - vbegin) << " sec." << std::endl;
        } catch (const char *err) {
            out << "verification error: " << err << std::endl;
            return -1;
        }
    }

    char buf[32];
    to_h(getCurrentRSS(), buf);
    out << "current memory usage: " << buf << std::endl;
    to_h(getPeakRSS(), buf);
    out << "peak memory usage: " << buf << std::endl;

    /**
     * STEP 8
     * Revert reindex if we need to output.
     */

    if (options.count("output") or options.count("p")) pg.permute(mapping);

    if (options.count("output")) {
        // write solution to file
        if (options.count("output")) {
            std::ofstream file(options["output"].as<std::string>());
            pg.write_sol(file);
        }
    }

    if (options.count("p")) {
        // print winning nodes
        bool banner = false;
        for (int i=0; i<pg.nodecount(); i++) {
            if (pg.solved[i] and pg.winner[i] == 0) {
                if (!banner) out << "won by even:";
                banner = true;
                // out << " " << i; // << "(" << pg.priority(i) << ")";
                out << " " << pg.label_vertex(i);
            }
        }
        if (banner) out << std::endl;
        banner = false;
        for (int i=0; i<pg.nodecount(); i++) {
            if (pg.solved[i] and pg.winner[i] == 1) {
                if (!banner) out << "won by odd:";
                banner = true;
                out << " " << pg.label_vertex(i);
            }
        }
        if (banner) out << std::endl;
    }

    delete[] mapping;

    resetsighandlers();
    return 0;
}
<commit_msg>Ensure oink does not optimize piped games when seeing --no<commit_after>/*
 * Copyright 2017-2018 Tom van Dijk, Johannes Kepler University Linz
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <csignal>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sys/time.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/bzip2.hpp>
#include <boost/iostreams/filter/gzip.hpp>

#include "cxxopts.hpp"
#include "game.hpp"
#include "oink.hpp"
#include "solvers.hpp"
#include "verifier.hpp"
#include "tools/getrss.h"

using namespace pg;

/*------------------------------------------------------------------------*/

static double
wctime()
{
    struct timeval time;
    gettimeofday(&time, NULL);
    return time.tv_sec + 1E-6 * time.tv_usec;
}

static double t_start;

/*------------------------------------------------------------------------*/

// timestamp_filter adds a timestamp at the beginning of every line.
namespace io = boost::iostreams;
class timestamp_filter : public io::output_filter
{
public:
    timestamp_filter() {}
    struct category : io::output_filter::category, io::flushable_tag { };

    template<typename Sink> bool put(Sink& snk, char c);
    template<typename Device> void close(Device&);
    template<typename Sink> bool flush(Sink& snk);

private:
    bool is_start = true;
    char sz[16];
    const char* pos = NULL;
    const char* end = NULL;
};

template<typename Sink>
bool timestamp_filter::put(Sink& dest, char c)
{
    if (is_start) {
        if (c == '\n') return true;  // ignore consecutive endl
        is_start = false;
        pos = sz;
        end = sz + snprintf(sz, 16, "[% 8.2f] ", wctime() - t_start);
    }

    while (pos != end) {
        if (!io::put(dest, *pos)) return false;
        pos++;
    }

    if (!io::put(dest, c)) return false;
    if (c == '\n') is_start = true;

    return true;
}

template<typename Sink>
bool timestamp_filter::flush(Sink& dest)
{
    while (pos != end) {
        if (!io::put(dest, *pos)) return false;
        pos++;
    }

    return io::flush(dest);
}

template<typename Device>
void timestamp_filter::close(Device&)
{
    is_start = true;
    pos = end = NULL;
}

// global variable so signal handlers can work with it
io::filtering_ostream out;

/*------------------------------------------------------------------------*/

static void (*sig_int_handler)(int);
static void (*sig_segv_handler)(int);
static void (*sig_abrt_handler)(int);
static void (*sig_term_handler)(int);
static void (*sig_alrm_handler)(int);

static void
resetsighandlers(void)
{
    (void)signal(SIGINT, sig_int_handler);
    (void)signal(SIGSEGV, sig_segv_handler);
    (void)signal(SIGABRT, sig_abrt_handler);
    (void)signal(SIGTERM, sig_term_handler);
    (void)signal(SIGALRM, sig_alrm_handler);
}

static void
catchsig(int sig)
{
    // note: this can actually deadlock because we are writing to stdout...

    if (sig == SIGALRM) {
        resetsighandlers();
        out << std::endl << "terminated due to timeout" << std::endl;
        out.flush();
        exit(-1);
    } else if (sig == SIGINT) {
        // CTRL-C
        resetsighandlers();
        out << std::endl << "received INT signal" << std::endl;
        out.flush();
        exit(-SIGINT);
    } else if (sig == SIGABRT) {
        // really bad
        resetsighandlers();
        out << std::endl << "terminated due to ABORT signal" << std::endl;
        out.flush();
        exit(-SIGABRT);
        raise(sig);
    } else {
        resetsighandlers();
        out << std::endl << "terminated due to signal " << sig << std::endl;
        out.flush();
        exit(-sig);
    }
}

static void
setsighandlers(void)
{
    sig_int_handler = signal(SIGINT, catchsig);
    sig_segv_handler = signal(SIGSEGV, catchsig);
    sig_abrt_handler = signal(SIGABRT, catchsig);
    sig_term_handler = signal(SIGTERM, catchsig);
    sig_alrm_handler = signal(SIGALRM, catchsig);
}

/*------------------------------------------------------------------------*/

static char*
to_h(double size, char *buf)
{
    const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
    int i = 0;
    for (;size>1024;size/=1024) i++;
    sprintf(buf, "%.*f %s", i, size, units[i]);
    return buf;
}

/*------------------------------------------------------------------------*/

int main(int argc, char **argv)
{
    t_start = wctime();

    setsighandlers();

    cxxopts::Options opts(argv[0], "Parity game solver");
    opts.add_options()
        ("help", "Print help")
        ("t,trace", "Generate trace (with increasing verbosity)")
        ("v,verify", "Verify solution")
        ("p,print", "Print solution to stdout")
        ("i,input", "Input parity game", cxxopts::value<std::string>())
        ("sol", "Input (partial) solution", cxxopts::value<std::string>())
        ("o,output", "Output game or solution", cxxopts::value<std::string>())
        ("dot", "Write .dot file (before preprocessing)", cxxopts::value<std::string>())
        /* Preprocessing */
        ("inflate", "Inflate game")
        ("compress", "Compress game")
        ("no-single", "Do not solve single-parity games during preprocessing")
        ("no-loops", "Do not remove self-loops during preprocessing (default behavior)")
        ("no-wcwc", "Do not solve winner-controlled winning cycles during preprocessing")
        ("no", "Do not touch the game at all")
        /* Solving */
        ("scc", "Iteratively solve bottom SCCs")
        ("s,solver", "Use given solver (--solvers for info)", cxxopts::value<std::string>())
        ("solvers", "List available solvers")
        ("w,workers", "Number of workers for parallel code", cxxopts::value<int>())
        ("z,timeout", "Number of seconds for timeout", cxxopts::value<int>())
        ;

    /* Add solvers */
    Solvers solvers;
    for (unsigned id=0; id<solvers.count(); id++) {
        opts.add_options()(solvers.label(id), solvers.desc(id));
    }

    /* Parse command line */
    opts.parse_positional(std::vector<std::string>({"input", "output"}));
    auto options = opts.parse(argc, argv);

    if (options.count("help")) {
        std::cout << opts.help() << std::endl;
        return 0;
    }

    if (options.count("solvers")) {
        solvers.list(std::cout);
        return 0;
    }

    /* Setup timestamp filter */

    out.push(timestamp_filter());
    out.push(std::cout);

    /**
     * STEP 1
     * Read the game that must be solved.
     * (Supports bz2 and gz compression.)
     */

    Game pg;

    try {
        if (options.count("input")) {
            std::string filename = options["input"].as<std::string>();
            io::filtering_istream in;
            if (boost::algorithm::ends_with(filename, ".bz2")) in.push(io::bzip2_decompressor());
            if (boost::algorithm::ends_with(filename, ".gz")) in.push(io::gzip_decompressor());
            std::ifstream file(filename, std::ios_base::binary);
            in.push(file);
            pg.parse_pgsolver(in, options.count("no-loops") == 0 and options.count("no") == 0);
            file.close();
        } else {
            pg.parse_pgsolver(std::cin, options.count("no-loops") == 0 and options.count("no") == 0);
        }
        out << "parity game with " << pg.nodecount() << " nodes and " << pg.edgecount() << " edges." << std::endl;
    } catch (const char *err) {
        out << "parsing error: " << err << std::endl;
        return -1;
    }

    /**
     * STEP 2
     * Parse the (partial) solution.
     */

    try {
        if (options.count("sol")) {
            std::ifstream file(options["sol"].as<std::string>());
            pg.parse_solution(file);
            file.close();
            out << "solution parsed." << std::endl;
        }
    } catch (const char *err) {
        out << "parsing error: " << err << std::endl;
        return -1;
    }

    /**
     * STEP 3
     * If requested, write .dot file
     */

    if (options.count("dot")) {
        std::ofstream file(options["dot"].as<std::string>());
        pg.write_dot(file);
        file.close();
        out << "dot file written." << std::endl;
    }

    /**
     * STEP 4
     * Reindex the game so all nodes are in order of priority.
     * (Remember the mapping to reverse the reindex later.)
     */

    int *mapping = new int[pg.nodecount()];
    pg.sort(mapping);
    out << "parity game reindexed" << std::endl;

    /**
     * STEP 5
     * Configure the solver.
     */

    Oink en(pg, out);
    en.setTrace(options.count("t"));

    // preprocessing options
    bool no = options.count("no");
    if (options.count("inflate")) en.setInflate();
    else if (options.count("compress")) en.setCompress();
    else if (!no) en.setRenumber();
    if (no or options.count("no-single")) en.setSolveSingle(false);
    if (no or options.count("no-loops")) en.setRemoveLoops(false);
    if (no or options.count("no-wcwc")) en.setRemoveWCWC(false);

    // solver
    if (options.count("solver")) {
        en.setSolver(solvers.id(options["solver"].as<std::string>()));
    } else {
        en.setSolver("tl"); // default solver
        for (unsigned id=0; id<solvers.count(); id++) {
            if (options.count(solvers.label(id))) en.setSolver(id);
        }
    }

    // solving options
    if (options.count("scc")) en.setBottomSCC(true);
    if (options.count("workers")) en.setWorkers(options["workers"].as<int>());

    /**
     * STEP 6
     * Run the solver and report the time.
     */

    if (options.count("timeout")) alarm(options["timeout"].as<int>());

    try {
        double begin = wctime();
        en.run();
        double end = wctime();
        out << "total solving time: " << std::fixed << (end-begin) << " sec." << std::endl;
    } catch (pg::Error &err) {
        out << "solving error: " << err.what() << std::endl;
        return -1;
    }

    /**
     * STEP 7
     * Verify the solution.
     */

    if (options.count("v")) {
        try {
            out << "verifying solution..." << std::endl;
            Verifier v(&pg, out);
            double vbegin = wctime();
            v.verify(true, true, true);
            double vend = wctime();
            out << "solution verified (" << v.n_strategies << " strategies)." << std::endl;
            out << "verification took " << std::fixed << (vend - vbegin) << " sec." << std::endl;
        } catch (const char *err) {
            out << "verification error: " << err << std::endl;
            return -1;
        }
    }

    char buf[32];
    to_h(getCurrentRSS(), buf);
    out << "current memory usage: " << buf << std::endl;
    to_h(getPeakRSS(), buf);
    out << "peak memory usage: " << buf << std::endl;

    /**
     * STEP 8
     * Revert reindex if we need to output.
     */

    if (options.count("output") or options.count("p")) pg.permute(mapping);

    if (options.count("output")) {
        // write solution to file
        if (options.count("output")) {
            std::ofstream file(options["output"].as<std::string>());
            pg.write_sol(file);
        }
    }

    if (options.count("p")) {
        // print winning nodes
        bool banner = false;
        for (int i=0; i<pg.nodecount(); i++) {
            if (pg.solved[i] and pg.winner[i] == 0) {
                if (!banner) out << "won by even:";
                banner = true;
                // out << " " << i; // << "(" << pg.priority(i) << ")";
                out << " " << pg.label_vertex(i);
            }
        }
        if (banner) out << std::endl;
        banner = false;
        for (int i=0; i<pg.nodecount(); i++) {
            if (pg.solved[i] and pg.winner[i] == 1) {
                if (!banner) out << "won by odd:";
                banner = true;
                out << " " << pg.label_vertex(i);
            }
        }
        if (banner) out << std::endl;
    }

    delete[] mapping;

    resetsighandlers();
    return 0;
}
<|endoftext|>