<commit_before>#include <nan.h>
#include <iostream>
#include <sys/msg.h>

using v8::Function;
using v8::Local;
using v8::Number;
using v8::Value;
using Nan::AsyncQueueWorker;
using Nan::AsyncWorker;
using Nan::Callback;
using Nan::New;
using Nan::Null;

#ifndef MSGMAX
#define MSGMAX 4056
#endif

#ifndef linux
struct msgbuf {
  long mtype;
  char mtext[MSGMAX - 4];
};
#endif

const char *ConcatString(std::string one, const char *two) {
  return one.append(two).c_str();
}

Local<Value> CreateError(std::string message, int errcode) {
  message.append(": ");

  Nan::MaybeLocal<Value> val = Nan::Error(ConcatString(message, strerror(errcode)));

  return val.ToLocalChecked();
}

class SendMessageWorker : public AsyncWorker {

  public:
    SendMessageWorker(Callback *callback, int id, char *data, size_t dataLength, long type, int flags)
      : AsyncWorker(callback), id(id), data(data), dataLength(dataLength), type(type), flags(flags) { }
    ~SendMessageWorker() { }

    void Execute() {
      msgbuf *message = new msgbuf;
      message->mtype = type;

      memcpy(message->mtext, data, dataLength);

      ret = msgsnd(id, message, dataLength, flags);
      error = errno;
    }

    void HandleOKCallback () {
      Local<Value> argv[] = { Null() };

      if (ret == -1) {
        argv[0] = CreateError("Failed to send message", error);
      }

      callback->Call(1, argv);
    }

  private:
    int id;
    char *data;
    int dataLength;
    long type;
    int flags;
    int ret;
    int error;

};

class ReceiveMessageWorker : public AsyncWorker {

  public:
    ReceiveMessageWorker(Callback *callback, int id, size_t bufferLength, long type, int flags)
      : AsyncWorker(callback), id(id), bufferLength(bufferLength), type(type), flags(flags) { }
    ~ReceiveMessageWorker() { }

    void Execute() {
      message = new msgbuf;

      bufferLength = msgrcv(id, message, bufferLength, type, flags);
      error = errno;
    }

    void HandleOKCallback () {
      Local<Value> argv[] = {
        Null(),
        Null()
      };

      if (bufferLength == (size_t) -1) {
        argv[0] = CreateError("Failed to receive message", error);
      } else {
        argv[1] = Nan::CopyBuffer(message->mtext, bufferLength).ToLocalChecked();
      }

      callback->Call(2, argv);
    }

  private:
    int id;
    msgbuf *message;
    size_t bufferLength;
    long type;
    int flags;
    int error;
};

NAN_METHOD(GetMessageQueue) {
  key_t key = (key_t) info[0]->Int32Value();
  int flags = info[1]->Int32Value();

  int queue = msgget(key, flags);

  if (queue == -1) {
    Nan::ThrowError(CreateError("Failed to get queue", errno));
  }

  info.GetReturnValue().Set(New(queue));
}

NAN_METHOD(ControlMessageQueue) {
  int id = info[0]->Int32Value();
  int cmd = info[1]->Int32Value();

  msqid_ds *buf;

  if (cmd != IPC_STAT && cmd != IPC_SET) {
    buf = nullptr;
  }
#ifdef linux
  else if (cmd != MSG_STAT) {
    buf = nullptr;
  }
#endif
  else {
    buf = new msqid_ds;
  }

  int ret = msgctl(id, cmd, buf);

  size_t bufSize = sizeof(msqid_ds);
  char rawBuf[bufSize];
  memcpy(rawBuf, buf, bufSize);

  if (ret == 0) {
    info.GetReturnValue().Set(Nan::NewBuffer(rawBuf, bufSize).ToLocalChecked());
  } else {
    info.GetReturnValue().Set(New(ret));
  }
}

NAN_METHOD(CloseMessageQueue) {
  int id = info[0]->Int32Value();

  int ret = msgctl(id, IPC_RMID, nullptr);

  if (ret != 0) {
    Nan::ThrowError(CreateError("Failed to close queue", errno));
  }

  info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(SendMessage) {
  int id = info[0]->Int32Value();
  char* bufferData = node::Buffer::Data(info[1]);
  size_t bufferLength = (size_t)  node::Buffer::Length(info[1]);
  long type = info[2]->Int32Value();
  int flags = info[3]->Int32Value();
  Callback *callback = new Callback(info[4].As<Function>());

  AsyncQueueWorker(new SendMessageWorker(callback, id, bufferData, bufferLength, type, flags));
}

NAN_METHOD(ReceiveMessage) {
  int id = info[0]->Int32Value();
  size_t bufferLength = (size_t) info[1]->Int32Value();
  long type = info[2]->Int32Value();
  int flags = info[3]->Int32Value();
  Callback *callback = new Callback(info[4].As<Function>());

  AsyncQueueWorker(new ReceiveMessageWorker(callback, id, bufferLength, type, flags));
}
<commit_msg>Memory fixes for #1<commit_after>#include <nan.h>
#include <iostream>
#include <sys/msg.h>

using v8::Function;
using v8::Local;
using v8::Number;
using v8::Value;
using Nan::AsyncQueueWorker;
using Nan::AsyncWorker;
using Nan::Callback;
using Nan::New;
using Nan::Null;

#ifndef MSGMAX
#define MSGMAX 4056
#endif

#ifndef linux
struct msgbuf {
  long mtype;
  char mtext[1];
};
#endif

const char *ConcatString(std::string one, const char *two) {
  return one.append(two).c_str();
}

Local<Value> CreateError(std::string message, int errcode) {
  message.append(": ");

  Nan::MaybeLocal<Value> val = Nan::Error(ConcatString(message, strerror(errcode)));

  return val.ToLocalChecked();
}

class SendMessageWorker : public AsyncWorker {

  public:
    SendMessageWorker(Callback *callback, int id, char *data, size_t dataLength, long type, int flags)
      : AsyncWorker(callback), id(id), data(data), dataLength(dataLength), type(type), flags(flags) { }
    ~SendMessageWorker() { }

    void Execute() {
      struct msgbuf* message =
        (struct msgbuf*)malloc(sizeof(struct msgbuf) + dataLength);

      message->mtype = type;
      memcpy(message->mtext, data, dataLength);

      ret = msgsnd(id, message, dataLength, flags);
      error = errno;

      free(message);
    }

    void HandleOKCallback () {
      Local<Value> argv[] = { Null() };

      if (ret == -1) {
        argv[0] = CreateError("Failed to send message", error);
      }

      callback->Call(1, argv);
    }

  private:
    int id;
    char *data;
    int dataLength;
    long type;
    int flags;
    int ret;
    int error;

};

class ReceiveMessageWorker : public AsyncWorker {

  public:
    ReceiveMessageWorker(Callback *callback, int id, size_t bufferLength, long type, int flags)
      : AsyncWorker(callback), id(id), bufferLength(bufferLength), type(type), flags(flags) { }
    ~ReceiveMessageWorker() { }

    void Execute() {
      message = new msgbuf;

      bufferLength = msgrcv(id, message, bufferLength, type, flags);
      error = errno;
    }

    void HandleOKCallback () {
      Local<Value> argv[] = {
        Null(),
        Null()
      };

      if (bufferLength == (size_t) -1) {
        argv[0] = CreateError("Failed to receive message", error);
      } else {
        argv[1] = Nan::CopyBuffer(message->mtext, bufferLength).ToLocalChecked();
      }

      callback->Call(2, argv);
    }

  private:
    int id;
    msgbuf *message;
    size_t bufferLength;
    long type;
    int flags;
    int error;
};

NAN_METHOD(GetMessageQueue) {
  key_t key = (key_t) info[0]->Int32Value();
  int flags = info[1]->Int32Value();

  int queue = msgget(key, flags);

  if (queue == -1) {
    Nan::ThrowError(CreateError("Failed to get queue", errno));
  }

  info.GetReturnValue().Set(New(queue));
}

NAN_METHOD(ControlMessageQueue) {
  int id = info[0]->Int32Value();
  int cmd = info[1]->Int32Value();

  msqid_ds *buf;

  if (cmd != IPC_STAT && cmd != IPC_SET) {
    buf = nullptr;
  }
#ifdef linux
  else if (cmd != MSG_STAT) {
    buf = nullptr;
  }
#endif
  else {
    buf = new msqid_ds;
  }

  int ret = msgctl(id, cmd, buf);

  size_t bufSize = sizeof(msqid_ds);
  char rawBuf[bufSize];
  memcpy(rawBuf, buf, bufSize);

  if (ret == 0) {
    info.GetReturnValue().Set(Nan::NewBuffer(rawBuf, bufSize).ToLocalChecked());
  } else {
    info.GetReturnValue().Set(New(ret));
  }
}

NAN_METHOD(CloseMessageQueue) {
  int id = info[0]->Int32Value();

  int ret = msgctl(id, IPC_RMID, nullptr);

  if (ret != 0) {
    Nan::ThrowError(CreateError("Failed to close queue", errno));
  }

  info.GetReturnValue().Set(Nan::True());
}

NAN_METHOD(SendMessage) {
  int id = info[0]->Int32Value();
  char* bufferData = node::Buffer::Data(info[1]);
  size_t bufferLength = (size_t)  node::Buffer::Length(info[1]);
  long type = info[2]->Int32Value();
  int flags = info[3]->Int32Value();
  Callback *callback = new Callback(info[4].As<Function>());

  AsyncQueueWorker(new SendMessageWorker(callback, id, bufferData, bufferLength, type, flags));
}

NAN_METHOD(ReceiveMessage) {
  int id = info[0]->Int32Value();
  size_t bufferLength = (size_t) info[1]->Int32Value();
  long type = info[2]->Int32Value();
  int flags = info[3]->Int32Value();
  Callback *callback = new Callback(info[4].As<Function>());

  AsyncQueueWorker(new ReceiveMessageWorker(callback, id, bufferLength, type, flags));
}
<|endoftext|>


<commit_before>#include <SDL2/SDL.h>

SDL_Window *g_pWindow = 0;
SDL_Renderer *g_pRenderer = 0;

int main(int argc, char *argv[])
{
    // init SDL
    if (SDL_Init(SDL_INIT_EVERYTHING) >= 0) {
        g_pWindow = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 640, SDL_WINDOW_SHOWN);

        if (g_pWindow != 0) {
            g_pRenderer = SDL_CreateRenderer(g_pWindow, -1, 0);
        }
    }
    else {
        return -1;
    }

    SDL_SetRenderDrawColor(g_pRenderer, 0, 0, 0, 255);

    SDL_RenderClear(g_pRenderer);

    SDL_RenderPresent(g_pRenderer);

    SDL_Delay(5000);

    SDL_Quit();

    return 0;
}
<commit_msg>Make code cleaner by move init and render out of main<commit_after>#include <SDL2/SDL.h>

