<commit_before>/*******************************************************************************
 The MIT License (MIT)

 Copyright (c) 2015 Alexander Zolotarev <me@alex.bio> from Minsk, Belarus

 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.
 *******************************************************************************/

// clang-format off
// This FastCGI server implementation is designed to store statistics received from remote clients.
// By default, everything is stored in <specified folder>/alohalytics_messages file.
// If you have tons of data, it is better to use logrotate utility to archive it (see logrotate.conf).

// Validity checks for requests should be mostly done on nginx side (see nginx.conf):
// $request_method should be POST only
// $content_length should be set and greater than zero (we re-check it below anyway)
// $content_type should be set to application/alohalytics-binary-blob (except of monitoring uri)
// $http_content_encoding should be set to gzip (except of monitoring uri)

// Monitoring URI is a simple is-server-alive check. POST any content-type there and get it back without any modifications.

// This binary shoud be spawn as a FastCGI app, for example:
// $ spawn-fcgi [-n] -a 127.0.0.1 -p <port number> -P /path/to/pid.file -- ./fcgi_server /dir/to/store/received/data /monitoring/uri [/optional/path/to/log.file]
// pid.file can be used by logrotate (see logrotate.conf).
// clang-format on

#include <chrono>
#include <csignal>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
#include <thread>

#include <fcgiapp.h>
#include <fcgio.h>

#include "../src/logger.h"

#include "statistics_receiver.h"

using namespace std;

// Can be used as a basic check on the client-side if it has connected to the right server.
static const string kBodyTextForGoodServerReply = "Mahalo";
static const string kBodyTextForBadServerReply = "Hohono";

// We always reply to our clients that we have received everything they sent, even if it was a complete junk.
// The difference is only in the body of the reply.
// Custom content type is used for monitoring.
void Reply200OKWithBody(FCGX_Stream * out, const string & body, const char * content_type = "text/plain") {
  FCGX_FPrintF(out, "Status: 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\n\r\n%s\n", content_type,
               body.size(), body.c_str());
}

// Global variables to correctly reopen data and log files after signals from logrotate utility.
volatile sig_atomic_t gReceivedSIGHUP = 0;
volatile sig_atomic_t gReceivedSIGUSR1 = 0;
// Redirects all cout output into a file if good log_file_path was given in constructor.
// Can always ReopenLogFile() if needed (e.g. for log rotation).
struct CoutToFileRedirector {
  char const * path;
  unique_ptr<ofstream> log_file;
  streambuf * original_cout_buf;

  CoutToFileRedirector(const char * log_file_path) : path(log_file_path), original_cout_buf(cout.rdbuf()) {
    ReopenLogFile();
  }
  void ReopenLogFile() {
    if (!path) {
      return;
    }
    log_file.reset(nullptr);
    log_file.reset(new ofstream(path, ofstream::out | ofstream::app));
    if (log_file->good()) {
      cout.rdbuf(log_file->rdbuf());
    } else {
      ALOG("ERROR: Can't open log file", path, "for writing.");
    }
  }
  // Restore original cout streambuf.
  ~CoutToFileRedirector() { cout.rdbuf(original_cout_buf); }
};

int main(int argc, char * argv[]) {

  if (argc < 3) {
    ALOG("Usage:", argv[0], "<directory to store received data> </special/uri/for/monitoring> [path to error log file]");
    ALOG("  - Monitoring URI always replies with the same body and content-type which was received.");
    ALOG("  - SIGHUP reopens main data file and SIGUSR1 reopens debug log file for logrotate utility.");
    return -1;
  }

  const string kMonitoringURI = argv[2];
  if (kMonitoringURI.empty() || kMonitoringURI.front() != '/') {
    ALOG("Given monitoring URI", kMonitoringURI, "shoud start with a slash.");
    return -1;
  }

  int result = FCGX_Init();
  if (0 != result) {
    ALOG("ERROR: FCGX_Init has failed with code", result);
    return result;
  }

  FCGX_Request request;
  result = FCGX_InitRequest(&request, 0, FCGI_FAIL_ACCEPT_ON_INTR);
  if (0 != result) {
    ALOG("ERROR: FCGX_InitRequest has failed with code", result);
    return result;
  }

  // Redirect cout into a file if it was given in the command line.
  CoutToFileRedirector log_redirector(argc > 3 ? argv[3] : nullptr);
  // Correctly reopen data file on SIGHUP for logrotate.
  if (SIG_ERR == ::signal(SIGHUP, [](int) { gReceivedSIGHUP = SIGHUP; })) {
    ALOG("WARNING: Can't set SIGHUP handler. Logrotate will not work correctly.");
  }
  // Correctly reopen debug log file on SIGUSR1 for logrotate.
  if (SIG_ERR == ::signal(SIGUSR1, [](int) { gReceivedSIGUSR1 = SIGUSR1; })) {
    ALOG("WARNING: Can't set SIGUSR1 handler. Logrotate will not work correctly.");
  }
  // NOTE: On most systems, when we get a signal, FCGX_Accept_r blocks even with a FCGI_FAIL_ACCEPT_ON_INTR flag set
  // in the request. Looks like on these systems default signal function installs the signals with the SA_RESTART flag
  // set (see man sigaction for more details) and syscalls are automatically restart themselves if a signal occurs.
  // To "fix" this behavior and gracefully shutdown our server, we use a trick from
  // W. Richard Stevens, Stephen A. Rago, "Advanced Programming in the UNIX Environment", 2nd edition, page 329.
  // It is also described here: http://comments.gmane.org/gmane.comp.web.fastcgi.devel/942
  for (auto signo : {SIGTERM, SIGINT}) {
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    act.sa_handler = [](int) { FCGX_ShutdownPending(); };
    const int result = sigaction(signo, &act, nullptr);
    if (result != 0) {
      ALOG("WARNING: Can't set", signo, "signal handler");
    }
  }

  alohalytics::StatisticsReceiver receiver(argv[1]);
  string gzipped_body;
  long long content_length;
  const char * remote_addr_str = nullptr;
  const char * request_uri_str = nullptr;
  const char * user_agent_str = nullptr;
  ALOG("FastCGI Server instance is ready to serve clients' requests.");
  while (FCGX_Accept_r(&request) >= 0) {
    // Correctly reopen data file in the queue.
    if (gReceivedSIGHUP == SIGHUP) {
      receiver.ReopenDataFile();
      gReceivedSIGHUP = 0;
    }
    // Correctly reopen debug log file.
    if (gReceivedSIGUSR1 == SIGUSR1) {
      log_redirector.ReopenLogFile();
      gReceivedSIGUSR1 = 0;
    }

    try {
      remote_addr_str = FCGX_GetParam("REMOTE_ADDR", request.envp);
      if (!remote_addr_str) {
        ALOG("WARNING: Missing REMOTE_ADDR. Please check your http server configuration.");
      }
      request_uri_str = FCGX_GetParam("REQUEST_URI", request.envp);
      if (!request_uri_str) {
        ALOG("WARNING: Missing REQUEST_URI. Please check your http server configuration.");
      }
      user_agent_str = FCGX_GetParam("HTTP_USER_AGENT", request.envp);
      if (!user_agent_str) {
        ALOG("WARNING: Missing HTTP User-Agent. Please check your http server configuration.");
      }

      const char * content_length_str = FCGX_GetParam("HTTP_CONTENT_LENGTH", request.envp);
      content_length = 0;
      if (!content_length_str || ((content_length = atoll(content_length_str)) <= 0)) {
        ALOG("WARNING: Request is ignored due to invalid or missing Content-Length header", content_length_str,
              remote_addr_str, request_uri_str, user_agent_str);
        Reply200OKWithBody(request.out, kBodyTextForBadServerReply);
        continue;
      }
      // TODO(AlexZ): Should we make a better check for Content-Length or basic exception handling would be enough?
      gzipped_body.resize(content_length);
      if (fcgi_istream(request.in).read(&gzipped_body[0], content_length).fail()) {
        ALOG("WARNING: Request is ignored because it's body can't be read.", remote_addr_str, request_uri_str,
              user_agent_str);
        Reply200OKWithBody(request.out, kBodyTextForBadServerReply);
        continue;
      }

      // Handle special URI for server monitoring.
      if (request_uri_str && request_uri_str == kMonitoringURI) {
        const char * content_type_str = FCGX_GetParam("HTTP_CONTENT_TYPE", request.envp);
        // Reply with the same content and content-type.
        Reply200OKWithBody(request.out, gzipped_body, content_type_str ? content_type_str : "text/plain");
        continue;
      }

      // Process and store received body.
      // This call can throw different exceptions.
      receiver.ProcessReceivedHTTPBody(gzipped_body,
                                       AlohalyticsBaseEvent::CurrentTimestamp(),
                                       remote_addr_str ? remote_addr_str : "",
                                       user_agent_str ? user_agent_str : "",
                                       request_uri_str ? request_uri_str : "");
      Reply200OKWithBody(request.out, kBodyTextForGoodServerReply);
    } catch (const exception & ex) {
      ALOG("ERROR: Exception was thrown:", ex.what(), remote_addr_str, request_uri_str, user_agent_str);
      // TODO(AlexZ): Log "bad" received body for investigation.
      Reply200OKWithBody(request.out, kBodyTextForBadServerReply);
    }
  }
  ALOG("Shutting down FastCGI server instance.");
  return 0;
}
<commit_msg>Better fcgi_server documentation.<commit_after>/*******************************************************************************
 The MIT License (MIT)

 Copyright (c) 2015 Alexander Zolotarev <me@alex.bio> from Minsk, Belarus

 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.
 *******************************************************************************/

// clang-format off
// This FastCGI server implementation is designed to store statistics received from remote clients.
// By default, everything is stored in <specified folder>/alohalytics_messages file.
// If you have tons of data, it is better to use logrotate utility to archive it (see logrotate.conf).

