<commit_before>/*
 * Copyright (C) 2017 Tmplt <tmplt@dragons.rocks>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <system_error>
#include <cerrno>

#include <array>
#include <experimental/filesystem>

#include "utils.hpp"
#include "python.hpp"
#include "components/script_butler.hpp"

namespace fs = std::experimental::filesystem;

namespace butler {

script_butler::script_butler(const bookwyrm::item &&wanted)
    : wanted_(wanted) {}

vector<pybind11::module> script_butler::load_sources()
{
#ifdef DEBUG
    /* Bookwyrm must be run from build/ in DEBUG mode. */
    const auto source_path = fs::canonical(fs::path("../src/sources"));
#else
    const std::array<fs::path, 2> paths = {"/etc/bookwyrm/sources",
                                           "~/.config/bookwyrm/sources"};

    // TODO: follow <https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>
#endif

    /*
     * Append source_path to Python's sys.path,
     * allowing them to be imported.
     */
    auto sys_path = py::reinterpret_borrow<py::list>(py::module::import("sys").attr("path"));
    sys_path.append(source_path.c_str());

    /*
     * Find all Python modules and populate the
     * list of sources by loading them.
     *
     * The first occurance of a module will be imported,
     * the latter ones will be ignored by Python. So we
     * either need to prepend the paths to sys.path, or
     * make sure that we don't clash with the many module
     * names in Python.
     */
    vector<py::module> sources;
    for (const fs::path &p : fs::directory_iterator(source_path)) {
        if (p.extension() != ".py") continue;

        if (!utils::readable_file(p)) {
            logger_->warn("can't load module '{}': not a regular file or unreadable"
                    "; ignoring...", p.string());
            continue;
        }

        try {
            string module = p.stem();
            logger_->debug("loading module '{}'...", module);
            sources.emplace_back(py::module::import(module.c_str()));
        } catch (const py::error_already_set &err) {
            logger_->warn("{}; ignoring...", err.what());
        }
    }

    if (sources.empty())
        throw program_error("couldn't find any valid source modules, terminating...");

    return sources;
}

script_butler::~script_butler()
{
    /*
     * Current behaviour is that the program cannot terminate unless
     * all source threads has joined. We'll of course want do to this.
     *
     * It's not possible to end a std::thread in a smooth matter. We could
     * instead have a control variable that the source scripts check every
     * once in a while. When this is set upon quitting the curses UI, we'll
     * have to let each script handle its own termination.
     *
     * Not joining the threads here doesn't make the OS very happy.
     */
    py::gil_scoped_release nogil;

    for (auto &t : threads_)
        t.join();
}

void script_butler::async_search(vector<py::module> &sources)
{
    for (const auto &m : sources) {
        try {
            threads_.emplace_back([&m, wanted = wanted_, bw_instance = this]() {
                /* Required whenever we need to run anything Python. */
                py::gil_scoped_acquire gil;
                m.attr("find")(wanted, bw_instance);
            });
        } catch (const py::error_already_set &err) {
            logger_->error("module '{}' did something wrong ({}); ignoring...",
                    m.attr("__name__").cast<string>(), err.what());
            continue;
        }
    }
}

void script_butler::add_item(std::tuple<bookwyrm::nonexacts_t, bookwyrm::exacts_t> item_comps)
{
    bookwyrm::item item(item_comps);

    std::lock_guard<std::mutex> guard(items_mutex_);
    /* if (!item.matches(wanted_)) */
    /*     return; */

    items_.push_back(item);
    screen_butler_->update_screens();
}

/* ns butler */
}
<commit_msg>butler/script: import scripts in releasg (XDG)<commit_after>/*
 * Copyright (C) 2017 Tmplt <tmplt@dragons.rocks>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <system_error>
#include <cerrno>
#include <cstdlib>

#include <array>
#include <experimental/filesystem>

#include "utils.hpp"
#include "python.hpp"
#include "components/script_butler.hpp"

namespace fs = std::experimental::filesystem;

namespace butler {

script_butler::script_butler(const bookwyrm::item &&wanted)
    : wanted_(wanted) {}

vector<pybind11::module> script_butler::load_sources()
{
    vector<fs::path> source_paths;
#ifdef DEBUG
    /* Bookwyrm must be run from build/ in DEBUG mode. */
    source_paths = { fs::canonical(fs::path("../src/sources")) };
#else
    if (fs::path conf = std::getenv("XDG_CONFIG_HOME"); !conf.empty())
        source_paths.push_back(conf / "bookwyrm/sources");
    else if (fs::path home = std::getenv("HOME"); !home.empty())
        source_paths.push_back(home / ".config/bookwyrm/sources");
    else
        logger_->error("couldn't find any source script directories.");
#endif

    /*
     * Append the source paths to Python's sys.path,
     * allowing them to be imported.
     */
    auto sys_path = py::reinterpret_borrow<py::list>(py::module::import("sys").attr("path"));
    for (auto &p : source_paths)
        sys_path.append(p.string().c_str());

    /*
     * Find all Python modules and populate the
     * list of sources by loading them.
     *
     * The first occurance of a module will be imported,
     * the latter ones will be ignored by Python. So we
     * either need to prepend the paths to sys.path, or
     * make sure that we don't clash with the many module
     * names in Python.
     */
    vector<py::module> sources;
    for (const auto &source_path : source_paths) {
        for (const fs::path &p : fs::directory_iterator(source_path)) {
            if (p.extension() != ".py") continue;

            if (!utils::readable_file(p)) {
                logger_->warn("can't load module '{}': not a regular file or unreadable"
                        "; ignoring...", p.string());
                continue;
            }

            try {
                string module = p.stem();
                logger_->debug("loading module '{}'...", module);
                sources.emplace_back(py::module::import(module.c_str()));
            } catch (const py::error_already_set &err) {
                logger_->warn("{}; ignoring...", err.what());
            }
        }
    }

    if (sources.empty())
        throw program_error("couldn't find any valid source scripts, terminating...");

    return sources;
}

script_butler::~script_butler()
{
    /*
     * Current behaviour is that the program cannot terminate unless
     * all source threads has joined. We'll of course want do to this.
     *
     * It's not possible to end a std::thread in a smooth matter. We could
     * instead have a control variable that the source scripts check every
     * once in a while. When this is set upon quitting the curses UI, we'll
     * have to let each script handle its own termination.
     *
     * Not joining the threads here doesn't make the OS very happy.
     */
    py::gil_scoped_release nogil;

    for (auto &t : threads_)
        t.join();
}

void script_butler::async_search(vector<py::module> &sources)
{
    for (const auto &m : sources) {
        try {
            threads_.emplace_back([&m, wanted = wanted_, bw_instance = this]() {
                /* Required whenever we need to run anything Python. */
                py::gil_scoped_acquire gil;
                m.attr("find")(wanted, bw_instance);
            });
        } catch (const py::error_already_set &err) {
            logger_->error("module '{}' did something wrong ({}); ignoring...",
                    m.attr("__name__").cast<string>(), err.what());
            continue;
        }
    }
}

void script_butler::add_item(std::tuple<bookwyrm::nonexacts_t, bookwyrm::exacts_t> item_comps)
{
    bookwyrm::item item(item_comps);

    std::lock_guard<std::mutex> guard(items_mutex_);
    /* if (!item.matches(wanted_)) */
    /*     return; */

    items_.push_back(item);
    screen_butler_->update_screens();
}

/* ns butler */
}
<|endoftext|>


<commit_before>#include "UnixSocketHandler.hpp"

#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>

namespace et {
UnixSocketHandler::UnixSocketHandler() {}

bool UnixSocketHandler::hasData(int fd) {
  lock_guard<std::recursive_mutex> guard(mutex);
  fd_set input;
  FD_ZERO(&input);
  FD_SET(fd, &input);
  struct timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = 0;
  int n = select(fd + 1, &input, NULL, NULL, &timeout);
  if (n == -1) {
    // Select timed out or failed.
    return false;
  } else if (n == 0)
    return false;
  if (!FD_ISSET(fd, &input)) {
    LOG(FATAL) << "FD_ISSET is false but we should have data by now.";
  }
  return true;
}

ssize_t UnixSocketHandler::read(int fd, void *buf, size_t count) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (fd <= 0) {
    LOG(FATAL) << "Tried to read from an invalid socket: " << fd;
  }
  if (activeSockets.find(fd) == activeSockets.end()) {
    LOG(INFO) << "Tried to read from a socket that has been closed: " << fd;
    return 0;
  }
  ssize_t readBytes = ::read(fd, buf, count);
  if (readBytes == 0) {
    throw runtime_error("Remote host closed connection");
  }
  if (readBytes < 0) {
    LOG(ERROR) << "Error reading: " << errno << " " << strerror(errno) << endl;
  }
  return readBytes;
}

ssize_t UnixSocketHandler::write(int fd, const void *buf, size_t count) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (fd <= 0) {
    LOG(FATAL) << "Tried to write to an invalid socket: " << fd;
  }
#ifdef MSG_NOSIGNAL
  return ::send(fd, buf, count, MSG_NOSIGNAL);
#else
  return ::write(fd, buf, count);
#endif
}