SDL_Window *g_pWindow = nullptr;
SDL_Renderer *g_pRenderer = nullptr;

bool g_bRunning = false;

bool init(const char *title, int width, int height)
{
    if (SDL_Init(SDL_INIT_EVERYTHING) >= 0) {
        g_pWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN);

        if (g_pWindow != nullptr) {
            g_pRenderer = SDL_CreateRenderer(g_pWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
        }
    }
    else {
        return false;
    }

    return true;
}

void render()
{
    // Set to black
    SDL_SetRenderDrawColor(g_pRenderer, 0, 0, 0, 255);

    // Clear window
    SDL_RenderClear(g_pRenderer);

    // Render to window
    SDL_RenderPresent(g_pRenderer);
}

int main(int argc, char *argv[])
{
    if (init("Awesome Game", 640, 480)) {
        g_bRunning = true;
    }
    else {
        return -1;
    }

    while (g_bRunning) {
        render();
    }

    SDL_Quit();

    return 0;
}
<|endoftext|>


<commit_before>#include "gameitem.h"
#include "gamescene.h"

#include <QDeclarativeExpression>

GameItem::GameItem(GameScene *parent)
    : QQuickItem((QQuickItem *)parent)
    , m_expression(0)
    , m_updateInterval(0)
    , m_collided(false)
    , m_scene(0)
{
}

void GameItem::update(long delta)
{
    if ((m_updateInterval && m_updateTime.elapsed() >= m_updateInterval)
        || !m_updateInterval) {
        m_updateTime.restart();
        if (m_expression)
            m_expression->evaluate();
    }
}

QDeclarativeScriptString GameItem::updateScript() const
{
    return m_updateScript;
}

void GameItem::setUpdateScript(QDeclarativeScriptString updateScript)
{
    if (m_updateScript.script() != updateScript.script()) {
        m_updateScript = updateScript;

        if (m_expression)
            delete m_expression;

        m_expression = new QDeclarativeExpression(m_updateScript.context(), m_updateScript.scopeObject(), m_updateScript.script());

        emit updateScriptChanged();
    }
}

int GameItem::updateInterval() const
{
    return m_updateInterval;
}

void GameItem::setUpdateInterval(int updateInterval)
{
    if (m_updateInterval != updateInterval) {
        m_updateInterval = updateInterval;

        emit updateScriptChanged();
    }
}

bool GameItem::collided()
{
    return m_collided;
}

void GameItem::setCollided(bool collided)
{
    if (m_collided != collided) {
        m_collided = collided;

        emit collidedChanged();
    }
}

QList<QObject *> GameItem::collidedItems()
{
    GameScene *scene = qobject_cast<GameScene *>(parent());

    return scene->collidedItems(this);
}

GameScene *GameItem::scene()
{
    return m_scene;
}

void GameItem::setScene(GameScene *scene)
{
    m_scene = scene;
}
<commit_msg>Make game items to update their chiltren<commit_after>#include "gameitem.h"
#include "gamescene.h"

#include <QDeclarativeExpression>

GameItem::GameItem(GameScene *parent)
    : QQuickItem((QQuickItem *)parent)
    , m_expression(0)
    , m_updateInterval(0)
    , m_collided(false)
    , m_scene(0)
{
}

void GameItem::update(long delta)
{
    if ((m_updateInterval && m_updateTime.elapsed() >= m_updateInterval)
        || !m_updateInterval) {
        m_updateTime.restart();
        if (m_expression)
            m_expression->evaluate();
    }

    foreach (QQuickItem *child, childItems())
        if (GameItem *item = dynamic_cast<GameItem *>(child)) {
            item->update(delta);
        }
}

QDeclarativeScriptString GameItem::updateScript() const
{
    return m_updateScript;
}

void GameItem::setUpdateScript(QDeclarativeScriptString updateScript)
{
    if (m_updateScript.script() != updateScript.script()) {
        m_updateScript = updateScript;

        if (m_expression)
            delete m_expression;

        m_expression = new QDeclarativeExpression(m_updateScript.context(), m_updateScript.scopeObject(), m_updateScript.script());

        emit updateScriptChanged();
    }
}

int GameItem::updateInterval() const
{
    return m_updateInterval;
}

void GameItem::setUpdateInterval(int updateInterval)
{
    if (m_updateInterval != updateInterval) {
        m_updateInterval = updateInterval;

        emit updateScriptChanged();
    }
}

bool GameItem::collided()
{
    return m_collided;
}

void GameItem::setCollided(bool collided)
{
    if (m_collided != collided) {
        m_collided = collided;

        emit collidedChanged();
    }
}

QList<QObject *> GameItem::collidedItems()
{
    GameScene *scene = qobject_cast<GameScene *>(parent());

    return scene->collidedItems(this);
}

GameScene *GameItem::scene()
{
    return m_scene;
}

void GameItem::setScene(GameScene *scene)
{
    m_scene = scene;
}
<|endoftext|>


<commit_before>#include "ocisession.h"
#include <algorithm>

#include "oci_lib_intf.h"

#include <oci.h>

void * ocisession::envhp = NULL;
list<ocisession*> ocisession::_sessions;

ocisession::ocisession(const char * connect_str, const int connect_str_len,
					   const char * user_name, const int user_name_len,
					   const char * password, const int password_len)
{
	intf_ret r;
	OCIAuthInfo *authp = NULL;

	init();

	r.handle = envhp;

	// allocate error handle
	checkenv(&r, OCIHandleAlloc((OCIEnv*)envhp,	/* environment handle */
                            (void **) &_errhp,	/* returned err handle */
                            OCI_HTYPE_ERROR,	/* typ of handle to allocate */
                            (size_t) 0,			/* optional extra memory size */
                            (void **) NULL));	/* returned extra memeory */

	if(r.fn_ret != SUCCESS) {
   		REMOTE_LOG("failed OCISessionGet %s\n", r.gerrbuf);
        throw r;
	}

	// allocate auth handle
	checkenv(&r, OCIHandleAlloc((OCIEnv*)envhp,
							(void**)&authp, OCI_HTYPE_AUTHINFO,
							(size_t)0, (void **) NULL));

	r.handle = _errhp;

	// usrname and password
	checkerr(&r, OCIAttrSet(authp, OCI_HTYPE_AUTHINFO,
								(void*) user_name, user_name_len,
								OCI_ATTR_USERNAME, (OCIError *)_errhp));
	checkerr(&r, OCIAttrSet(authp, OCI_HTYPE_AUTHINFO,
								(void*) password, password_len,
								OCI_ATTR_PASSWORD, (OCIError *)_errhp));

    /* get the database connection */
    checkerr(&r, OCISessionGet((OCIEnv*)envhp, (OCIError *)_errhp,
                               (OCISvcCtx**)&_svchp,					/* returned database connection */
                               authp,									/* initialized authentication handle */
                               (OraText *) connect_str, connect_str_len,/* connect string */
                               NULL, 0, NULL, NULL, NULL,				/* session tagging parameters: optional */
                               OCI_DEFAULT));					/* modes */
	if(r.fn_ret != SUCCESS) {
		REMOTE_LOG("failed OCISessionGet %s\n", r.gerrbuf);
        throw r;
	}

	(void) OCIHandleFree(authp, OCI_HTYPE_AUTHINFO);

	REMOTE_LOG("got session %p %.*s user %.*s\n", _svchp, connect_str_len, connect_str, user_name_len, user_name);

	_sessions.push_back(this);
}

ocistmt* ocisession::prepare_stmt(OraText *stmt, ub4 stmt_len)
{
	ocistmt * statement = new ocistmt(this, stmt, stmt_len);
	_statements.push_back(statement);
	return statement;
}

void ocisession::release_stmt(ocistmt *stmt)
{
	list<ocistmt*>::iterator it = std::find(_statements.begin(), _statements.end(), stmt);
	if (it != _statements.end()) {
		_statements.remove(*it);
	}
}

ocisession::~ocisession(void)
{
	intf_ret r;

	// delete all the statements
	for (list<ocistmt*>::const_iterator it = _statements.begin(); it != _statements.end(); it++)
		(*it)->close();
	_statements.clear();

	checkerr(&r, OCISessionRelease((OCISvcCtx*)_svchp, (OCIError*)_errhp, NULL, 0, OCI_DEFAULT));
	if(r.fn_ret != SUCCESS) {
		REMOTE_LOG("failed OCISessionRelease %s\n", r.gerrbuf);
        throw r;
	}

	(void) OCIHandleFree(_errhp, OCI_HTYPE_ERROR);

	// cleanup the environment if this is the last oci session from this environment
	_sessions.remove(this);

	//REMOTE_LOG("release session %p\n", _svchp);
}

void ocisession::init(void)
{
	intf_ret r;
 	r.fn_ret = SUCCESS;

	if(envhp == NULL) {
		sword ret = 0;
		ret = OCIEnvCreate((OCIEnv**)&envhp,		/* returned env handle */
						   OCI_THREADED,			/* initilization modes */
						   NULL, NULL, NULL, NULL,	/* callbacks, context */
						   (size_t) 0,				/* optional extra memory size: optional */
						   (void**) NULL);			/* returned extra memeory */

		r.handle = envhp;
		checkenv(&r, ret);
		if(r.fn_ret != SUCCESS)
        throw r;
	}
}
<commit_msg>conficts fixed<commit_after>#include "ocisession.h"
#include <algorithm>

