<commit_before>/*
 *  Copyright (c) 2004-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "TunIntf.h"

extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <netlink/route/link.h>
}

#include "fboss/agent/RxPacket.h"
#include "fboss/agent/SwSwitch.h"
#include "fboss/agent/SysError.h"
#include "fboss/agent/TxPacket.h"
#include "fboss/agent/packet/EthHdr.h"
#include <folly/io/async/EventBase.h>
#include <folly/io/async/EventHandler.h>

namespace facebook { namespace fboss {

namespace {

const std::string kTunIntfPrefix = "front";
const std::string kTunDev = "/dev/net/tun";

// Max packets to be processed which are received from host
const int kMaxSentOneTime = 16;

} // anonymous namespace

TunIntf::TunIntf(
    SwSwitch *sw,
    folly::EventBase *evb,
    InterfaceID ifID,
    int ifIndex,
    int mtu)
    : folly::EventHandler(evb),
      sw_(sw),
      name_(createTunIntfName(ifID)),
      ifID_(ifID),
      ifIndex_(ifIndex),
      mtu_(mtu) {
  DCHECK(sw) << "NULL pointer to SwSwitch.";
  DCHECK(evb) << "NULL pointer to EventBase";

  openFD();
  SCOPE_FAIL {
    closeFD();
  };

  LOG(INFO) << "Added interface " << name_ << " with fd " << fd_
            << " @ index " << ifIndex_;
}

TunIntf::TunIntf(
    SwSwitch *sw,
    folly::EventBase *evb,
    InterfaceID ifID,
    const Interface::Addresses& addr,
    int mtu)
    : folly::EventHandler(evb),
      sw_(sw),
      name_(createTunIntfName(ifID)),
      ifID_(ifID),
      addrs_(addr),
      mtu_(mtu) {
  DCHECK(sw) << "NULL pointer to SwSwitch.";
  DCHECK(evb) << "NULL pointer to EventBase";

  // Open Tun interface FD for socket-IO
  openFD();
  SCOPE_FAIL {
    closeFD();
  };

  // Make the Tun interface persistent, so that the network sessions from the
  // application (i.e. BGP)  will not be reset if controller restarts
  auto ret = ioctl(fd_, TUNSETPERSIST, 1);
  sysCheckError(ret, "Failed to set persist interface ", name_);

  // TODO: if needed, we can adjust send buffer size, TUNSETSNDBUF
  auto sock = nl_socket_alloc();
  if (!sock) {
    throw SysError(errno, "failed to open libnl socket");
  }
  SCOPE_EXIT { nl_socket_free(sock); };

  // Connect netlink socket.
  ret = nl_connect(sock, NETLINK_ROUTE);
  sysCheckError(ret, "failed to connect", nl_geterror(ret));
  SCOPE_EXIT { nl_close(sock); };

  // Allocate cache
  nl_cache *cache = nullptr;
  ret = rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
  sysCheckError(ret, "failed to get all links: error: ", nl_geterror(ret));
  SCOPE_EXIT { nl_cache_free(cache); };

  // Extract ifIndex
  ifIndex_ = rtnl_link_name2i(cache, name_.c_str());
  if (ifIndex_ <= 0) {
    FbossError("Got invalid value ", ifIndex_, " for Tun interface ", name_);
  }

  LOG(INFO) << "Created interface " << name_ << " with fd " << fd_
            << " @ index " << ifIndex_;
}

TunIntf::~TunIntf() {
  stop();

  // We must have a valid fd to TunIntf
  CHECK_NE(fd_, -1);

  // Delete interface if need be
  if (toDelete_) {
    auto ret = ioctl(fd_, TUNSETPERSIST, 0);
    sysLogError(ret, "Failed to unset persist interface ", name_);
  }

  // Close FD. This will delete the interface if TUNSETPERSIST is not on
  closeFD();
  LOG(INFO) << (toDelete_ ? "Delete" : "Detach") << " interface " << name_;
}

bool TunIntf::isTunIntfName(std::string const& ifName) {
  return ifName.find(kTunIntfPrefix) == 0;
}

std::string TunIntf::createTunIntfName(InterfaceID ifID) {
  return folly::sformat("{}{}", kTunIntfPrefix, folly::to<std::string>(ifID));
}

InterfaceID TunIntf::getIDFromTunIntfName(std::string const& ifName) {
  if (not isTunIntfName(ifName)) {
    throw FbossError(ifName, " is not a valid tun interface");
  }
  return InterfaceID(atoi(ifName.substr(kTunIntfPrefix.size()).c_str()));
}

void TunIntf::stop() {
  unregisterHandler();
}

void TunIntf::start() {
  if (fd_ != -1 && !isHandlerRegistered()) {
    changeHandlerFD(fd_);
    registerHandler(folly::EventHandler::READ | folly::EventHandler::PERSIST);
  }
}

void TunIntf::openFD() {
  fd_ = open(kTunDev.c_str(), O_RDWR);
  sysCheckError(fd_, "Cannot open ", kTunDev.c_str());
  SCOPE_FAIL {
    closeFD();
  };

  struct ifreq ifr;
  memset(&ifr, 0, sizeof(ifr));
  // Flags: IFF_TUN   - TUN device (no Ethernet headers)
  //        IFF_NO_PI - Do not provide packet information
  ifr.ifr_flags = IFF_TUN|IFF_NO_PI;
  bzero(ifr.ifr_name, sizeof(ifr.ifr_name));
  size_t len = std::min(name_.size(), sizeof(ifr.ifr_name));
  memmove(ifr.ifr_name, name_.c_str(), len);
  auto ret = ioctl(fd_, TUNSETIFF, (void *) &ifr);
  sysCheckError(ret, "Failed to create/attach interface ", name_);

  // Set configured MTU
  setMtu(mtu_);

  // make fd non-blocking
  auto flags = fcntl(fd_, F_GETFL);
  sysCheckError(flags, "Failed to get flags from fd ", fd_);
  flags |= O_NONBLOCK;
  ret = fcntl(fd_, F_SETFL, flags);
  sysCheckError(ret, "Failed to set non-blocking flags ", flags,
                " to fd ", fd_);
  flags = fcntl(fd_, F_GETFD);
  sysCheckError(flags, "Failed to get flags from fd ", fd_);
  flags |= FD_CLOEXEC;
  ret = fcntl(fd_, F_SETFD, flags);
  sysCheckError(ret, "Failed to set close-on-exec flags ", flags,
                " to fd ", fd_);

  LOG(INFO) << "Create/attach to tun interface " << name_ << " @ fd " << fd_;
}

void TunIntf::closeFD() noexcept {
  auto ret = close(fd_);
  sysLogError(ret, "Failed to close fd ", fd_, " for interface ", name_);
  if (ret == 0) {
    LOG(INFO) << "Closed fd " << fd_ << " for interface " << name_;
    fd_ = -1;
  }
}

void TunIntf::addAddress(const folly::IPAddress& addr, uint8_t mask) {
  auto ret = addrs_.emplace(addr, mask);
  if (!ret.second) {
    throw FbossError("Duplication interface address ", addr, "/",
                     static_cast<int>(mask), " for interface ", name_,
                     " @ index", ifIndex_);
  }
  VLOG(3) << "Added address " << addr.str() << "/"
          << static_cast<int>(mask) << " to interface " << name_
          << " @ index " << ifIndex_;
}

void TunIntf::setMtu(int mtu) {
  mtu_ = mtu;
  auto sock = socket(PF_INET, SOCK_DGRAM, 0);
  sysCheckError(sock, "Failed to open socket");

  struct ifreq ifr;
  size_t len = std::min(name_.size(), sizeof(ifr.ifr_name));
  memset(&ifr, 0, sizeof(ifr));
  memmove(ifr.ifr_name, name_.c_str(), len);
  ifr.ifr_mtu = mtu_;
  auto ret = ioctl(sock, SIOCSIFMTU, (void*)&ifr);
  close(sock);
  sysCheckError(ret, "Failed to set MTU ", ifr.ifr_mtu,
                " to fd ", fd_, " errno = ", errno);
  VLOG(3) << "Set tun " << name_ << " MTU to " << mtu;
}

void TunIntf::handlerReady(uint16_t events) noexcept {
  CHECK(fd_ != -1);

  // Since this is L3 packet size, we should also reserve some space for L2
  // header, which is 18 bytes (including one vlan tag)
  int sent = 0;
  int dropped = 0;
  uint64_t bytes = 0;
  bool fdFail = false;
  try {
    while (sent + dropped < kMaxSentOneTime) {
      std::unique_ptr<TxPacket> pkt;
      pkt = sw_->allocateL3TxPacket(mtu_);
      auto buf = pkt->buf();
      int ret = 0;
      do {
        ret = read(fd_, buf->writableTail(), buf->tailroom());
      } while (ret == -1 && errno == EINTR);
      if (ret < 0) {
        if (errno != EAGAIN) {
          sysLogError(ret, "Failed to read on ", fd_);
          // Cannot continue read on this fd
          fdFail = true;
        }
        break;
      } else if (ret == 0) {
        // Nothing to read. It shall not happen as the fd is non-blocking.
        // Just add this case to be safe. Adding DCHECK for sanity checking
        // in debug mode.
        DCHECK(false) << "Unexpected event. Nothing to read.";
        break;
      } else if (ret > buf->tailroom()) {
        // The pkt is larger than the buffer. We don't have complete packet.
        // It shall not happen unless the MTU is mis-match. Drop the packet.
        LOG(ERROR) << "Too large packet (" << ret << " > " << buf->tailroom()
                   << ") received from host. Drop the packet.";
        ++dropped;
      } else {
        bytes += ret;
        buf->append(ret);
        sw_->sendL3Packet(RouterID(0), std::move(pkt));
        ++sent;
      }
    } // while
  } catch (const std::exception& ex) {
    LOG(ERROR) << "Hit some error when forwarding packets :"
               << folly::exceptionStr(ex);
  }

  if (fdFail) {
    unregisterHandler();
  }

  VLOG(4) << "Forwarded " << sent << " packets (" << bytes
          << " bytes) from host @ fd " << fd_ << " for interface " << name_
          << " dropped:" << dropped;
}

bool TunIntf::sendPacketToHost(std::unique_ptr<RxPacket> pkt) {
  CHECK(fd_ != -1);
  const int l2Len = EthHdr::SIZE;

  auto buf = pkt->buf();
  if (buf->length() <= l2Len) {
    LOG(ERROR) << "Received a too small packet with length " << buf->length();
    return false;
  }

  // skip L2 header
  buf->trimStart(l2Len);

  int ret = 0;
  do {
    ret = write(fd_, buf->data(), buf->length());
  } while (ret == -1 && errno == EINTR);
  if (ret < 0) {
    sysLogError(ret, "Failed to send packet to host from Interface ", ifID_);
    return false;
  } else if (ret < buf->length()) {
    LOG(ERROR) << "Failed to send full packet to host from Interface " << ifID_
               << ". " << ret << " bytes sent instead of " << buf->length();
    return false;
  }

  VLOG(4) << "Send packet (" << ret << " bytes) to host from Interface "
          << ifID_;
  return true;
}

}}  // namespace facebook::fboss
<commit_msg>Rename tun interfaces with `fboss` prefix<commit_after>/*
 *  Copyright (c) 2004-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "TunIntf.h"

extern "C" {
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <netlink/route/link.h>
}

#include "fboss/agent/RxPacket.h"
#include "fboss/agent/SwSwitch.h"
#include "fboss/agent/SysError.h"
#include "fboss/agent/TxPacket.h"
#include "fboss/agent/packet/EthHdr.h"
#include <folly/io/async/EventBase.h>
#include <folly/io/async/EventHandler.h>

namespace facebook { namespace fboss {

namespace {

const std::string kTunIntfPrefix = "fboss";
const std::string kTunDev = "/dev/net/tun";

// Max packets to be processed which are received from host
const int kMaxSentOneTime = 16;

} // anonymous namespace

TunIntf::TunIntf(
    SwSwitch *sw,
    folly::EventBase *evb,
    InterfaceID ifID,
    int ifIndex,
    int mtu)
    : folly::EventHandler(evb),
      sw_(sw),
      name_(createTunIntfName(ifID)),
      ifID_(ifID),
      ifIndex_(ifIndex),
      mtu_(mtu) {
  DCHECK(sw) << "NULL pointer to SwSwitch.";
  DCHECK(evb) << "NULL pointer to EventBase";

  openFD();
  SCOPE_FAIL {
    closeFD();
  };

  LOG(INFO) << "Added interface " << name_ << " with fd " << fd_
            << " @ index " << ifIndex_;
}

TunIntf::TunIntf(
    SwSwitch *sw,
    folly::EventBase *evb,
    InterfaceID ifID,
    const Interface::Addresses& addr,
    int mtu)
    : folly::EventHandler(evb),
      sw_(sw),
      name_(createTunIntfName(ifID)),
      ifID_(ifID),
      addrs_(addr),
      mtu_(mtu) {
  DCHECK(sw) << "NULL pointer to SwSwitch.";
  DCHECK(evb) << "NULL pointer to EventBase";

  // Open Tun interface FD for socket-IO
  openFD();
  SCOPE_FAIL {
    closeFD();
  };

  // Make the Tun interface persistent, so that the network sessions from the
  // application (i.e. BGP)  will not be reset if controller restarts
  auto ret = ioctl(fd_, TUNSETPERSIST, 1);
  sysCheckError(ret, "Failed to set persist interface ", name_);

  // TODO: if needed, we can adjust send buffer size, TUNSETSNDBUF
  auto sock = nl_socket_alloc();
  if (!sock) {
    throw SysError(errno, "failed to open libnl socket");
  }
  SCOPE_EXIT { nl_socket_free(sock); };

  // Connect netlink socket.
  ret = nl_connect(sock, NETLINK_ROUTE);
  sysCheckError(ret, "failed to connect", nl_geterror(ret));
  SCOPE_EXIT { nl_close(sock); };

  // Allocate cache
  nl_cache *cache = nullptr;
  ret = rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
  sysCheckError(ret, "failed to get all links: error: ", nl_geterror(ret));
  SCOPE_EXIT { nl_cache_free(cache); };

  // Extract ifIndex
  ifIndex_ = rtnl_link_name2i(cache, name_.c_str());
  if (ifIndex_ <= 0) {
    FbossError("Got invalid value ", ifIndex_, " for Tun interface ", name_);
  }

  LOG(INFO) << "Created interface " << name_ << " with fd " << fd_
            << " @ index " << ifIndex_;
}

TunIntf::~TunIntf() {
  stop();

  // We must have a valid fd to TunIntf
  CHECK_NE(fd_, -1);

  // Delete interface if need be
  if (toDelete_) {
    auto ret = ioctl(fd_, TUNSETPERSIST, 0);
    sysLogError(ret, "Failed to unset persist interface ", name_);
  }

  // Close FD. This will delete the interface if TUNSETPERSIST is not on
  closeFD();
  LOG(INFO) << (toDelete_ ? "Delete" : "Detach") << " interface " << name_;
}

bool TunIntf::isTunIntfName(std::string const& ifName) {
  // Special case to handle old front0 interface.
  // XXX: Delete this case after 6 months (atleast one full rollout). 08-27-2016
  if (ifName == "front0") {
    return true;
  }

  return ifName.find(kTunIntfPrefix) == 0;
}

std::string TunIntf::createTunIntfName(InterfaceID ifID) {
  // Special case to handle old front0 interface.
  // XXX: Delete this case after 6 months (atleast one full rollout). 08-27-2016
  if (ifID == InterfaceID(0)) {
    return "front0";
  }

  return folly::sformat("{}{}", kTunIntfPrefix, folly::to<std::string>(ifID));
}

InterfaceID TunIntf::getIDFromTunIntfName(std::string const& ifName) {
  if (not isTunIntfName(ifName)) {
    throw FbossError(ifName, " is not a valid tun interface");
  }

  // Special case to handle old front0 interface.
  // XXX: Delete this case after 6 months (atleast one full rollout). 08-27-2016
  if (ifName == "front0") {
    return InterfaceID(0);
  }

  return InterfaceID(atoi(ifName.substr(kTunIntfPrefix.size()).c_str()));
}

void TunIntf::stop() {
  unregisterHandler();
}

void TunIntf::start() {
  if (fd_ != -1 && !isHandlerRegistered()) {
    changeHandlerFD(fd_);
    registerHandler(folly::EventHandler::READ | folly::EventHandler::PERSIST);
  }
}

void TunIntf::openFD() {
  fd_ = open(kTunDev.c_str(), O_RDWR);
  sysCheckError(fd_, "Cannot open ", kTunDev.c_str());
  SCOPE_FAIL {
    closeFD();
  };

  struct ifreq ifr;
  memset(&ifr, 0, sizeof(ifr));
  // Flags: IFF_TUN   - TUN device (no Ethernet headers)
  //        IFF_NO_PI - Do not provide packet information
  ifr.ifr_flags = IFF_TUN|IFF_NO_PI;
  bzero(ifr.ifr_name, sizeof(ifr.ifr_name));
  size_t len = std::min(name_.size(), sizeof(ifr.ifr_name));
  memmove(ifr.ifr_name, name_.c_str(), len);
  auto ret = ioctl(fd_, TUNSETIFF, (void *) &ifr);
  sysCheckError(ret, "Failed to create/attach interface ", name_);

  // Set configured MTU
  setMtu(mtu_);

  // make fd non-blocking
  auto flags = fcntl(fd_, F_GETFL);
  sysCheckError(flags, "Failed to get flags from fd ", fd_);
  flags |= O_NONBLOCK;
  ret = fcntl(fd_, F_SETFL, flags);
  sysCheckError(ret, "Failed to set non-blocking flags ", flags,
                " to fd ", fd_);
  flags = fcntl(fd_, F_GETFD);
  sysCheckError(flags, "Failed to get flags from fd ", fd_);
  flags |= FD_CLOEXEC;
  ret = fcntl(fd_, F_SETFD, flags);
  sysCheckError(ret, "Failed to set close-on-exec flags ", flags,
                " to fd ", fd_);

  LOG(INFO) << "Create/attach to tun interface " << name_ << " @ fd " << fd_;
}

void TunIntf::closeFD() noexcept {
  auto ret = close(fd_);
  sysLogError(ret, "Failed to close fd ", fd_, " for interface ", name_);
  if (ret == 0) {
    LOG(INFO) << "Closed fd " << fd_ << " for interface " << name_;
    fd_ = -1;
  }
}

void TunIntf::addAddress(const folly::IPAddress& addr, uint8_t mask) {
  auto ret = addrs_.emplace(addr, mask);
  if (!ret.second) {
    throw FbossError("Duplication interface address ", addr, "/",
                     static_cast<int>(mask), " for interface ", name_,
                     " @ index", ifIndex_);
  }
  VLOG(3) << "Added address " << addr.str() << "/"
          << static_cast<int>(mask) << " to interface " << name_
          << " @ index " << ifIndex_;
}

void TunIntf::setMtu(int mtu) {
  mtu_ = mtu;
  auto sock = socket(PF_INET, SOCK_DGRAM, 0);
  sysCheckError(sock, "Failed to open socket");

  struct ifreq ifr;
  size_t len = std::min(name_.size(), sizeof(ifr.ifr_name));
  memset(&ifr, 0, sizeof(ifr));
  memmove(ifr.ifr_name, name_.c_str(), len);
  ifr.ifr_mtu = mtu_;
  auto ret = ioctl(sock, SIOCSIFMTU, (void*)&ifr);
  close(sock);
  sysCheckError(ret, "Failed to set MTU ", ifr.ifr_mtu,
                " to fd ", fd_, " errno = ", errno);
  VLOG(3) << "Set tun " << name_ << " MTU to " << mtu;
}

void TunIntf::handlerReady(uint16_t events) noexcept {
  CHECK(fd_ != -1);

  // Since this is L3 packet size, we should also reserve some space for L2
  // header, which is 18 bytes (including one vlan tag)
  int sent = 0;
  int dropped = 0;
  uint64_t bytes = 0;
  bool fdFail = false;
  try {
    while (sent + dropped < kMaxSentOneTime) {
      std::unique_ptr<TxPacket> pkt;
      pkt = sw_->allocateL3TxPacket(mtu_);
      auto buf = pkt->buf();
      int ret = 0;
      do {
        ret = read(fd_, buf->writableTail(), buf->tailroom());
      } while (ret == -1 && errno == EINTR);
      if (ret < 0) {
        if (errno != EAGAIN) {
          sysLogError(ret, "Failed to read on ", fd_);
          // Cannot continue read on this fd
          fdFail = true;
        }
        break;
      } else if (ret == 0) {
        // Nothing to read. It shall not happen as the fd is non-blocking.
        // Just add this case to be safe. Adding DCHECK for sanity checking
        // in debug mode.
        DCHECK(false) << "Unexpected event. Nothing to read.";
        break;
      } else if (ret > buf->tailroom()) {
        // The pkt is larger than the buffer. We don't have complete packet.
        // It shall not happen unless the MTU is mis-match. Drop the packet.
        LOG(ERROR) << "Too large packet (" << ret << " > " << buf->tailroom()
                   << ") received from host. Drop the packet.";
        ++dropped;
      } else {
        bytes += ret;
        buf->append(ret);
        sw_->sendL3Packet(RouterID(0), std::move(pkt));
        ++sent;
      }
    } // while
  } catch (const std::exception& ex) {
    LOG(ERROR) << "Hit some error when forwarding packets :"
               << folly::exceptionStr(ex);
  }

  if (fdFail) {
    unregisterHandler();
  }

  VLOG(4) << "Forwarded " << sent << " packets (" << bytes
          << " bytes) from host @ fd " << fd_ << " for interface " << name_
          << " dropped:" << dropped;
}

bool TunIntf::sendPacketToHost(std::unique_ptr<RxPacket> pkt) {
  CHECK(fd_ != -1);
  const int l2Len = EthHdr::SIZE;

  auto buf = pkt->buf();
  if (buf->length() <= l2Len) {
    LOG(ERROR) << "Received a too small packet with length " << buf->length();
    return false;
  }

  // skip L2 header
  buf->trimStart(l2Len);

  int ret = 0;
  do {
    ret = write(fd_, buf->data(), buf->length());
  } while (ret == -1 && errno == EINTR);
  if (ret < 0) {
    sysLogError(ret, "Failed to send packet to host from Interface ", ifID_);
    return false;
  } else if (ret < buf->length()) {
    LOG(ERROR) << "Failed to send full packet to host from Interface " << ifID_
               << ". " << ret << " bytes sent instead of " << buf->length();
    return false;
  }

  VLOG(4) << "Send packet (" << ret << " bytes) to host from Interface "
          << ifID_;
  return true;
}

}}  // namespace facebook::fboss
<|endoftext|>


<commit_before>/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>

  This program can be distributed under the terms of the GNU GPL.
  See the file COPYING.

  gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp
*/