int UnixSocketHandler::connect(const std::string &hostname, int port) {
  lock_guard<std::recursive_mutex> guard(mutex);
  int sockfd = -1;
  addrinfo *results;
  addrinfo *p;
  addrinfo hints;
  memset(&hints, 0, sizeof(addrinfo));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_CANONNAME;
  std::string portname = std::to_string(port);

  int rc = getaddrinfo(hostname.c_str(), portname.c_str(), &hints, &results);

  if (rc != 0) {
    LOG(ERROR) << "Error getting address info for " << hostname << ":"
               << portname << ": " << rc << " (" << gai_strerror(rc) << ")";
    return -1;
  }

  // loop through all the results and connect to the first we can
  for (p = results; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
      LOG(INFO) << "Error creating socket: " << errno
                << " " << strerror(errno);
      continue;
    }
    initSocket(sockfd);

    // Set nonblocking just for the connect phase
    {
      int opts;
      opts = fcntl(sockfd, F_GETFL);
      FATAL_FAIL(opts);
      opts |= O_NONBLOCK;
      FATAL_FAIL(fcntl(sockfd, F_SETFL, opts));
    }
    if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1 &&
        errno != EINPROGRESS) {
      LOG(INFO) << "Error connecting with " << p->ai_canonname << ": " << errno
                << " " << strerror(errno);
      ::close(sockfd);
      sockfd = -1;
      continue;
    }

    fd_set fdset;
    FD_ZERO(&fdset);
    FD_SET(sockfd, &fdset);
    timeval tv;
    tv.tv_sec = 3; /* 3 second timeout */
    tv.tv_usec = 0;

    if (::select(sockfd + 1, NULL, &fdset, NULL, &tv) == 1) {
      int so_error;
      socklen_t len = sizeof so_error;

      FATAL_FAIL(::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len));

      if (so_error == 0) {
        LOG(INFO) << "Connected to server: " << p->ai_canonname << " using fd "
                  << sockfd;
        // Make sure that socket becomes blocking once it's attached to a
        // server.
        {
          int opts;
          opts = fcntl(sockfd, F_GETFL);
          FATAL_FAIL(opts);
          opts &= (~O_NONBLOCK);
          FATAL_FAIL(fcntl(sockfd, F_SETFL, opts));
        }
        break;  // if we get here, we must have connected successfully
      } else {
        if (p->ai_canonname) {
          LOG(INFO) << "Error connecting with " << p->ai_canonname << ": "
                    << so_error << " " << strerror(so_error);
        } else {
          LOG(INFO) << "Error connecting to " << hostname << ": "
                    << so_error << " " << strerror(so_error);
        }
        ::close(sockfd);
        sockfd = -1;
        continue;
      }
    } else {
      LOG(INFO) << "Error connecting with " << p->ai_canonname << ": " << errno
                << " " << strerror(errno);
      ::close(sockfd);
      sockfd = -1;
      continue;
    }
  }

  if (sockfd == -1) {
    LOG(ERROR) << "ERROR, no host found";
  } else {
      if (activeSockets.find(sockfd) != activeSockets.end()) {
        LOG(FATAL) << "Tried to insert an fd that already exists: " << sockfd;
      }
      activeSockets.insert(sockfd);
  }

  freeaddrinfo(results);
  return sockfd;
}

int UnixSocketHandler::listen(int port) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (serverSockets.empty()) {
    addrinfo hints, *servinfo, *p;
    int rc;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;  // use my IP address

    std::string portname = std::to_string(port);

    if ((rc = getaddrinfo(NULL, portname.c_str(), &hints, &servinfo)) != 0) {
      LOG(ERROR) << "Error getting address info for " << port << ": " << rc
                 << " (" << gai_strerror(rc) << ")";
      exit(1);
    }

    // loop through all the results and bind to the first we can
    for (p = servinfo; p != NULL; p = p->ai_next) {
      int sockfd;
      if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) ==
          -1) {
        LOG(INFO) << "Error creating socket " << p->ai_family << "/"
                  << p->ai_socktype << "/" << p->ai_protocol << ": " << errno
                  << " " << strerror(errno);
        continue;
      }
      initSocket(sockfd);
      // Also set the accept socket as non-blocking
      {
        int opts;
        opts = fcntl(sockfd, F_GETFL);
        FATAL_FAIL(opts);
        opts |= O_NONBLOCK;
        FATAL_FAIL(fcntl(sockfd, F_SETFL, opts));
      }
      // Also set the accept socket as reusable
      {
        int flag = 1;
        FATAL_FAIL(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag,
                              sizeof(int)));
      }

      if (p->ai_family == AF_INET6) {
        // Also ensure that IPV6 sockets only listen on IPV6
        // interfaces.  We will create another socket object for IPV4
        // if it doesn't already exist.
        int flag = 1;
        FATAL_FAIL(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&flag,
                              sizeof(int)));
      }

      if (::bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        // This most often happens because the port is in use.
        LOG(ERROR) << "Error binding " << p->ai_family << "/" << p->ai_socktype
                   << "/" << p->ai_protocol << ": " << errno << " "
                   << strerror(errno);
        cerr << "Error binding " << p->ai_family << "/" << p->ai_socktype << "/"
             << p->ai_protocol << ": " << errno << " " << strerror(errno)
             << flush;
        exit(1);
        // close(sockfd);
        // continue;
      }

      // Listen
      FATAL_FAIL(::listen(sockfd, 32));
      LOG(INFO) << "Listening on " << inet_ntoa(((sockaddr_in*)p->ai_addr)->sin_addr) << ":" << port << "/" << p->ai_family << "/" << p->ai_socktype
                << "/" << p->ai_protocol;

      // if we get here, we must have connected successfully
      serverSockets.push_back(sockfd);
      activeSockets.insert(sockfd);
    }

    if (serverSockets.empty()) {
      LOG(FATAL) << "Could not bind to any interface!";
    }
  }

  for (int sockfd : serverSockets) {
    sockaddr_in client;
    socklen_t c = sizeof(sockaddr_in);
    int client_sock = ::accept(sockfd, (sockaddr *)&client, &c);
    if (client_sock >= 0) {
      initSocket(client_sock);
      activeSockets.insert(client_sock);
      // Make sure that socket becomes blocking once it's attached to a client.
      {
        int opts;
        opts = fcntl(client_sock, F_GETFL);
        FATAL_FAIL(opts);
        opts &= (~O_NONBLOCK);
        FATAL_FAIL(fcntl(client_sock, F_SETFL, opts));
      }
      return client_sock;
    } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
      FATAL_FAIL(-1);  // LOG(FATAL) with the error
    }
  }

  return -1;
}

void UnixSocketHandler::stopListening() {
  lock_guard<std::recursive_mutex> guard(mutex);
  for (int sockfd : serverSockets) {
    close(sockfd);
  }
}

void UnixSocketHandler::close(int fd) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (fd == -1) {
    return;
  }
  if (activeSockets.find(fd) == activeSockets.end()) {
    // Connection was already killed.
    LOG(ERROR) << "Tried to close a connection that doesn't exist: " << fd;
    return;
  }
  activeSockets.erase(activeSockets.find(fd));
#if 0
  VLOG(1) << "Shutting down connection: " << fd << endl;
  int rc = ::shutdown(fd, SHUT_RDWR);
  if (rc == -1) {
    if (errno == ENOTCONN || errno == EADDRNOTAVAIL) {
      // Shutdown is failing on OS/X with errno (49): Can't assign requested address
      // Possibly an OS bug but I don't think it's necessary anyways.

      // ENOTCONN is harmless
    } else {
      FATAL_FAIL(rc);
    }
  }
#endif
  VLOG(1) << "Closing connection: " << fd << endl;
  FATAL_FAIL(::close(fd));
}

void UnixSocketHandler::initSocket(int fd) {
  int flag = 1;
  FATAL_FAIL(setsockopt(fd,            /* socket affected */
                        IPPROTO_TCP,   /* set option at TCP level */
                        TCP_NODELAY,   /* name of option */
                        (char *)&flag, /* the cast is historical cruft */
                        sizeof(int))); /* length of option value */
  timeval tv;
  tv.tv_sec = 5;
  tv.tv_usec = 0;
  FATAL_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)));
  FATAL_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)));
#ifndef MSG_NOSIGNAL
  // If we don't have MSG_NOSIGNAL, use SO_NOSIGPIPE
  int val = 1;
  FATAL_FAIL(setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)));
#endif
}
}
<commit_msg>Bail early if trying to write to an unknown socket<commit_after>#include "UnixSocketHandler.hpp"

#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>

namespace et {
UnixSocketHandler::UnixSocketHandler() {}

bool UnixSocketHandler::hasData(int fd) {
  lock_guard<std::recursive_mutex> guard(mutex);
  fd_set input;
  FD_ZERO(&input);
  FD_SET(fd, &input);
  struct timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = 0;
  int n = select(fd + 1, &input, NULL, NULL, &timeout);
  if (n == -1) {
    // Select timed out or failed.
    return false;
  } else if (n == 0)
    return false;
  if (!FD_ISSET(fd, &input)) {
    LOG(FATAL) << "FD_ISSET is false but we should have data by now.";
  }
  return true;
}

ssize_t UnixSocketHandler::read(int fd, void *buf, size_t count) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (fd <= 0) {
    LOG(FATAL) << "Tried to read from an invalid socket: " << fd;
  }
  if (activeSockets.find(fd) == activeSockets.end()) {
    LOG(INFO) << "Tried to read from a socket that has been closed: " << fd;
    return 0;
  }
  ssize_t readBytes = ::read(fd, buf, count);
  if (readBytes == 0) {
    throw runtime_error("Remote host closed connection");
  }
  if (readBytes < 0) {
    LOG(ERROR) << "Error reading: " << errno << " " << strerror(errno) << endl;
  }
  return readBytes;
}