#include "oci_lib_intf.h"

#include <oci.h>

void * ocisession::envhp = NULL;
list<ocisession*> ocisession::_sessions;

ocisession::ocisession(const char * connect_str, const int connect_str_len,
					   const char * user_name, const int user_name_len,
					   const char * password, const int password_len)
{
	intf_ret r;
	OCIAuthInfo *authp = NULL;

	init();

	r.handle = envhp;

	// allocate error handle
	checkenv(&r, OCIHandleAlloc((OCIEnv*)envhp,	/* environment handle */
                            (void **) &_errhp,	/* returned err handle */
                            OCI_HTYPE_ERROR,	/* typ of handle to allocate */
                            (size_t) 0,			/* optional extra memory size */
                            (void **) NULL));	/* returned extra memeory */

	if(r.fn_ret != SUCCESS) {
   		REMOTE_LOG("failed OCISessionGet %s\n", r.gerrbuf);
        throw r;
	}

	// allocate auth handle
	checkenv(&r, OCIHandleAlloc((OCIEnv*)envhp,
							(void**)&authp, OCI_HTYPE_AUTHINFO,
							(size_t)0, (void **) NULL));

	r.handle = _errhp;

	// usrname and password
	checkerr(&r, OCIAttrSet(authp, OCI_HTYPE_AUTHINFO,
								(void*) user_name, user_name_len,
								OCI_ATTR_USERNAME, (OCIError *)_errhp));
	checkerr(&r, OCIAttrSet(authp, OCI_HTYPE_AUTHINFO,
								(void*) password, password_len,
								OCI_ATTR_PASSWORD, (OCIError *)_errhp));

    /* get the database connection */
    checkerr(&r, OCISessionGet((OCIEnv*)envhp, (OCIError *)_errhp,
                               (OCISvcCtx**)&_svchp,					/* returned database connection */
                               authp,									/* initialized authentication handle */
                               (OraText *) connect_str, connect_str_len,/* connect string */
                               NULL, 0, NULL, NULL, NULL,				/* session tagging parameters: optional */
                               OCI_DEFAULT));					        /* modes */
	if(r.fn_ret != SUCCESS) {
		REMOTE_LOG("failed OCISessionGet %s\n", r.gerrbuf);
        throw r;
	}

	(void) OCIHandleFree(authp, OCI_HTYPE_AUTHINFO);

	REMOTE_LOG("got session %p %.*s user %.*s\n", _svchp, connect_str_len, connect_str, user_name_len, user_name);

	_sessions.push_back(this);
}

ocistmt* ocisession::prepare_stmt(OraText *stmt, ub4 stmt_len)
{
	ocistmt * statement = new ocistmt(this, stmt, stmt_len);
	_statements.push_back(statement);
	return statement;
}

void ocisession::release_stmt(ocistmt *stmt)
{
	list<ocistmt*>::iterator it = std::find(_statements.begin(), _statements.end(), stmt);
	if (it != _statements.end()) {
		_statements.remove(*it);
	}
}

ocisession::~ocisession(void)
{
	intf_ret r;

	// delete all the statements
	for (list<ocistmt*>::const_iterator it = _statements.begin(); it != _statements.end(); it++)
		(*it)->close();
	_statements.clear();

	checkerr(&r, OCISessionRelease((OCISvcCtx*)_svchp, (OCIError*)_errhp, NULL, 0, OCI_DEFAULT));
	if(r.fn_ret != SUCCESS) {
		REMOTE_LOG("failed OCISessionRelease %s\n", r.gerrbuf);
        throw r;
	}

	(void) OCIHandleFree(_errhp, OCI_HTYPE_ERROR);

	// cleanup the environment if this is the last oci session from this environment
	_sessions.remove(this);

	//REMOTE_LOG("release session %p\n", _svchp);
}

void ocisession::init(void)
{
	intf_ret r;
 	r.fn_ret = SUCCESS;

	if(envhp == NULL) {
		sword ret = 0;
		ret = OCIEnvCreate((OCIEnv**)&envhp,		/* returned env handle */
						   OCI_THREADED,			/* initilization modes */
						   NULL, NULL, NULL, NULL,	/* callbacks, context */
						   (size_t) 0,				/* optional extra memory size: optional */
						   (void**) NULL);			/* returned extra memeory */

		r.handle = envhp;
		checkenv(&r, ret);
		if(r.fn_ret != SUCCESS)
        throw r;
	}
}
<|endoftext|>


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

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

#include "base/hashmap.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "cpu/smt.hh"
#include "sim/core.hh"
#include "sim/eventq.hh"

using namespace std;

//
// Main Event Queue
//
// Events on this queue are processed at the *beginning* of each
// cycle, before the pipeline simulation is performed.
//
EventQueue mainEventQueue("Main Event Queue");

#ifndef NDEBUG
Counter Event::instanceCounter = 0;
#endif

Event::~Event()
{
    assert(!scheduled());
    flags = 0;
}

const std::string
Event::name() const
{
#ifndef NDEBUG
    return csprintf("Event_%d", instance);
#else
    return csprintf("Event_%x", (uintptr_t)this);
#endif
}

Event *
Event::insertBefore(Event *event, Event *curr)
{
    // Either way, event will be the top element in the 'in bin' list
    // which is the pointer we need in order to look into the list, so
    // we need to insert that into the bin list.
    if (!curr || *event < *curr) {
        // Insert the event before the current list since it is in the future.
        event->nextBin = curr;
        event->nextInBin = NULL;
    } else {
        // Since we're on the correct list, we need to point to the next list
        event->nextBin = curr->nextBin;  // curr->nextBin can now become stale

        // Insert event at the top of the stack
        event->nextInBin = curr;
    }

    return event;
}

void
EventQueue::insert(Event *event)
{
    // Deal with the head case
    if (!head || *event <= *head) {
        head = Event::insertBefore(event, head);
        return;
    }

    // Figure out either which 'in bin' list we are on, or where a new list
    // needs to be inserted
    Event *prev = head;
    Event *curr = head->nextBin;
    while (curr && *curr < *event) {
        prev = curr;
        curr = curr->nextBin;
    }

    // Note: this operation may render all nextBin pointers on the
    // prev 'in bin' list stale (except for the top one)
    prev->nextBin = Event::insertBefore(event, curr);
}

Event *
Event::removeItem(Event *event, Event *top)
{
    Event *curr = top;
    Event *next = top->nextInBin;

    // if we removed the top item, we need to handle things specially
    // and just remove the top item, fixing up the next bin pointer of
    // the new top item
    if (event == top) {
        if (!next)
            return top->nextBin;
        next->nextBin = top->nextBin;
        return next;
    }

    // Since we already checked the current element, we're going to
    // keep checking event against the next element.
    while (event != next) {
        if (!next)
            panic("event not found!");

        curr = next;
        next = next->nextInBin;
    }

    // remove next from the 'in bin' list since it's what we're looking for
    curr->nextInBin = next->nextInBin;
    return top;
}

void
EventQueue::remove(Event *event)
{
    if (head == NULL)
        panic("event not found!");

    // deal with an event on the head's 'in bin' list (event has the same
    // time as the head)
    if (*head == *event) {
        head = Event::removeItem(event, head);
        return;
    }

    // Find the 'in bin' list that this event belongs on
    Event *prev = head;
    Event *curr = head->nextBin;
    while (curr && *curr < *event) {
        prev = curr;
        curr = curr->nextBin;
    }

    if (!curr || *curr != *event)
        panic("event not found!");

    // curr points to the top item of the the correct 'in bin' list, when
    // we remove an item, it returns the new top item (which may be
    // unchanged)
    prev->nextBin = Event::removeItem(event, curr);
}

Event *
EventQueue::serviceOne()
{
    Event *event = head;
    Event *next = head->nextInBin;
    event->flags.clear(Event::Scheduled);

    if (next) {
        // update the next bin pointer since it could be stale
        next->nextBin = head->nextBin;

        // pop the stack
        head = next;
    } else {
        // this was the only element on the 'in bin' list, so get rid of
        // the 'in bin' list and point to the next bin list
        head = head->nextBin;
    }

    // handle action
    if (!event->squashed()) {
        event->process();
        if (event->isExitEvent()) {
            assert(!event->flags.isSet(Event::AutoDelete)); // would be silly
            return event;
        }
    } else {
        event->flags.clear(Event::Squashed);
    }

    if (event->flags.isSet(Event::AutoDelete) && !event->scheduled())
        delete event;

    return NULL;
}

void
Event::serialize(std::ostream &os)
{
    SERIALIZE_SCALAR(_when);
    SERIALIZE_SCALAR(_priority);
    short _flags = flags;
    SERIALIZE_SCALAR(_flags);
}

void
Event::unserialize(Checkpoint *cp, const string &section)
{
    if (scheduled())
        mainEventQueue.deschedule(this);

    UNSERIALIZE_SCALAR(_when);
    UNSERIALIZE_SCALAR(_priority);

    // need to see if original event was in a scheduled, unsquashed
    // state, but don't want to restore those flags in the current
    // object itself (since they aren't immediately true)
    short _flags;
    UNSERIALIZE_SCALAR(_flags);
    assert(initialized());
    flags = _flags;
    flags.set(Initialized);

    bool wasScheduled = flags.isSet(Scheduled) && !flags.isSet(Squashed);
    flags.clear(Squashed | Scheduled);

    if (wasScheduled) {
        DPRINTF(Config, "rescheduling at %d\n", _when);
        mainEventQueue.schedule(this, _when);
    }
}

void
EventQueue::serialize(ostream &os)
{
    std::list<Event *> eventPtrs;

    int numEvents = 0;
    Event *nextBin = head;
    while (nextBin) {
        Event *nextInBin = nextBin;

        while (nextInBin) {
            if (nextInBin->flags.isSet(Event::AutoSerialize)) {
                eventPtrs.push_back(nextInBin);
                paramOut(os, csprintf("event%d", numEvents++),
                         nextInBin->name());
            }
            nextInBin = nextInBin->nextInBin;
        }

        nextBin = nextBin->nextBin;
    }

    SERIALIZE_SCALAR(numEvents);

    for (std::list<Event *>::iterator it = eventPtrs.begin();
         it != eventPtrs.end(); ++it) {
        (*it)->nameOut(os);
        (*it)->serialize(os);
    }
}