#define FUSE_USE_VERSION 26

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#endif

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

// Non-FUSE includes
#include <vector>
#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>
#include "serverconnection.hpp"
#include <sys/types.h>

/**************
 * GLOBALS *
 ***********/

static std::vector<ServerConnection> connections;

static int agfs_getattr(const char *path, struct stat *stbuf)
{
  memset(stbuf, 0, sizeof(struct stat));
  agerr_t err = 0;
  if (connections.size() > 0) {
    std::pair<struct stat, agerr_t> retVal{connections.front().getattr(path)};
    (*stbuf) = std::get<0>(retVal);
    err = std::get<1>(retVal);
  }

  return -err;
}

static int agfs_access(const char *path, int mask)
{
  int res;

  res = access(path, mask);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_readlink(const char *path, char *buf, size_t size)
{
  int res;

  res = readlink(path, buf, size - 1);
  if (res == -1)
    return -errno;

  buf[res] = '\0';
  return 0;
}

static int agfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		       off_t offset, struct fuse_file_info *fi)
{
  DIR *dp;
  struct dirent *de;

  (void) offset;
  (void) fi;

  dp = opendir(path);
  if (dp == NULL)
    return -errno;

  while ((de = readdir(dp)) != NULL) {
    struct stat st;
    memset(&st, 0, sizeof(st));
    st.st_ino = de->d_ino;
    st.st_mode = de->d_type << 12;
    if (filler(buf, de->d_name, &st, 0))
      break;
  }

  closedir(dp);
  return 0;
}