ssize_t UnixSocketHandler::write(int fd, const void *buf, size_t count) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (fd <= 0) {
    LOG(FATAL) << "Tried to write to an invalid socket: " << fd;
  }
  if (activeSockets.find(fd) == activeSockets.end()) {
    LOG(INFO) << "Tried to write to a socket that has been closed: " << fd;
    return 0;
  }
#ifdef MSG_NOSIGNAL
  return ::send(fd, buf, count, MSG_NOSIGNAL);
#else
  return ::write(fd, buf, count);
#endif
}

int UnixSocketHandler::connect(const std::string &hostname, int port) {
  lock_guard<std::recursive_mutex> guard(mutex);
  int sockfd = -1;
  addrinfo *results;
  addrinfo *p;
  addrinfo hints;
  memset(&hints, 0, sizeof(addrinfo));
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_CANONNAME;
  std::string portname = std::to_string(port);

  int rc = getaddrinfo(hostname.c_str(), portname.c_str(), &hints, &results);

  if (rc != 0) {
    LOG(ERROR) << "Error getting address info for " << hostname << ":"
               << portname << ": " << rc << " (" << gai_strerror(rc) << ")";
    return -1;
  }

  // loop through all the results and connect to the first we can
  for (p = results; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
      LOG(INFO) << "Error creating socket: " << errno
                << " " << strerror(errno);
      continue;
    }
    initSocket(sockfd);

    // Set nonblocking just for the connect phase
    {
      int opts;
      opts = fcntl(sockfd, F_GETFL);
      FATAL_FAIL(opts);
      opts |= O_NONBLOCK;
      FATAL_FAIL(fcntl(sockfd, F_SETFL, opts));
    }
    if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1 &&
        errno != EINPROGRESS) {
      LOG(INFO) << "Error connecting with " << p->ai_canonname << ": " << errno
                << " " << strerror(errno);
      ::close(sockfd);
      sockfd = -1;
      continue;
    }

    fd_set fdset;
    FD_ZERO(&fdset);
    FD_SET(sockfd, &fdset);
    timeval tv;
    tv.tv_sec = 3; /* 3 second timeout */
    tv.tv_usec = 0;

    if (::select(sockfd + 1, NULL, &fdset, NULL, &tv) == 1) {
      int so_error;
      socklen_t len = sizeof so_error;

      FATAL_FAIL(::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len));

      if (so_error == 0) {
        LOG(INFO) << "Connected to server: " << p->ai_canonname << " using fd "
                  << sockfd;
        // Make sure that socket becomes blocking once it's attached to a
        // server.
        {
          int opts;
          opts = fcntl(sockfd, F_GETFL);
          FATAL_FAIL(opts);
          opts &= (~O_NONBLOCK);
          FATAL_FAIL(fcntl(sockfd, F_SETFL, opts));
        }
        break;  // if we get here, we must have connected successfully
      } else {
        if (p->ai_canonname) {
          LOG(INFO) << "Error connecting with " << p->ai_canonname << ": "
                    << so_error << " " << strerror(so_error);
        } else {
          LOG(INFO) << "Error connecting to " << hostname << ": "
                    << so_error << " " << strerror(so_error);
        }
        ::close(sockfd);
        sockfd = -1;
        continue;
      }
    } else {
      LOG(INFO) << "Error connecting with " << p->ai_canonname << ": " << errno
                << " " << strerror(errno);
      ::close(sockfd);
      sockfd = -1;
      continue;
    }
  }

  if (sockfd == -1) {
    LOG(ERROR) << "ERROR, no host found";
  } else {
      if (activeSockets.find(sockfd) != activeSockets.end()) {
        LOG(FATAL) << "Tried to insert an fd that already exists: " << sockfd;
      }
      activeSockets.insert(sockfd);
  }

  freeaddrinfo(results);
  return sockfd;
}

int UnixSocketHandler::listen(int port) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (serverSockets.empty()) {
    addrinfo hints, *servinfo, *p;
    int rc;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;  // use my IP address

    std::string portname = std::to_string(port);

    if ((rc = getaddrinfo(NULL, portname.c_str(), &hints, &servinfo)) != 0) {
      LOG(ERROR) << "Error getting address info for " << port << ": " << rc
                 << " (" << gai_strerror(rc) << ")";
      exit(1);
    }

    // loop through all the results and bind to the first we can
    for (p = servinfo; p != NULL; p = p->ai_next) {
      int sockfd;
      if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) ==
          -1) {
        LOG(INFO) << "Error creating socket " << p->ai_family << "/"
                  << p->ai_socktype << "/" << p->ai_protocol << ": " << errno
                  << " " << strerror(errno);
        continue;
      }
      initSocket(sockfd);
      // Also set the accept socket as non-blocking
      {
        int opts;
        opts = fcntl(sockfd, F_GETFL);
        FATAL_FAIL(opts);
        opts |= O_NONBLOCK;
        FATAL_FAIL(fcntl(sockfd, F_SETFL, opts));
      }
      // Also set the accept socket as reusable
      {
        int flag = 1;
        FATAL_FAIL(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag,
                              sizeof(int)));
      }

      if (p->ai_family == AF_INET6) {
        // Also ensure that IPV6 sockets only listen on IPV6
        // interfaces.  We will create another socket object for IPV4
        // if it doesn't already exist.
        int flag = 1;
        FATAL_FAIL(setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&flag,
                              sizeof(int)));
      }

      if (::bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        // This most often happens because the port is in use.
        LOG(ERROR) << "Error binding " << p->ai_family << "/" << p->ai_socktype
                   << "/" << p->ai_protocol << ": " << errno << " "
                   << strerror(errno);
        cerr << "Error binding " << p->ai_family << "/" << p->ai_socktype << "/"
             << p->ai_protocol << ": " << errno << " " << strerror(errno)
             << flush;
        exit(1);
        // close(sockfd);
        // continue;
      }

      // Listen
      FATAL_FAIL(::listen(sockfd, 32));
      LOG(INFO) << "Listening on " << inet_ntoa(((sockaddr_in*)p->ai_addr)->sin_addr) << ":" << port << "/" << p->ai_family << "/" << p->ai_socktype
                << "/" << p->ai_protocol;

      // if we get here, we must have connected successfully
      serverSockets.push_back(sockfd);
      activeSockets.insert(sockfd);
    }

    if (serverSockets.empty()) {
      LOG(FATAL) << "Could not bind to any interface!";
    }
  }

  for (int sockfd : serverSockets) {
    sockaddr_in client;
    socklen_t c = sizeof(sockaddr_in);
    int client_sock = ::accept(sockfd, (sockaddr *)&client, &c);
    if (client_sock >= 0) {
      initSocket(client_sock);
      activeSockets.insert(client_sock);
      // Make sure that socket becomes blocking once it's attached to a client.
      {
        int opts;
        opts = fcntl(client_sock, F_GETFL);
        FATAL_FAIL(opts);
        opts &= (~O_NONBLOCK);
        FATAL_FAIL(fcntl(client_sock, F_SETFL, opts));
      }
      return client_sock;
    } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
      FATAL_FAIL(-1);  // LOG(FATAL) with the error
    }
  }

  return -1;
}

void UnixSocketHandler::stopListening() {
  lock_guard<std::recursive_mutex> guard(mutex);
  for (int sockfd : serverSockets) {
    close(sockfd);
  }
}

void UnixSocketHandler::close(int fd) {
  lock_guard<std::recursive_mutex> guard(mutex);
  if (fd == -1) {
    return;
  }
  if (activeSockets.find(fd) == activeSockets.end()) {
    // Connection was already killed.
    LOG(ERROR) << "Tried to close a connection that doesn't exist: " << fd;
    return;
  }
  activeSockets.erase(activeSockets.find(fd));
#if 0
  VLOG(1) << "Shutting down connection: " << fd << endl;
  int rc = ::shutdown(fd, SHUT_RDWR);
  if (rc == -1) {
    if (errno == ENOTCONN || errno == EADDRNOTAVAIL) {
      // Shutdown is failing on OS/X with errno (49): Can't assign requested address
      // Possibly an OS bug but I don't think it's necessary anyways.

      // ENOTCONN is harmless
    } else {
      FATAL_FAIL(rc);
    }
  }
#endif
  VLOG(1) << "Closing connection: " << fd << endl;
  FATAL_FAIL(::close(fd));
}

void UnixSocketHandler::initSocket(int fd) {
  int flag = 1;
  FATAL_FAIL(setsockopt(fd,            /* socket affected */
                        IPPROTO_TCP,   /* set option at TCP level */
                        TCP_NODELAY,   /* name of option */
                        (char *)&flag, /* the cast is historical cruft */
                        sizeof(int))); /* length of option value */
  timeval tv;
  tv.tv_sec = 5;
  tv.tv_usec = 0;
  FATAL_FAIL(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)));
  FATAL_FAIL(setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)));