// Validity checks for requests should be mostly done on nginx side (see nginx.conf):
// $request_method should be POST only
// $content_length should be set and greater than zero (we re-check it below anyway)
// $content_type should be set to application/alohalytics-binary-blob (except of monitoring uri)
// $http_content_encoding should be set to gzip (except of monitoring uri)

// Monitoring URI is a simple is-server-alive check. POST any content-type there and get it back without any modifications.

// This binary shoud be spawn as a FastCGI app, for example:
// $ spawn-fcgi [-n] -a 127.0.0.1 -p <port number> -P /path/to/pid.file -- ./fcgi_server /dir/to/store/received/data /monitoring/uri [/optional/path/to/log.file]
// pid.file can be used by logrotate (see logrotate.conf).
// clang-format on

#include <chrono>
#include <csignal>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <fstream>
#include <memory>
#include <sstream>
#include <string>
#include <thread>

#include <fcgiapp.h>
#include <fcgio.h>

#include "../src/logger.h"

#include "statistics_receiver.h"

using namespace std;

// Can be used as a basic check on the client-side if it has connected to the right server.
static const string kBodyTextForGoodServerReply = "Mahalo";
static const string kBodyTextForBadServerReply = "Hohono";

// We always reply to our clients that we have received everything they sent, even if it was a complete junk.
// The difference is only in the body of the reply.
// Custom content type is used for monitoring.
void Reply200OKWithBody(FCGX_Stream * out, const string & body, const char * content_type = "text/plain") {
  FCGX_FPrintF(out, "Status: 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\n\r\n%s\n", content_type,
               body.size(), body.c_str());
}

// Global variables to correctly reopen data and log files after signals from logrotate utility.
volatile sig_atomic_t gReceivedSIGHUP = 0;
volatile sig_atomic_t gReceivedSIGUSR1 = 0;
// Redirects all cout output into a file if good log_file_path was given in constructor.
// Can always ReopenLogFile() if needed (e.g. for log rotation).
struct CoutToFileRedirector {
  char const * path;
  unique_ptr<ofstream> log_file;
  streambuf * original_cout_buf;

  CoutToFileRedirector(const char * log_file_path) : path(log_file_path), original_cout_buf(cout.rdbuf()) {
    ReopenLogFile();
  }
  void ReopenLogFile() {
    if (!path) {
      return;
    }
    log_file.reset(nullptr);
    log_file.reset(new ofstream(path, ofstream::out | ofstream::app));
    if (log_file->good()) {
      cout.rdbuf(log_file->rdbuf());
    } else {
      ALOG("ERROR: Can't open log file", path, "for writing.");
    }
  }
  // Restore original cout streambuf.
  ~CoutToFileRedirector() { cout.rdbuf(original_cout_buf); }
};

int main(int argc, char * argv[]) {

  if (argc < 3) {
    ALOG("Usage:", argv[0], "<directory to store received data> "
                            "</special/uri/for/monitoring> "
                            "[optional path to error log file]");
    ALOG("  - Monitoring URI always replies with the same body and content-type which was received.");
    ALOG("  - Errors are logged to stdout if error log file has not been specified.");
    ALOG("  - SIGHUP reopens main data file and SIGUSR1 reopens debug log file for logrotate utility.");
    ALOG("  - SIGTERM gracefully shutdowns server daemon.");
    return -1;
  }
    return -1;
  }

  const string kMonitoringURI = argv[2];
  if (kMonitoringURI.empty() || kMonitoringURI.front() != '/') {
    ALOG("Given monitoring URI", kMonitoringURI, "shoud start with a slash.");
    return -1;
  }

  int result = FCGX_Init();
  if (0 != result) {
    ALOG("ERROR: FCGX_Init has failed with code", result);
    return result;
  }

  FCGX_Request request;
  result = FCGX_InitRequest(&request, 0, FCGI_FAIL_ACCEPT_ON_INTR);
  if (0 != result) {
    ALOG("ERROR: FCGX_InitRequest has failed with code", result);
    return result;
  }

  // Redirect cout into a file if it was given in the command line.
  CoutToFileRedirector log_redirector(argc > 3 ? argv[3] : nullptr);
  // Correctly reopen data file on SIGHUP for logrotate.
  if (SIG_ERR == ::signal(SIGHUP, [](int) { gReceivedSIGHUP = SIGHUP; })) {
    ALOG("WARNING: Can't set SIGHUP handler. Logrotate will not work correctly.");
  }
  // Correctly reopen debug log file on SIGUSR1 for logrotate.
  if (SIG_ERR == ::signal(SIGUSR1, [](int) { gReceivedSIGUSR1 = SIGUSR1; })) {
    ALOG("WARNING: Can't set SIGUSR1 handler. Logrotate will not work correctly.");
  }
  // NOTE: On most systems, when we get a signal, FCGX_Accept_r blocks even with a FCGI_FAIL_ACCEPT_ON_INTR flag set
  // in the request. Looks like on these systems default signal function installs the signals with the SA_RESTART flag
  // set (see man sigaction for more details) and syscalls are automatically restart themselves if a signal occurs.
  // To "fix" this behavior and gracefully shutdown our server, we use a trick from
  // W. Richard Stevens, Stephen A. Rago, "Advanced Programming in the UNIX Environment", 2nd edition, page 329.
  // It is also described here: http://comments.gmane.org/gmane.comp.web.fastcgi.devel/942
  for (auto signo : {SIGTERM, SIGINT}) {
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
#ifdef SA_INTERRUPT
    act.sa_flags |= SA_INTERRUPT;
#endif
    act.sa_handler = [](int) { FCGX_ShutdownPending(); };
    const int result = sigaction(signo, &act, nullptr);
    if (result != 0) {
      ALOG("WARNING: Can't set", signo, "signal handler");
    }
  }

  alohalytics::StatisticsReceiver receiver(argv[1]);
  string gzipped_body;
  long long content_length;
  const char * remote_addr_str = nullptr;
  const char * request_uri_str = nullptr;
  const char * user_agent_str = nullptr;
  ALOG("FastCGI Server instance is ready to serve clients' requests.");
  while (FCGX_Accept_r(&request) >= 0) {
    // Correctly reopen data file in the queue.
    if (gReceivedSIGHUP == SIGHUP) {
      receiver.ReopenDataFile();
      gReceivedSIGHUP = 0;
    }
    // Correctly reopen debug log file.
    if (gReceivedSIGUSR1 == SIGUSR1) {
      log_redirector.ReopenLogFile();
      gReceivedSIGUSR1 = 0;
    }

    try {
      remote_addr_str = FCGX_GetParam("REMOTE_ADDR", request.envp);
      if (!remote_addr_str) {
        ALOG("WARNING: Missing REMOTE_ADDR. Please check your http server configuration.");
      }
      request_uri_str = FCGX_GetParam("REQUEST_URI", request.envp);
      if (!request_uri_str) {
        ALOG("WARNING: Missing REQUEST_URI. Please check your http server configuration.");
      }
      user_agent_str = FCGX_GetParam("HTTP_USER_AGENT", request.envp);
      if (!user_agent_str) {
        ALOG("WARNING: Missing HTTP User-Agent. Please check your http server configuration.");
      }

      const char * content_length_str = FCGX_GetParam("HTTP_CONTENT_LENGTH", request.envp);
      content_length = 0;
      if (!content_length_str || ((content_length = atoll(content_length_str)) <= 0)) {
        ALOG("WARNING: Request is ignored due to invalid or missing Content-Length header", content_length_str,
              remote_addr_str, request_uri_str, user_agent_str);
        Reply200OKWithBody(request.out, kBodyTextForBadServerReply);
        continue;
      }
      // TODO(AlexZ): Should we make a better check for Content-Length or basic exception handling would be enough?
      gzipped_body.resize(content_length);
      if (fcgi_istream(request.in).read(&gzipped_body[0], content_length).fail()) {
        ALOG("WARNING: Request is ignored because it's body can't be read.", remote_addr_str, request_uri_str,
              user_agent_str);
        Reply200OKWithBody(request.out, kBodyTextForBadServerReply);
        continue;
      }

      // Handle special URI for server monitoring.
      if (request_uri_str && request_uri_str == kMonitoringURI) {
        const char * content_type_str = FCGX_GetParam("HTTP_CONTENT_TYPE", request.envp);
        // Reply with the same content and content-type.
        Reply200OKWithBody(request.out, gzipped_body, content_type_str ? content_type_str : "text/plain");
        continue;
      }

      // Process and store received body.
      // This call can throw different exceptions.
      receiver.ProcessReceivedHTTPBody(gzipped_body,
                                       AlohalyticsBaseEvent::CurrentTimestamp(),
                                       remote_addr_str ? remote_addr_str : "",
                                       user_agent_str ? user_agent_str : "",
                                       request_uri_str ? request_uri_str : "");
      Reply200OKWithBody(request.out, kBodyTextForGoodServerReply);
    } catch (const exception & ex) {
      ALOG("ERROR: Exception was thrown:", ex.what(), remote_addr_str, request_uri_str, user_agent_str);
      // TODO(AlexZ): Log "bad" received body for investigation.
      Reply200OKWithBody(request.out, kBodyTextForBadServerReply);
    }
  }
  ALOG("Shutting down FastCGI server instance.");
  return 0;
}
<|endoftext|>


<commit_before>// This file is part of MLDB. Copyright 2015 Datacratic. All rights reserved.

/* mldb_runner.cc
   Jeremy Barnes, 12 December 2014
   Copyright (c) 2014 Datacratic Inc.  All rights reserved.

   Runner for MLDB.
*/

#include "mldb/arch/futex.h"
#include "mldb/server/mldb_server.h"
#include "mldb/server/plugin_resource.h"
#include "mldb/http/http_rest_proxy.h"
#include "mldb/server/credential_collection.h"
#include "mldb/vfs/filter_streams.h"
#include "mldb/utils/config.h"
#include "mldb/soa/credentials/credential_provider.h"
#include "mldb/soa/credentials/credentials.h"
#include <boost/filesystem.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/algorithm/string.hpp>
#include <signal.h>