void
EventQueue::unserialize(Checkpoint *cp, const std::string &section)
{
    int numEvents;
    UNSERIALIZE_SCALAR(numEvents);

    std::string eventName;
    for (int i = 0; i < numEvents; i++) {
        // get the pointer value associated with the event
        paramIn(cp, section, csprintf("event%d", i), eventName);

        // create the event based on its pointer value
        Serializable::create(cp, eventName);
    }
}

void
EventQueue::dump() const
{
    cprintf("============================================================\n");
    cprintf("EventQueue Dump  (cycle %d)\n", curTick);
    cprintf("------------------------------------------------------------\n");

    if (empty())
        cprintf("<No Events>\n");
    else {
        Event *nextBin = head;
        while (nextBin) {
            Event *nextInBin = nextBin;
            while (nextInBin) {
                nextInBin->dump();
                nextInBin = nextInBin->nextInBin;
            }

            nextBin = nextBin->nextBin;
        }
    }

    cprintf("============================================================\n");
}

bool
EventQueue::debugVerify() const
{
    m5::hash_map<long, bool> map;

    Tick time = 0;
    short priority = 0;

    Event *nextBin = head;
    while (nextBin) {
        Event *nextInBin = nextBin;
        while (nextInBin) {
            if (nextInBin->when() < time) {
                cprintf("time goes backwards!");
                nextInBin->dump();
                return false;
            } else if (nextInBin->when() == time &&
                       nextInBin->priority() < priority) {
                cprintf("priority inverted!");
                nextInBin->dump();
                return false;
            }

            if (map[reinterpret_cast<long>(nextInBin)]) {
                cprintf("Node already seen");
                nextInBin->dump();
                return false;
            }
            map[reinterpret_cast<long>(nextInBin)] = true;

            time = nextInBin->when();
            priority = nextInBin->priority();

            nextInBin = nextInBin->nextInBin;
        }

        nextBin = nextBin->nextBin;
    }

    return true;
}

void
dumpMainQueue()
{
    mainEventQueue.dump();
}

const char *
Event::description() const
{
    return "generic";
}

void
Event::trace(const char *action)
{
    // This DPRINTF is unconditional because calls to this function
    // are protected by an 'if (DTRACE(Event))' in the inlined Event
    // methods.
    //
    // This is just a default implementation for derived classes where
    // it's not worth doing anything special.  If you want to put a
    // more informative message in the trace, override this method on
    // the particular subclass where you have the information that
    // needs to be printed.
    DPRINTFN("%s event %s @ %d\n", description(), action, when());
}

void
Event::dump() const
{
    cprintf("Event %s (%s)\n", name(), description());
    cprintf("Flags: %#x\n", flags);
#ifdef EVENTQ_DEBUG
    cprintf("Created: %d\n", whenCreated);
#endif
    if (scheduled()) {
#ifdef EVENTQ_DEBUG
        cprintf("Scheduled at  %d\n", whenScheduled);
#endif
        cprintf("Scheduled for %d, priority %d\n", when(), _priority);
    } else {
        cprintf("Not Scheduled\n");
    }
}

EventQueue::EventQueue(const string &n)
    : objName(n), head(NULL)
{}
<commit_msg>flags: add comment to avoid future deletions since code appears redundant.<commit_after>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * Copyright (c) 2008 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 *          Nathan Binkert
 *          Steve Raasch
 */

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

#include "base/hashmap.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "cpu/smt.hh"
#include "sim/core.hh"
#include "sim/eventq.hh"

using namespace std;

//
// Main Event Queue
//
// Events on this queue are processed at the *beginning* of each
// cycle, before the pipeline simulation is performed.
//
EventQueue mainEventQueue("Main Event Queue");

#ifndef NDEBUG
Counter Event::instanceCounter = 0;
#endif

Event::~Event()
{
    assert(!scheduled());
    flags = 0;
}

const std::string
Event::name() const
{
#ifndef NDEBUG
    return csprintf("Event_%d", instance);
#else
    return csprintf("Event_%x", (uintptr_t)this);
#endif
}

Event *
Event::insertBefore(Event *event, Event *curr)
{
    // Either way, event will be the top element in the 'in bin' list
    // which is the pointer we need in order to look into the list, so
    // we need to insert that into the bin list.
    if (!curr || *event < *curr) {
        // Insert the event before the current list since it is in the future.
        event->nextBin = curr;
        event->nextInBin = NULL;
    } else {
        // Since we're on the correct list, we need to point to the next list
        event->nextBin = curr->nextBin;  // curr->nextBin can now become stale

        // Insert event at the top of the stack
        event->nextInBin = curr;
    }

    return event;
}

void
EventQueue::insert(Event *event)
{
    // Deal with the head case
    if (!head || *event <= *head) {
        head = Event::insertBefore(event, head);
        return;
    }

    // Figure out either which 'in bin' list we are on, or where a new list
    // needs to be inserted
    Event *prev = head;
    Event *curr = head->nextBin;
    while (curr && *curr < *event) {
        prev = curr;
        curr = curr->nextBin;
    }

    // Note: this operation may render all nextBin pointers on the
    // prev 'in bin' list stale (except for the top one)
    prev->nextBin = Event::insertBefore(event, curr);
}

Event *
Event::removeItem(Event *event, Event *top)
{
    Event *curr = top;
    Event *next = top->nextInBin;

    // if we removed the top item, we need to handle things specially
    // and just remove the top item, fixing up the next bin pointer of
    // the new top item
    if (event == top) {
        if (!next)
            return top->nextBin;
        next->nextBin = top->nextBin;
        return next;
    }

    // Since we already checked the current element, we're going to
    // keep checking event against the next element.
    while (event != next) {
        if (!next)
            panic("event not found!");

        curr = next;
        next = next->nextInBin;
    }

    // remove next from the 'in bin' list since it's what we're looking for
    curr->nextInBin = next->nextInBin;
    return top;
}

void
EventQueue::remove(Event *event)
{
    if (head == NULL)
        panic("event not found!");

    // deal with an event on the head's 'in bin' list (event has the same
    // time as the head)
    if (*head == *event) {
        head = Event::removeItem(event, head);
        return;
    }

    // Find the 'in bin' list that this event belongs on
    Event *prev = head;
    Event *curr = head->nextBin;
    while (curr && *curr < *event) {
        prev = curr;
        curr = curr->nextBin;
    }

    if (!curr || *curr != *event)
        panic("event not found!");

    // curr points to the top item of the the correct 'in bin' list, when
    // we remove an item, it returns the new top item (which may be
    // unchanged)
    prev->nextBin = Event::removeItem(event, curr);
}

Event *
EventQueue::serviceOne()
{
    Event *event = head;
    Event *next = head->nextInBin;
    event->flags.clear(Event::Scheduled);

    if (next) {
        // update the next bin pointer since it could be stale
        next->nextBin = head->nextBin;

        // pop the stack
        head = next;
    } else {
        // this was the only element on the 'in bin' list, so get rid of
        // the 'in bin' list and point to the next bin list
        head = head->nextBin;
    }

    // handle action
    if (!event->squashed()) {
        event->process();
        if (event->isExitEvent()) {
            assert(!event->flags.isSet(Event::AutoDelete)); // would be silly
            return event;
        }
    } else {
        event->flags.clear(Event::Squashed);
    }

    if (event->flags.isSet(Event::AutoDelete) && !event->scheduled())
        delete event;

    return NULL;
}

void
Event::serialize(std::ostream &os)
{
    SERIALIZE_SCALAR(_when);
    SERIALIZE_SCALAR(_priority);
    short _flags = flags;
    SERIALIZE_SCALAR(_flags);
}

void
Event::unserialize(Checkpoint *cp, const string &section)
{
    if (scheduled())
        mainEventQueue.deschedule(this);

    UNSERIALIZE_SCALAR(_when);
    UNSERIALIZE_SCALAR(_priority);

    short _flags;
    UNSERIALIZE_SCALAR(_flags);

    // Old checkpoints had no concept of the Initialized flag
    // so restoring from old checkpoints always fail.
    // Events are initialized on construction but original code
    // "flags = _flags" would just overwrite the initialization.
    // So, read in the checkpoint flags, but then set the Initialized
    // flag on top of it in order to avoid failures.
    assert(initialized());
    flags = _flags;
    flags.set(Initialized);

    // need to see if original event was in a scheduled, unsquashed
    // state, but don't want to restore those flags in the current
    // object itself (since they aren't immediately true)
    bool wasScheduled = flags.isSet(Scheduled) && !flags.isSet(Squashed);
    flags.clear(Squashed | Scheduled);

    if (wasScheduled) {
        DPRINTF(Config, "rescheduling at %d\n", _when);
        mainEventQueue.schedule(this, _when);
    }
}

void
EventQueue::serialize(ostream &os)
{
    std::list<Event *> eventPtrs;

    int numEvents = 0;
    Event *nextBin = head;
    while (nextBin) {
        Event *nextInBin = nextBin;

        while (nextInBin) {
            if (nextInBin->flags.isSet(Event::AutoSerialize)) {
                eventPtrs.push_back(nextInBin);
                paramOut(os, csprintf("event%d", numEvents++),
                         nextInBin->name());
            }
            nextInBin = nextInBin->nextInBin;
        }

        nextBin = nextBin->nextBin;
    }

    SERIALIZE_SCALAR(numEvents);

    for (std::list<Event *>::iterator it = eventPtrs.begin();
         it != eventPtrs.end(); ++it) {
        (*it)->nameOut(os);
        (*it)->serialize(os);
    }
}

void
EventQueue::unserialize(Checkpoint *cp, const std::string &section)
{
    int numEvents;
    UNSERIALIZE_SCALAR(numEvents);

    std::string eventName;
    for (int i = 0; i < numEvents; i++) {
        // get the pointer value associated with the event
        paramIn(cp, section, csprintf("event%d", i), eventName);

        // create the event based on its pointer value
        Serializable::create(cp, eventName);
    }
}