#ifndef MSG_NOSIGNAL
  // If we don't have MSG_NOSIGNAL, use SO_NOSIGPIPE
  int val = 1;
  FATAL_FAIL(setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)));
#endif
}
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, 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 <iostream>
#include <boost/config.hpp>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> // for exit()
#include "setup_transfer.hpp" // for tests_failure

int test_main();

#include "libtorrent/assert.hpp"
#include "libtorrent/file.hpp"
#include <signal.h>

void sig_handler(int sig)
{
	char stack_text[10000];

#if (defined TORRENT_DEBUG && !TORRENT_NO_ASSERTS) || TORRENT_RELEASE_ASSERTS
	print_backtrace(stack_text, sizeof(stack_text), 30);
#elif defined __FUNCTION__
	strcat(stack_text, __FUNCTION__);
#else
	stack_text[0] = 0;
#endif
	char const* sig_name = 0;
	switch (sig)
	{
#define SIG(x) case x: sig_name = #x; break
		SIG(SIGSEGV);
#ifdef SIGBUS
		SIG(SIGBUS);
#endif
		SIG(SIGILL);
		SIG(SIGABRT);
		SIG(SIGFPE);
#ifdef SIGSYS
		SIG(SIGSYS);
#endif
#undef SIG
	};
	fprintf(stderr, "signal: %s caught:\n%s\n", sig_name, stack_text);
	exit(138);
}

using namespace libtorrent;

int main()
{
#ifdef O_NONBLOCK
	// on darwin, stdout is set to non-blocking mode by default
	// which sometimes causes tests to fail with EAGAIN just
	// by printing logs
	int flags = fcntl(fileno(stdout), F_GETFL, 0);
	fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK);
	flags = fcntl(fileno(stderr), F_GETFL, 0);
	fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK);
#endif

	signal(SIGSEGV, &sig_handler);
#ifdef SIGBUS
	signal(SIGBUS, &sig_handler);
#endif
	signal(SIGILL, &sig_handler);
	signal(SIGABRT, &sig_handler);
	signal(SIGFPE, &sig_handler);
#ifdef SIGSYS
	signal(SIGSYS, &sig_handler);
#endif

	char dir[40];
	snprintf(dir, sizeof(dir), "test_tmp_%u", rand());
	std::string test_dir = complete(dir);
	error_code ec;
	create_directory(test_dir, ec);
	if (ec)
	{
		fprintf(stderr, "Failed to create test directory: %s\n", ec.message().c_str());
		return 1;
	}
#ifdef TORRENT_WINDOWS
	SetCurrentDirectoryA(dir);
#else
	chdir(dir);
#endif

#ifndef BOOST_NO_EXCEPTIONS
	try
	{
#endif
		test_main();
#ifndef BOOST_NO_EXCEPTIONS
	}
	catch (std::exception const& e)
	{
		std::cerr << "Terminated with exception: \"" << e.what() << "\"\n";
		tests_failure = true;
	}
	catch (...)
	{
		std::cerr << "Terminated with unknown exception\n";
		tests_failure = true;
	}
#endif
	fflush(stdout);
	fflush(stderr);
	remove_all(test_dir, ec);
	if (ec)
		fprintf(stderr, "failed to remove test dir: %s\n", ec.message().c_str());
	return tests_failure ? 1 : 0;
}