using namespace std;
using namespace Datacratic;
using namespace Datacratic::MLDB;
namespace fs = boost::filesystem;

constexpr int minimumWorkerThreads(4);

std::atomic<int> serviceShutdown(false);

void onSignal(int sig)
{
    serviceShutdown = true;
    ML::futex_wake(serviceShutdown);
}

struct CommandLineCredentialProvider: public CredentialProvider {

    CommandLineCredentialProvider(const std::vector<string> & credsStr)
    {
        for (auto & c: credsStr) {
            creds.emplace_back(jsonDecodeStr<StoredCredentials>(c));
        }
    }

    std::vector<StoredCredentials> creds;

    virtual std::vector<StoredCredentials>
    getCredentialsOfType(const std::string & resourceType) const
    {
        vector<StoredCredentials> matchingCreds;

        for (auto & cred: creds) {
            if (resourceType != cred.resourceType)
                continue;
            matchingCreds.push_back(cred);
        }

        return matchingCreds;
    }
};

int main(int argc, char ** argv)
{
    struct sigaction action;
    action.sa_handler = onSignal;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGUSR2, &action, nullptr);

    using namespace boost::program_options;

    options_description configuration_options("Configuration options");
    options_description script_options("Script options");
    options_description plugin_options("Plugin options");

    int numThreads(16);
    // Defaults for operational characteristics
    string httpListenPort = "11700-18000";
    string httpListenHost = "0.0.0.0";
    string runScript;
    bool dontExitAfterScript = false;

    string cacheDir;
    string httpBaseUrl = "";

#if 0
    string peerListenPort = "18000-19000";
    string peerListenHost = "0.0.0.0";
    int peerPublishPort = -1;
    string peerPublishHost;
#endif
    string configPath;  // path to the configuration file
    std::string staticAssetsPath = "mldb/container_files/public_html/resources";
    std::string staticDocPath = "mldb/container_files/public_html/doc";

    string etcdUri;
    string etcdPath;

    string scriptArgs;
    string scriptArgsUrl;

    // List of credentials to add.  Each should be in JSON format as a
    //
    vector<string> addCredentials;
    string addCredentialsFromUrl;
    std::string credentialsPath;

    // List of directories to scan for plugins
    vector<string> pluginDirectory;

    bool muteFinalOutput = false;

    configuration_options.add_options()
#if 0
        ("etcd-uri", value(&etcdUri),
         "URI to connect to etcd")
        ("etcd-path", value(&etcdPath),
         "Base path in etcd")
#endif
        ("num-threads,t", value(&numThreads), "Number of HTTP worker threads")
        ("http-listen-port,p",
         value(&httpListenPort)->default_value(httpListenPort),
         "Port to listen on for HTTP")
        ("http-listen-host,h",
         value(&httpListenHost)->default_value(httpListenHost),
         "host to listen to")
        ("static-assets-path",
         value(&staticAssetsPath)->default_value(staticAssetsPath),
         "directory to serve static assets from")
        ("static-doc-path",
         value(&staticDocPath)->default_value(staticDocPath),
         "directory to serve documentation from")
        ("cache-dir", value(&cacheDir),
         "Cache directory to memory map large files and store downloads")

#if 0
        ("peer-listen-port,l",
         value(&peerListenPort)->default_value(peerListenPort),
         "port to listen to")
        ("peer-listen-host",
         value(&peerListenHost)->default_value(peerListenHost),
         "host to listen to")
        ("peer-publish-port,P",
         value(&peerPublishPort)->default_value(peerPublishPort),
         "port to publish for the outside world")
        ("peer-publish-host,H",
         value(&peerPublishHost)->default_value(peerPublishHost),
         "host to publish for the outside world")