static int agfs_mknod(const char *path, mode_t mode, dev_t rdev)
{
  int res;

  /* On Linux this could just be 'mknod(path, mode, rdev)' but this
     is more portable */
  if (S_ISREG(mode)) {
    res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
    if (res >= 0)
      res = close(res);
  } else if (S_ISFIFO(mode))
    res = mkfifo(path, mode);
  else
    res = mknod(path, mode, rdev);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_mkdir(const char *path, mode_t mode)
{
  int res;

  res = mkdir(path, mode);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_unlink(const char *path)
{
  int res;

  res = unlink(path);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_rmdir(const char *path)
{
  int res;

  res = rmdir(path);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_symlink(const char *to, const char *from)
{
  int res;

  res = symlink(to, from);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_rename(const char *from, const char *to)
{
  int res;

  res = rename(from, to);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_link(const char *from, const char *to)
{
  int res;

  res = link(from, to);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_chmod(const char *path, mode_t mode)
{
  int res;

  res = chmod(path, mode);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_chown(const char *path, uid_t uid, gid_t gid)
{
  int res;

  res = lchown(path, uid, gid);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_truncate(const char *path, off_t size)
{
  int res;

  res = truncate(path, size);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_utimens(const char *path, const struct timespec ts[2])
{
  int res;
  struct timeval tv[2];

  tv[0].tv_sec = ts[0].tv_sec;
  tv[0].tv_usec = ts[0].tv_nsec / 1000;
  tv[1].tv_sec = ts[1].tv_sec;
  tv[1].tv_usec = ts[1].tv_nsec / 1000;

  res = utimes(path, tv);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_open(const char *path, struct fuse_file_info *fi)
{
  int res;

  res = open(path, fi->flags);
  if (res == -1)
    return -errno;

  close(res);
  return 0;
}

static int agfs_read(const char *path, char *buf, size_t size, off_t offset,
		    struct fuse_file_info *fi)
{
  int fd;
  int res;

  (void) fi;
  fd = open(path, O_RDONLY);
  if (fd == -1)
    return -errno;

  res = pread(fd, buf, size, offset);
  if (res == -1)
    res = -errno;

  close(fd);
  return res;
}

static int agfs_write(const char *path, const char *buf, size_t size,
		     off_t offset, struct fuse_file_info *fi)
{
  int fd;
  int res;

  (void) fi;
  fd = open(path, O_WRONLY);
  if (fd == -1)
    return -errno;

  res = pwrite(fd, buf, size, offset);
  if (res == -1)
    res = -errno;

  close(fd);
  return res;
}

static int agfs_statfs(const char *path, struct statvfs *stbuf)
{
  int res;

  res = statvfs(path, stbuf);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_release(const char *path, struct fuse_file_info *fi)
{
  /* Just a stub. This method is optional and can safely be left
     unimplemented */

  (void) path;
  (void) fi;
  return 0;
}

static int agfs_fsync(const char *path, int isdatasync,
		     struct fuse_file_info *fi)
{
  /* Just a stub. This method is optional and can safely be left
     unimplemented */

  (void) path;
  (void) isdatasync;
  (void) fi;
  return 0;
}

#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int agfs_setxattr(const char *path, const char *name, const char *value,
			size_t size, int flags)
{
  int res = lsetxattr(path, name, value, size, flags);
  if (res == -1)
    return -errno;
  return 0;
}

static int agfs_getxattr(const char *path, const char *name, char *value,
			size_t size)
{
  int res = lgetxattr(path, name, value, size);
  if (res == -1)
    return -errno;
  return res;
}

static int agfs_listxattr(const char *path, char *list, size_t size)
{
  int res = llistxattr(path, list, size);
  if (res == -1)
    return -errno;
  return res;
}

static int agfs_removexattr(const char *path, const char *name)
{
  int res = lremovexattr(path, name);
  if (res == -1)
    return -errno;
  return 0;
}
#endif /* HAVE_SETXATTR */

static struct fuse_operations agfs_oper = {
  .getattr= agfs_getattr,
  .access= agfs_access,
  .readlink= agfs_readlink,
  .readdir= agfs_readdir,
  .mknod= agfs_mknod,
  .mkdir= agfs_mkdir,
  .symlink= agfs_symlink,
  .unlink= agfs_unlink,
  .rmdir= agfs_rmdir,
  .rename= agfs_rename,
  .link= agfs_link,
  .chmod= agfs_chmod,
  .chown= agfs_chown,
  .truncate= agfs_truncate,
  .utimens= agfs_utimens,
  .open= agfs_open,
  .read= agfs_read,
  .write= agfs_write,
  .statfs= agfs_statfs,
  .release= agfs_release,
  .fsync= agfs_fsync,
#ifdef HAVE_SETXATTR
  .setxattr= agfs_setxattr,
  .getxattr= agfs_getxattr,
  .listxattr= agfs_listxattr,
  .removexattr= agfs_removexattr,
#endif
};

/************************************
 * OPTIONS PROCESSING (Not working) *
 ************************************/

/*struct agfs_config {
  char* instanceFile;
};

enum {
     KEY_HELP,
     KEY_VERSION,
};
#define AGFS_OPT(t, p, v) { t, offsetof(struct agfs_config, p), v }

static struct fuse_opt agfs_opts[] = {
     AGFS_OPT("-i %s",          instanceFile, 0),
     AGFS_OPT("--instance=%s", instanceFile, 0),
     AGFS_OPT("instance=%s", instanceFile, 0),

     FUSE_OPT_KEY("-V",             KEY_VERSION),
     FUSE_OPT_KEY("--version",      KEY_VERSION),
     FUSE_OPT_KEY("-h",             KEY_HELP),
     FUSE_OPT_KEY("--help",         KEY_HELP),
     FUSE_OPT_END
};

#define PACKAGE_VERSION "0.0.0 beta"

static int agfs_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
{
     switch (key) {
     case KEY_HELP:
             fprintf(stderr,
                     "usage: %s mountpoint [options]\n"
                     "\n"
                     "general options:\n"
                     "    -o opt,[opt...]  mount options\n"
                     "    -h   --help      print help\n"
                     "    -V   --version   print version\n"
                     "\n"
                     "agfs options:\n"
                     "    -o instance=STRING\n"
                     "    -i STRING          same as '-o instance=STRING'\n"
                     "    --instance=STRING    same as -i STRING'\n\n"
                     , outargs->argv[0]);
             fuse_opt_add_arg(outargs, "-ho");
             fuse_main(outargs->argc, outargs->argv, &agfs_oper, NULL);
             exit(1);

     case KEY_VERSION:
             fprintf(stderr, "agfs version %s\n", PACKAGE_VERSION);
             fuse_opt_add_arg(outargs, "--version");
             fuse_main(outargs->argc, outargs->argv, &agfs_oper, NULL);
             exit(0);
     }
     return 1;
}*/

static const boost::filesystem::path KEYDIRPATH(".agfs");
static const std::string EXTENSION(".agkey");

using namespace boost::filesystem;

int main(int argc, char *argv[])
{
  path homeDir{getenv("HOME")};
  homeDir /= KEYDIRPATH;
  if(!exists(homeDir)) {
    std::cerr << "Could not find key directory: ~/.agfs" << std::endl;
    exit(1);
  }

  directory_iterator end_itr; // default construction yields past-the-end
  for ( directory_iterator itr( homeDir ); itr != end_itr; ++itr ) {
    if( is_regular_file(*itr) ) {
      if( extension(itr->path()) == EXTENSION) {
        std::cout << "Found keyfile: " << itr->path() << std::endl;
        std::fstream keyfile;
        keyfile.open(itr->path().native(), std::fstream::in);
        if(keyfile.is_open()) {
          std::cout << "Opened keyfile" << std::endl;
          std::string hostname, port, key;
          keyfile >> hostname;
          keyfile >> port;
          keyfile >> key;
          connections.push_back(ServerConnection(hostname, port, key));
        }
        keyfile.close();
      }
    }
  }
  return fuse_main(argc, argv, &agfs_oper, NULL);
}
<commit_msg>Modified the fuse_operations struct to eliminate the annoying warnings on compilation<commit_after>/*
  FUSE: Filesystem in Userspace
  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>

  This program can be distributed under the terms of the GNU GPL.
  See the file COPYING.

  gcc -Wall `pkg-config fuse --cflags --libs` fusexmp.c -o fusexmp
*/

#define FUSE_USE_VERSION 26

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#endif

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

// Non-FUSE includes
#include <vector>
#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>
#include "serverconnection.hpp"
#include <sys/types.h>

/**************
 * GLOBALS *
 ***********/

static std::vector<ServerConnection> connections;

static int agfs_getattr(const char *path, struct stat *stbuf)
{
  memset(stbuf, 0, sizeof(struct stat));
  agerr_t err = 0;
  if (connections.size() > 0) {
    std::pair<struct stat, agerr_t> retVal{connections.front().getattr(path)};
    (*stbuf) = std::get<0>(retVal);
    err = std::get<1>(retVal);
  }

  return -err;
}

static int agfs_access(const char *path, int mask)
{
  int res;

  res = access(path, mask);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_readlink(const char *path, char *buf, size_t size)
{
  int res;

  res = readlink(path, buf, size - 1);
  if (res == -1)
    return -errno;

  buf[res] = '\0';
  return 0;
}

static int agfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		       off_t offset, struct fuse_file_info *fi)
{
  DIR *dp;
  struct dirent *de;

  (void) offset;
  (void) fi;

  dp = opendir(path);
  if (dp == NULL)
    return -errno;

  while ((de = readdir(dp)) != NULL) {
    struct stat st;
    memset(&st, 0, sizeof(st));
    st.st_ino = de->d_ino;
    st.st_mode = de->d_type << 12;
    if (filler(buf, de->d_name, &st, 0))
      break;
  }

  closedir(dp);
  return 0;
}

static int agfs_mknod(const char *path, mode_t mode, dev_t rdev)
{
  int res;

  /* On Linux this could just be 'mknod(path, mode, rdev)' but this
     is more portable */
  if (S_ISREG(mode)) {
    res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
    if (res >= 0)
      res = close(res);
  } else if (S_ISFIFO(mode))
    res = mkfifo(path, mode);
  else
    res = mknod(path, mode, rdev);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_mkdir(const char *path, mode_t mode)
{
  int res;

  res = mkdir(path, mode);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_unlink(const char *path)
{
  int res;

  res = unlink(path);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_rmdir(const char *path)
{
  int res;

  res = rmdir(path);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_symlink(const char *to, const char *from)
{
  int res;

  res = symlink(to, from);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_rename(const char *from, const char *to)
{
  int res;

  res = rename(from, to);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_link(const char *from, const char *to)
{
  int res;

  res = link(from, to);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_chmod(const char *path, mode_t mode)
{
  int res;

  res = chmod(path, mode);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_chown(const char *path, uid_t uid, gid_t gid)
{
  int res;

  res = lchown(path, uid, gid);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_truncate(const char *path, off_t size)
{
  int res;

  res = truncate(path, size);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_utimens(const char *path, const struct timespec ts[2])
{
  int res;
  struct timeval tv[2];

  tv[0].tv_sec = ts[0].tv_sec;
  tv[0].tv_usec = ts[0].tv_nsec / 1000;
  tv[1].tv_sec = ts[1].tv_sec;
  tv[1].tv_usec = ts[1].tv_nsec / 1000;

  res = utimes(path, tv);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_open(const char *path, struct fuse_file_info *fi)
{
  int res;

  res = open(path, fi->flags);
  if (res == -1)
    return -errno;

  close(res);
  return 0;
}

static int agfs_read(const char *path, char *buf, size_t size, off_t offset,
		    struct fuse_file_info *fi)
{
  int fd;
  int res;

  (void) fi;
  fd = open(path, O_RDONLY);
  if (fd == -1)
    return -errno;

  res = pread(fd, buf, size, offset);
  if (res == -1)
    res = -errno;

  close(fd);
  return res;
}

static int agfs_write(const char *path, const char *buf, size_t size,
		     off_t offset, struct fuse_file_info *fi)
{
  int fd;
  int res;

  (void) fi;
  fd = open(path, O_WRONLY);
  if (fd == -1)
    return -errno;

  res = pwrite(fd, buf, size, offset);
  if (res == -1)
    res = -errno;

  close(fd);
  return res;
}

static int agfs_statfs(const char *path, struct statvfs *stbuf)
{
  int res;

  res = statvfs(path, stbuf);
  if (res == -1)
    return -errno;

  return 0;
}

static int agfs_release(const char *path, struct fuse_file_info *fi)
{
  /* Just a stub. This method is optional and can safely be left
     unimplemented */

  (void) path;
  (void) fi;
  return 0;
}

static int agfs_fsync(const char *path, int isdatasync,
		     struct fuse_file_info *fi)
{
  /* Just a stub. This method is optional and can safely be left
     unimplemented */

  (void) path;
  (void) isdatasync;
  (void) fi;
  return 0;
}

#ifdef HAVE_SETXATTR
/* xattr operations are optional and can safely be left unimplemented */
static int agfs_setxattr(const char *path, const char *name, const char *value,
			size_t size, int flags)
{
  int res = lsetxattr(path, name, value, size, flags);
  if (res == -1)
    return -errno;
  return 0;
}

static int agfs_getxattr(const char *path, const char *name, char *value,
			size_t size)
{
  int res = lgetxattr(path, name, value, size);
  if (res == -1)
    return -errno;
  return res;
}

static int agfs_listxattr(const char *path, char *list, size_t size)
{
  int res = llistxattr(path, list, size);
  if (res == -1)
    return -errno;
  return res;
}

static int agfs_removexattr(const char *path, const char *name)
{
  int res = lremovexattr(path, name);
  if (res == -1)
    return -errno;
  return 0;
}
#endif /* HAVE_SETXATTR */

/************************************
 * OPTIONS PROCESSING (Not working) *
 ************************************/

/*struct agfs_config {
  char* instanceFile;
};

enum {
     KEY_HELP,
     KEY_VERSION,
};
#define AGFS_OPT(t, p, v) { t, offsetof(struct agfs_config, p), v }

static struct fuse_opt agfs_opts[] = {
     AGFS_OPT("-i %s",          instanceFile, 0),
     AGFS_OPT("--instance=%s", instanceFile, 0),
     AGFS_OPT("instance=%s", instanceFile, 0),

     FUSE_OPT_KEY("-V",             KEY_VERSION),
     FUSE_OPT_KEY("--version",      KEY_VERSION),
     FUSE_OPT_KEY("-h",             KEY_HELP),
     FUSE_OPT_KEY("--help",         KEY_HELP),
     FUSE_OPT_END
};

#define PACKAGE_VERSION "0.0.0 beta"

static int agfs_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
{
     switch (key) {
     case KEY_HELP:
             fprintf(stderr,
                     "usage: %s mountpoint [options]\n"
                     "\n"
                     "general options:\n"
                     "    -o opt,[opt...]  mount options\n"
                     "    -h   --help      print help\n"
                     "    -V   --version   print version\n"
                     "\n"
                     "agfs options:\n"
                     "    -o instance=STRING\n"
                     "    -i STRING          same as '-o instance=STRING'\n"
                     "    --instance=STRING    same as -i STRING'\n\n"
                     , outargs->argv[0]);
             fuse_opt_add_arg(outargs, "-ho");
             fuse_main(outargs->argc, outargs->argv, &agfs_oper, NULL);
             exit(1);

     case KEY_VERSION:
             fprintf(stderr, "agfs version %s\n", PACKAGE_VERSION);
             fuse_opt_add_arg(outargs, "--version");
             fuse_main(outargs->argc, outargs->argv, &agfs_oper, NULL);
             exit(0);
     }
     return 1;
}*/

static const boost::filesystem::path KEYDIRPATH(".agfs");
static const std::string EXTENSION(".agkey");

using namespace boost::filesystem;

static struct fuse_operations agfs_oper;

int main(int argc, char *argv[])
{
  path homeDir{getenv("HOME")};
  homeDir /= KEYDIRPATH;
  if(!exists(homeDir)) {
    std::cerr << "Could not find key directory: ~/.agfs" << std::endl;
    exit(1);
  }

  directory_iterator end_itr; // default construction yields past-the-end
  for ( directory_iterator itr( homeDir ); itr != end_itr; ++itr ) {
    if( is_regular_file(*itr) ) {
      if( extension(itr->path()) == EXTENSION) {
        std::cout << "Found keyfile: " << itr->path() << std::endl;
        std::fstream keyfile;
        keyfile.open(itr->path().native(), std::fstream::in);
        if(keyfile.is_open()) {
          std::cout << "Opened keyfile" << std::endl;
          std::string hostname, port, key;
          keyfile >> hostname;
          keyfile >> port;
          keyfile >> key;
          connections.push_back(ServerConnection(hostname, port, key));
        }
        keyfile.close();
      }
    }
  }

  memset(&agfs_oper, 0, sizeof(struct fuse_operations));

  agfs_oper.getattr= agfs_getattr;
  agfs_oper.access= agfs_access;
  agfs_oper.readlink= agfs_readlink;
  agfs_oper.readdir= agfs_readdir;
  agfs_oper.mknod= agfs_mknod;
  agfs_oper.mkdir= agfs_mkdir;
  agfs_oper.symlink= agfs_symlink;
  agfs_oper.unlink= agfs_unlink;
  agfs_oper.rmdir= agfs_rmdir;
  agfs_oper.rename= agfs_rename;
  agfs_oper.link= agfs_link;
  agfs_oper.chmod= agfs_chmod;
  agfs_oper.chown= agfs_chown;
  agfs_oper.truncate= agfs_truncate;
  agfs_oper.utimens= agfs_utimens;
  agfs_oper.open= agfs_open;
  agfs_oper.read= agfs_read;
  agfs_oper.write= agfs_write;
  agfs_oper.statfs= agfs_statfs;
  agfs_oper.release= agfs_release;
  agfs_oper.fsync= agfs_fsync;
#ifdef HAVE_SETXATTR
  agfs_oper.setxattr= agfs_setxattr;
  agfs_oper.getxattr= agfs_getxattr;
  agfs_oper.listxattr= agfs_listxattr;
  agfs_oper.removexattr= agfs_removexattr;
#endif

  return fuse_main(argc, argv, &agfs_oper, NULL);
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Bitsend developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "core.h"
#include "util.h"
#include "main.h"
#include "uint256.h"

std::string COutPoint::ToString() const
{
    return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,64), n);
}

void COutPoint::print() const
{
    LogPrintf("%s\n", ToString());
}

CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn)
{
    prevout = prevoutIn;
    scriptSig = scriptSigIn;
    nSequence = nSequenceIn;
}

CTxIn::CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn, unsigned int nSequenceIn)
{
    prevout = COutPoint(hashPrevTx, nOut);
    scriptSig = scriptSigIn;
    nSequence = nSequenceIn;
}

std::string CTxIn::ToString() const
{
    std::string str;
    str += "CTxIn(";
    str += prevout.ToString();
    if (prevout.IsNull())
        str += strprintf(", coinbase %s", HexStr(scriptSig));
    else
        str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
    if (nSequence != std::numeric_limits<unsigned int>::max())
        str += strprintf(", nSequence=%u", nSequence);
    str += ")";
    return str;
}

void CTxIn::print() const
{
    LogPrintf("%s\n", ToString());
}

CTxOut::CTxOut(int64_t nValueIn, CScript scriptPubKeyIn)
{
    nValue = nValueIn;
    nRounds = -10; // an initial value, should be no way to get this by calculations
    scriptPubKey = scriptPubKeyIn;
}

uint256 CTxOut::GetHash() const
{
    return SerializeHash(*this);
}

std::string CTxOut::ToString() const
{
    return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
}

void CTxOut::print() const
{
    LogPrintf("%s\n", ToString());
}

uint256 CTransaction::GetHash() const
{
    return SerializeHash(*this);
}

bool CTransaction::IsNewerThan(const CTransaction& old) const
{
    if (vin.size() != old.vin.size())
        return false;
    for (unsigned int i = 0; i < vin.size(); i++)
        if (vin[i].prevout != old.vin[i].prevout)
            return false;

    bool fNewer = false;
    unsigned int nLowest = std::numeric_limits<unsigned int>::max();
    for (unsigned int i = 0; i < vin.size(); i++)
    {
        if (vin[i].nSequence != old.vin[i].nSequence)
        {
            if (vin[i].nSequence <= nLowest)
            {
                fNewer = false;
                nLowest = vin[i].nSequence;
            }
            if (old.vin[i].nSequence < nLowest)
            {
                fNewer = true;
                nLowest = old.vin[i].nSequence;
            }
        }
    }
    return fNewer;
}

int64_t CTransaction::GetValueOut() const
{
    int64_t nValueOut = 0;
    BOOST_FOREACH(const CTxOut& txout, vout)
    {
        nValueOut += txout.nValue;
        if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
            throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
    }
    return nValueOut;
}

double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
{
    // In order to avoid disincentivizing cleaning up the UTXO set we don't count
    // the constant overhead for each txin and up to 110 bytes of scriptSig (which
    // is enough to cover a compressed pubkey p2sh redemption) for priority.
    // Providing any more cleanup incentive than making additional inputs free would
    // risk encouraging people to create junk outputs to redeem later.
    if (nTxSize == 0)
        nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
    BOOST_FOREACH(const CTxIn& txin, vin)
    {
        unsigned int offset = 41U + std::min(110U, (unsigned int)txin.scriptSig.size());
        if (nTxSize > offset)
            nTxSize -= offset;
    }
    if (nTxSize == 0) return 0.0;
    return dPriorityInputs / nTxSize;
}

std::string CTransaction::ToString() const
{
    std::string str;
    str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
        GetHash().ToString().substr(0,10),
        nVersion,
        vin.size(),
        vout.size(),
        nLockTime);
    for (unsigned int i = 0; i < vin.size(); i++)
        str += "    " + vin[i].ToString() + "\n";
    for (unsigned int i = 0; i < vout.size(); i++)
        str += "    " + vout[i].ToString() + "\n";
    return str;
}

void CTransaction::print() const
{
    LogPrintf("%s", ToString());
}

// Amount compression:
// * If the amount is 0, output 0
// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
//   * call the result n
//   * output 1 + 10*(9*n + d - 1) + e
// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
// (this is decodable, as d is in [1-9] and e is in [0-9])

uint64_t CTxOutCompressor::CompressAmount(uint64_t n)
{
    if (n == 0)
        return 0;
    int e = 0;
    while (((n % 10) == 0) && e < 9) {
        n /= 10;
        e++;
    }
    if (e < 9) {
        int d = (n % 10);
        assert(d >= 1 && d <= 9);
        n /= 10;
        return 1 + (n*9 + d - 1)*10 + e;
    } else {
        return 1 + (n - 1)*10 + 9;
    }
}

uint64_t CTxOutCompressor::DecompressAmount(uint64_t x)
{
    // x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9
    if (x == 0)
        return 0;
    x--;
    // x = 10*(9*n + d - 1) + e
    int e = x % 10;
    x /= 10;
    uint64_t n = 0;
    if (e < 9) {
        // x = 9*n + d - 1
        int d = (x % 9) + 1;
        x /= 9;
        // x = n
        n = x*10 + d;
    } else {
        n = x+1;
    }
    while (e) {
        n *= 10;
        e--;
    }
    return n;
}
/*uint256 CBlockHeader::GetHash() const
{
	CChain a1;
	int nHeight= a1.Height();
	//pblock->LastHeight = pindexPrev->nHeight;
	if (nHeight <=10){
    return HashX11(BEGIN(nVersion), END(nNonce));
	}
    else {
	   return HashX17(BEGIN(nVersion), END(nNonce));
	}
}*/
/*uint256 CBlockHeader::GetHash() const{
	if (LastHeight>=15){
    return HashX11(BEGIN(nVersion), END(nNonce));
	}
    else {
	   return HashX17(BEGIN(nVersion), END(nNonce));
	}
    }*/

uint256 CBlockHeader::GetHashX11() const
{
    return HashX11(BEGIN(nVersion), END(nNonce));
}

uint256 CBlock::BuildMerkleTree() const
{
    vMerkleTree.clear();
    BOOST_FOREACH(const CTransaction& tx, vtx)
        vMerkleTree.push_back(tx.GetHash());
    int j = 0;
    for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
    {
        for (int i = 0; i < nSize; i += 2)
        {
            int i2 = std::min(i+1, nSize-1);
            vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),
                                       BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
        }
        j += nSize;
    }
    return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}

std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
{
    if (vMerkleTree.empty())
        BuildMerkleTree();
    std::vector<uint256> vMerkleBranch;
    int j = 0;
    for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
    {
        int i = std::min(nIndex^1, nSize-1);
        vMerkleBranch.push_back(vMerkleTree[j+i]);
        nIndex >>= 1;
        j += nSize;
    }
    return vMerkleBranch;
}

uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
{
    if (nIndex == -1)
        return 0;
    BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
    {
        if (nIndex & 1)
            hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
        else
            hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
        nIndex >>= 1;
    }
    return hash;
}

void CBlock::print() const
{
	//GetHashX11().ToString(),
    LogPrintf("CBlock(hash=disable, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
        nVersion,
        hashPrevBlock.ToString(),
        hashMerkleRoot.ToString(),
        nTime, nBits, nNonce,
        vtx.size());
    for (unsigned int i = 0; i < vtx.size(); i++)
    {
        LogPrintf("  ");
        vtx[i].print();
    }
    LogPrintf("  vMerkleTree: ");
    for (unsigned int i = 0; i < vMerkleTree.size(); i++)
        LogPrintf("%s ", vMerkleTree[i].ToString());
    LogPrintf("\n");
}
<commit_msg>Revert "New way from line 229 to 36"<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Bitsend developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "core.h"
#include "util.h"
#include "main.h"
#include "uint256.h"

std::string COutPoint::ToString() const
{
    return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,64), n);
}

void COutPoint::print() const
{
    LogPrintf("%s\n", ToString());
}

CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn)
{
    prevout = prevoutIn;
    scriptSig = scriptSigIn;
    nSequence = nSequenceIn;
}

CTxIn::CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn, unsigned int nSequenceIn)
{
    prevout = COutPoint(hashPrevTx, nOut);
    scriptSig = scriptSigIn;
    nSequence = nSequenceIn;
}

std::string CTxIn::ToString() const
{
    std::string str;
    str += "CTxIn(";
    str += prevout.ToString();
    if (prevout.IsNull())
        str += strprintf(", coinbase %s", HexStr(scriptSig));
    else
        str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24));
    if (nSequence != std::numeric_limits<unsigned int>::max())
        str += strprintf(", nSequence=%u", nSequence);
    str += ")";
    return str;
}

void CTxIn::print() const
{
    LogPrintf("%s\n", ToString());
}

CTxOut::CTxOut(int64_t nValueIn, CScript scriptPubKeyIn)
{
    nValue = nValueIn;
    nRounds = -10; // an initial value, should be no way to get this by calculations
    scriptPubKey = scriptPubKeyIn;
}

uint256 CTxOut::GetHash() const
{
    return SerializeHash(*this);
}

std::string CTxOut::ToString() const
{
    return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
}

void CTxOut::print() const
{
    LogPrintf("%s\n", ToString());
}

uint256 CTransaction::GetHash() const
{
    return SerializeHash(*this);
}

bool CTransaction::IsNewerThan(const CTransaction& old) const
{
    if (vin.size() != old.vin.size())
        return false;
    for (unsigned int i = 0; i < vin.size(); i++)
        if (vin[i].prevout != old.vin[i].prevout)
            return false;

    bool fNewer = false;
    unsigned int nLowest = std::numeric_limits<unsigned int>::max();
    for (unsigned int i = 0; i < vin.size(); i++)
    {
        if (vin[i].nSequence != old.vin[i].nSequence)
        {
            if (vin[i].nSequence <= nLowest)
            {
                fNewer = false;
                nLowest = vin[i].nSequence;
            }
            if (old.vin[i].nSequence < nLowest)
            {
                fNewer = true;
                nLowest = old.vin[i].nSequence;
            }
        }
    }
    return fNewer;
}

int64_t CTransaction::GetValueOut() const
{
    int64_t nValueOut = 0;
    BOOST_FOREACH(const CTxOut& txout, vout)
    {
        nValueOut += txout.nValue;
        if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
            throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
    }
    return nValueOut;
}

double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
{
    // In order to avoid disincentivizing cleaning up the UTXO set we don't count
    // the constant overhead for each txin and up to 110 bytes of scriptSig (which
    // is enough to cover a compressed pubkey p2sh redemption) for priority.
    // Providing any more cleanup incentive than making additional inputs free would
    // risk encouraging people to create junk outputs to redeem later.
    if (nTxSize == 0)
        nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
    BOOST_FOREACH(const CTxIn& txin, vin)
    {
        unsigned int offset = 41U + std::min(110U, (unsigned int)txin.scriptSig.size());
        if (nTxSize > offset)
            nTxSize -= offset;
    }
    if (nTxSize == 0) return 0.0;
    return dPriorityInputs / nTxSize;
}

std::string CTransaction::ToString() const
{
    std::string str;
    str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
        GetHash().ToString().substr(0,10),
        nVersion,
        vin.size(),
        vout.size(),
        nLockTime);
    for (unsigned int i = 0; i < vin.size(); i++)
        str += "    " + vin[i].ToString() + "\n";
    for (unsigned int i = 0; i < vout.size(); i++)
        str += "    " + vout[i].ToString() + "\n";
    return str;
}

void CTransaction::print() const
{
    LogPrintf("%s", ToString());
}

// Amount compression:
// * If the amount is 0, output 0
// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10)
//   * call the result n
//   * output 1 + 10*(9*n + d - 1) + e
// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9
// (this is decodable, as d is in [1-9] and e is in [0-9])

uint64_t CTxOutCompressor::CompressAmount(uint64_t n)
{
    if (n == 0)
        return 0;
    int e = 0;
    while (((n % 10) == 0) && e < 9) {
        n /= 10;
        e++;
    }
    if (e < 9) {
        int d = (n % 10);
        assert(d >= 1 && d <= 9);
        n /= 10;
        return 1 + (n*9 + d - 1)*10 + e;
    } else {
        return 1 + (n - 1)*10 + 9;
    }
}

uint64_t CTxOutCompressor::DecompressAmount(uint64_t x)
{
    // x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9
    if (x == 0)
        return 0;
    x--;
    // x = 10*(9*n + d - 1) + e
    int e = x % 10;
    x /= 10;
    uint64_t n = 0;
    if (e < 9) {
        // x = 9*n + d - 1
        int d = (x % 9) + 1;
        x /= 9;
        // x = n
        n = x*10 + d;
    } else {
        n = x+1;
    }
    while (e) {
        n *= 10;
        e--;
    }
    return n;
}
/*uint256 CBlockHeader::GetHash() const
{
	CChain a1;
	int nHeight= a1.Height();
	//pblock->LastHeight = pindexPrev->nHeight;
	if (nHeight <=10){
    return HashX11(BEGIN(nVersion), END(nNonce));
	}
    else {
	   return HashX17(BEGIN(nVersion), END(nNonce));
	}
}*/

uint256 CBlockHeader::GetHashX11() const
{
    return HashX11(BEGIN(nVersion), END(nNonce));
}

uint256 CBlock::BuildMerkleTree() const
{
    vMerkleTree.clear();
    BOOST_FOREACH(const CTransaction& tx, vtx)
        vMerkleTree.push_back(tx.GetHash());
    int j = 0;
    for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
    {
        for (int i = 0; i < nSize; i += 2)
        {
            int i2 = std::min(i+1, nSize-1);
            vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),
                                       BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
        }
        j += nSize;
    }
    return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}

std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const
{
    if (vMerkleTree.empty())
        BuildMerkleTree();
    std::vector<uint256> vMerkleBranch;
    int j = 0;
    for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
    {
        int i = std::min(nIndex^1, nSize-1);
        vMerkleBranch.push_back(vMerkleTree[j+i]);
        nIndex >>= 1;
        j += nSize;
    }
    return vMerkleBranch;
}

uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
{
    if (nIndex == -1)
        return 0;
    BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
    {
        if (nIndex & 1)
            hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
        else
            hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
        nIndex >>= 1;
    }
    return hash;
}

void CBlock::print() const
{
	//GetHashX11().ToString(),
    LogPrintf("CBlock(hash=disable, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
        nVersion,
        hashPrevBlock.ToString(),
        hashMerkleRoot.ToString(),
        nTime, nBits, nNonce,
        vtx.size());
    for (unsigned int i = 0; i < vtx.size(); i++)
    {
        LogPrintf("  ");
        vtx[i].print();
    }
    LogPrintf("  vMerkleTree: ");
    for (unsigned int i = 0; i < vMerkleTree.size(); i++)
        LogPrintf("%s ", vMerkleTree[i].ToString());
    LogPrintf("\n");
}
<|endoftext|>


<commit_before>// -----------------------------------------------------------------------------
//
// MIT License
//
// Copyright (c) 2016 Alberto Sola
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------

#include "date.hpp"
#include <iostream>

char Date::separator = '/';

// -----------------------------------------------------------------------------

Date::Date(){
  set_date(0,0,0);
}

// -----------------------------------------------------------------------------

Date::Date(const std::string & date){
  set_from_str(date);
}

// -----------------------------------------------------------------------------

void Date::set_date(short int iday, short int imonth, int iyear){
  day = iday;
  month = imonth;
  year = iyear;
}

// -----------------------------------------------------------------------------

short int Date::get_day() const{ return day; }

// -----------------------------------------------------------------------------

short int Date::get_month() const{ return month; }

// -----------------------------------------------------------------------------

int Date::get_year() const{ return year; }

// -----------------------------------------------------------------------------

void Date::set_day(short int iday){ day = iday; }

// -----------------------------------------------------------------------------

void Date::set_month(short int imonth){ month = imonth; }

// -----------------------------------------------------------------------------

void Date::set_year(int iyear){ year = iyear; }

// -----------------------------------------------------------------------------

void Date::set_current(){
  const int BASE_YEAR = 1900;
  std::time_t time_ = std::time(nullptr);
  std::tm * current_time = std::localtime(&time_);

  day = current_time->tm_mday;
  month = current_time->tm_mon;
  year = BASE_YEAR + current_time->tm_year;

}

// -----------------------------------------------------------------------------

void Date::set_from_str(const std::string & date){
  //TODO: improve

  std::vector<std::string> date_parts;
  std::string word = "";

  for( auto c: date ){

    if( c == separator ){
      date_parts.push_back(word);
      word = "";
    }
    else
      word += c;

  }

  date_parts.push_back(word);

  day = std::stoi(date_parts[0]);
  month = std::stoi(date_parts[1]);
  year = std::stoi(date_parts[2]);

}

// -----------------------------------------------------------------------------

std::string Date::to_str() const{
  std::string date = "";

  date += std::to_string(day);
  date += separator;
  date += std::to_string(month);
  date += separator;
  date += std::to_string(year);

  return date;
}

// -----------------------------------------------------------------------------

bool Date::empty() const{
  return day == 0 || month == 0 || year == 0;
}

// -----------------------------------------------------------------------------

Date & Date::operator=(const Date & date){
  day = date.day;
  month = date.month;
  year = date.year;

  return (*this);
}

// -----------------------------------------------------------------------------
<commit_msg>Month bug fixed.<commit_after>// -----------------------------------------------------------------------------
//
// MIT License
//
// Copyright (c) 2016 Alberto Sola
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------

#include "date.hpp"
#include <iostream>

char Date::separator = '/';

// -----------------------------------------------------------------------------

Date::Date(){
  set_date(0,0,0);
}

// -----------------------------------------------------------------------------

Date::Date(const std::string & date){
  set_from_str(date);
}

// -----------------------------------------------------------------------------

void Date::set_date(short int iday, short int imonth, int iyear){
  day = iday;
  month = imonth;
  year = iyear;
}

// -----------------------------------------------------------------------------

short int Date::get_day() const{ return day; }

// -----------------------------------------------------------------------------

short int Date::get_month() const{ return month; }

// -----------------------------------------------------------------------------

int Date::get_year() const{ return year; }

// -----------------------------------------------------------------------------

void Date::set_day(short int iday){ day = iday; }

// -----------------------------------------------------------------------------

void Date::set_month(short int imonth){ month = imonth; }

// -----------------------------------------------------------------------------

void Date::set_year(int iyear){ year = iyear; }

// -----------------------------------------------------------------------------

void Date::set_current(){
  const int BASE_YEAR = 1900;
  std::time_t time_ = std::time(nullptr);
  std::tm * current_time = std::localtime(&time_);

  day = current_time->tm_mday;
  month = current_time->tm_mon + 1;
  year = BASE_YEAR + current_time->tm_year;

}

// -----------------------------------------------------------------------------

void Date::set_from_str(const std::string & date){
  //TODO: improve

  std::vector<std::string> date_parts;
  std::string word = "";

  for( auto c: date ){

    if( c == separator ){
      date_parts.push_back(word);
      word = "";
    }
    else
      word += c;

  }

  date_parts.push_back(word);

  day = std::stoi(date_parts[0]);
  month = std::stoi(date_parts[1]);
  year = std::stoi(date_parts[2]);

}

// -----------------------------------------------------------------------------

std::string Date::to_str() const{
  std::string date = "";

  date += std::to_string(day);
  date += separator;
  date += std::to_string(month);
  date += separator;
  date += std::to_string(year);

  return date;
}

// -----------------------------------------------------------------------------

bool Date::empty() const{
  return day == 0 || month == 0 || year == 0;
}

// -----------------------------------------------------------------------------

Date & Date::operator=(const Date & date){
  day = date.day;
  month = date.month;
  year = date.year;

  return (*this);
}

// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>
#define DECLSPEC_EXPORT __declspec(dllexport)
#define WINAPI __stdcall

#include <ctime>
#include "tetris_core.h"
#include "random.h"
#include "search_simple.h"
#include "ai_easy.h"
#include "rule_st.h"

//for https://misakamm.com/blog/504

m_tetris::TetrisEngine<rule_st::TetrisRule, ai_easy::AI,search_simple::Search> tetris_ai;

extern "C" void attach_init()
{
    ege::mtsrand(unsigned int(time(nullptr)));
}

//AI֣ʾڽ
extern "C" DECLSPEC_EXPORT char const *WINAPI Name()
{
    static std::string name = "ai demo (random)";
    return name.c_str();
}

namespace demo
{
    using namespace m_tetris;

    double eval(TetrisNode const *node, TetrisMap const &map, TetrisMap const &src_map, size_t clear)
    {
        return clear * 100 + ege::mtdrand() * 100;
    }
}

/*
 * path ڽղ̲أַ
 *      'l': һ
 *      'r': һ
 *      'd': һ
 *      'L': Ƶͷ
 *      'R': Ƶͷ
 *      'D': Ƶףճϣɼƶ
 *      'z': ʱת
 *      'c': ˳ʱת
 * ַĩβҪ'\0'ʾزӲ䣩
 *
 * ֧·Ҫ˺ֻʹһĻɾ
 */
extern "C" DECLSPEC_EXPORT int WINAPI AIPath(int boardW, int boardH, char board[], char curPiece, int curX, int curY, int curR, char nextPiece, char path[])
{
    if(!tetris_ai.prepare(boardW, boardH))
    {
        return 0;
    }
    tetris_ai.ai_config()->eval_func = demo::eval;
    tetris_ai.ai_config()->str_name = "Demo Random AI";
    m_tetris::TetrisMap map(boardW, boardH);
    for(int y = 0, add = 0; y < boardH; ++y, add += boardW)
    {
        for(int x = 0; x < boardW; ++x)
        {
            if(board[x + add] == '1')
            {
                map.top[x] = map.roof = y + 1;
                map.row[y] |= 1 << x;
                ++map.count;
            }
        }
    }
    m_tetris::TetrisBlockStatus status(curPiece, curX - 1, curY - 1, curR - 1);
    size_t next_length = nextPiece == ' ' ? 0 : 1;
    m_tetris::TetrisNode const *node = tetris_ai.get(status);
    auto target = tetris_ai.run(map, node, &nextPiece, next_length, 49).target;
    if(target != nullptr)
    {
        std::vector<char> ai_path = tetris_ai.make_path(node, target, map);
        memcpy(path, ai_path.data(), ai_path.size());
        path[ai_path.size()] = '\0';
    }
    return 0;
}
<commit_msg>demo调整<commit_after>
#define DECLSPEC_EXPORT __declspec(dllexport)
#define WINAPI __stdcall

#include <ctime>
#include "tetris_core.h"
#include "random.h"
#include "search_simple.h"
#include "ai_easy.h"
#include "rule_st.h"

//for https://misakamm.com/blog/504

m_tetris::TetrisEngine<rule_st::TetrisRule, ai_easy::AI,search_simple::Search> tetris_ai;

extern "C" void attach_init()
{
    ege::mtsrand(unsigned int(time(nullptr)));
}

//AI֣ʾڽ
extern "C" DECLSPEC_EXPORT char const *WINAPI Name()
{
    static std::string name = tetris_ai.ai_name();
    return name.c_str();
}

namespace demo
{
    using namespace m_tetris;

    double eval(TetrisNode const *node, TetrisMap const &map, TetrisMap const &src_map, size_t clear)
    {
        return clear * 100 + ege::mtdrand() * 100;
    }
}

/*
 * path ڽղ̲أַ
 *      'l': һ
 *      'r': һ
 *      'd': һ
 *      'L': Ƶͷ
 *      'R': Ƶͷ
 *      'D': Ƶףճϣɼƶ
 *      'z': ʱת
 *      'c': ˳ʱת
 * ַĩβҪ'\0'ʾزӲ䣩
 *
 * ֧·Ҫ˺ֻʹһĻɾ
 */
extern "C" DECLSPEC_EXPORT int WINAPI AIPath(int boardW, int boardH, char board[], char curPiece, int curX, int curY, int curR, char nextPiece, char path[])
{
    if(!tetris_ai.prepare(boardW, boardH))
    {
        return 0;
    }
    tetris_ai.ai_config()->eval_func = demo::eval;
    tetris_ai.ai_config()->str_name = "Demo Random AI";
    m_tetris::TetrisMap map(boardW, boardH);
    for(int y = 0, add = 0; y < boardH; ++y, add += boardW)
    {
        for(int x = 0; x < boardW; ++x)
        {
            if(board[x + add] == '1')
            {
                map.top[x] = map.roof = y + 1;
                map.row[y] |= 1 << x;
                ++map.count;
            }
        }
    }
    m_tetris::TetrisBlockStatus status(curPiece, curX - 1, curY - 1, curR - 1);
    size_t next_length = nextPiece == ' ' ? 0 : 1;
    m_tetris::TetrisNode const *node = tetris_ai.get(status);
    auto target = tetris_ai.run(map, node, &nextPiece, next_length, 49).target;
    if(target != nullptr)
    {
        std::vector<char> ai_path = tetris_ai.make_path(node, target, map);
        memcpy(path, ai_path.data(), ai_path.size());
        path[ai_path.size()] = '\0';
    }
    return 0;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include "draw.hpp"
#include "logics.hpp"

SDL_Renderer * _render = NULL;

void draw_init( SDL_Renderer * render ) {
    _render = render;
}

Uint32 get_coloru( void ) {
    Uint8 r, g, b;

    SDL_GetRenderDrawColor( _render, &r, &g, &b, NULL );
    return ( r << 16 ) + ( g << 8 ) + b;
}

int set_coloru( Uint32 color ) {
    Uint8 r, ro, g, go, b, bo, ao;

    r = ( color >> 16 );
    g = ( ( color >> 8 ) & 0xff );
    b = ( color & 0xff );
    SDL_GetRenderDrawColor( _render, &ro, &go, &bo, &ao );
    return SDL_SetRenderDrawColor( _render, r, g, b, 0xff );
}

int set_color3u( Uint8 red, Uint8 green, Uint8 blue ) {
    Uint8 ro, go, bo, ao;

    SDL_GetRenderDrawColor( _render, &ro, &go, &bo, &ao );
    return SDL_SetRenderDrawColor( _render, red, green, blue, 0xff );
}

int set_color4u( Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha ) {
    Uint8 ro, go, bo, ao;

    SDL_GetRenderDrawColor( _render, &ro, &go, &bo, &ao );
    return SDL_SetRenderDrawColor( _render, red, green, blue, alpha );
}

int draw_aaline( int x1, int y1, int x2, int y2 ) {
    Uint32 intshift, erracc, erradj, erracctmp, wgt;
    int dx, dy, tmp, xdir, y0p1, x0pxdir, result;
    Sint32 xx0, yy0, xx1, yy1;
    Uint8 r, g, b, a;

    result = SDL_GetRenderDrawColor( _render, &r, &g, &b, &a );
    xx0 = x1; yy0 = y1;
    xx1 = x2; yy1 = y2;
    if ( yy0 > yy1 ) {
        tmp = yy0; yy0 = yy1;
        yy1 = tmp; tmp = xx0;
        xx0 = xx1; xx1 = tmp;
    }
    dx = xx1 - xx0;
    dy = yy1 - yy0;
    if ( dx == 0 || dy == 0 ) {
        return SDL_RenderDrawLine( _render, x1, y1, x2, y2 );
    }
    xdir = 1;
    if ( dx < 0 ) {
        xdir = -1;
        dx = -dx;
    }
    erracc = 0;
    intshift = 24;
    result |= set_color3u( r, g, b );
    result |= SDL_RenderDrawPoint( _render, x1, y1 );
    if ( dy > dx ) {
        erradj = ( ( dx << 16 ) / dy ) << 16;
        x0pxdir = xx0 + xdir;
        while ( --dy ) {
            erracctmp = erracc;
            erracc += erradj;
            if ( erracc <= erracctmp ) {
                xx0 = x0pxdir;
                x0pxdir += xdir;
            }
            yy0++;
            wgt = ( erracc >> intshift ) & 255;
            result |= set_color4u( r, g, b, 255 - wgt );
            result |= SDL_RenderDrawPoint( _render, xx0, yy0 );
            result |= set_color4u( r, g, b, wgt );
            result |= SDL_RenderDrawPoint( _render, x0pxdir, yy0 );
        }
    } else {
        erradj = ( ( dy << 16 ) / dx ) << 16;
        y0p1 = yy0 + 1;
        while ( --dx ) {
            erracctmp = erracc;
            erracc += erradj;
            if ( erracc <= erracctmp ) {
                yy0 = y0p1;
                y0p1++;
            }
            xx0 += xdir;
            wgt = ( erracc >> intshift ) & 255;
            result |= set_color4u( r, g, b, 255 - wgt );
            result |= SDL_RenderDrawPoint( _render, xx0, yy0 );
            result |= set_color4u( r, g, b, wgt );
            result |= SDL_RenderDrawPoint( _render, xx0, y0p1 );
        }
    }
    return result;
}

void draw_path(vec3s n, SDL_Point center, std::vector<vec3s> vs) {
    // отрисовываем путь
    // пока без проверки невидимых линий
    SDL_Point prev;
    bool pe = false;
    for ( auto v: vs ) {
        if ( visible ( n, v ) )
        {
            SDL_Point cur = surf_to_screen( n, v, center);
            if ( pe )
                draw_aaline( prev.x, prev.y, cur.x, cur.y );
            prev = cur;
            pe = true;
        }
        else
            pe = false;
    }
}

void draw_sphere( vec3s n, SDL_Point center, float R, field & f ) {
    Uint32 color = get_coloru();

    // отрисуем все клетки для теста
    set_color3u(255, 0, 255);
    for ( size_t i = 0; i < f.f.size(); i++ ) {
        for ( size_t j = 0; j < f.f[i].size(); j++ ) {
            if ( f.f[i][j] ) {
                auto cc = cell_contour( { (int)i, (int)j }, f, 32 );
                SDL_Point sc[cc.size()];
                for (std::size_t i = 0; i < cc.size(); ++i)
                {
                    cc[i].r = R;
                    sc[i] = surf_to_screen( n, cc[i], center);
                }
                if ( n * cc[0] >= 0 ) { // так не видно косяков
                // if ( visible( n, cc[0] ) ) {
                    draw_filled_polygon( sc, 32 );
                }
            }
        }
    }

    set_coloru( color );

    // набор точек от 0 до 2pi
    int size = 65;
    std::vector<vec3s> v(size);
    for (int i = 0; i < size; ++i) {
        v[i].r = R;
        v[i].theta = 2 * M_PI * i / (size - 1);
    }
    // меридианы
    for ( unsigned int i = 0; i < f.width; ++i ) {
        float p = i * 2 * M_PI / f.width;
        for (int i = 0; i < size; ++i) {v[i].phi = p;};
        draw_path( n, center, v);
    }

    for (int i = 0; i < size; ++i) {v[i].phi = 2 * M_PI * i / (size - 1);}
    // широты
    for ( unsigned int i = 1; i < f.height; ++i ) {
        float p = i * M_PI / f.height;
        for (int i = 0; i < size; ++i) {v[i].theta = p;};
        draw_path( n, center, v);
    }

    // оси координат (для проверки корректности отрисовки)
    set_color3u(255, 0, 0);
    draw_path( n, center, {{0,0,0}, {1.2f*R, M_PI/2, 0}});
    set_color3u(0, 255, 0);
    draw_path( n, center, {{0,0,0}, {1.2f*R, M_PI/2, M_PI / 2}});
    set_color3u(0, 0, 255);
    draw_path( n, center, {{0,0,0}, {1.2f*R, 0, 0}});
}

int draw_filled_polygon( const SDL_Point* vs, const int n ) {
    int min_y, max_y, result, counts;
    int ind1, ind2, x1, x2, y1, y2;
    int * polygons = new int [n];
    int xa, xb;

    if ( vs == nullptr || n < 3 ) {
        return -1;
    }
    // нужно тестирование
    min_y = std::min_element( vs, vs + n,
            [](const SDL_Point & a, const SDL_Point & b)
            { return a.y < b.y; } ) -> y;
    max_y = std::max_element( vs, vs + n,
            [](const SDL_Point & a, const SDL_Point & b)
            { return a.y < b.y; } ) -> y;
    result = 0;
    for ( int y = min_y; y < max_y; y++ ) {
        counts = 0;
        for ( int i = 0; i < n; i++ ) {
            if ( !i ) {
                ind1 = n - 1;
                ind2 = 0;
            } else {
                ind1 = i - 1;
                ind2 = i;
            }
            y1 = vs[ind1].y;
            y2 = vs[ind2].y;
            if ( y1 < y2 ) {
                x1 = vs[ind1].x;
                x2 = vs[ind2].x;
            } else if ( y1 > y2 ) {
                y2 = vs[ind1].y;
                y1 = vs[ind2].y;
                x2 = vs[ind1].x;
                x1 = vs[ind2].x;
            } else {
                continue;
            }
            if ( ( ( y >= y1 ) && ( y < y2 ) ) ||
                 ( ( y == max_y ) && ( y > y1 ) && ( y <= y2 ) ) ) {
                polygons[counts++] =
                    ( ( 65536 * ( y - y1 ) ) / ( y2 - y1 ) ) * ( x2 - x1 ) +
                    ( 65536 * x1 );
            }
        }
        std::sort( polygons, polygons + counts );
        result = 0;
        for ( int i = 0; i < counts; i += 2 ) {
            xa = polygons[i+0] + 1;
            xb = polygons[i+1] - 1;
            xa = ( xa >> 16 ) + ( ( xa & 32768 ) >> 15 );
            xb = ( xb >> 16 ) + ( ( xb & 32768 ) >> 15 );
            result |= SDL_RenderDrawLine( _render, xa, y, xb, y );
        }
    }
    delete[] polygons;
    return result;
}
<commit_msg>[fix] working with visible<commit_after>#include <algorithm>
#include "draw.hpp"
#include "logics.hpp"

SDL_Renderer * _render = NULL;

void draw_init( SDL_Renderer * render ) {
    _render = render;
}

Uint32 get_coloru( void ) {
    Uint8 r, g, b;

    SDL_GetRenderDrawColor( _render, &r, &g, &b, NULL );
    return ( r << 16 ) + ( g << 8 ) + b;
}

int set_coloru( Uint32 color ) {
    Uint8 r, ro, g, go, b, bo, ao;

    r = ( color >> 16 );
    g = ( ( color >> 8 ) & 0xff );
    b = ( color & 0xff );
    SDL_GetRenderDrawColor( _render, &ro, &go, &bo, &ao );
    return SDL_SetRenderDrawColor( _render, r, g, b, 0xff );
}

int set_color3u( Uint8 red, Uint8 green, Uint8 blue ) {
    Uint8 ro, go, bo, ao;

    SDL_GetRenderDrawColor( _render, &ro, &go, &bo, &ao );
    return SDL_SetRenderDrawColor( _render, red, green, blue, 0xff );
}

int set_color4u( Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha ) {
    Uint8 ro, go, bo, ao;

    SDL_GetRenderDrawColor( _render, &ro, &go, &bo, &ao );
    return SDL_SetRenderDrawColor( _render, red, green, blue, alpha );
}

int draw_aaline( int x1, int y1, int x2, int y2 ) {
    Uint32 intshift, erracc, erradj, erracctmp, wgt;
    int dx, dy, tmp, xdir, y0p1, x0pxdir, result;
    Sint32 xx0, yy0, xx1, yy1;
    Uint8 r, g, b, a;

    result = SDL_GetRenderDrawColor( _render, &r, &g, &b, &a );
    xx0 = x1; yy0 = y1;
    xx1 = x2; yy1 = y2;
    if ( yy0 > yy1 ) {
        tmp = yy0; yy0 = yy1;
        yy1 = tmp; tmp = xx0;
        xx0 = xx1; xx1 = tmp;
    }
    dx = xx1 - xx0;
    dy = yy1 - yy0;
    if ( dx == 0 || dy == 0 ) {
        return SDL_RenderDrawLine( _render, x1, y1, x2, y2 );
    }
    xdir = 1;
    if ( dx < 0 ) {
        xdir = -1;
        dx = -dx;
    }
    erracc = 0;
    intshift = 24;
    result |= set_color3u( r, g, b );
    result |= SDL_RenderDrawPoint( _render, x1, y1 );
    if ( dy > dx ) {
        erradj = ( ( dx << 16 ) / dy ) << 16;
        x0pxdir = xx0 + xdir;
        while ( --dy ) {
            erracctmp = erracc;
            erracc += erradj;
            if ( erracc <= erracctmp ) {
                xx0 = x0pxdir;
                x0pxdir += xdir;
            }
            yy0++;
            wgt = ( erracc >> intshift ) & 255;
            result |= set_color4u( r, g, b, 255 - wgt );
            result |= SDL_RenderDrawPoint( _render, xx0, yy0 );
            result |= set_color4u( r, g, b, wgt );
            result |= SDL_RenderDrawPoint( _render, x0pxdir, yy0 );
        }
    } else {
        erradj = ( ( dy << 16 ) / dx ) << 16;
        y0p1 = yy0 + 1;
        while ( --dx ) {
            erracctmp = erracc;
            erracc += erradj;
            if ( erracc <= erracctmp ) {
                yy0 = y0p1;
                y0p1++;
            }
            xx0 += xdir;
            wgt = ( erracc >> intshift ) & 255;
            result |= set_color4u( r, g, b, 255 - wgt );
            result |= SDL_RenderDrawPoint( _render, xx0, yy0 );
            result |= set_color4u( r, g, b, wgt );
            result |= SDL_RenderDrawPoint( _render, xx0, y0p1 );
        }
    }
    return result;
}

void draw_path(vec3s n, SDL_Point center, std::vector<vec3s> vs) {
    // отрисовываем путь
    // пока без проверки невидимых линий
    SDL_Point prev;
    bool pe = false;
    for ( auto v: vs ) {
        if ( visible ( n, v ) )
        {
            SDL_Point cur = surf_to_screen( n, v, center);
            if ( pe )
                draw_aaline( prev.x, prev.y, cur.x, cur.y );
            prev = cur;
            pe = true;
        }
        else
            pe = false;
    }
}

void draw_sphere( vec3s n, SDL_Point center, float R, field & f ) {
    Uint32 color = get_coloru();

    // отрисуем все клетки для теста
    set_color3u(255, 0, 255);
    for ( size_t i = 0; i < f.f.size(); i++ ) {
        for ( size_t j = 0; j < f.f[i].size(); j++ ) {
            if ( f.f[i][j] ) {
                auto cc = cell_contour( { (int)i, (int)j }, f, 32 );
                if ( n * cc[0] >= 0 ) { // так не видно косяков
                // if ( visible( n, cc[0] ) ) {
                    SDL_Point sc[cc.size()];
                    for (std::size_t i = 0; i < cc.size(); ++i)
                    {
                        cc[i].r = R;
                        sc[i] = surf_to_screen( n, cc[i], center);
                    }
                    draw_filled_polygon( sc, 32 );
                }
            }
        }
    }

    set_coloru( color );

    // набор точек от 0 до 2pi
    int size = 65;
    std::vector<vec3s> v(size);
    for (int i = 0; i < size; ++i) {
        v[i].r = R;
        v[i].theta = 2 * M_PI * i / (size - 1);
    }
    // меридианы
    for ( unsigned int i = 0; i < f.width; ++i ) {
        float p = i * 2 * M_PI / f.width;
        for (int i = 0; i < size; ++i) {v[i].phi = p;};
        draw_path( n, center, v);
    }

    for (int i = 0; i < size; ++i) {v[i].phi = 2 * M_PI * i / (size - 1);}
    // широты
    for ( unsigned int i = 1; i < f.height; ++i ) {
        float p = i * M_PI / f.height;
        for (int i = 0; i < size; ++i) {v[i].theta = p;};
        draw_path( n, center, v);
    }

    // оси координат (для проверки корректности отрисовки)
    set_color3u(255, 0, 0);
    draw_path( n, center, {{0,0,0}, {1.2f*R, M_PI/2, 0}});
    set_color3u(0, 255, 0);
    draw_path( n, center, {{0,0,0}, {1.2f*R, M_PI/2, M_PI / 2}});
    set_color3u(0, 0, 255);
    draw_path( n, center, {{0,0,0}, {1.2f*R, 0, 0}});
}

int draw_filled_polygon( const SDL_Point* vs, const int n ) {
    int min_y, max_y, result, counts;
    int ind1, ind2, x1, x2, y1, y2;
    int * polygons = new int [n];
    int xa, xb;

    if ( vs == nullptr || n < 3 ) {
        return -1;
    }
    // нужно тестирование
    min_y = std::min_element( vs, vs + n,
            [](const SDL_Point & a, const SDL_Point & b)
            { return a.y < b.y; } ) -> y;
    max_y = std::max_element( vs, vs + n,
            [](const SDL_Point & a, const SDL_Point & b)
            { return a.y < b.y; } ) -> y;
    result = 0;
    for ( int y = min_y; y < max_y; y++ ) {
        counts = 0;
        for ( int i = 0; i < n; i++ ) {
            if ( !i ) {
                ind1 = n - 1;
                ind2 = 0;
            } else {
                ind1 = i - 1;
                ind2 = i;
            }
            y1 = vs[ind1].y;
            y2 = vs[ind2].y;
            if ( y1 < y2 ) {
                x1 = vs[ind1].x;
                x2 = vs[ind2].x;
            } else if ( y1 > y2 ) {
                y2 = vs[ind1].y;
                y1 = vs[ind2].y;
                x2 = vs[ind1].x;
                x1 = vs[ind2].x;
            } else {
                continue;
            }
            if ( ( ( y >= y1 ) && ( y < y2 ) ) ||
                 ( ( y == max_y ) && ( y > y1 ) && ( y <= y2 ) ) ) {
                polygons[counts++] =
                    ( ( 65536 * ( y - y1 ) ) / ( y2 - y1 ) ) * ( x2 - x1 ) +
                    ( 65536 * x1 );
            }
        }
        std::sort( polygons, polygons + counts );
        result = 0;
        for ( int i = 0; i < counts; i += 2 ) {
            xa = polygons[i+0] + 1;
            xb = polygons[i+1] - 1;
            xa = ( xa >> 16 ) + ( ( xa & 32768 ) >> 15 );
            xb = ( xb >> 16 ) + ( ( xb & 32768 ) >> 15 );
            result |= SDL_RenderDrawLine( _render, xa, y, xb, y );
        }
    }
    delete[] polygons;
    return result;
}
<|endoftext|>