void
EventQueue::dump() const
{
    cprintf("============================================================\n");
    cprintf("EventQueue Dump  (cycle %d)\n", curTick);
    cprintf("------------------------------------------------------------\n");

    if (empty())
        cprintf("<No Events>\n");
    else {
        Event *nextBin = head;
        while (nextBin) {
            Event *nextInBin = nextBin;
            while (nextInBin) {
                nextInBin->dump();
                nextInBin = nextInBin->nextInBin;
            }

            nextBin = nextBin->nextBin;
        }
    }

    cprintf("============================================================\n");
}

bool
EventQueue::debugVerify() const
{
    m5::hash_map<long, bool> map;

    Tick time = 0;
    short priority = 0;

    Event *nextBin = head;
    while (nextBin) {
        Event *nextInBin = nextBin;
        while (nextInBin) {
            if (nextInBin->when() < time) {
                cprintf("time goes backwards!");
                nextInBin->dump();
                return false;
            } else if (nextInBin->when() == time &&
                       nextInBin->priority() < priority) {
                cprintf("priority inverted!");
                nextInBin->dump();
                return false;
            }

            if (map[reinterpret_cast<long>(nextInBin)]) {
                cprintf("Node already seen");
                nextInBin->dump();
                return false;
            }
            map[reinterpret_cast<long>(nextInBin)] = true;

            time = nextInBin->when();
            priority = nextInBin->priority();

            nextInBin = nextInBin->nextInBin;
        }

        nextBin = nextBin->nextBin;
    }

    return true;
}

void
dumpMainQueue()
{
    mainEventQueue.dump();
}

const char *
Event::description() const
{
    return "generic";
}

void
Event::trace(const char *action)
{
    // This DPRINTF is unconditional because calls to this function
    // are protected by an 'if (DTRACE(Event))' in the inlined Event
    // methods.
    //
    // This is just a default implementation for derived classes where
    // it's not worth doing anything special.  If you want to put a
    // more informative message in the trace, override this method on
    // the particular subclass where you have the information that
    // needs to be printed.
    DPRINTFN("%s event %s @ %d\n", description(), action, when());
}

void
Event::dump() const
{
    cprintf("Event %s (%s)\n", name(), description());
    cprintf("Flags: %#x\n", flags);
#ifdef EVENTQ_DEBUG
    cprintf("Created: %d\n", whenCreated);
#endif
    if (scheduled()) {
#ifdef EVENTQ_DEBUG
        cprintf("Scheduled at  %d\n", whenScheduled);
#endif
        cprintf("Scheduled for %d, priority %d\n", when(), _priority);
    } else {
        cprintf("Not Scheduled\n");
    }
}

EventQueue::EventQueue(const string &n)
    : objName(n), head(NULL)
{}
<|endoftext|>


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

#ifndef __FAULTS_HH__
#define __FAULTS_HH__

#include "base/refcnt.hh"
#include "sim/stats.hh"
#include "config/full_system.hh"

class ThreadContext;
class FaultBase;
typedef RefCountingPtr<FaultBase> Fault;

typedef const char * FaultName;
typedef Stats::Scalar FaultStat;

// Each class has it's name statically define in _name,
// and has a virtual function to access it's name.
// The function is necessary because otherwise, all objects
// which are being accessed cast as a FaultBase * (namely
// all faults returned using the Fault type) will use the
// generic FaultBase name.

class FaultBase : public RefCounted
{
  public:
    virtual FaultName name() const = 0;
    virtual void invoke(ThreadContext * tc);
//    template<typename T>
//    bool isA() {return dynamic_cast<T *>(this);}
    virtual bool isMachineCheckFault() const {return false;}
    virtual bool isAlignmentFault() const {return false;}
};

FaultBase * const NoFault = 0;

class UnimpFault : public FaultBase
{
  private:
    std::string panicStr;
  public:
    UnimpFault(std::string _str)
        : panicStr(_str)
    { }

    FaultName name() const {return "Unimplemented simulator feature";}
    void invoke(ThreadContext * tc);
};

#if !FULL_SYSTEM
class GenericPageTableFault : public FaultBase
{
  private:
    Addr vaddr;
  public:
    FaultName name() const {return "Generic page table fault";}
    GenericPageTableFault(Addr va) : vaddr(va) {}
    void invoke(ThreadContext * tc);
};

class GenericAlignmentFault : public FaultBase
{
  private:
    Addr vaddr;
  public:
    FaultName name() const {return "Generic alignment fault";}
    GenericAlignmentFault(Addr va) : vaddr(va) {}
    void invoke(ThreadContext * tc);
};
#endif

#endif // __FAULTS_HH__
<commit_msg>Faults: Get rid of some commented out code in sim/faults.hh.<commit_after>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 *          Gabe Black
 */

#ifndef __FAULTS_HH__
#define __FAULTS_HH__

#include "base/refcnt.hh"
#include "sim/stats.hh"
#include "config/full_system.hh"

class ThreadContext;
class FaultBase;
typedef RefCountingPtr<FaultBase> Fault;

typedef const char * FaultName;
typedef Stats::Scalar FaultStat;

// Each class has it's name statically define in _name,
// and has a virtual function to access it's name.
// The function is necessary because otherwise, all objects
// which are being accessed cast as a FaultBase * (namely
// all faults returned using the Fault type) will use the
// generic FaultBase name.

class FaultBase : public RefCounted
{
  public:
    virtual FaultName name() const = 0;
    virtual void invoke(ThreadContext * tc);
    virtual bool isMachineCheckFault() const {return false;}
    virtual bool isAlignmentFault() const {return false;}
};

FaultBase * const NoFault = 0;

class UnimpFault : public FaultBase
{
  private:
    std::string panicStr;
  public:
    UnimpFault(std::string _str)
        : panicStr(_str)
    { }

    FaultName name() const {return "Unimplemented simulator feature";}
    void invoke(ThreadContext * tc);
};

#if !FULL_SYSTEM
class GenericPageTableFault : public FaultBase
{
  private:
    Addr vaddr;
  public:
    FaultName name() const {return "Generic page table fault";}
    GenericPageTableFault(Addr va) : vaddr(va) {}
    void invoke(ThreadContext * tc);
};

class GenericAlignmentFault : public FaultBase
{
  private:
    Addr vaddr;
  public:
    FaultName name() const {return "Generic alignment fault";}
    GenericAlignmentFault(Addr va) : vaddr(va) {}
    void invoke(ThreadContext * tc);
};
#endif

#endif // __FAULTS_HH__
<|endoftext|>


<commit_before>#include "geometry.hpp"

Segment::Segment()
{
    p1=sf::Vector2f(0.f,0.f);
    p2=sf::Vector2f(0.f,0.f);
}

Segment::Segment(sf::Vector2f pointA, sf::Vector2f pointB)
{
    p1=pointA;
    p2=pointB;
}

const sf::Vector2f Segment::intersection_time(const Segment &other) const
{
    auto dir1 = p2 - p1;
    auto dir2 = other.p2 - other.p1;
    /*
    Now we try to solve p1 + t1 * dir1 = other.p1 + t2 * dir2
    This is a system of two linear equations
    */
    float a = dir1.x;
    float b = -dir2.x;
    float c = dir1.y;
    float d = -dir2.y;
    float det = (a * d - b * c);
    if (-epsilon <= det && det <= epsilon) {
        return sf::Vector2f(-42, -42); // Segments are parallel
    }
    float e = other.p1.x - p1.x;
    float f = other.p1.y - p1.y;
    float t1 = (d * e - b * f) / det;
    float t2 = (-c * e + a * f) / det;
    return sf::Vector2f(t1, t2);
}

const sf::Vector2f Segment::intersection(const Segment &other) const {
    sf::Vector2f it = intersection_time(other);
    if (check(it.x) && check(it.y)) {
        // Intersection
        return interp(p1, p2, it.x);
    }
    return sf::Vector2f(-42, -42);
};

const sf::Vector2f Segment::intersection_droites(const Segment &other) const
{
    sf::Vector2f it = intersection_time(other);
    return interp(p1, p2, it.x);
};