<commit_msg>initialize random number generator for tests<commit_after>/*

Copyright (c) 2008, 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 <iostream>
#include <boost/config.hpp>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> // for exit()
#include "setup_transfer.hpp" // for tests_failure

int test_main();

#include "libtorrent/assert.hpp"
#include "libtorrent/file.hpp"
#include <signal.h>

void sig_handler(int sig)
{
	char stack_text[10000];

#if (defined TORRENT_DEBUG && !TORRENT_NO_ASSERTS) || TORRENT_RELEASE_ASSERTS
	print_backtrace(stack_text, sizeof(stack_text), 30);
#elif defined __FUNCTION__
	strcat(stack_text, __FUNCTION__);
#else
	stack_text[0] = 0;
#endif
	char const* sig_name = 0;
	switch (sig)
	{
#define SIG(x) case x: sig_name = #x; break
		SIG(SIGSEGV);
#ifdef SIGBUS
		SIG(SIGBUS);
#endif
		SIG(SIGILL);
		SIG(SIGABRT);
		SIG(SIGFPE);
#ifdef SIGSYS
		SIG(SIGSYS);
#endif
#undef SIG
	};
	fprintf(stderr, "signal: %s caught:\n%s\n", sig_name, stack_text);
	exit(138);
}

using namespace libtorrent;

int main()
{
	srand(total_microseconds(time_now_hires() - min_time()));
#ifdef O_NONBLOCK
	// on darwin, stdout is set to non-blocking mode by default
	// which sometimes causes tests to fail with EAGAIN just
	// by printing logs
	int flags = fcntl(fileno(stdout), F_GETFL, 0);
	fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK);
	flags = fcntl(fileno(stderr), F_GETFL, 0);
	fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK);
#endif

	signal(SIGSEGV, &sig_handler);
#ifdef SIGBUS
	signal(SIGBUS, &sig_handler);
#endif
	signal(SIGILL, &sig_handler);
	signal(SIGABRT, &sig_handler);
	signal(SIGFPE, &sig_handler);
#ifdef SIGSYS
	signal(SIGSYS, &sig_handler);
#endif

	char dir[40];
	snprintf(dir, sizeof(dir), "test_tmp_%u", rand());
	std::string test_dir = complete(dir);
	error_code ec;
	create_directory(test_dir, ec);
	if (ec)
	{
		fprintf(stderr, "Failed to create test directory: %s\n", ec.message().c_str());
		return 1;
	}
#ifdef TORRENT_WINDOWS
	SetCurrentDirectoryA(dir);
#else
	chdir(dir);
#endif

#ifndef BOOST_NO_EXCEPTIONS
	try
	{
#endif
		test_main();
#ifndef BOOST_NO_EXCEPTIONS
	}
	catch (std::exception const& e)
	{
		std::cerr << "Terminated with exception: \"" << e.what() << "\"\n";
		tests_failure = true;
	}
	catch (...)
	{
		std::cerr << "Terminated with unknown exception\n";
		tests_failure = true;
	}
#endif
	fflush(stdout);
	fflush(stderr);
	remove_all(test_dir, ec);
	if (ec)
		fprintf(stderr, "failed to remove test dir: %s\n", ec.message().c_str());
	return tests_failure ? 1 : 0;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2008, 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 <iostream>
#include <boost/config.hpp>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> // for exit()
#include "setup_transfer.hpp" // for tests_failure
#include "dht_server.hpp" // for stop_dht
#include "peer_server.hpp" // for stop_peer

int test_main();

#include "libtorrent/assert.hpp"
#include "libtorrent/file.hpp"
#include <signal.h>

void sig_handler(int sig)
{
	char stack_text[10000];

#if (defined TORRENT_DEBUG && !TORRENT_NO_ASSERTS) || TORRENT_RELEASE_ASSERTS
	print_backtrace(stack_text, sizeof(stack_text), 30);
#elif defined __FUNCTION__
	strcat(stack_text, __FUNCTION__);
#else
	stack_text[0] = 0;
#endif
	char const* sig_name = 0;
	switch (sig)
	{
#define SIG(x) case x: sig_name = #x; break
		SIG(SIGSEGV);
#ifdef SIGBUS
		SIG(SIGBUS);
#endif
		SIG(SIGILL);
		SIG(SIGABRT);
		SIG(SIGFPE);
#ifdef SIGSYS
		SIG(SIGSYS);
#endif
#undef SIG
	};
	fprintf(stderr, "signal: %s caught:\n%s\n", sig_name, stack_text);
	exit(138);
}

using namespace libtorrent;

int main()
{
	srand(total_microseconds(time_now_hires() - min_time()));
#ifdef O_NONBLOCK
	// on darwin, stdout is set to non-blocking mode by default
	// which sometimes causes tests to fail with EAGAIN just
	// by printing logs
	int flags = fcntl(fileno(stdout), F_GETFL, 0);
	fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK);
	flags = fcntl(fileno(stderr), F_GETFL, 0);
	fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK);
#endif

	signal(SIGSEGV, &sig_handler);
#ifdef SIGBUS
	signal(SIGBUS, &sig_handler);
#endif
	signal(SIGILL, &sig_handler);
	signal(SIGABRT, &sig_handler);
	signal(SIGFPE, &sig_handler);
#ifdef SIGSYS
	signal(SIGSYS, &sig_handler);
#endif

	char dir[40];
	snprintf(dir, sizeof(dir), "test_tmp_%u", rand());
	std::string test_dir = complete(dir);
	error_code ec;
	create_directory(test_dir, ec);
	if (ec)
	{
		fprintf(stderr, "Failed to create test directory: %s\n", ec.message().c_str());
		return 1;
	}
#ifdef TORRENT_WINDOWS
	SetCurrentDirectoryA(dir);
#else
	chdir(dir);
#endif

#ifndef BOOST_NO_EXCEPTIONS
	try
	{
#endif
		test_main();
#ifndef BOOST_NO_EXCEPTIONS
	}
	catch (std::exception const& e)
	{
		std::cerr << "Terminated with exception: \"" << e.what() << "\"\n";
		tests_failure = true;
	}
	catch (...)
	{
		std::cerr << "Terminated with unknown exception\n";
		tests_failure = true;
	}
#endif

	// just in case of premature exits
	// make sure we try to clean up some
	stop_tracker();
	stop_all_proxies();
	stop_web_server();
	stop_peer();
	stop_dht();

	fflush(stdout);
	fflush(stderr);
	remove_all(test_dir, ec);
	if (ec)
		fprintf(stderr, "failed to remove test dir: %s\n", ec.message().c_str());
	return tests_failure ? 1 : 0;
}

<commit_msg>SetErrorMode at the start of unit tests (on windows)<commit_after>/*

Copyright (c) 2008, 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 <iostream>
#include <boost/config.hpp>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> // for exit()
#include "setup_transfer.hpp" // for tests_failure
#include "dht_server.hpp" // for stop_dht
#include "peer_server.hpp" // for stop_peer

int test_main();

#include "libtorrent/assert.hpp"
#include "libtorrent/file.hpp"
#include <signal.h>

#ifdef WIN32
#include <windows.h> // fot SetErrorMode
#endif

void sig_handler(int sig)
{
	char stack_text[10000];

#if (defined TORRENT_DEBUG && !TORRENT_NO_ASSERTS) || TORRENT_RELEASE_ASSERTS
	print_backtrace(stack_text, sizeof(stack_text), 30);
#elif defined __FUNCTION__
	strcat(stack_text, __FUNCTION__);
#else
	stack_text[0] = 0;
#endif
	char const* sig_name = 0;
	switch (sig)
	{
#define SIG(x) case x: sig_name = #x; break
		SIG(SIGSEGV);
#ifdef SIGBUS
		SIG(SIGBUS);
#endif
		SIG(SIGILL);
		SIG(SIGABRT);
		SIG(SIGFPE);
#ifdef SIGSYS
		SIG(SIGSYS);
#endif
#undef SIG
	};
	fprintf(stderr, "signal: %s caught:\n%s\n", sig_name, stack_text);
	exit(138);
}

using namespace libtorrent;

int main()
{
#ifdef WIN32
	// try to suppress hanging the process by windows displaying
	// modal dialogs.
	SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOALIGNMENTFAULTEXCEPT
		| SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
#endif

	srand(total_microseconds(time_now_hires() - min_time()));
#ifdef O_NONBLOCK
	// on darwin, stdout is set to non-blocking mode by default
	// which sometimes causes tests to fail with EAGAIN just
	// by printing logs
	int flags = fcntl(fileno(stdout), F_GETFL, 0);
	fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK);
	flags = fcntl(fileno(stderr), F_GETFL, 0);
	fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK);
#endif

	signal(SIGSEGV, &sig_handler);
#ifdef SIGBUS
	signal(SIGBUS, &sig_handler);
#endif
	signal(SIGILL, &sig_handler);
	signal(SIGABRT, &sig_handler);
	signal(SIGFPE, &sig_handler);
#ifdef SIGSYS
	signal(SIGSYS, &sig_handler);
#endif

	char dir[40];
	snprintf(dir, sizeof(dir), "test_tmp_%u", rand());
	std::string test_dir = complete(dir);
	error_code ec;
	create_directory(test_dir, ec);
	if (ec)
	{
		fprintf(stderr, "Failed to create test directory: %s\n", ec.message().c_str());
		return 1;
	}
#ifdef TORRENT_WINDOWS
	SetCurrentDirectoryA(dir);
#else
	chdir(dir);
#endif

#ifndef BOOST_NO_EXCEPTIONS
	try
	{
#endif
		test_main();
#ifndef BOOST_NO_EXCEPTIONS
	}
	catch (std::exception const& e)
	{
		std::cerr << "Terminated with exception: \"" << e.what() << "\"\n";
		tests_failure = true;
	}
	catch (...)
	{
		std::cerr << "Terminated with unknown exception\n";
		tests_failure = true;
	}
#endif

	// just in case of premature exits
	// make sure we try to clean up some
	stop_tracker();
	stop_all_proxies();
	stop_web_server();
	stop_peer();
	stop_dht();

	fflush(stdout);
	fflush(stderr);
	remove_all(test_dir, ec);
	if (ec)
		fprintf(stderr, "failed to remove test dir: %s\n", ec.message().c_str());
	return tests_failure ? 1 : 0;
}

<|endoftext|>


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

#include <memory>

#include <grpc++/channel.h>
#include <grpc++/create_channel.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/channel_arguments.h>

#include "src/cpp/client/create_channel_internal.h"

namespace grpc {
class ChannelArguments;

std::shared_ptr<Channel> CreateChannel(
    const grpc::string& target,
    const std::shared_ptr<ChannelCredentials>& creds) {
  return CreateCustomChannel(target, creds, ChannelArguments());
}

std::shared_ptr<Channel> CreateCustomChannel(
    const grpc::string& target,
    const std::shared_ptr<ChannelCredentials>& creds,
    const ChannelArguments& args) {
  GrpcLibraryCodegen
      init_lib;  // We need to call init in case of a bad creds.
  return creds
             ? creds->CreateChannel(target, args)
             : CreateChannelInternal("", grpc_lame_client_channel_create(
                                             NULL, GRPC_STATUS_INVALID_ARGUMENT,
                                             "Invalid credentials."));
}

}  // namespace grpc
<commit_msg>Update create_channel.cc<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <memory>

#include <grpc++/channel.h>
#include <grpc++/create_channel.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/channel_arguments.h>

#include "src/cpp/client/create_channel_internal.h"

namespace grpc {
class ChannelArguments;

std::shared_ptr<Channel> CreateChannel(
    const grpc::string& target,
    const std::shared_ptr<ChannelCredentials>& creds) {
  return CreateCustomChannel(target, creds, ChannelArguments());
}

std::shared_ptr<Channel> CreateCustomChannel(
    const grpc::string& target,
    const std::shared_ptr<ChannelCredentials>& creds,
    const ChannelArguments& args) {
  GrpcLibraryCodegen init_lib;  // We need to call init in case of a bad creds.
  return creds
             ? creds->CreateChannel(target, args)
             : CreateChannelInternal("", grpc_lame_client_channel_create(
                                             NULL, GRPC_STATUS_INVALID_ARGUMENT,
                                             "Invalid credentials."));
}

}  // namespace grpc
<|endoftext|>


<commit_before>/*
tinyxml2ex - a set of add-on classes and helper functions bringing C++11/14 features, such as iterators, strings and exceptions, to tinyxml2

Copyright (c) 2016 Stan Thomas

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.

tinyxml2 is the work of Lee Thomason (www.grinninglizard.com) and others.
It can be found here: https://github.com/leethomason/tinyxml2 and has it's own licensing terms.

*/

#include <string>
#include <iostream>
#include <algorithm>
#include <conio.h>

// include the header for tinyxml2ex which includes tinyxml2, remember to put them on your include path
#include <tixml2ex.h>

using namespace std;
using namespace std::literals::string_literals;