#endif
        ("config-path",
         value(&configPath),
         "Path to the mldb configuration.  This is optional. Configuration option "
         "in that file have acceptable default values.")
        ("credentials-path,c", value(&credentialsPath),
         "Path in which to store saved credentials and rules "
         "(file:// for filesystem or s3:// for S3 uri)")
        ("hide-internal-entities",
         "Hide in the documentation entities that are not meant to be exposed")
        ("mute-final-output", bool_switch(&muteFinalOutput),
         "Mutes the output printed right before mldb_runner ends with an error"
         "condition")
        ("enable-access-log",
         "Enable the logging of each http request.  By default, the logging is disabled."
         "Specify this option to enable it.")
        ("http-base-url", value(&httpBaseUrl),
         "Prefix to prepend to all /doc urls.");

    script_options.add_options()
        ("run-script", value(&runScript),
         "Run the given script (JS or Python) and shutdown once done")
        ("script-args", value(&scriptArgs),
         "Provide the given (JSON) arguments to the script directly")
        ("script-args-url", value(&scriptArgsUrl),
         "Provide the given (JSON) arguments to the script loading from the given file")
        ("dont-exit-after-script", value(&dontExitAfterScript),
         "Don't exit immediately after running the script")
        ("add-credential", value(&addCredentials),
         "Add credential (see documentation for format) to MLDB before startup.  "
         "Multiple can be added per call.")
        ("add-credentials-from-url", value(&addCredentialsFromUrl),
         "Read credentials from file with list of JSON objects to add to MLDB before startup");

    plugin_options.add_options()
        ("plugin-directory", value(&pluginDirectory),
         "URL of directory to scan for plugins (can be added multiple times). "
         "Don't forget file://.");

    options_description all_opt;
    all_opt
        .add(configuration_options)
        .add(script_options)
        .add(plugin_options)
        .add_options()
        ("help", "print this message");

    variables_map vm;
    // command line has precendence over config
    store(command_line_parser(argc, argv)
          .options(all_opt)
          //.positional(p)
          .run(),
          vm);

    notify(vm);

    auto cmdConfig = Config::createFromProgramOptions(vm);

    if (vm.count("config-path")) {
        cerr << "reading configuration from file: '" << configPath << "'" << endl;
        auto parsed_options = parse_config_file<char>(configPath.c_str(), all_opt, true);
        store(parsed_options, vm);
        auto fileConfig = Config::createFromProgramOptions(parsed_options);
    }

    if (vm.count("help")) {
        cerr << all_opt << endl;
        exit(1);
    }

    if (numThreads < minimumWorkerThreads) {
        cerr << ML::format("'num-threads' cannot be less than %d: %d\n",
                           minimumWorkerThreads, numThreads);
        exit(1);
    }

    // Add these first so that if needed they can be used to load the credentials
    // file
    if (!addCredentials.empty()) {
        try {
            CredentialProvider::registerProvider
                (std::make_shared<CommandLineCredentialProvider>(addCredentials));
        }
        catch (const HttpReturnException & exc) {
            cerr << "error reading credentials from command line: "
                 << exc.what() << endl;
            cerr << jsonEncode(exc.details) << endl;
            return 1;
        }
        catch (const std::exception & exc) {
            cerr << "error reading credentials from command line: "
                 << exc.what() << endl;
            return 1;
        }
        JML_CATCH_ALL {
            cerr << "error reading credentials from command line: unknown error"
                 << endl;
            return 1;
        }
    }

    // Now load the credentials file
    if (!addCredentialsFromUrl.empty()) {
        try {
            filter_istream stream(addCredentialsFromUrl);
            vector<string> fileCredentials;
            while (stream) {
                Json::Value val = Json::parse(stream);
                if (val.type() == Json::arrayValue) {
                    for (auto & v: val) {
                        fileCredentials.push_back(v.toString());
                    }
                }
                else if (val.type() == Json::objectValue) {
                    fileCredentials.push_back(val.toString());
                }
                else if (val.type() == Json::nullValue) {
                    // skip
                }
                else throw ML::Exception("Couldn't understand credentials " + val.toString());
            }

            if (!fileCredentials.empty()) {
                CredentialProvider::registerProvider
                    (std::make_shared<CommandLineCredentialProvider>(fileCredentials));
            }
        }
        catch (const HttpReturnException & exc) {
            cerr << "error reading credentials from file "
                 << addCredentialsFromUrl
                 << ": " << exc.what()
                 << endl;
            cerr << jsonEncode(exc.details) << endl;
            return 1;
        }
        catch (const std::exception & exc) {
            cerr << "error reading credentials from file "
                 << addCredentialsFromUrl
                 << ": " << exc.what()
                 << endl;
            return 1;
        }
        JML_CATCH_ALL {
            cerr << "error reading credentials from file "
                 << addCredentialsFromUrl << ": unknown error"
                 << endl;
            return 1;
        }
    }

    bool enableAccessLog = vm.count("enable-access-log");
    bool hideInternalEntities = vm.count("hide-internal-entities");

    MldbServer server("mldb", etcdUri, etcdPath, enableAccessLog, httpBaseUrl);
    bool initSuccess = server.init(credentialsPath, staticAssetsPath,
                                   staticDocPath, hideInternalEntities);

    // if the server initialization fails don't register plugins
    // but let MLDB starts with disabled features
    if (initSuccess) {
        // Set up the SSD cache, if configured
        if (!cacheDir.empty()) {
            server.setCacheDirectory(cacheDir);
        }

        // Scan each of our plugin directories
        for (auto & d: pluginDirectory) {
            server.scanPlugins(d);
        }
    }

    server.httpBoundAddress = server.bindTcp(httpListenPort, httpListenHost);
    server.router.addAutodocRoute("/autodoc", "/v1/help", "autodoc");
    server.threadPool->ensureThreads(numThreads);
    server.httpEndpoint->allowAllOrigins();

    server.start();

    cerr << "\n\nMLDB ready\n\n\n";

    if (!runScript.empty()) {
        // Run the script that implements the example

        fs::path path(runScript);
        string extension = path.extension().string();
        string runner = "";
        if     (extension == ".js")   runner = "javascript";
        else if(extension == ".py")   runner = "python";
        else throw ML::Exception("Unsupported extension '" +extension+ "'");

        HttpRestProxy proxy(server.httpBoundAddress);

        PluginResource config;
        if (runScript.find("://") == string::npos)
            config.address = "file://" + runScript;
        else config.address = runScript;

        // Get arguments
        if (!scriptArgsUrl.empty()) {
            try {
                filter_istream stream(scriptArgsUrl);
                Json::Value args = Json::parse(stream);
                config.args = args;
            } catch (const HttpReturnException & exc) {
                cerr << "error reading script arguments from url "
                     << scriptArgsUrl
                     << ": " << exc.what()
                     << endl;
                cerr << jsonEncode(exc.details) << endl;
                return 1;
            } catch (const std::exception & exc) {
                cerr << "error reading script arguments from url "
                     << scriptArgsUrl
                     << ": " << exc.what()
                     << endl;
                return 1;
            }
        }
        else if (!scriptArgs.empty()) {
            try {
                Json::Value args = Json::parse(scriptArgs);
                config.args = args;
            } catch (const std::exception & exc) {
                cerr << "error reading script arguments from command line: "
                     << exc.what() << endl;
                return 1;
            }
        }

        auto output = proxy.post("/v1/types/plugins/" + runner + "/routes/run",
                                 jsonEncode(config));

        bool success = false;

        auto result = output.jsonBody();
        if (result["result"] == "success")
            success = true;

        if (!success) {
            if (!muteFinalOutput) {
                cerr << output << endl;
            }
            return 1;  // startup script didn't succeed
        }

        if (!dontExitAfterScript) {
            return 0;
        }
    }

    while (!serviceShutdown) {
        ML::futex_wait(serviceShutdown, false, 10.0);
    }

    cerr << "shutting down" << endl;
    server.shutdown();
}
<commit_msg>MLDB-1912 fix add creds from url (#638)<commit_after>// This file is part of MLDB. Copyright 2015 Datacratic. All rights reserved.

/* mldb_runner.cc
   Jeremy Barnes, 12 December 2014
   Copyright (c) 2014 Datacratic Inc.  All rights reserved.

   Runner for MLDB.
*/

#include "mldb/arch/futex.h"
#include "mldb/server/mldb_server.h"
#include "mldb/server/plugin_resource.h"
#include "mldb/http/http_rest_proxy.h"
#include "mldb/server/credential_collection.h"
#include "mldb/vfs/filter_streams.h"
#include "mldb/utils/config.h"
#include "mldb/soa/credentials/credential_provider.h"
#include "mldb/soa/credentials/credentials.h"
#include <boost/filesystem.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/algorithm/string.hpp>
#include <signal.h>

using namespace std;
using namespace Datacratic;
using namespace Datacratic::MLDB;
namespace fs = boost::filesystem;

constexpr int minimumWorkerThreads(4);

std::atomic<int> serviceShutdown(false);

void onSignal(int sig)
{
    serviceShutdown = true;
    ML::futex_wake(serviceShutdown);
}

struct CommandLineCredentialProvider: public CredentialProvider {

    CommandLineCredentialProvider(const std::vector<string> & credsStr)
    {
        for (auto & c: credsStr) {
            creds.emplace_back(jsonDecodeStr<StoredCredentials>(c));
        }
    }

    std::vector<StoredCredentials> creds;

    virtual std::vector<StoredCredentials>
    getCredentialsOfType(const std::string & resourceType) const
    {
        vector<StoredCredentials> matchingCreds;

        for (auto & cred: creds) {
            if (resourceType != cred.resourceType)
                continue;
            matchingCreds.push_back(cred);
        }

        return matchingCreds;
    }
};

int main(int argc, char ** argv)
{
    struct sigaction action;
    action.sa_handler = onSignal;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGUSR2, &action, nullptr);

    using namespace boost::program_options;

    options_description configuration_options("Configuration options");
    options_description script_options("Script options");
    options_description plugin_options("Plugin options");

    int numThreads(16);
    // Defaults for operational characteristics
    string httpListenPort = "11700-18000";
    string httpListenHost = "0.0.0.0";
    string runScript;
    bool dontExitAfterScript = false;

    string cacheDir;
    string httpBaseUrl = "";

#if 0
    string peerListenPort = "18000-19000";
    string peerListenHost = "0.0.0.0";
    int peerPublishPort = -1;
    string peerPublishHost;
#endif
    string configPath;  // path to the configuration file
    std::string staticAssetsPath = "mldb/container_files/public_html/resources";
    std::string staticDocPath = "mldb/container_files/public_html/doc";

    string etcdUri;
    string etcdPath;

    string scriptArgs;
    string scriptArgsUrl;

    // List of credentials to add.  Each should be in JSON format as a
    //
    vector<string> addCredentials;
    string addCredentialsFromUrl;
    std::string credentialsPath;

    // List of directories to scan for plugins
    vector<string> pluginDirectory;

    bool muteFinalOutput = false;

    configuration_options.add_options()
#if 0
        ("etcd-uri", value(&etcdUri),
         "URI to connect to etcd")
        ("etcd-path", value(&etcdPath),
         "Base path in etcd")
#endif
        ("num-threads,t", value(&numThreads), "Number of HTTP worker threads")
        ("http-listen-port,p",
         value(&httpListenPort)->default_value(httpListenPort),
         "Port to listen on for HTTP")
        ("http-listen-host,h",
         value(&httpListenHost)->default_value(httpListenHost),
         "host to listen to")
        ("static-assets-path",
         value(&staticAssetsPath)->default_value(staticAssetsPath),
         "directory to serve static assets from")
        ("static-doc-path",
         value(&staticDocPath)->default_value(staticDocPath),
         "directory to serve documentation from")
        ("cache-dir", value(&cacheDir),
         "Cache directory to memory map large files and store downloads")

#if 0
        ("peer-listen-port,l",
         value(&peerListenPort)->default_value(peerListenPort),
         "port to listen to")
        ("peer-listen-host",
         value(&peerListenHost)->default_value(peerListenHost),
         "host to listen to")
        ("peer-publish-port,P",
         value(&peerPublishPort)->default_value(peerPublishPort),
         "port to publish for the outside world")
        ("peer-publish-host,H",
         value(&peerPublishHost)->default_value(peerPublishHost),
         "host to publish for the outside world")
#endif
        ("config-path",
         value(&configPath),
         "Path to the mldb configuration.  This is optional. Configuration option "
         "in that file have acceptable default values.")
        ("credentials-path,c", value(&credentialsPath),
         "Path in which to store saved credentials and rules "
         "(file:// for filesystem or s3:// for S3 uri)")
        ("hide-internal-entities",
         "Hide in the documentation entities that are not meant to be exposed")
        ("mute-final-output", bool_switch(&muteFinalOutput),
         "Mutes the output printed right before mldb_runner ends with an error"
         "condition")
        ("enable-access-log",
         "Enable the logging of each http request.  By default, the logging is disabled."
         "Specify this option to enable it.")
        ("http-base-url", value(&httpBaseUrl),
         "Prefix to prepend to all /doc urls.");

    script_options.add_options()
        ("run-script", value(&runScript),
         "Run the given script (JS or Python) and shutdown once done")
        ("script-args", value(&scriptArgs),
         "Provide the given (JSON) arguments to the script directly")
        ("script-args-url", value(&scriptArgsUrl),
         "Provide the given (JSON) arguments to the script loading from the given file")
        ("dont-exit-after-script", value(&dontExitAfterScript),
         "Don't exit immediately after running the script")
        ("add-credential", value(&addCredentials),
         "Add credential (see documentation for format) to MLDB before startup.  "
         "Multiple can be added per call.")
        ("add-credentials-from-url", value(&addCredentialsFromUrl),
         "Read credentials from file with list of JSON objects to add to MLDB before startup");

    plugin_options.add_options()
        ("plugin-directory", value(&pluginDirectory),
         "URL of directory to scan for plugins (can be added multiple times). "
         "Don't forget file://.");

    options_description all_opt;
    all_opt
        .add(configuration_options)
        .add(script_options)
        .add(plugin_options)
        .add_options()
        ("help", "print this message");

    variables_map vm;
    // command line has precendence over config
    store(command_line_parser(argc, argv)
          .options(all_opt)
          //.positional(p)
          .run(),
          vm);

    notify(vm);

    auto cmdConfig = Config::createFromProgramOptions(vm);

    if (vm.count("config-path")) {
        cerr << "reading configuration from file: '" << configPath << "'" << endl;
        auto parsed_options = parse_config_file<char>(configPath.c_str(), all_opt, true);
        store(parsed_options, vm);
        auto fileConfig = Config::createFromProgramOptions(parsed_options);
    }

    if (vm.count("help")) {
        cerr << all_opt << endl;
        exit(1);
    }

    if (numThreads < minimumWorkerThreads) {
        cerr << ML::format("'num-threads' cannot be less than %d: %d\n",
                           minimumWorkerThreads, numThreads);
        exit(1);
    }

    // Add these first so that if needed they can be used to load the credentials
    // file
    if (!addCredentials.empty()) {
        try {
            CredentialProvider::registerProvider
                (std::make_shared<CommandLineCredentialProvider>(addCredentials));
        }
        catch (const HttpReturnException & exc) {
            cerr << "error reading credentials from command line: "
                 << exc.what() << endl;
            cerr << jsonEncode(exc.details) << endl;
            return 1;
        }
        catch (const std::exception & exc) {
            cerr << "error reading credentials from command line: "
                 << exc.what() << endl;
            return 1;
        }
        JML_CATCH_ALL {
            cerr << "error reading credentials from command line: unknown error"
                 << endl;
            return 1;
        }
    }

    // Now load the credentials file
    if (!addCredentialsFromUrl.empty()) {
        try {
            filter_istream stream(addCredentialsFromUrl);
            vector<string> fileCredentials;
            Json::Value val = Json::parse(stream);
            if (val.type() == Json::arrayValue) {
                for (auto & v: val) {
                    fileCredentials.push_back(v.toString());
                }
            }
            else if (val.type() == Json::objectValue) {
                fileCredentials.push_back(val.toString());
            }
            else if (val.type() == Json::nullValue) {
                // skip
            }
            else throw ML::Exception("Couldn't understand credentials " + val.toString());

            if (!fileCredentials.empty()) {
                CredentialProvider::registerProvider
                    (std::make_shared<CommandLineCredentialProvider>(fileCredentials));
            }
        }
        catch (const HttpReturnException & exc) {
            cerr << "error reading credentials from file "
                 << addCredentialsFromUrl
                 << ": " << exc.what()
                 << endl;
            cerr << jsonEncode(exc.details) << endl;
            return 1;
        }
        catch (const std::exception & exc) {
            cerr << "error reading credentials from file "
                 << addCredentialsFromUrl
                 << ": " << exc.what()
                 << endl;
            return 1;
        }
        JML_CATCH_ALL {
            cerr << "error reading credentials from file "
                 << addCredentialsFromUrl << ": unknown error"
                 << endl;
            return 1;
        }
    }

    bool enableAccessLog = vm.count("enable-access-log");
    bool hideInternalEntities = vm.count("hide-internal-entities");

    MldbServer server("mldb", etcdUri, etcdPath, enableAccessLog, httpBaseUrl);
    bool initSuccess = server.init(credentialsPath, staticAssetsPath,
                                   staticDocPath, hideInternalEntities);

    // if the server initialization fails don't register plugins
    // but let MLDB starts with disabled features
    if (initSuccess) {
        // Set up the SSD cache, if configured
        if (!cacheDir.empty()) {
            server.setCacheDirectory(cacheDir);
        }

        // Scan each of our plugin directories
        for (auto & d: pluginDirectory) {
            server.scanPlugins(d);
        }
    }

    server.httpBoundAddress = server.bindTcp(httpListenPort, httpListenHost);
    server.router.addAutodocRoute("/autodoc", "/v1/help", "autodoc");
    server.threadPool->ensureThreads(numThreads);
    server.httpEndpoint->allowAllOrigins();

    server.start();

    cerr << "\n\nMLDB ready\n\n\n";

    if (!runScript.empty()) {
        // Run the script that implements the example

        fs::path path(runScript);
        string extension = path.extension().string();
        string runner = "";
        if     (extension == ".js")   runner = "javascript";
        else if(extension == ".py")   runner = "python";
        else throw ML::Exception("Unsupported extension '" +extension+ "'");

        HttpRestProxy proxy(server.httpBoundAddress);

        PluginResource config;
        if (runScript.find("://") == string::npos)
            config.address = "file://" + runScript;
        else config.address = runScript;

        // Get arguments
        if (!scriptArgsUrl.empty()) {
            try {
                filter_istream stream(scriptArgsUrl);
                Json::Value args = Json::parse(stream);
                config.args = args;
            } catch (const HttpReturnException & exc) {
                cerr << "error reading script arguments from url "
                     << scriptArgsUrl
                     << ": " << exc.what()
                     << endl;
                cerr << jsonEncode(exc.details) << endl;
                return 1;
            } catch (const std::exception & exc) {
                cerr << "error reading script arguments from url "
                     << scriptArgsUrl
                     << ": " << exc.what()
                     << endl;
                return 1;
            }
        }
        else if (!scriptArgs.empty()) {
            try {
                Json::Value args = Json::parse(scriptArgs);
                config.args = args;
            } catch (const std::exception & exc) {
                cerr << "error reading script arguments from command line: "
                     << exc.what() << endl;
                return 1;
            }
        }

        auto output = proxy.post("/v1/types/plugins/" + runner + "/routes/run",
                                 jsonEncode(config));

        bool success = false;

        auto result = output.jsonBody();
        if (result["result"] == "success")
            success = true;

        if (!success) {
            if (!muteFinalOutput) {
                cerr << output << endl;
            }
            return 1;  // startup script didn't succeed
        }

        if (!dontExitAfterScript) {
            return 0;
        }
    }

    while (!serviceShutdown) {
        ML::futex_wait(serviceShutdown, false, 10.0);
    }

    cerr << "shutting down" << endl;
    server.shutdown();
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2010, 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 "test.hpp"
#include "setup_transfer.hpp"
#include "udp_tracker.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/error_code.hpp"

#include <fstream>

using namespace libtorrent;

int test_main()
{
	int http_port = start_web_server();
	int udp_port = start_udp_tracker();

	int prev_udp_announces = num_udp_announces();

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	s->set_settings(sett);

	error_code ec;
	remove_all("tmp1_tracker", ec);
	create_directory("tmp1_tracker", ec);
	std::ofstream file(combine_path("tmp1_tracker", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char tracker_url[200];
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url, 0);

	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.flags |= add_torrent_params::flag_seed_mode;
	addp.ti = t;
	addp.save_path = "tmp1_tracker";
	torrent_handle h = s->add_torrent(addp);

	for (int i = 0; i < 50; ++i)
	{
		print_alerts(*s, "s");
		test_sleep(100);
		if (num_udp_announces() == prev_udp_announces + 1)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(num_udp_announces(), prev_udp_announces + 1);

	fprintf(stderr, "destructing session\n");
	delete s;
	fprintf(stderr, "done\n");

	// we should have announced the stopped event now
	TEST_EQUAL(num_udp_announces(), prev_udp_announces + 2);

	// ========================================
	// test that we move on to try the next tier if the first one fails
	// ========================================

	s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(39775, 39800), "0.0.0.0", 0, alert_mask);

	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = false;
	sett.tracker_completion_timeout = 2;
	sett.tracker_receive_timeout = 1;
	s->set_settings(sett);

	remove_all("tmp2_tracker", ec);
	create_directory("tmp2_tracker", ec);
	file.open(combine_path("tmp2_tracker", "temporary").c_str());
	t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	// this should fail
	snprintf(tracker_url, sizeof(tracker_url), "udp://www1.non-existent.com:80/announce");
	t->add_tracker(tracker_url, 0);

	// and this should fail
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.2:3/announce");
	t->add_tracker(tracker_url, 1);

	// this should be announced to
	// udp trackers are prioritized if they're on the same host as an http one
	// so this must be before the http one on 127.0.0.1
	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url, 2);

	// and this should not be announced to (since the one before it succeeded)
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url, 3);

	prev_udp_announces = num_udp_announces();

	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.flags |= add_torrent_params::flag_seed_mode;
	addp.ti = t;
	addp.save_path = "tmp2_tracker";
	h = s->add_torrent(addp);

	for (int i = 0; i < 50; ++i)
	{
		print_alerts(*s, "s");
		test_sleep(100);
		if (num_udp_announces() == prev_udp_announces + 1) break;
	}

	test_sleep(1000);

	TEST_EQUAL(num_udp_announces(), prev_udp_announces + 1);

	fprintf(stderr, "destructing session\n");
	delete s;
	fprintf(stderr, "done\n");

	stop_udp_tracker();
	stop_web_server();

	return 0;
}