void Segment::intersection_triangle(const sf::Vector2f lumiere,
        const Segment &tri, std::vector<Segment> &result) {
    Segment tri1 = Segment(lumiere, tri.p1);
    Segment tri2 = Segment(lumiere, tri.p2);
    sf::Vector2f it1 = intersection_time(tri1);
    sf::Vector2f it2 = intersection_time(tri2);
    sf::Vector2f it3 = intersection_time(tri);
    sf::Vector2f si1 = interp(lumiere, tri.p1, it1.y);
    sf::Vector2f si2 = interp(lumiere, tri.p2, it2.y);
    sf::Vector2f si3 = interp(tri.p1, tri.p2, it3.y);

    if (!(check(it1.y) || check(it2.y) || check(it3.y))) {
        // La droite du segment ne passe pas dans le triangle
        result.push_back(tri);
        return;
    }

    if (!check_strict(it3.y)) {
        // La droite coupe les deux cotes principaux
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection_droites(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection_droites(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it1.x)) {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    }

    if (!check_strict(it1.y)) {
        // On coupe cote 2 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it3.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it3.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it3.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection_droites(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection_droites(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, si3));
            result.push_back(Segment(si3, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    } else {
        // On coupe cote 1 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it3.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it3.x;
        } else {
            pp1 = p2; pp2 = p1; u = it3.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection_droites(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection_droites(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si3));
            result.push_back(Segment(si3, tri.p2));
            return;
        } else {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
    }
};
<commit_msg>Fix la lumière passe à travers les murs<commit_after>#include "geometry.hpp"

Segment::Segment()
{
    p1=sf::Vector2f(0.f,0.f);
    p2=sf::Vector2f(0.f,0.f);
}

Segment::Segment(sf::Vector2f pointA, sf::Vector2f pointB)
{
    p1=pointA;
    p2=pointB;
}

const sf::Vector2f Segment::intersection_time(const Segment &other) const
{
    auto dir1 = p2 - p1;
    auto dir2 = other.p2 - other.p1;
    /*
    Now we try to solve p1 + t1 * dir1 = other.p1 + t2 * dir2
    This is a system of two linear equations
    */
    float a = dir1.x;
    float b = -dir2.x;
    float c = dir1.y;
    float d = -dir2.y;
    float det = (a * d - b * c);
    if (-epsilon <= det && det <= epsilon) {
        return sf::Vector2f(-42, -42); // Segments are parallel
    }
    float e = other.p1.x - p1.x;
    float f = other.p1.y - p1.y;
    float t1 = (d * e - b * f) / det;
    float t2 = (-c * e + a * f) / det;
    return sf::Vector2f(t1, t2);
}

const sf::Vector2f Segment::intersection(const Segment &other) const {
    sf::Vector2f it = intersection_time(other);
    if (check(it.x) && check(it.y)) {
        // Intersection
        return interp(p1, p2, it.x);
    }
    return sf::Vector2f(-42, -42);
};

const sf::Vector2f Segment::intersection_droites(const Segment &other) const
{
    sf::Vector2f it = intersection_time(other);
    return interp(p1, p2, it.x);
};

void Segment::intersection_triangle(const sf::Vector2f lumiere,
        const Segment &tri, std::vector<Segment> &result) {
    Segment tri1 = Segment(lumiere, tri.p1);
    Segment tri2 = Segment(lumiere, tri.p2);
    sf::Vector2f it1 = intersection_time(tri1);
    sf::Vector2f it2 = intersection_time(tri2);
    sf::Vector2f it3 = intersection_time(tri);
    sf::Vector2f si1 = interp(lumiere, tri.p1, it1.y);
    sf::Vector2f si2 = interp(lumiere, tri.p2, it2.y);
    sf::Vector2f si3 = interp(tri.p1, tri.p2, it3.y);

    if (!(check(it1.y) || check(it2.y) || check(it3.y))) {
        // La droite du segment ne passe pas dans le triangle
        result.push_back(tri);
        return;
    }

    if (!check_strict(it3.y)) {
        // La droite coupe les deux cotes principaux
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection_droites(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection_droites(Segment(lumiere, pp2));
        if (-epsilon > u && v > 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
		if (check(it1.x) && check(it2.x)) {
			// On intersecte les deux cotes
			result.push_back(Segment(si1, si2));
			return;
        // On intersecte un seul cote
        } else if (check(it1.x)) {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    }

    if (!check_strict(it1.y)) {
        // On coupe cote 2 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it3.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it3.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it3.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection_droites(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection_droites(Segment(lumiere, pp2));
        if (-epsilon > u && v > 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
		if (check(it2.x) && check(it3.x)) {
			// On intersecte les deux cotes
			result.push_back(Segment(tri.p1, si3));
			result.push_back(Segment(si3, si2));
			return;
        // On intersecte un seul cote
        } else if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, si3));
            result.push_back(Segment(si3, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    } else {
        // On coupe cote 1 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it3.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it3.x;
        } else {
            pp1 = p2; pp2 = p1; u = it3.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection_droites(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection_droites(Segment(lumiere, pp2));
        if (-epsilon > u && v > 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
		if (check(it3.x) && check(it1.x)) {
			// On intersecte les deux cotes
			result.push_back(Segment(si1, si3));
			result.push_back(Segment(si3, tri.p2));
			return;
        // On intersecte un seul cote
        } else if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si3));
            result.push_back(Segment(si3, tri.p2));
            return;
        } else {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
    }
};
<|endoftext|>


<commit_before>#include <QApplication>
#include <QFontDatabase>
#include <QtGlobal>
#include <QFile>
#include <QCommandLineParser>
#include "neovimconnector.h"
#include "mainwindow.h"

/**
 * A log handler for Qt messages, all messages are dumped into the file
 * passed via the NVIM_QT_LOG variable. Some information is only available
 * in debug builds (e.g. qDebug is only called in debug builds).
 *
 * In UNIX Qt prints messages to the console output, but in Windows this is
 * the only way to get Qt's debug/warning messages.
 */
void logger(QtMsgType type, const QMessageLogContext& ctx, const QString& msg)
{
	QFile logFile(qgetenv("NVIM_QT_LOG"));
	if (logFile.open(QIODevice::Append | QIODevice::Text)) {
		QTextStream stream(&logFile);
		stream << msg << "\n";
	}
}

/**
 * Neovim Qt GUI
 *
 * Usage:
 *   nvim-qt --server <SOCKET>
 *   nvim-qt [...]
 *
 * When --server is not provided, a Neovim instance will be spawned. All arguments
 * are passed to the Neovim process.
 */
int main(int argc, char **argv)
{
	QApplication app(argc, argv);
	app.setApplicationDisplayName("Neovim");
	app.setWindowIcon(QIcon(":/neovim.png"));

	if (!qgetenv("NVIM_QT_LOG").isEmpty()) {
		qInstallMessageHandler(logger);
	}

	QCommandLineParser parser;
	parser.addOption(QCommandLineOption("embed",
		QCoreApplication::translate("main", "Communicate with Neovim over stdin/out")));
	parser.addOption(QCommandLineOption("server",
		QCoreApplication::translate("main", "Connect to existing Neovim instance"),
		QCoreApplication::translate("main", "addr")));
	parser.addOption(QCommandLineOption("geometry",
		QCoreApplication::translate("main", "Initial window geometry"),
		QCoreApplication::translate("main", "geometry")));
	parser.addOption(QCommandLineOption("maximized",
		QCoreApplication::translate("main", "Maximize the window on startup")));
	parser.addPositionalArgument("...", "Additional arguments are fowarded to Neovim", "[-- ...]");
	parser.addHelpOption();

	int sep = app.arguments().indexOf("--");
	QStringList neovimArgs;
	if (sep != -1) {
		QStringList args = app.arguments().mid(0, sep);
		neovimArgs += app.arguments().mid(sep+1);
		parser.process(app.arguments());
	} else {
		parser.process(app.arguments());
	}

	if (parser.isSet("help")) {
		parser.showHelp();
	}

	NeovimQt::NeovimConnector *c;
	if (parser.isSet("embed")) {
		c = NeovimQt::NeovimConnector::fromStdinOut();
	} else {
		if (parser.isSet("server")) {
			QString server = parser.value("server");
			c = NeovimQt::NeovimConnector::connectToNeovim(server);
		} else {
			c = NeovimQt::NeovimConnector::spawn(neovimArgs);
		}
	}

#ifdef NEOVIMQT_GUI_WIDGET
	NeovimQt::Shell *win = new NeovimQt::Shell(c);
	win->show();
	if (parser.isSet("maximized")) {
		win->showMaximized();
	} else {
		win->show();
	}
#else
	NeovimQt::MainWindow *win = new NeovimQt::MainWindow(c);
	if (parser.isSet("maximized")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::Maximized);
	} else {
		win->delayedShow();
	}
#endif
	return app.exec();
}

<commit_msg>GUI: Implement --fullscreen CLI option<commit_after>#include <QApplication>
#include <QFontDatabase>
#include <QtGlobal>
#include <QFile>
#include <QCommandLineParser>
#include "neovimconnector.h"
#include "mainwindow.h"

/**
 * A log handler for Qt messages, all messages are dumped into the file
 * passed via the NVIM_QT_LOG variable. Some information is only available
 * in debug builds (e.g. qDebug is only called in debug builds).
 *
 * In UNIX Qt prints messages to the console output, but in Windows this is
 * the only way to get Qt's debug/warning messages.
 */
void logger(QtMsgType type, const QMessageLogContext& ctx, const QString& msg)
{
	QFile logFile(qgetenv("NVIM_QT_LOG"));
	if (logFile.open(QIODevice::Append | QIODevice::Text)) {
		QTextStream stream(&logFile);
		stream << msg << "\n";
	}
}

/**
 * Neovim Qt GUI
 *
 * Usage:
 *   nvim-qt --server <SOCKET>
 *   nvim-qt [...]
 *
 * When --server is not provided, a Neovim instance will be spawned. All arguments
 * are passed to the Neovim process.
 */
int main(int argc, char **argv)
{
	QApplication app(argc, argv);
	app.setApplicationDisplayName("Neovim");
	app.setWindowIcon(QIcon(":/neovim.png"));

	if (!qgetenv("NVIM_QT_LOG").isEmpty()) {
		qInstallMessageHandler(logger);
	}

	QCommandLineParser parser;
	parser.addOption(QCommandLineOption("embed",
		QCoreApplication::translate("main", "Communicate with Neovim over stdin/out")));
	parser.addOption(QCommandLineOption("server",
		QCoreApplication::translate("main", "Connect to existing Neovim instance"),
		QCoreApplication::translate("main", "addr")));
	parser.addOption(QCommandLineOption("geometry",
		QCoreApplication::translate("main", "Initial window geometry"),
		QCoreApplication::translate("main", "geometry")));
	parser.addOption(QCommandLineOption("maximized",
		QCoreApplication::translate("main", "Maximize the window on startup")));
	parser.addOption(QCommandLineOption("fullscreen",
		QCoreApplication::translate("main", "Open the window in fullscreen on startup")));
	parser.addPositionalArgument("...", "Additional arguments are fowarded to Neovim", "[-- ...]");
	parser.addHelpOption();

	int sep = app.arguments().indexOf("--");
	QStringList neovimArgs;
	if (sep != -1) {
		QStringList args = app.arguments().mid(0, sep);
		neovimArgs += app.arguments().mid(sep+1);
		parser.process(app.arguments());
	} else {
		parser.process(app.arguments());
	}

	if (parser.isSet("help")) {
		parser.showHelp();
	}

	NeovimQt::NeovimConnector *c;
	if (parser.isSet("embed")) {
		c = NeovimQt::NeovimConnector::fromStdinOut();
	} else {
		if (parser.isSet("server")) {
			QString server = parser.value("server");
			c = NeovimQt::NeovimConnector::connectToNeovim(server);
		} else {
			c = NeovimQt::NeovimConnector::spawn(neovimArgs);
		}
	}

#ifdef NEOVIMQT_GUI_WIDGET
	NeovimQt::Shell *win = new NeovimQt::Shell(c);
	win->show();
	if (parser.isSet("fullscreen")) {
		win->showFullScreen();
	} else if (parser.isSet("maximized")) {
		win->showMaximized();
	} else {
		win->show();
	}
#else
	NeovimQt::MainWindow *win = new NeovimQt::MainWindow(c);
	if (parser.isSet("fullscreen")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::FullScreen);
	} else if (parser.isSet("maximized")) {
		win->delayedShow(NeovimQt::MainWindow::DelayedShow::Maximized);
	} else {
		win->delayedShow();
	}
#endif
	return app.exec();
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#ifndef TORRENT_DISABLE_EXTENSIONS

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include <map>
#include <utility>
#include <numeric>
#include <cstdio>

#include "libtorrent/hasher.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/smart_ban.hpp"
#include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/random.hpp"

//#define TORRENT_LOG_HASH_FAILURES

#ifdef TORRENT_LOG_HASH_FAILURES

#include "libtorrent/peer_id.hpp" // sha1_hash
#include "libtorrent/escape_string.hpp" // to_hex

void log_hash_block(FILE** f, libtorrent::torrent const& t, int piece, int block
	, libtorrent::address a, char const* bytes, int len, bool corrupt)
{
	using namespace libtorrent;

	mkdir("hash_failures", 0755);

	if (*f == NULL)
	{
		char filename[1024];
		snprintf(filename, sizeof(filename), "hash_failures/%s.log"
			, to_hex(t.info_hash().to_string()).c_str());
		*f = fopen(filename, "w");
	}

	file_storage const& fs = t.torrent_file().files();
	std::vector<file_slice> files = fs.map_block(piece, block * 0x4000, len);

	std::string fn = fs.file_path(fs.internal_at(files[0].file_index));

	char filename[4094];
	int offset = 0;
	for (int i = 0; i < files.size(); ++i)
	{
		offset += snprintf(filename+offset, sizeof(filename)-offset
			, "%s[%"PRId64",%d]", libtorrent::filename(fn).c_str(), files[i].offset, int(files[i].size));
		if (offset >= sizeof(filename)) break;
	}

	fprintf(*f, "%s\t%04d\t%04d\t%s\t%s\t%s\n", to_hex(t.info_hash().to_string()).c_str(), piece
		, block, corrupt ? " bad" : "good", print_address(a).c_str(), filename);

	snprintf(filename, sizeof(filename), "hash_failures/%s_%d_%d_%s.block"
		, to_hex(t.info_hash().to_string()).c_str(), piece, block, corrupt ? "bad" : "good");
	FILE* data = fopen(filename, "w+");
	fwrite(bytes, 1, len, data);
	fclose(data);
}

#endif

namespace libtorrent {

	class torrent;

namespace
{

	struct smart_ban_plugin : torrent_plugin, boost::enable_shared_from_this<smart_ban_plugin>
	{
		smart_ban_plugin(torrent& t)
			: m_torrent(t)
			, m_salt(random())
		{
#ifdef TORRENT_LOG_HASH_FAILURES
			m_log_file = NULL;
#endif
		}

#ifdef TORRENT_LOG_HASH_FAILURES
		~smart_ban_plugin()
		{ fclose(m_log_file); }
#endif

		void on_piece_pass(int p)
		{
#ifdef TORRENT_LOGGING
			(*m_torrent.session().m_logger) << time_now_string() << " PIECE PASS [ p: " << p
				<< " | block_hash_size: " << m_block_hashes.size() << " ]\n";
#endif
			// has this piece failed earlier? If it has, go through the
			// CRCs from the time it failed and ban the peers that
			// sent bad blocks
			std::map<piece_block, block_entry>::iterator i = m_block_hashes.lower_bound(piece_block(p, 0));
			if (i == m_block_hashes.end() || int(i->first.piece_index) != p) return;

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			while (size > 0)
			{
				if (i->first.block_index == pb.block_index)
				{
					m_torrent.filesystem().async_read(r, boost::bind(&smart_ban_plugin::on_read_ok_block
						, shared_from_this(), *i, _1, _2));
					m_block_hashes.erase(i++);
				}
				else
				{
					TORRENT_ASSERT(i->first.block_index > pb.block_index);
				}

				if (i == m_block_hashes.end() || int(i->first.piece_index) != p)
					break;

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}

#ifndef NDEBUG
			// make sure we actually removed all the entries for piece 'p'
			i = m_block_hashes.lower_bound(piece_block(p, 0));
			TORRENT_ASSERT(i == m_block_hashes.end() || int(i->first.piece_index) != p);
#endif

			if (m_torrent.is_seed())
			{
				std::map<piece_block, block_entry>().swap(m_block_hashes);
				return;
			}
		}

		void on_piece_failed(int p)
		{
			// The piece failed the hash check. Record
			// the CRC and origin peer of every block

			// if the torrent is aborted, no point in starting
			// a bunch of read operations on it
			if (m_torrent.is_aborted()) return;

			std::vector<void*> downloaders;
			m_torrent.picker().get_downloaders(downloaders, p);

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			for (std::vector<void*>::iterator i = downloaders.begin()
				, end(downloaders.end()); i != end; ++i)
			{
				if (*i != 0)
				{
					m_torrent.filesystem().async_read(r, boost::bind(&smart_ban_plugin::on_read_failed_block
						, shared_from_this(), pb, ((policy::peer*)*i)->address(), _1, _2));
				}

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}
			TORRENT_ASSERT(size <= 0);
		}

	private:

		// this entry ties a specific block CRC to
		// a peer.
		struct block_entry
		{
			policy::peer* peer;
			sha1_hash digest;
		};

		void on_read_failed_block(piece_block b, address a, int ret, disk_io_job const& j)
		{
			TORRENT_ASSERT(m_torrent.session().is_network_thread());

			disk_buffer_holder buffer(m_torrent.session(), j.buffer);

			// ignore read errors
			if (ret != j.buffer_size) return;

			hasher h;
			h.update(j.buffer, j.buffer_size);
			h.update((char const*)&m_salt, sizeof(m_salt));

			std::pair<policy::iterator, policy::iterator> range
				= m_torrent.get_policy().find_peers(a);

			// there is no peer with this address anymore
			if (range.first == range.second) return;

			policy::peer* p = (*range.first);
			block_entry e = {p, h.final()};

#ifdef TORRENT_LOG_HASH_FAILURES
			log_hash_block(&m_log_file, m_torrent, b.piece_index
				, b.block_index, p->address(), j.buffer, j.buffer_size, true);
#endif

			std::map<piece_block, block_entry>::iterator i = m_block_hashes.lower_bound(b);

			if (i != m_block_hashes.end() && i->first == b && i->second.peer == p)
			{
				// this peer has sent us this block before
				if (i->second.digest != e.digest)
				{
					// this time the digest of the block is different
					// from the first time it sent it
					// at least one of them must be bad

					// verify that this is not a dangling pointer
					// if the pointer is in the policy's list, it
					// still live, if it's not, it has been removed
					// and we can't use this pointer
					if (!m_torrent.get_policy().has_peer(p)) return;

#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
					char const* client = "-";
					peer_info info;
					if (p->connection)
					{
						p->connection->get_peer_info(info);
						client = info.client.c_str();
					}
					(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.piece_index
						<< " | b: " << b.block_index
						<< " | c: " << client
						<< " | hash1: " << i->second.digest
						<< " | hash2: " << e.digest
						<< " | ip: " << p->ip() << " ]\n";
#endif
					m_torrent.get_policy().ban_peer(p);
					if (p->connection) p->connection->disconnect(
						errors::peer_banned);
				}
				// we already have this exact entry in the map
				// we don't have to insert it
				return;
			}

			m_block_hashes.insert(i, std::pair<const piece_block, block_entry>(b, e));

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " STORE BLOCK CRC [ p: " << b.piece_index
				<< " | b: " << b.block_index
				<< " | c: " << client
				<< " | digest: " << e.digest
				<< " | ip: " << p->ip() << " ]\n";
#endif
		}

		void on_read_ok_block(std::pair<piece_block, block_entry> b, int ret, disk_io_job const& j)
		{
			TORRENT_ASSERT(m_torrent.session().is_network_thread());

			disk_buffer_holder buffer(m_torrent.session(), j.buffer);

			// ignore read errors
			if (ret != j.buffer_size) return;

			hasher h;
			h.update(j.buffer, j.buffer_size);
			h.update((char const*)&m_salt, sizeof(m_salt));
			sha1_hash ok_digest = h.final();

			policy::peer* p = b.second.peer;

			if (b.second.digest == ok_digest) return;

#ifdef TORRENT_LOG_HASH_FAILURES
			log_hash_block(&m_log_file, m_torrent, b.first.piece_index
				, b.first.block_index, p->address(), j.buffer, j.buffer_size, false);
#endif

			if (p == 0) return;
			if (!m_torrent.get_policy().has_peer(p)) return;

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.first.piece_index
				<< " | b: " << b.first.block_index
				<< " | c: " << client
				<< " | ok_digest: " << ok_digest
				<< " | bad_digest: " << b.second.digest
				<< " | ip: " << p->ip() << " ]\n";
#endif
			m_torrent.get_policy().ban_peer(p);
			if (p->connection) p->connection->disconnect(
				errors::peer_banned);
		}

		torrent& m_torrent;

		// This table maps a piece_block (piece and block index
		// pair) to a peer and the block CRC. The CRC is calculated
		// from the data in the block + the salt
		std::map<piece_block, block_entry> m_block_hashes;

		// This salt is a random value used to calculate the block CRCs
		// Since the CRC function that is used is not a one way function
		// the salt is required to avoid attacks where bad data is sent
		// that is forged to match the CRC of the good data.
		int m_salt;

#ifdef TORRENT_LOG_HASH_FAILURES
		FILE* m_log_file;
#endif
	};

} }

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_smart_ban_plugin(torrent* t, void*)
	{
		return boost::shared_ptr<torrent_plugin>(new smart_ban_plugin(*t));
	}

}

#endif

<commit_msg>minor fix<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#ifndef TORRENT_DISABLE_EXTENSIONS

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include <map>
#include <utility>
#include <numeric>
#include <cstdio>

#include "libtorrent/hasher.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/smart_ban.hpp"
#include "libtorrent/disk_io_thread.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/random.hpp"

//#define TORRENT_LOG_HASH_FAILURES

#ifdef TORRENT_LOG_HASH_FAILURES

#include "libtorrent/peer_id.hpp" // sha1_hash
#include "libtorrent/escape_string.hpp" // to_hex

void log_hash_block(FILE** f, libtorrent::torrent const& t, int piece, int block
	, libtorrent::address a, char const* bytes, int len, bool corrupt)
{
	using namespace libtorrent;

	mkdir("hash_failures", 0755);

	if (*f == NULL)
	{
		char filename[1024];
		snprintf(filename, sizeof(filename), "hash_failures/%s.log"
			, to_hex(t.info_hash().to_string()).c_str());
		*f = fopen(filename, "w");
	}

	file_storage const& fs = t.torrent_file().files();
	std::vector<file_slice> files = fs.map_block(piece, block * 0x4000, len);

	std::string fn = fs.file_path(fs.internal_at(files[0].file_index));

	char filename[4094];
	int offset = 0;
	for (int i = 0; i < files.size(); ++i)
	{
		offset += snprintf(filename+offset, sizeof(filename)-offset
			, "%s[%"PRId64",%d]", libtorrent::filename(fn).c_str(), files[i].offset, int(files[i].size));
		if (offset >= sizeof(filename)) break;
	}

	fprintf(*f, "%s\t%04d\t%04d\t%s\t%s\t%s\n", to_hex(t.info_hash().to_string()).c_str(), piece
		, block, corrupt ? " bad" : "good", print_address(a).c_str(), filename);

	snprintf(filename, sizeof(filename), "hash_failures/%s_%d_%d_%s.block"
		, to_hex(t.info_hash().to_string()).c_str(), piece, block, corrupt ? "bad" : "good");
	FILE* data = fopen(filename, "w+");
	fwrite(bytes, 1, len, data);
	fclose(data);
}

#endif

namespace libtorrent {

	class torrent;

namespace
{

	struct smart_ban_plugin : torrent_plugin, boost::enable_shared_from_this<smart_ban_plugin>
	{
		smart_ban_plugin(torrent& t)
			: m_torrent(t)
			, m_salt(random())
		{
#ifdef TORRENT_LOG_HASH_FAILURES
			m_log_file = NULL;
#endif
		}

#ifdef TORRENT_LOG_HASH_FAILURES
		~smart_ban_plugin()
		{ fclose(m_log_file); }
#endif

		void on_piece_pass(int p)
		{
#ifdef TORRENT_LOGGING
			(*m_torrent.session().m_logger) << time_now_string() << " PIECE PASS [ p: " << p
				<< " | block_hash_size: " << m_block_hashes.size() << " ]\n";
#endif
			// has this piece failed earlier? If it has, go through the
			// CRCs from the time it failed and ban the peers that
			// sent bad blocks
			std::map<piece_block, block_entry>::iterator i = m_block_hashes.lower_bound(piece_block(p, 0));
			if (i == m_block_hashes.end() || int(i->first.piece_index) != p) return;

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			while (size > 0)
			{
				if (i->first.block_index == pb.block_index)
				{
					m_torrent.filesystem().async_read(r, boost::bind(&smart_ban_plugin::on_read_ok_block
						, shared_from_this(), *i, _1, _2));
					m_block_hashes.erase(i++);
				}
				else
				{
					TORRENT_ASSERT(i->first.block_index > pb.block_index);
				}

				if (i == m_block_hashes.end() || int(i->first.piece_index) != p)
					break;

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}

#ifndef NDEBUG
			// make sure we actually removed all the entries for piece 'p'
			i = m_block_hashes.lower_bound(piece_block(p, 0));
			TORRENT_ASSERT(i == m_block_hashes.end() || int(i->first.piece_index) != p);
#endif

			if (m_torrent.is_seed())
			{
				std::map<piece_block, block_entry>().swap(m_block_hashes);
				return;
			}
		}

		void on_piece_failed(int p)
		{
			// The piece failed the hash check. Record
			// the CRC and origin peer of every block

			// if the torrent is aborted, no point in starting
			// a bunch of read operations on it
			if (m_torrent.is_aborted()) return;

			std::vector<void*> downloaders;
			m_torrent.picker().get_downloaders(downloaders, p);

			int size = m_torrent.torrent_file().piece_size(p);
			peer_request r = {p, 0, (std::min)(16*1024, size)};
			piece_block pb(p, 0);
			for (std::vector<void*>::iterator i = downloaders.begin()
				, end(downloaders.end()); i != end; ++i)
			{
				if (*i != 0)
				{
					m_torrent.filesystem().async_read(r, boost::bind(&smart_ban_plugin::on_read_failed_block
						, shared_from_this(), pb, ((policy::peer*)*i)->address(), _1, _2));
				}

				r.start += 16*1024;
				size -= 16*1024;
				r.length = (std::min)(16*1024, size);
				++pb.block_index;
			}
			TORRENT_ASSERT(size <= 0);
		}

	private:

		// this entry ties a specific block CRC to
		// a peer.
		struct block_entry
		{
			policy::peer* peer;
			sha1_hash digest;
		};

		void on_read_failed_block(piece_block b, address a, int ret, disk_io_job const& j)
		{
			TORRENT_ASSERT(m_torrent.session().is_network_thread());

			disk_buffer_holder buffer(m_torrent.session(), j.buffer);

			// ignore read errors
			if (ret != j.buffer_size) return;

			hasher h;
			h.update(j.buffer, j.buffer_size);
			h.update((char const*)&m_salt, sizeof(m_salt));

			std::pair<policy::iterator, policy::iterator> range
				= m_torrent.get_policy().find_peers(a);

			// there is no peer with this address anymore
			if (range.first == range.second) return;

			policy::peer* p = (*range.first);
			block_entry e = {p, h.final()};

#ifdef TORRENT_LOG_HASH_FAILURES
			log_hash_block(&m_log_file, m_torrent, b.piece_index
				, b.block_index, p->address(), j.buffer, j.buffer_size, true);
#endif

			std::map<piece_block, block_entry>::iterator i = m_block_hashes.lower_bound(b);

			if (i != m_block_hashes.end() && i->first == b && i->second.peer == p)
			{
				// this peer has sent us this block before
				if (i->second.digest != e.digest)
				{
					// this time the digest of the block is different
					// from the first time it sent it
					// at least one of them must be bad

					// verify that this is not a dangling pointer
					// if the pointer is in the policy's list, it
					// still live, if it's not, it has been removed
					// and we can't use this pointer
					if (!m_torrent.get_policy().has_peer(p)) return;

#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
					char const* client = "-";
					peer_info info;
					if (p->connection)
					{
						p->connection->get_peer_info(info);
						client = info.client.c_str();
					}
					(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.piece_index
						<< " | b: " << b.block_index
						<< " | c: " << client
						<< " | hash1: " << i->second.digest
						<< " | hash2: " << e.digest
						<< " | ip: " << p->ip() << " ]\n";
#endif
					m_torrent.get_policy().ban_peer(p);
					if (p->connection) p->connection->disconnect(
						errors::peer_banned);
				}
				// we already have this exact entry in the map
				// we don't have to insert it
				return;
			}

			m_block_hashes.insert(i, std::pair<const piece_block, block_entry>(b, e));

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " STORE BLOCK CRC [ p: " << b.piece_index
				<< " | b: " << b.block_index
				<< " | c: " << client
				<< " | digest: " << e.digest
				<< " | ip: " << p->ip() << " ]\n";
#endif
		}

		void on_read_ok_block(std::pair<piece_block, block_entry> b, int ret, disk_io_job const& j)
		{
			TORRENT_ASSERT(m_torrent.session().is_network_thread());

			disk_buffer_holder buffer(m_torrent.session(), j.buffer);

			// ignore read errors
			if (ret != j.buffer_size) return;

			hasher h;
			h.update(j.buffer, j.buffer_size);
			h.update((char const*)&m_salt, sizeof(m_salt));
			sha1_hash ok_digest = h.final();

			policy::peer* p = b.second.peer;

			if (b.second.digest == ok_digest) return;
			if (p == 0) return;

#ifdef TORRENT_LOG_HASH_FAILURES
			log_hash_block(&m_log_file, m_torrent, b.first.piece_index
				, b.first.block_index, p->address(), j.buffer, j.buffer_size, false);
#endif

			if (!m_torrent.get_policy().has_peer(p)) return;

#ifdef TORRENT_LOGGING
			char const* client = "-";
			peer_info info;
			if (p->connection)
			{
				p->connection->get_peer_info(info);
				client = info.client.c_str();
			}
			(*m_torrent.session().m_logger) << time_now_string() << " BANNING PEER [ p: " << b.first.piece_index
				<< " | b: " << b.first.block_index
				<< " | c: " << client
				<< " | ok_digest: " << ok_digest
				<< " | bad_digest: " << b.second.digest
				<< " | ip: " << p->ip() << " ]\n";
#endif
			m_torrent.get_policy().ban_peer(p);
			if (p->connection) p->connection->disconnect(
				errors::peer_banned);
		}

		torrent& m_torrent;

		// This table maps a piece_block (piece and block index
		// pair) to a peer and the block CRC. The CRC is calculated
		// from the data in the block + the salt
		std::map<piece_block, block_entry> m_block_hashes;

		// This salt is a random value used to calculate the block CRCs
		// Since the CRC function that is used is not a one way function
		// the salt is required to avoid attacks where bad data is sent
		// that is forged to match the CRC of the good data.
		int m_salt;

#ifdef TORRENT_LOG_HASH_FAILURES
		FILE* m_log_file;
#endif
	};

} }

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_smart_ban_plugin(torrent* t, void*)
	{
		return boost::shared_ptr<torrent_plugin>(new smart_ban_plugin(*t));
	}

}

#endif

<|endoftext|>