int main()
{
	// a simple XML document
	string testXml {R"-(
<?xml version="1.0" encoding="UTF-8"?>

		<C code="1234">
			A-B(one)-C.1234
		</C>
		<C code="5678">
			<![CDATA[A-B(one)-C.5678]]>
		</C>
		<C code="9ABC"> A-B{one)-C.9ABC</C>
		<D code="9ABC" id="dd" />

		<D id="dd" />

		<C code="1234">
			A-B(three)-C.1234
		</C>
		<C code="9ABC">A-B(three)-C.9ABC</C>
		<D description="A-B(three)-D.9ABC" />

			one {B4} two {B4}

)-"s};

	// these three blocks are equivalent and demonstrate different ways to iterate over
	// all <C> element children of  element children of the document element
	// we only want to inspect the elements and attributes, so treat the XMLElements as const
	// 1) native TinyXML2
	{
		printf ("\n1)   <C> element children of  element children of the document element \nnative TinyXML2\n");
		tinyxml2::XMLDocument doc;
		if (doc .Parse (testXml .c_str()) == 0/*XML_NO_ERORR*/)
		{
			const tinyxml2::XMLElement * eA = doc .FirstChildElement();
			if (eA)
			{
				const tinyxml2::XMLElement * eB = eA -> FirstChildElement("B");
				while (eB)
				{
					const tinyxml2::XMLElement * eC = eB -> FirstChildElement ("C");
					while (eC)
					{
						printf ("%s = %s\n", eC -> Name(), eC -> GetText());
						eC = eC -> NextSiblingElement ("C");
					}
					eB = eB -> NextSiblingElement ("B");
				}
			}
			else
				printf ("unable to load XML document\n");
		}
	}
	cout << "----" << endl << endl;

	// 2) tixml2ex XPath selector
	cout << "2)   <C> element children of  element children of the document element " << endl
		<< "tixml2ex XPath selector" << endl;
	try
	{
		auto doc = tinyxml2::load_document (testXml);
		for (auto eC : tinyxml2::selection (static_cast <const tinyxml2::XMLDocument &> (*doc), "A/B/C"))
			cout << eC -> Name() << " = " << text (eC) << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << "XmlException caught" << e .what() << endl;
	}
	cout << "----" << endl << endl;

	// 3) simple tixml2ex element iterator
	cout << endl << "3)   <C> element children of  element children of the document element " << endl
		<< "simple tixml2ex element iterator" << endl;
	try
	{
		auto doc = tinyxml2::load_document (testXml);
		auto eA = doc -> FirstChildElement();
		if (eA)
			for (auto eB : eA)
			{
				// just for fun, use standard algorithm for_each to iterate over the children of
				for_each (cbegin (eB), cend (eB),
					[](auto e)
				{
						// simple iterators are just that, they iterate over all children
						// therefore we must test element name (type) to examine only <C> elements
					if (strcmp (e -> Name(), "C") == 0) cout << e -> Name() << " = " << text (e) << endl;
				});
			}
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << "XmlException caught" << e .what() << endl;
	}

	cout << "=================================================" << endl << endl;

	// additional element selection and iteration using XPath syntax
	// illustrating helper functions
	try
	{
		auto doc = tinyxml2::load_document (testXml);

		// find first matching an element in the document
		cout << "find an element by attribute value" << endl;
		auto bThree = find_element (static_cast<const tinyxml2::XMLDocument &>(*doc), "A/B[@id='three']"s);
		cout << attribute_value (bThree, "id"s) << " - " << attribute_value (bThree, "org"s) << endl;
		cout << "=================================================" << endl << endl;

		// find the first instance of a child element of the selected type
		cout << "get description attribute of <D> element" << endl;
		if (auto ch1 = find_element (bThree, "D"s))
			cout << attribute_value (ch1, "description"s) << text (ch1) << endl << endl;
		cout << "=================================================" << endl << endl;

		// iterate over all <C> children of selected
		cout << "iterate over all <C> children of selected " << endl;
		for (auto cc : tinyxml2::selection (bThree, "C"s))
		{
			cout << cc -> Parent() -> ToElement() -> Name() << "[" << attribute_value (cc -> Parent() -> ToElement(), "id") << "] / " << cc -> Name() << "[@code='";
			if (!attribute_value (cc, "code") .empty())
				cout << attribute_value (cc, "code");
			else
				cout << "**element has no attribute - code**";
			cout << "']" << endl;
		}
		cout << "=================================================" << endl << endl;

		// iterate over all elements in the document along the selected path by starting with '/'
		// note that because path starts from the document, bThree is used only as an element in the document not the root of the search
		cout << "iterate over all <C> children : /A/B[@id='three']/C" << endl;
		int nC = 0;
		for (auto cc : tinyxml2::selection (bThree, "/A/B[@id='three']/C"s))
		{
			++nC;
			cout << cc -> Parent() -> ToElement() -> Name() << "[" << attribute_value (cc -> Parent() -> ToElement(), "id") << "] / " << cc -> Name() << "[@code='";
			if (!attribute_value (cc, "code") .empty())
				cout << attribute_value (cc, "code");
			else
				cout << "**element has no attribute - code**";
			cout << "']" << endl;
		}
		cout << nC << " Cs in B[@id='three']" << endl << endl;
		cout << "=================================================" << endl << endl;

		// iterate over all children, any name (type), with code attribute value
		cout << "iterate over all children of any name (type) : /A/B/[@code='9ABC']" << endl;
		for (auto cc : tinyxml2::selection (bThree, "/A/B/[@code='9ABC']"s))
		{
			cout << cc -> Parent() -> ToElement() -> Name() << "[" << attribute_value (cc -> Parent() -> ToElement(), "id") << "] / " << cc -> Name() << "[@code='";
			if (!attribute_value (cc, "code") .empty())
				cout << attribute_value (cc, "code");
			else
				cout << "**element has no attribute - code**";
			cout << "']" << endl;
		}
		cout << "=================================================" << endl << endl;

		// find the first instance of a child element of the selected type with a matching attribute value
		cout << "find C[@code='9ABC'] within B[@id='three']" << endl;
		if (auto cc = find_element (bThree, "C[@code='9ABC']"s))
			cout << text (cc) << " , " << attribute_value (cc, "description") << endl << endl;
		else
			cout << "could not find C[@code='9ABC'] in B" << endl;
		cout << "=================================================" << endl << endl;

		// find the same element within document
		cout << "find B[@id='three']/C[@code='9ABC']" << endl;
		if (auto cc = find_element (*doc, "/A/B[@id='three']/C[@code='9ABC']"s))
			cout << text (cc) << " , " << attribute_value (cc, "description") << endl << endl;
		else
			cout << "could not find A/B[@id='three']/C[@code='9ABC'] in document" << endl;
		cout << "=================================================" << endl << endl;

	}
	catch (tinyxml2::XmlException & e)
	{
		cout << e .what() << endl;
	}

	/////////////////////// modify the document

	try
	{
		auto doc = tinyxml2::load_document (testXml);
		// create new CZ element in branch below selected <C> element with new CX and new CY
		auto ne = append_element (find_element (*doc, "/A/B[@id='three']/C[@code='9ABC']"s), "CX/CY[@id='099']/CZ", {{"id"s, "0998"s}, {"code"s, "ASDF"s}}, "magnum"s);
		// now use the inserted element to insert another after it
		auto czId {"1233"s};
		auto czCode {"ZXCV"s};
		auto czData {"corneto"s};
		insert_next_element  (ne, "CZ", {{"id"s, czId}, {"code"s, czCode}}, czData);

		// todo:
		// what do we want find_element to do when path is empty?
		// . find the first child element (which is what it does now) ?
		// . or simply return the parent element passed in ?

		tinyxml2::XMLPrinter printer;
		doc -> Print (&printer);
		cout << printer .CStr() << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << e .what() << endl;
	}

	/////////////////////// copy
	try
	{
		auto source = tinyxml2::load_document (testXml);
		auto dest = std::make_unique <tinyxml2::XMLDocument>();
		auto e = dest -> NewElement ("mycopy");
		dest -> InsertEndChild (e);

		xcopy (source -> FirstChildElement(), e, {{"extern", "internal"}, {"B4", "Bee Four"}});

		tinyxml2::XMLPrinter printer;
		dest -> Print (&printer);
		cout << printer .CStr() << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << e .what() << endl;
	}

	// hold console window open so we can see the output
	std::cout << "hit any key to close" << std::endl;
	auto c = _getch();

	return 0;
}
<commit_msg>Update test example to include tixml2cx.h<commit_after>/*
tinyxml2ex - a set of add-on classes and helper functions bringing C++11/14 features, such as iterators, strings and exceptions, to tinyxml2

Copyright (c) 2016 Stan Thomas

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.

tinyxml2 is the work of Lee Thomason (www.grinninglizard.com) and others.
It can be found here: https://github.com/leethomason/tinyxml2 and has it's own licensing terms.

*/

#include <string>
#include <iostream>
#include <algorithm>
#include <conio.h>

// include the header for tinyxml2ex which includes tinyxml2, remember to put them on your include path
#include <tixml2cx.h>

using namespace std;
using namespace std::literals::string_literals;