<commit_msg>improve debug output from test_tracker<commit_after>/*

Copyright (c) 2010, 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 "test.hpp"
#include "setup_transfer.hpp"
#include "udp_tracker.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/error_code.hpp"

#include <fstream>

using namespace libtorrent;

int test_main()
{
	int http_port = start_web_server();
	int udp_port = start_udp_tracker();

	int prev_udp_announces = num_udp_announces();

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	s->set_settings(sett);

	error_code ec;
	remove_all("tmp1_tracker", ec);
	create_directory("tmp1_tracker", ec);
	std::ofstream file(combine_path("tmp1_tracker", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char tracker_url[200];
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url, 0);

	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.flags |= add_torrent_params::flag_seed_mode;
	addp.ti = t;
	addp.save_path = "tmp1_tracker";
	torrent_handle h = s->add_torrent(addp);

	for (int i = 0; i < 50; ++i)
	{
		print_alerts(*s, "s");
		if (num_udp_announces() == prev_udp_announces + 1)
			break;

		fprintf(stderr, "UDP: %d / %d\n", int(num_udp_announces())
			, int(prev_udp_announces) + 1);
		test_sleep(100);
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(num_udp_announces(), prev_udp_announces + 1);

	fprintf(stderr, "destructing session\n");
	delete s;
	fprintf(stderr, "done\n");

	// we should have announced the stopped event now
	TEST_EQUAL(num_udp_announces(), prev_udp_announces + 2);

	// ========================================
	// test that we move on to try the next tier if the first one fails
	// ========================================

	s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(39775, 39800), "0.0.0.0", 0, alert_mask);

	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = false;
	sett.tracker_completion_timeout = 2;
	sett.tracker_receive_timeout = 1;
	s->set_settings(sett);

	remove_all("tmp2_tracker", ec);
	create_directory("tmp2_tracker", ec);
	file.open(combine_path("tmp2_tracker", "temporary").c_str());
	t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	// this should fail
	snprintf(tracker_url, sizeof(tracker_url), "udp://www1.non-existent.com:80/announce");
	t->add_tracker(tracker_url, 0);

	// and this should fail
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.2:3/announce");
	t->add_tracker(tracker_url, 1);

	// this should be announced to
	// udp trackers are prioritized if they're on the same host as an http one
	// so this must be before the http one on 127.0.0.1
	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url, 2);

	// and this should not be announced to (since the one before it succeeded)
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url, 3);

	prev_udp_announces = num_udp_announces();

	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.flags |= add_torrent_params::flag_seed_mode;
	addp.ti = t;
	addp.save_path = "tmp2_tracker";
	h = s->add_torrent(addp);

	for (int i = 0; i < 50; ++i)
	{
		print_alerts(*s, "s");
		if (num_udp_announces() == prev_udp_announces + 1) break;

		fprintf(stderr, "UDP: %d / %d\n", int(num_udp_announces())
			, int(prev_udp_announces) + 1);
		test_sleep(100);
	}

	test_sleep(1000);

	TEST_EQUAL(num_udp_announces(), prev_udp_announces + 1);

	fprintf(stderr, "destructing session\n");
	delete s;
	fprintf(stderr, "done\n");

	stop_udp_tracker();
	stop_web_server();

	return 0;
}

<|endoftext|>


<commit_before>#ifndef CDM_BOOST_HPP
#define CDM_BOOST_HPP

#include <ventura/file_operations.hpp>
#include <ventura/run_process.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <boost/lexical_cast.hpp>

// Boost is so large that the output of cp exceeds the 4 MB log limit of travis
// which aborts the build job then.
// On Windows, the console is so slow (especially in Virtualbox) that we want
// to avoid the megabytes of output from the Boost build process.
// TODO: Buffer the output in memory and save it somewhere if something fails.
#if CDM_TESTS_RUNNING_ON_TRAVIS_CI || defined(_WIN32)
#define CDM_AVOID_CONSOLE_OUTPUT 1
#else
#define CDM_AVOID_CONSOLE_OUTPUT 0
#endif

namespace cdm
{
	struct boost_paths
	{
		ventura::absolute_path root;
	};

	inline boost_paths install_boost(ventura::absolute_path const &source, ventura::absolute_path const &temporary,
	                                 ventura::absolute_path const &install_root, unsigned make_parallelism,
	                                 Si::Sink<char, Si::success>::interface &output)
	{
		ventura::absolute_path const module_in_cache = install_root / "boost";
		if (!ventura::file_exists(module_in_cache, Si::throw_))
		{
			ventura::absolute_path const copy_of_boost = temporary / "src";
			ventura::copy_recursively(source, copy_of_boost,
#if CDM_AVOID_CONSOLE_OUTPUT
			                          nullptr
#else
			                          &output
#endif
			                          ,
			                          Si::throw_);

			ventura::create_directories(module_in_cache, Si::throw_);

			{
				std::vector<Si::os_string> arguments;
#ifdef _MSC_VER
				ventura::absolute_path const exe = copy_of_boost / "bootstrap.bat";
#else
				ventura::absolute_path const exe = *ventura::absolute_path::create("/usr/bin/env");
				arguments.emplace_back(SILICIUM_OS_STR("bash"));
				arguments.emplace_back(to_os_string(copy_of_boost / "bootstrap.sh"));
#endif
				int const rc = ventura::run_process(exe, arguments, copy_of_boost, output).get();
				if (rc != 0)
				{
					throw std::runtime_error("bootstrap failed");
				}
			}

			{
#if CDM_AVOID_CONSOLE_OUTPUT
				std::vector<char> output_buffer;
				auto buffering = Si::Sink<char, Si::success>::erase(Si::make_container_sink(output_buffer));
#endif
				std::vector<Si::os_string> arguments;
				arguments.emplace_back(SILICIUM_OS_STR("install"));
				{
					Si::os_string const install_argument = SILICIUM_OS_STR("--prefix=") + to_os_string(module_in_cache);
					arguments.emplace_back(install_argument);
				}
				arguments.emplace_back(SILICIUM_OS_STR("link=static"));
#ifdef _MSC_VER
				arguments.emplace_back(SILICIUM_OS_STR("toolset=msvc-12.0"));
#endif
#ifndef CDM_TESTS_RUNNING_ON_TRAVIS_CI
				// GCC 4.6 crashes when compiling Boost.Log on travis probably due
				// to lack of RAM.
				// Thus we do not parallelize the build on travis so that the
				// compiler can use all of the memory available to the machine.
				arguments.emplace_back(SILICIUM_OS_STR("-j ") + boost::lexical_cast<Si::os_string>(make_parallelism));
#else
				boost::ignore_unused_variable_warning(make_parallelism);
#endif
				int const rc = ventura::run_process(copy_of_boost / "b2"
#ifdef _WIN32
				                                                    ".exe"
#endif
				                                    ,
				                                    arguments, copy_of_boost,
#if CDM_AVOID_CONSOLE_OUTPUT
				                                    buffering
#else
				                                    output
#endif
				                                    ).get();
				if (rc != 0)
				{
#if CDM_AVOID_CONSOLE_OUTPUT
					// TODO: do not buffer more characters than necessary
					std::size_t const max_output = 3500 * 1000;
					std::size_t const actual_output = (std::min)(max_output, output_buffer.size());
					char const *const end = output_buffer.data() + output_buffer.size();
					Si::append_range(output, Si::make_iterator_range(end - actual_output, end));
#endif
					throw std::runtime_error("b2 failed");
				}
			}
		}
		boost_paths result;
		result.root = module_in_cache;
		return result;
	}
}

#endif
<commit_msg>remove Boost log buffering because we do not print that to the console anymore<commit_after>#ifndef CDM_BOOST_HPP
#define CDM_BOOST_HPP

#include <ventura/file_operations.hpp>
#include <ventura/run_process.hpp>
#include <silicium/sink/iterator_sink.hpp>
#include <boost/lexical_cast.hpp>

namespace cdm
{
	struct boost_paths
	{
		ventura::absolute_path root;
	};

	inline boost_paths install_boost(ventura::absolute_path const &source, ventura::absolute_path const &temporary,
	                                 ventura::absolute_path const &install_root, unsigned make_parallelism,
	                                 Si::Sink<char, Si::success>::interface &output)
	{
		ventura::absolute_path const module_in_cache = install_root / "boost";
		if (!ventura::file_exists(module_in_cache, Si::throw_))
		{
			ventura::absolute_path const copy_of_boost = temporary / "src";
			ventura::copy_recursively(source, copy_of_boost, &output, Si::throw_);

			ventura::create_directories(module_in_cache, Si::throw_);

			{
				std::vector<Si::os_string> arguments;
#ifdef _MSC_VER
				ventura::absolute_path const exe = copy_of_boost / "bootstrap.bat";
#else
				ventura::absolute_path const exe = *ventura::absolute_path::create("/usr/bin/env");
				arguments.emplace_back(SILICIUM_OS_STR("bash"));
				arguments.emplace_back(to_os_string(copy_of_boost / "bootstrap.sh"));
#endif
				int const rc = ventura::run_process(exe, arguments, copy_of_boost, output).get();
				if (rc != 0)
				{
					throw std::runtime_error("bootstrap failed");
				}
			}

			{
				std::vector<Si::os_string> arguments;
				arguments.emplace_back(SILICIUM_OS_STR("install"));
				{
					Si::os_string const install_argument = SILICIUM_OS_STR("--prefix=") + to_os_string(module_in_cache);
					arguments.emplace_back(install_argument);
				}
				arguments.emplace_back(SILICIUM_OS_STR("link=static"));
#ifdef _MSC_VER
				arguments.emplace_back(SILICIUM_OS_STR("toolset=msvc-12.0"));
#endif
#ifndef CDM_TESTS_RUNNING_ON_TRAVIS_CI
				// GCC 4.6 crashes when compiling Boost.Log on travis probably due
				// to lack of RAM.
				// Thus we do not parallelize the build on travis so that the
				// compiler can use all of the memory available to the machine.
				arguments.emplace_back(SILICIUM_OS_STR("-j ") + boost::lexical_cast<Si::os_string>(make_parallelism));
#else
				boost::ignore_unused_variable_warning(make_parallelism);
#endif
				int const rc = ventura::run_process(copy_of_boost / "b2"
#ifdef _WIN32
				                                                    ".exe"
#endif
				                                    ,
				                                    arguments, copy_of_boost, output).get();
				if (rc != 0)
				{
					throw std::runtime_error("b2 failed");
				}
			}
		}
		boost_paths result;
		result.root = module_in_cache;
		return result;
	}
}

#endif
<|endoftext|>


<commit_before>/// Generate training data sets for double-moon classification problem
/// Chapter 1. Section 1.5.

#include <iostream>
#include <fstream>
#include <cmath>
#include <random>
#include <algorithm> // any_of

#include "dataset.hh"

using namespace std;

const double r = 10.0; // radius
const double w = 6.0;  // width
const double default_d = 1.0;
const double default_n = 1000;

void usage() {
    cout << "usage: gentwomoon distance [numpoints [output_file]]";
    cout << "\ndefault options:\n";
    cout << "    distance = 1.0\n";
    cout << "    numpoints = 1000\n";
    cout << "    output_file = stdout\n";
    exit(-1);
}

void generate(double r, double w, double d, int n, ostream &out) {
    LabeledSet data;
    double epsilon = 1e-6 * w;
    uniform_real_distribution<> x1(-r - 0.5 * w, r + 0.5 * w + epsilon);
    uniform_real_distribution<> y1(0.0, r + 0.5 * w + epsilon);
    uniform_real_distribution<> x2(-0.5 * w, 2 * r + 0.5 * w + epsilon);
    uniform_real_distribution<> y2(-d - r - 0.5 * w, -d + epsilon);
    random_device rd;
    mt19937 rng(rd());
    auto inMoon1 = [r, w](double x, double y) {
        double rr = sqrt(x * x + y * y);
        return rr >= (r - 0.5 * w) && rr <= (r + 0.5 * w);
    };
    auto inMoon2 = [r, w, d](double x, double y) {
        double x_ = x - r;
        double y_ = y - (-d);
        double rr = sqrt(x_ * x_ + y_ * y_);
        return rr >= (r - 0.5 * w) && rr <= (r + 0.5 * w);
    };
    int n1 = 0;
    int n2 = 0;
    while (n1 < n / 2) {
        double x = x1(rng);
        double y = y1(rng);
        if (inMoon1(x, y)) {
            Input input = {x, y};
            Output output = {+1};
            data.append(input, output);
            n1++;
        }
    }
    while ((n1 + n2) < n) {
        double x = x2(rng);
        double y = y2(rng);
        if (inMoon2(x, y)) {
            Input input = {x, y};
            Output output = {-1};
            data.append(input, output);
            n2++;
        }
    }
    out << data;
}

int main(int argc, char *argv[]) {
    auto is_help_flag = [](const char *arg) {
        return string(arg) == "--help" || string(arg) == "-h";
    };
    if ((argc > 1) && any_of(argv + 1, argv + argc, is_help_flag)) {
        usage();
    } else if (argc == 1 + 3) {
        double d = atof(argv[1]);
        int n = atoi(argv[2]);
        ofstream out(argv[3], ios::out);
        generate(r, w, d, n, out);
    } else if (argc == 1 + 2) {
        double d = atof(argv[1]);
        int n = atoi(argv[2]);
        generate(r, w, d, n, cout);
    } else if (argc == 1 + 1) {
        double d = atof(argv[1]);
        int n = default_n;
        generate(r, w, d, n, cout);
    } else {
        usage();
    }
}
<commit_msg>fix/update gen_twomoons<commit_after>/// Generate training data sets for double-moon classification problem
/// Chapter 1. Section 1.5.

#include <iostream>
#include <fstream>
#include <cmath>
#include <random>
#include <algorithm> // any_of

#include "dataset.hh"

using namespace std;

const double r = 10.0; // radius
const double w = 6.0;  // width
const double default_d = 1.0;
const double default_n = 1000;

void usage() {
    cout << "usage: gen_twomoons distance [numpoints [output_file]]";
    cout << "\ndefault options:\n";
    cout << "    distance = 1.0\n";
    cout << "    numpoints = 1000\n";
    cout << "    output_file = stdout\n";
    exit(-1);
}

void generate(double r, double w, double d, int n, ostream &out) {
    LabeledDataset data;
    double epsilon = 1e-6 * w;
    uniform_real_distribution<> x1(-r - 0.5 * w, r + 0.5 * w + epsilon);
    uniform_real_distribution<> y1(0.0, r + 0.5 * w + epsilon);
    uniform_real_distribution<> x2(-0.5 * w, 2 * r + 0.5 * w + epsilon);
    uniform_real_distribution<> y2(-d - r - 0.5 * w, -d + epsilon);
    random_device rd;
    mt19937 rng(rd());
    auto inMoon1 = [r, w](double x, double y) {
        double rr = sqrt(x * x + y * y);
        return rr >= (r - 0.5 * w) && rr <= (r + 0.5 * w);
    };
    auto inMoon2 = [r, w, d](double x, double y) {
        double x_ = x - r;
        double y_ = y - (-d);
        double rr = sqrt(x_ * x_ + y_ * y_);
        return rr >= (r - 0.5 * w) && rr <= (r + 0.5 * w);
    };
    int n1 = 0;
    int n2 = 0;
    while (n1 < n / 2) {
        double x = x1(rng);
        double y = y1(rng);
        if (inMoon1(x, y)) {
            Input input = {x, y};
            Output output = {+1};
            data.append(input, output);
            n1++;
        }
    }
    while ((n1 + n2) < n) {
        double x = x2(rng);
        double y = y2(rng);
        if (inMoon2(x, y)) {
            Input input = {x, y};
            Output output = {-1};
            data.append(input, output);
            n2++;
        }
    }
    out << data;
}

int main(int argc, char *argv[]) {
    auto is_help_flag = [](const char *arg) {
        return string(arg) == "--help" || string(arg) == "-h";
    };
    if ((argc > 1) && any_of(argv + 1, argv + argc, is_help_flag)) {
        usage();
    } else if (argc == 1 + 3) {
        double d = atof(argv[1]);
        int n = atoi(argv[2]);
        ofstream out(argv[3], ios::out);
        generate(r, w, d, n, out);
    } else if (argc == 1 + 2) {
        double d = atof(argv[1]);
        int n = atoi(argv[2]);
        generate(r, w, d, n, cout);
    } else if (argc == 1 + 1) {
        double d = atof(argv[1]);
        int n = default_n;
        generate(r, w, d, n, cout);
    } else {
        usage();
    }
}
<|endoftext|>


<commit_before>#include <SDL2/SDL.h>
#include <iostream>
#include "life.h"

const int SCREEN_WIDTH = 1300;
const int SCREEN_HEIGHT = 700;

const int CELL_SIZE = 15;
int CELL_WIDTH = CELL_SIZE;
int CELL_HEIGHT = CELL_SIZE;

SDL_Window* window;
SDL_Renderer* renderer1;

int delay = 100;

//get everything ready for the game
bool initEverything();
//initialize SDL
bool initSDL();
//create the SDL window
bool createWindow();
//create the SDL renderer1
bool createRenderer();
//setup renderer1
void setupRenderer();
//render current iteration, called every time we update grid
void render(life * gameRef);
//game loop
void runGame(life * gameRef);

void processClick(int x, int y);

struct rectMore
{
	SDL_Rect mRect;
	bool on;
};

int main( int argc, char* args[])
{
	life ourgame = life();
	std::cout << "Do you have an input file? (1 = yes, 0 = no)" << std::endl;
	bool input;
	std::cin >> input;
	if (input)
	{
		std::cout << "Please enter the name of your input file" << std::endl;
		std::string filename;
		std::cin >> filename;
		ourgame = life(filename);
	}
	else
	{
		int col;
		int row;
		std::cout << "Please Enter the number of columns you want your grid to have" << std::endl;
		std::cin >> col;
		std::cout << "Please Enter the number of rows you want your grid to have" << std::endl;
		std::cin >> row;
		ourgame = life(row,col);

	}

	ourgame.setToroidal(0);

	if( !initEverything() )
		return -1;

	runGame(&ourgame);
};

void runGame(life * gameRef)
{
	bool loop = true;
	//small flag to keep track if game is paused
	bool paused = true;

	while ( loop )
	{
		SDL_Event event;
		while ( SDL_PollEvent( &event ) )
		{
			if ( event.type == SDL_QUIT )
				loop = false;
			else if ( event.type == SDL_KEYDOWN )
			{
				switch ( event.key.keysym.sym )
				{
					case SDLK_RIGHT:
						delay-=1;
						break;
					case SDLK_LEFT:
						delay+=1;
						break;
						// Remeber 0,0 in SDL is left-top. So when the user pressus down, the y need to increase
					case SDLK_DOWN:
						gameRef->setToroidal( 0 );
						break;
					case SDLK_UP:
						gameRef->setToroidal( 1 );
						break;

					case SDLK_SPACE:
						paused = !paused;

					default :
						break;
				}
			}
			else if ( event.type == SDL_MOUSEBUTTONDOWN )
			{
				if( event.button.button == SDL_BUTTON_LEFT )
				{
					int col = event.button.x / CELL_SIZE;
					int row = event.button.y / CELL_SIZE;
					gameRef->setValAt( row, col , !(gameRef->getValAt( row, col) ));
					render(gameRef);

				}

			}

		}

		if( !paused )
		{
			gameRef->update();
			render(gameRef);
		}

		// Add a 100msec delay to make our game run at a reasonable rate
		SDL_Delay(delay);
	}
}
void render( life * gameRef)
{
	// Clear the window and make it all red
	SDL_RenderClear( renderer1 );

	rectMore r[gameRef->getRows()][gameRef->getColumns()];
	for(int row = 0; row < gameRef->getRows(); row++ )
	{
		for ( int col = 0; col < gameRef->getColumns(); col++ )
		{
			r[row][col].mRect.x = col*CELL_WIDTH;
			r[row][col].mRect.y = row*CELL_HEIGHT;
			r[row][col].mRect.w = CELL_WIDTH;
			r[row][col].mRect.h = CELL_HEIGHT;
			r[row][col].on = gameRef->getValAt( row, col );
			if (r[row][col].on)
			{
				SDL_RenderFillRect(renderer1, &r[row][col].mRect);
			}
			else
			{
				SDL_RenderDrawRect(renderer1, &r[row][col].mRect);
			}
		}
	}

	// Render the changes above
	SDL_RenderPresent( renderer1);
}
bool initEverything()
{
	if ( !initSDL() )
		return false;

	if ( !createWindow() )
		return false;

	if ( !createRenderer() )
		return false;

	setupRenderer();

	return true;
}
bool initSDL()
{
	if ( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
	{
		std::cout << " Failed to initialize SDL : " << SDL_GetError() << std::endl;
		return false;
	}

	return true;
}
bool createWindow()
{
	window = SDL_CreateWindow( "Server", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 );

	if ( window == nullptr )
	{
		std::cout << "Failed to create window : " << SDL_GetError();
		return false;
	}

	return true;
}
bool createRenderer()
{
	renderer1 = SDL_CreateRenderer( window, -1, 0 );

	if ( renderer1 == nullptr )
	{
		std::cout << "Failed to create renderer1 : " << SDL_GetError();
		return false;
	}

	return true;
}
void setupRenderer()
{
	// Set size of renderer1 to the same as window
	SDL_RenderSetLogicalSize( renderer1, SCREEN_WIDTH, SCREEN_HEIGHT );

	// Set color of renderer1 to black
	SDL_SetRenderDrawColor( renderer1, 0, 0, 0, 0 );

}

<commit_msg>Allow user to see initial configuration<commit_after>#include <SDL2/SDL.h>
#include <iostream>
#include "life.h"

const int SCREEN_WIDTH = 1300;
const int SCREEN_HEIGHT = 700;

const int CELL_SIZE = 15;
int CELL_WIDTH = CELL_SIZE;
int CELL_HEIGHT = CELL_SIZE;

SDL_Window* window;
SDL_Renderer* renderer1;

int delay = 100;

//get everything ready for the game
bool initEverything();
//initialize SDL
bool initSDL();
//create the SDL window
bool createWindow();
//create the SDL renderer1
bool createRenderer();
//setup renderer1
void setupRenderer();
//render current iteration, called every time we update grid
void render(life * gameRef);
//game loop
void runGame(life * gameRef);

void processClick(int x, int y);

struct rectMore
{
	SDL_Rect mRect;
	bool on;
};

int main( int argc, char* args[])
{
	life ourgame = life();
	std::cout << "Do you have an input file? (1 = yes, 0 = no)" << std::endl;
	bool input;
	std::cin >> input;
	if (input)
	{
		std::cout << "Please enter the name of your input file" << std::endl;
		std::string filename;
		std::cin >> filename;
		ourgame = life(filename);
	}
	else
	{
		int col;
		int row;
		std::cout << "Please Enter the number of columns you want your grid to have" << std::endl;
		std::cin >> col;
		std::cout << "Please Enter the number of rows you want your grid to have" << std::endl;
		std::cin >> row;
		ourgame = life(row,col);

	}

	ourgame.setToroidal(0);

	if( !initEverything() )
		return -1;

	runGame(&ourgame);
};

void runGame(life * gameRef)
{
	render(gameRef);
	bool loop = true;
	//small flag to keep track if game is paused
	bool paused = true;

	while ( loop )
	{
		SDL_Event event;
		while ( SDL_PollEvent( &event ) )
		{
			if ( event.type == SDL_QUIT )
				loop = false;
			else if ( event.type == SDL_KEYDOWN )
			{
				switch ( event.key.keysym.sym )
				{
					case SDLK_RIGHT:
						delay-=1;
						break;
					case SDLK_LEFT:
						delay+=1;
						break;
						// Remeber 0,0 in SDL is left-top. So when the user pressus down, the y need to increase
					case SDLK_DOWN:
						gameRef->setToroidal( 0 );
						break;
					case SDLK_UP:
						gameRef->setToroidal( 1 );
						break;

					case SDLK_SPACE:
						paused = !paused;

					default :
						break;
				}
			}
			else if ( event.type == SDL_MOUSEBUTTONDOWN )
			{
				if( event.button.button == SDL_BUTTON_LEFT )
				{
					int col = event.button.x / CELL_SIZE;
					int row = event.button.y / CELL_SIZE;
					gameRef->setValAt( row, col , !(gameRef->getValAt( row, col) ));
					render(gameRef);

				}

			}

		}

		if( !paused )
		{
			gameRef->update();
			render(gameRef);
		}

		// Add a 100msec delay to make our game run at a reasonable rate
		SDL_Delay(delay);
	}
}
void render( life * gameRef)
{
	// Clear the window and make it all red
	SDL_RenderClear( renderer1 );

	rectMore r[gameRef->getRows()][gameRef->getColumns()];
	for(int row = 0; row < gameRef->getRows(); row++ )
	{
		for ( int col = 0; col < gameRef->getColumns(); col++ )
		{
			r[row][col].mRect.x = col*CELL_WIDTH;
			r[row][col].mRect.y = row*CELL_HEIGHT;
			r[row][col].mRect.w = CELL_WIDTH;
			r[row][col].mRect.h = CELL_HEIGHT;
			r[row][col].on = gameRef->getValAt( row, col );
			if (r[row][col].on)
			{
				SDL_RenderFillRect(renderer1, &r[row][col].mRect);
			}
			else
			{
				SDL_RenderDrawRect(renderer1, &r[row][col].mRect);
			}
		}
	}

	// Render the changes above
	SDL_RenderPresent( renderer1);
}
bool initEverything()
{
	if ( !initSDL() )
		return false;

	if ( !createWindow() )
		return false;

	if ( !createRenderer() )
		return false;

	setupRenderer();

	return true;
}
bool initSDL()
{
	if ( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
	{
		std::cout << " Failed to initialize SDL : " << SDL_GetError() << std::endl;
		return false;
	}

	return true;
}
bool createWindow()
{
	window = SDL_CreateWindow( "Server", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0 );

	if ( window == nullptr )
	{
		std::cout << "Failed to create window : " << SDL_GetError();
		return false;
	}

	return true;
}
bool createRenderer()
{
	renderer1 = SDL_CreateRenderer( window, -1, 0 );

	if ( renderer1 == nullptr )
	{
		std::cout << "Failed to create renderer1 : " << SDL_GetError();
		return false;
	}

	return true;
}
void setupRenderer()
{
	// Set size of renderer1 to the same as window
	SDL_RenderSetLogicalSize( renderer1, SCREEN_WIDTH, SCREEN_HEIGHT );

	// Set color of renderer1 to black
	SDL_SetRenderDrawColor( renderer1, 0, 0, 0, 0 );

}

<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net)
/// 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.
///
/// Restrictions:
///		By making use of the Software for military purposes, you choose to make
///		a Bunny unhappy.
///
/// 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.
///
/// @ref gtx_bit
/// @file glm/gtx/bit.hpp
/// @date 2007-03-14 / 2011-06-07
/// @author Christophe Riccio
///
/// @see core (dependence)
/// @see gtc_half_float (dependence)
///
/// @defgroup gtx_bit GLM_GTX_bit
/// @ingroup gtx
///
/// @brief Allow to perform bit operations on integer values
///
/// <glm/gtx/bit.hpp> need to be included to use these functionalities.
///////////////////////////////////////////////////////////////////////////////////

#pragma once

// Dependencies
#include "../gtc/bitfield.hpp"

#if(defined(GLM_MESSAGES))
#	pragma message("GLM: GLM_GTX_bit extension is deprecated, include GLM_GTC_bitfield and GLM_GTC_integer instead")
#endif

namespace glm
{
	/// @addtogroup gtx_bit
	/// @{

	/// @see gtx_bit
	template <typename genIUType>
	GLM_FUNC_DECL genIUType highestBitValue(genIUType Value);

	/// Find the highest bit set to 1 in a integer variable and return its value.
	///
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_FUNC_DECL vecType<T, P> highestBitValue(vecType<T, P> const & value);

	/// Return the power of two number which value is just higher the input value.
	///
	/// @see gtx_bit
	template <typename genIUType>
	GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value);

	/// Return the power of two number which value is just higher the input value.
	///
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_FUNC_DECL vecType<T, P> powerOfTwoAbove(vecType<T, P> const & value);

	/// Return the power of two number which value is just lower the input value.
	///
	/// @see gtx_bit
	template <typename genIUType>
	GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value);

	/// Return the power of two number which value is just lower the input value.
	///
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_FUNC_DECL vecType<T, P> powerOfTwoBelow(vecType<T, P> const & value);

	/// Return the power of two number which value is the closet to the input value.
	///
	/// @see gtx_bit
	template <typename genIUType>
	GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value);

	/// Return the power of two number which value is the closet to the input value.
	///
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_FUNC_DECL vecType<T, P> powerOfTwoNearest(vecType<T, P> const & value);

	/// @}
} //namespace glm

#include "bit.inl"

<commit_msg>Deprecate GTX_bit<commit_after>///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net)
/// 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.
///
/// Restrictions:
///		By making use of the Software for military purposes, you choose to make
///		a Bunny unhappy.
///
/// 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.
///
/// @ref gtx_bit
/// @file glm/gtx/bit.hpp
/// @date 2007-03-14 / 2011-06-07
/// @author Christophe Riccio
///
/// @see core (dependence)
/// @see gtc_half_float (dependence)
///
/// @defgroup gtx_bit GLM_GTX_bit
/// @ingroup gtx
///
/// @brief Allow to perform bit operations on integer values
///
/// <glm/gtx/bit.hpp> need to be included to use these functionalities.
///////////////////////////////////////////////////////////////////////////////////

#pragma once

// Dependencies
#include "../gtc/bitfield.hpp"

#if(defined(GLM_MESSAGES))
#	pragma message("GLM: GLM_GTX_bit extension is deprecated, include GLM_GTC_bitfield and GLM_GTC_integer instead")
#endif

namespace glm
{
	/// @addtogroup gtx_bit
	/// @{

	/// @see gtx_bit
	template <typename genIUType>
	GLM_FUNC_DECL genIUType highestBitValue(genIUType Value);

	/// Find the highest bit set to 1 in a integer variable and return its value.
	///
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_FUNC_DECL vecType<T, P> highestBitValue(vecType<T, P> const & value);

	/// Return the power of two number which value is just higher the input value.
	/// Deprecated, use ceilPowerOfTwo from GTC_round instead
	///
	/// @see gtc_round
	/// @see gtx_bit
	template <typename genIUType>
	GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value);

	/// Return the power of two number which value is just higher the input value.
	/// Deprecated, use ceilPowerOfTwo from GTC_round instead
	///
	/// @see gtc_round
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_DEPRECATED GLM_FUNC_DECL vecType<T, P> powerOfTwoAbove(vecType<T, P> const & value);

	/// Return the power of two number which value is just lower the input value.
	/// Deprecated, use floorPowerOfTwo from GTC_round instead
	///
	/// @see gtc_round
	/// @see gtx_bit
	template <typename genIUType>
	GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value);

	/// Return the power of two number which value is just lower the input value.
	/// Deprecated, use floorPowerOfTwo from GTC_round instead
	///
	/// @see gtc_round
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_DEPRECATED GLM_FUNC_DECL vecType<T, P> powerOfTwoBelow(vecType<T, P> const & value);

	/// Return the power of two number which value is the closet to the input value.
	/// Deprecated, use roundPowerOfTwo from GTC_round instead
	///
	/// @see gtc_round
	/// @see gtx_bit
	template <typename genIUType>
	GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value);

	/// Return the power of two number which value is the closet to the input value.
	/// Deprecated, use roundPowerOfTwo from GTC_round instead
	///
	/// @see gtc_round
	/// @see gtx_bit
	template <typename T, precision P, template <typename, precision> class vecType>
	GLM_DEPRECATED GLM_FUNC_DECL vecType<T, P> powerOfTwoNearest(vecType<T, P> const & value);

	/// @}
} //namespace glm

#include "bit.inl"

<|endoftext|>