int main()
{
	// a simple XML document
	string testXml {R"-(
<?xml version="1.0" encoding="UTF-8"?>

		<C code="1234">
			A-B(one)-C.1234
		</C>
		<C code="5678">
			<![CDATA[A-B(one)-C.5678]]>
		</C>
		<C code="9ABC"> A-B{one)-C.9ABC</C>
		<D code="9ABC" id="d1" />

		<D id="d2" />

		<C code="1234">
			A-B(three)-C.1234
		</C>
		<C code="9ABC">A-B(three)-C.9ABC</C>
		<D id="d3" description="A-B(three)-D.9ABC" />

			one {B4} two {B4}

)-"s};

	// these three blocks are equivalent and demonstrate different ways to iterate over
	// all <C> element children of  element children of the document element
	// we only want to inspect the elements and attributes, so treat the XMLElements as const
	// 1) native TinyXML2 : 21 lines of code
	{
		printf ("\n1)   <C> element children of  element children of the document element \nnative TinyXML2\n");
		tinyxml2::XMLDocument doc;
		if (doc .Parse (testXml .c_str()) == 0/*XML_NO_ERORR*/)
		{
			const tinyxml2::XMLElement * eA = doc .FirstChildElement();
			if (eA)
			{
				const tinyxml2::XMLElement * eB = eA -> FirstChildElement("B");
				while (eB)
				{
					const tinyxml2::XMLElement * eC = eB -> FirstChildElement ("C");
					while (eC)
					{
						printf ("%s = %s\n", eC -> Name(), eC -> GetText());
						eC = eC -> NextSiblingElement ("C");
					}
					eB = eB -> NextSiblingElement ("B");
				}
			}
			else
				printf ("unable to load XML document\n");
		}
	}
	cout << "----" << endl << endl;

	// 2) tixml2ex XPath selector : 10 lines of code
	cout << "2)   <C> element children of  element children of the document element " << endl
		<< "tixml2ex XPath selector" << endl;
	try
	{
		auto doc = tinyxml2::load_document (testXml);
		// n.b. the static_cast makes the XMLDocument const and hence all XMLElements returned are also const
		for (auto eC : tinyxml2::selection (static_cast <const tinyxml2::XMLDocument &> (*doc), "A/B/C"))
			cout << eC -> Name() << " = " << text (eC) << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << "XmlException caught" << e .what() << endl;
	}
	cout << "----" << endl << endl;

	// 3) simple tixml2ex element iterator : 18 lines of code
	cout << endl << "3)   <C> element children of  element children of the document element " << endl
		<< "simple tixml2ex element iterator" << endl;
	try
	{
		auto doc = tinyxml2::load_document (testXml);
		auto eA = doc -> FirstChildElement();
		if (eA)
			for (auto eB : eA)
			{
				// just for fun, use standard algorithm for_each to iterate over the children of
				for_each (cbegin (eB), cend (eB),
					[](auto e)
				{
						// simple iterators are just that, they iterate over all children
						// therefore we must test element name (type) to examine only <C> elements
					if (strcmp (e -> Name(), "C") == 0) cout << e -> Name() << " = " << text (e) << endl;
				});
			}
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << "XmlException caught" << e .what() << endl;
	}

	cout << "=================================================" << endl << endl;

	// additional element selection and iteration using XPath syntax
	// illustrating helper functions
	try
	{
		auto doc = tinyxml2::load_document (testXml);

		// find first matching an element in the document
		cout << "find an element by attribute value" << endl;
		auto bThree = find_element (static_cast<const tinyxml2::XMLDocument &>(*doc), "A/B[@id='three']"s);
		cout << attribute_value (bThree, "id"s) << " - " << attribute_value (bThree, "org"s) << endl;
		cout << "=================================================" << endl << endl;

		// find the first instance of a child element of the selected type
		cout << "get description attribute of <D> element" << endl;
		if (auto ch1 = find_element (bThree, "D"s))
			cout << attribute_value (ch1, "description"s) << text (ch1) << endl << endl;
		cout << "=================================================" << endl << endl;

		// iterate over all <C> children of selected
		cout << "iterate over all <C> children of selected " << endl;
		for (auto cc : tinyxml2::selection (bThree, "C"s))
		{
			cout << cc -> Parent() -> ToElement() -> Name() << "[" << attribute_value (cc -> Parent() -> ToElement(), "id") << "] / " << cc -> Name() << "[@code='";
			if (!attribute_value (cc, "code") .empty())
				cout << attribute_value (cc, "code");
			else
				cout << "**element has no attribute - code**";
			cout << "']" << endl;
		}
		cout << "=================================================" << endl << endl;

		// iterate over all elements in the document along the selected path by starting with '/'
		// note that because path starts from the document, bThree is used only as an element in the document not the root of the search
		cout << "iterate over all <C> children : /A/B[@id='three']/C" << endl;
		int nC = 0;
		for (auto cc : tinyxml2::selection (bThree, "/A/B[@id='three']/C"s))
		{
			++nC;
			cout << cc -> Parent() -> ToElement() -> Name() << "[" << attribute_value (cc -> Parent() -> ToElement(), "id") << "] / " << cc -> Name() << "[@code='";
			if (!attribute_value (cc, "code") .empty())
				cout << attribute_value (cc, "code");
			else
				cout << "**element has no attribute - code**";
			cout << "']" << endl;
		}
		cout << nC << " Cs in B[@id='three']" << endl << endl;
		cout << "=================================================" << endl << endl;

		// iterate over all children, any name (type), with code attribute value
		cout << "iterate over all children of any name (type) : /A/B/[@code='9ABC']" << endl;
		for (auto cc : tinyxml2::selection (bThree, "/A/B/[@code='9ABC']"s))
		{
			cout << cc -> Parent() -> ToElement() -> Name() << "[" << attribute_value (cc -> Parent() -> ToElement(), "id") << "] / " << cc -> Name() << "[@code='";
			if (!attribute_value (cc, "code") .empty())
				cout << attribute_value (cc, "code");
			else
				cout << "**element has no attribute - code**";
			cout << "']" << endl;
		}
		cout << "=================================================" << endl << endl;

		// find the first instance of a child element of the selected type with a matching attribute value
		cout << "find C[@code='9ABC'] within B[@id='three']" << endl;
		if (auto cc = find_element (bThree, "C[@code='9ABC']"s))
			cout << text (cc) << " , " << attribute_value (cc, "description") << endl << endl;
		else
			cout << "could not find C[@code='9ABC'] in B" << endl;
		cout << "=================================================" << endl << endl;

		// find the same element within document
		cout << "find B[@id='three']/C[@code='9ABC']" << endl;
		if (auto cc = find_element (*doc, "/A/B[@id='three']/C[@code='9ABC']"s))
			cout << text (cc) << " , " << attribute_value (cc, "description") << endl << endl;
		else
			cout << "could not find A/B[@id='three']/C[@code='9ABC'] in document" << endl;
		cout << "=================================================" << endl << endl;

		// iterate over all children, any name (type), of  elements which are children of the document element
		cout << "iterate over all children, any name (type), of  elements which are children of the document element" << endl;
		auto eA = doc -> FirstChildElement();
		for (auto cd : tinyxml2::selection (eA, "B/"))
			cout << cd -> Name() << " = " << text (cd) << " id=" << attribute_value (cd, "id") << endl;
		cout << "=================================================" << endl << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << e .what() << endl;
	}

	/////////////////////// modify the document

	try
	{
		auto doc = tinyxml2::load_document (testXml);
		// create new CZ element in branch below selected <C> element with new CX and new CY
		auto ne = append_element (find_element (*doc, "/A/B[@id='three']/C[@code='9ABC']"s), "CX/CY[@id='099']/CZ", {{"id"s, "0998"s}, {"code"s, "ASDF"s}}, "magnum"s);
		// now use the inserted element to insert another after it
		auto czId {"1233"s};
		auto czCode {"ZXCV"s};
		auto czData {"corneto"s};
		insert_next_element  (ne, "CZ", {{"id"s, czId}, {"code"s, czCode}}, czData);

		// todo:
		// what do we want find_element to do when path is empty?
		// . find the first child element (which is what it does now) ?
		// . or simply return the parent element passed in ?

		tinyxml2::XMLPrinter printer;
		doc -> Print (&printer);
		cout << printer .CStr() << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << e .what() << endl;
	}

	/////////////////////// copy
	try
	{
		auto source = tinyxml2::load_document (testXml);
		auto dest = std::make_unique <tinyxml2::XMLDocument>();
		auto e = dest -> NewElement ("mycopy");
		dest -> InsertEndChild (e);

		xcopy (source -> FirstChildElement(), e, {{"extern", "internal"}, {"B4", "Bee Four"}});

		tinyxml2::XMLPrinter printer;
		dest -> Print (&printer);
		cout << printer .CStr() << endl;
	}
	catch (tinyxml2::XmlException & e)
	{
		cout << e .what() << endl;
	}

	// hold console window open so we can see the output
	std::cout << "hit any key to close" << std::endl;
	auto c = _getch();

	return 0;
}
<|endoftext|>


<commit_before>#include <network/Client.h>
#include <network/Protocol.h>
#include <network/Server.h>

#include <iostream>
#include <string>

class TestProtocol : public network::Protocol
{
public:
    class Listener
    {
    public:
        virtual ~Listener() {}
        virtual void onPongRecv() = 0;
    };

    TestProtocol(network::MessageIO& messageIO, Listener* l) :
        network::Protocol(messageIO),
        mListener(l)
    {
    }

    virtual ~TestProtocol() {}

    void sendPing()
    {
        sendMessage(PING,"Ping",-1);
    }

    void sendPong()
    {
        sendMessage(PONG,"Pong",-1);
    }

private:
    enum MessageType
    {
        PING = 0,
        PONG
    };

    virtual void message(const network::Message& message) override
    {
        switch (message.type()) {
            case MessageType::PING:
                std::cout << "Ping received" << std::endl;
                sendPong();
                break;
            case MessageType::PONG:
                std::cout << "Pong received" << std::endl;
                if (mListener != nullptr) {
                    mListener->onPongRecv();
                }
                break;
        }
    }

    Listener* mListener;
};

class TestProtocolListener : public TestProtocol::Listener
{
public:
    virtual ~TestProtocolListener() {}
    virtual void onPongRecv() override
    {
        network::IOServiceManager::get().stop();
    }
};

class TestSession : public network::Session
{
public:
    TestSession() :
        mProtocol(*this, nullptr)

    {
    }

private:
    TestProtocol mProtocol;
};

void usage()
{
    std::cout << "Usage: network-test server <port> | client <ip>"
        << " <port>" << std::endl;
}

int main(int argc, char* argv[])
{
    // validate input
    if (argc < 2) {
        usage();
        return -1;
    }

    std::string action(argv[1]);

    if (action == "server" && argc != 3) {
        usage();
        return -1;
    }

    if (action == "client" && argc != 4) {
        usage();
        return -1;
    }

    if (action == "server") {
        auto port = atoi(argv[2]);
        network::Server<TestSession> server(port);
        network::IOServiceManager::get().run();
    } else if (action == "client") {
        std::string ip(argv[2]);
        std::string port(argv[3]);
        network::Client client(ip, port);
        TestProtocolListener listener;
        TestProtocol protocol{client, &listener};
        protocol.sendPing();
        network::IOServiceManager::get().run();
    } else {
        usage();
        return -1;
    }

    return 0;
}
<commit_msg>Increase example to 100 pings<commit_after>#include <network/Client.h>
#include <network/Protocol.h>
#include <network/Server.h>

#include <iostream>
#include <string>

const auto PING_COUNT = 100;

class TestProtocol : public network::Protocol
{
public:
    class Listener
    {
    public:
        virtual ~Listener() {}
        virtual void onPongRecv() = 0;
    };

    TestProtocol(network::MessageIO& messageIO, Listener* l) :
        network::Protocol(messageIO),
        mListener(l)
    {
    }

    virtual ~TestProtocol() {}

    void sendPing()
    {
        sendMessage(PING,"Ping",-1);
    }

    void sendPong()
    {
        sendMessage(PONG,"Pong",-1);
    }

private:
    enum MessageType
    {
        PING = 0,
        PONG
    };

    virtual void message(network::Message&& message) override
    {
        switch (message.type()) {
            case MessageType::PING:
                std::cout << "Ping received" << std::endl;
                sendPong();
                break;
            case MessageType::PONG:
                std::cout << "Pong received" << std::endl;
                if (mListener != nullptr) {
                    mListener->onPongRecv();
                }
                break;
        }
    }

    Listener* mListener;
};

class TestProtocolListener : public TestProtocol::Listener
{
public:
    virtual ~TestProtocolListener() {}
    virtual void onPongRecv() override
    {
        mRecCount++;
        if (mRecCount == PING_COUNT) {
            network::IOServiceManager::get().stop();
        }
    }
private:
    int mRecCount = 0;
};

class TestSession : public network::Session
{
public:
    TestSession() :
        mProtocol(*this, nullptr)

    {
    }

private:
    TestProtocol mProtocol;
};

void usage()
{
    std::cout << "Usage: network-test server <port> | client <ip>"
        << " <port>" << std::endl;
}

void iothread()
{
    network::IOServiceManager::get().run();
}

int main(int argc, char* argv[])
{
    // validate input
    if (argc < 2) {
        usage();
        return -1;
    }

    std::string action(argv[1]);

    if (action == "server" && argc != 3) {
        usage();
        return -1;
    }

    if (action == "client" && argc != 4) {
        usage();
        return -1;
    }

    if (action == "server") {
        auto port = atoi(argv[2]);
        network::Server<TestSession> server(port);
        std::thread t(iothread);
        if (t.joinable()) {
            t.join();
        }
    } else if (action == "client") {
        std::string ip(argv[2]);
        std::string port(argv[3]);
        network::Client client(ip, port);
        TestProtocolListener listener;
        TestProtocol protocol{client, &listener};
        std::thread t(iothread);
        for (auto i = 0; i < PING_COUNT; i++) {
            protocol.sendPing();
        }
        if (t.joinable()) {
            t.join();
        }
    } else {
        usage();
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// 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.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <Context.h>
#include <RX.h>
#include <cmake.h>
#include <test.h>

Context context;

int main (int argc, char** argv)
{
  UnitTest ut (23);

  std::string text = "This is a test.";

  RX r1 ("i. ", true);
  ut.ok (r1.match (text), text + " =~ /i. /");

  std::vector <std::string> matches;
  ut.ok (r1.match (matches, text), text + " =~ /i. /");
  ut.ok (matches.size () == 2, "2 match");
  ut.is (matches[0], "is ", "$1 == is\\s");
  ut.is (matches[1], "is ", "$1 == is\\s");

  text = "abcdefghijklmnopqrstuvwxyz";

  RX r3 ("t..", true);
  ut.ok (r3.match (text), "t..");

  RX r4 ("T..", false);
  ut.ok (r4.match (text), "T..");

  RX r5 ("T..", true);
  ut.ok (!r5.match (text), "! T..");

  text = "this is a test of the regex engine.";
  //      |...:....|....:....|....:....|....:

  RX r6 ("^this");
  ut.ok (r6.match (text),      "^this matches");

  RX r7 ("engine\\.$");
  ut.ok (r7.match (text), "engine\\.$ matches");

  std::vector <std::string> results;
  std::vector <int> start;
  std::vector <int> end;
  RX r8 ("e..", true);
  ut.ok (r8.match (results, text), "e.. there are matches");
  ut.ok (r8.match (start, end, text), "e.. there are matches");
  ut.is (results.size (), (size_t) 4, "e.. == 4 matches");
  ut.is (results[0], "est", "e..[0] == 'est'");
  ut.is (start[0],      11, "e..[0] == 11->");
  ut.is (end[0],        14, "e..[0] == ->14");

  results.clear ();
  RX r9 ("e", true);
  ut.ok (r9.match (results, text),           "e there are matches");
  ut.is (results.size (), (size_t) 6,        "e == 6 matches");

  start.clear ();
  end.clear ();
  ut.ok (r9.match (start, end, text),        "e there are matches");
  ut.is (start.size (), (size_t) 6,          "e == 6 matches");

#ifdef DARWIN
  text = "this is the end.";
  ut.pass (text + " =~ /\\bthe/");
  ut.pass (text + " =~ /the\\b/");
  ut.pass (text + " =~ /\\bthe\\b/");
#else
#ifdef SOLARIS
  RX r10 ("\\<the");
  text = "this is the end.";
  ut.ok (r10.match (text), text + " =~ /\\<the/");

  RX r11 ("the\\>");
  ut.ok (r11.match (text), text + " =~ /the\\>/");

  RX r12 ("\\<the\\>");
  ut.ok (r12.match (text), text + " =~ /\\<the\\>/");
#else
  RX r10 ("\\bthe");
  text = "this is the end.";
  ut.ok (r10.match (text), text + " =~ /\\bthe/");

  RX r11 ("the\\b");
  ut.ok (r11.match (text), text + " =~ /the\\b/");

  RX r12 ("\\bthe\\b");
  ut.ok (r12.match (text), text + " =~ /\\bthe\\b/");
#endif
#endif

  return 0;
}

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

<commit_msg>Unit Tests<commit_after>////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// 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.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <Context.h>
#include <RX.h>
#include <cmake.h>
#include <test.h>

Context context;

int main (int argc, char** argv)
{
  UnitTest ut (23);

  std::string text = "This is a test.";

  RX r1 ("i. ", true);
  ut.ok (r1.match (text), text + " =~ /i. /");

  std::vector <std::string> matches;
  ut.ok (r1.match (matches, text), text + " =~ /i. /");
  ut.ok (matches.size () == 2, "2 match");
  ut.is (matches[0], "is ", "$1 == is\\s");
  ut.is (matches[1], "is ", "$1 == is\\s");

  text = "abcdefghijklmnopqrstuvwxyz";

  RX r3 ("t..", true);
  ut.ok (r3.match (text), "t..");

  RX r4 ("T..", false);
  ut.ok (r4.match (text), "T..");

  RX r5 ("T..", true);
  ut.ok (!r5.match (text), "! T..");

  text = "this is a test of the regex engine.";
  //      |...:....|....:....|....:....|....:

  RX r6 ("^this");
  ut.ok (r6.match (text),      "^this matches");

  RX r7 ("engine\\.$");
  ut.ok (r7.match (text), "engine\\.$ matches");

  std::vector <std::string> results;
  std::vector <int> start;
  std::vector <int> end;
  RX r8 ("e..", true);
  ut.ok (r8.match (results, text), "e.. there are matches");
  ut.ok (r8.match (start, end, text), "e.. there are matches");
  ut.is (results.size (), (size_t) 4, "e.. == 4 matches");
  ut.is (results[0], "est", "e..[0] == 'est'");
  ut.is (start[0],      11, "e..[0] == 11->");
  ut.is (end[0],        14, "e..[0] == ->14");

  results.clear ();
  RX r9 ("e", true);
  ut.ok (r9.match (results, text),           "e there are matches");
  ut.is (results.size (), (size_t) 6,        "e == 6 matches");

  start.clear ();
  end.clear ();
  ut.ok (r9.match (start, end, text),        "e there are matches");
  ut.is (start.size (), (size_t) 6,          "e == 6 matches");

#if defined(DARWIN) || defined(CYGWIN) || defined(FREEBSD)
  text = "this is the end.";
  ut.pass (text + " =~ /\\bthe/");
  ut.pass (text + " =~ /the\\b/");
  ut.pass (text + " =~ /\\bthe\\b/");
#else
#ifdef SOLARIS
  RX r10 ("\\<the");
  text = "this is the end.";
  ut.ok (r10.match (text), text + " =~ /\\<the/");

  RX r11 ("the\\>");
  ut.ok (r11.match (text), text + " =~ /the\\>/");

  RX r12 ("\\<the\\>");
  ut.ok (r12.match (text), text + " =~ /\\<the\\>/");
#else
  RX r10 ("\\bthe");
  text = "this is the end.";
  ut.ok (r10.match (text), text + " =~ /\\bthe/");

  RX r11 ("the\\b");
  ut.ok (r11.match (text), text + " =~ /the\\b/");

  RX r12 ("\\bthe\\b");
  ut.ok (r12.match (text), text + " =~ /\\bthe\\b/");
#endif
#endif

  return 0;
}

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

<|endoftext|>


<commit_before><commit_msg>Added some comments and fixed formatting<commit_after><|endoftext|>