<commit_before>#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>

#include <algorithm>
#include <fstream>
#include <iostream>
#include <limits>
#include <map>
#include <sstream>
#include <streambuf>
#include <string>
#include <vector>

#include <fuse.h>

using namespace std;

static const char image_path[] = "/sparsebundle.dmg";

struct sparsebundle_data {
    char *path;
    off_t band_size;
    off_t size;
    off_t times_opened;
};

#define SB_DATA_CAST(ptr) ((struct sparsebundle_data *) ptr)
#define SB_DATA (SB_DATA_CAST(fuse_get_context()->private_data))

static int sparsebundle_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
              off_t offset, struct fuse_file_info *fi)
{
    if (strcmp(path, "/") != 0)
        return -ENOENT;

    filler(buf, ".", 0, 0);
    filler(buf, "..", 0, 0);
    filler(buf, image_path + 1, 0, 0);

    return 0;
}

static int sparsebundle_getattr(const char *path, struct stat *stbuf)
{
    memset(stbuf, 0, sizeof(struct stat));

    if (strcmp(path, "/") == 0) {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 3;
    } else if (strcmp(path, image_path) == 0) {
        stbuf->st_mode = S_IFREG | 0444;
        stbuf->st_nlink = 1;
        stbuf->st_size = SB_DATA->size;
    } else
        return -ENOENT;

    return 0;
}

static int sparsebundle_open(const char *path, struct fuse_file_info *fi)
{
    if (strcmp(path, image_path) != 0)
        return -ENOENT;

    if ((fi->flags & O_ACCMODE) != O_RDONLY)
        return -EACCES;

    SB_DATA->times_opened++;
    syslog(LOG_DEBUG, "opened %s, now referenced %llx times",
        SB_DATA->path, SB_DATA->times_opened);

    return 0;
}

static int sparsebundle_read(const char *path, char *buffer, size_t length, off_t offset,
           struct fuse_file_info *fi)
{
    if (strcmp(path, image_path) != 0)
        return -ENOENT;

    if (offset >= SB_DATA->size)
        return 0;

    if (offset + length > SB_DATA->size)
        length = SB_DATA->size - offset;

    syslog(LOG_DEBUG, "asked to read %zu bytes at offset %llu", length, offset);

    size_t bytes_read = 0;
    while (bytes_read < length) {
        off_t band_number = (offset + bytes_read) / SB_DATA->band_size;
        off_t band_offset = (offset + bytes_read) % SB_DATA->band_size;

        ssize_t to_read = min(static_cast<off_t>(length - bytes_read),
            SB_DATA->band_size - band_offset);

        char *band_name;
        if (asprintf(&band_name, "%s/bands/%llx", SB_DATA->path, band_number) == -1) {
            syslog(LOG_ERR, "failed to resolve band name");
            return -1;
        }

        syslog(LOG_DEBUG, "reading %zu bytes from band %llx at offset %llu",
            to_read, band_number, band_offset);

        ssize_t read = 0;
        int band_file = open(band_name, O_RDONLY);
        if (band_file != -1) {
            read = pread(band_file, buffer + bytes_read, to_read, band_offset);
            close(band_file);

            if (read == -1) {
                syslog(LOG_ERR, "failed to read band: %s", strerror(errno));
                free(band_name);
                return -1;
            }
        } else if (errno != ENOENT) {
            syslog(LOG_ERR, "failed to open band %s: %s", band_name, strerror(errno));
            free(band_name);
            return -1;
        }

        free(band_name);

        if (read < to_read) {
            syslog(LOG_DEBUG, "missing %zu bytes from band %llx, padding with zeroes",
                to_read - read, band_number);
            memset(buffer + bytes_read + read, 0, to_read - read);
        }

        bytes_read += to_read;

        syslog(LOG_DEBUG, "done reading from band %llx, %zu bytes left to read",
                band_number, length - bytes_read);
    }

    assert(bytes_read == length);
    return bytes_read;
}

static int sparsebundle_release(const char *path, struct fuse_file_info *fi)
{
    SB_DATA->times_opened--;
    syslog(LOG_DEBUG, "closed %s, now referenced %llx times",
        SB_DATA->path, SB_DATA->times_opened);

    if (SB_DATA->times_opened == 0) {
        syslog(LOG_DEBUG, "no more references to sparsebundle, cleaning up");
    }

    return 0;
}

static int sparsebundle_show_usage(char *program_name)
{
    fprintf(stderr, "usage: %s [-o options] [-f] [-D] <sparsebundle> <mountpoint>\n", program_name);
    return 1;
}

enum { SPARSEBUNDLE_OPT_DEBUG };

static int sparsebundle_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
{
    switch (key) {
    case SPARSEBUNDLE_OPT_DEBUG:
        setlogmask(LOG_UPTO(LOG_DEBUG));
        return 0;
    case FUSE_OPT_KEY_NONOPT:
        if (SB_DATA_CAST(data)->path)
            return 1;

        SB_DATA_CAST(data)->path = strdup(arg);
        return 0;
    }

    return 1;
}

static off_t read_size(const string &str)
{
    uintmax_t value = strtoumax(str.c_str(), 0, 10);
    if (errno == ERANGE || value > static_cast<uintmax_t>(numeric_limits<off_t>::max())) {
        fprintf(stderr, "Disk image too large to be mounted (%s bytes)\n", str.c_str());
        exit(-1);
    }

    return value;
}

int main(int argc, char **argv)
{
    openlog("sparsebundlefs", LOG_CONS | LOG_PERROR, LOG_USER);
    setlogmask(~(LOG_MASK(LOG_DEBUG)));

    struct sparsebundle_data data = {};

    static struct fuse_opt sparsebundle_options[] = {
        FUSE_OPT_KEY("-D",  SPARSEBUNDLE_OPT_DEBUG), FUSE_OPT_END
    };

    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    fuse_opt_parse(&args, &data, sparsebundle_options, sparsebundle_opt_proc);
    fuse_opt_add_arg(&args, "-oro"); // Force read-only mount

    if (!data.path)
        return sparsebundle_show_usage(argv[0]);

    char *abs_path = realpath(data.path, 0);
    if (!abs_path) {
        perror("Could not resolve absolute path");
        return -1;
    }

    free(data.path);
    data.path = abs_path;

    char *plist_path;
    if (asprintf(&plist_path, "%s/Info.plist", data.path) == -1) {
        perror("Failed to resolve Info.plist path");
        return -1;
    }

    ifstream plist_file(plist_path);
    stringstream plist_data;
    plist_data << plist_file.rdbuf();

    string key, line;
    while (getline(plist_data, line)) {
        static const char whitespace_chars[] = " \n\r\t";
        line.erase(0, line.find_first_not_of(whitespace_chars));
        line.erase(line.find_last_not_of(whitespace_chars) + 1);

        if (line.compare(0, 5, "<key>") == 0) {
            key = line.substr(5, line.length() - 11);
        } else if (!key.empty()) {
            line.erase(0, line.find_first_of('>') + 1);
            line.erase(line.find_first_of('<'));

            if (key == "band-size")
                data.band_size = read_size(line);
            else if (key == "size")
                data.size = read_size(line);

            key.clear();
        }
    }

    struct fuse_operations sparsebundle_filesystem_operations = {};
    sparsebundle_filesystem_operations.getattr = sparsebundle_getattr;
    sparsebundle_filesystem_operations.open = sparsebundle_open;
    sparsebundle_filesystem_operations.read = sparsebundle_read;
    sparsebundle_filesystem_operations.readdir = sparsebundle_readdir;
    sparsebundle_filesystem_operations.release = sparsebundle_release;

    return fuse_main(args.argc, args.argv, &sparsebundle_filesystem_operations, &data);
}
<commit_msg>Add some debug logging<commit_after>#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <string.h>

#include <algorithm>
#include <fstream>
#include <iostream>
#include <limits>
#include <map>
#include <sstream>
#include <streambuf>
#include <string>
#include <vector>

#include <fuse.h>

using namespace std;

static const char image_path[] = "/sparsebundle.dmg";

struct sparsebundle_data {
    char *path;
    off_t band_size;
    off_t size;
    off_t times_opened;
};

#define SB_DATA_CAST(ptr) ((struct sparsebundle_data *) ptr)
#define SB_DATA (SB_DATA_CAST(fuse_get_context()->private_data))

static int sparsebundle_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
              off_t offset, struct fuse_file_info *fi)
{
    if (strcmp(path, "/") != 0)
        return -ENOENT;

    filler(buf, ".", 0, 0);
    filler(buf, "..", 0, 0);
    filler(buf, image_path + 1, 0, 0);

    return 0;
}

static int sparsebundle_getattr(const char *path, struct stat *stbuf)
{
    memset(stbuf, 0, sizeof(struct stat));

    if (strcmp(path, "/") == 0) {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 3;
    } else if (strcmp(path, image_path) == 0) {
        stbuf->st_mode = S_IFREG | 0444;
        stbuf->st_nlink = 1;
        stbuf->st_size = SB_DATA->size;
    } else
        return -ENOENT;

    return 0;
}

static int sparsebundle_open(const char *path, struct fuse_file_info *fi)
{
    if (strcmp(path, image_path) != 0)
        return -ENOENT;

    if ((fi->flags & O_ACCMODE) != O_RDONLY)
        return -EACCES;

    SB_DATA->times_opened++;
    syslog(LOG_DEBUG, "opened %s, now referenced %llx times",
        SB_DATA->path, SB_DATA->times_opened);

    return 0;
}

static int sparsebundle_read(const char *path, char *buffer, size_t length, off_t offset,
           struct fuse_file_info *fi)
{
    if (strcmp(path, image_path) != 0)
        return -ENOENT;

    if (offset >= SB_DATA->size)
        return 0;

    if (offset + length > SB_DATA->size)
        length = SB_DATA->size - offset;

    syslog(LOG_DEBUG, "asked to read %zu bytes at offset %llu", length, offset);

    size_t bytes_read = 0;
    while (bytes_read < length) {
        off_t band_number = (offset + bytes_read) / SB_DATA->band_size;
        off_t band_offset = (offset + bytes_read) % SB_DATA->band_size;

        ssize_t to_read = min(static_cast<off_t>(length - bytes_read),
            SB_DATA->band_size - band_offset);

        char *band_name;
        if (asprintf(&band_name, "%s/bands/%llx", SB_DATA->path, band_number) == -1) {
            syslog(LOG_ERR, "failed to resolve band name");
            return -1;
        }

        syslog(LOG_DEBUG, "reading %zu bytes from band %llx at offset %llu",
            to_read, band_number, band_offset);

        ssize_t read = 0;
        int band_file = open(band_name, O_RDONLY);
        if (band_file != -1) {
            read = pread(band_file, buffer + bytes_read, to_read, band_offset);
            close(band_file);

            if (read == -1) {
                syslog(LOG_ERR, "failed to read band: %s", strerror(errno));
                free(band_name);
                return -1;
            }
        } else if (errno != ENOENT) {
            syslog(LOG_ERR, "failed to open band %s: %s", band_name, strerror(errno));
            free(band_name);
            return -1;
        }

        free(band_name);

        if (read < to_read) {
            syslog(LOG_DEBUG, "missing %zu bytes from band %llx, padding with zeroes",
                to_read - read, band_number);
            memset(buffer + bytes_read + read, 0, to_read - read);
        }

        bytes_read += to_read;

        syslog(LOG_DEBUG, "done reading from band %llx, %zu bytes left to read",
                band_number, length - bytes_read);
    }

    assert(bytes_read == length);
    return bytes_read;
}

static int sparsebundle_release(const char *path, struct fuse_file_info *fi)
{
    SB_DATA->times_opened--;
    syslog(LOG_DEBUG, "closed %s, now referenced %llx times",
        SB_DATA->path, SB_DATA->times_opened);

    if (SB_DATA->times_opened == 0) {
        syslog(LOG_DEBUG, "no more references to sparsebundle, cleaning up");
    }

    return 0;
}

static int sparsebundle_show_usage(char *program_name)
{
    fprintf(stderr, "usage: %s [-o options] [-f] [-D] <sparsebundle> <mountpoint>\n", program_name);
    return 1;
}

enum { SPARSEBUNDLE_OPT_DEBUG };

static int sparsebundle_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs)
{
    switch (key) {
    case SPARSEBUNDLE_OPT_DEBUG:
        setlogmask(LOG_UPTO(LOG_DEBUG));
        return 0;
    case FUSE_OPT_KEY_NONOPT:
        if (SB_DATA_CAST(data)->path)
            return 1;

        SB_DATA_CAST(data)->path = strdup(arg);
        return 0;
    }

    return 1;
}

static off_t read_size(const string &str)
{
    uintmax_t value = strtoumax(str.c_str(), 0, 10);
    if (errno == ERANGE || value > static_cast<uintmax_t>(numeric_limits<off_t>::max())) {
        fprintf(stderr, "Disk image too large to be mounted (%s bytes)\n", str.c_str());
        exit(-1);
    }

    return value;
}

int main(int argc, char **argv)
{
    openlog("sparsebundlefs", LOG_CONS | LOG_PERROR, LOG_USER);
    setlogmask(~(LOG_MASK(LOG_DEBUG)));

    struct sparsebundle_data data = {};

    static struct fuse_opt sparsebundle_options[] = {
        FUSE_OPT_KEY("-D",  SPARSEBUNDLE_OPT_DEBUG), FUSE_OPT_END
    };

    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    fuse_opt_parse(&args, &data, sparsebundle_options, sparsebundle_opt_proc);
    fuse_opt_add_arg(&args, "-oro"); // Force read-only mount

    if (!data.path)
        return sparsebundle_show_usage(argv[0]);

    char *abs_path = realpath(data.path, 0);
    if (!abs_path) {
        perror("Could not resolve absolute path");
        return -1;
    }

    free(data.path);
    data.path = abs_path;

    char *plist_path;
    if (asprintf(&plist_path, "%s/Info.plist", data.path) == -1) {
        perror("Failed to resolve Info.plist path");
        return -1;
    }

    ifstream plist_file(plist_path);
    stringstream plist_data;
    plist_data << plist_file.rdbuf();

    string key, line;
    while (getline(plist_data, line)) {
        static const char whitespace_chars[] = " \n\r\t";
        line.erase(0, line.find_first_not_of(whitespace_chars));
        line.erase(line.find_last_not_of(whitespace_chars) + 1);

        if (line.compare(0, 5, "<key>") == 0) {
            key = line.substr(5, line.length() - 11);
        } else if (!key.empty()) {
            line.erase(0, line.find_first_of('>') + 1);
            line.erase(line.find_first_of('<'));

            if (key == "band-size")
                data.band_size = read_size(line);
            else if (key == "size")
                data.size = read_size(line);

            key.clear();
        }
    }

    syslog(LOG_DEBUG, "initialized %s, band size %llu, total size %llu",
        data.path, data.band_size, data.size);

    struct fuse_operations sparsebundle_filesystem_operations = {};
    sparsebundle_filesystem_operations.getattr = sparsebundle_getattr;
    sparsebundle_filesystem_operations.open = sparsebundle_open;
    sparsebundle_filesystem_operations.read = sparsebundle_read;
    sparsebundle_filesystem_operations.readdir = sparsebundle_readdir;
    sparsebundle_filesystem_operations.release = sparsebundle_release;

    return fuse_main(args.argc, args.argv, &sparsebundle_filesystem_operations, &data);
}
<|endoftext|>


<commit_before>
#include "Utils.hpp"
#include "Log.hpp"
#include <botan/pem.h>
#include <botan/base64.h>
#include <botan/auto_rng.h>
#include <cstdio>
#include <stdexcept>
#include <sstream>

bool Utils::parse(int argc, const poptContext& pc)
{  // http://privatemisc.blogspot.com/2012/12/popt-basic-example.html
  poptSetOtherOptionHelp(pc, "[ARG...]");
  if (argc < 2)
  {
    poptPrintUsage(pc, stderr, 0);
    return false;
  }

  // process options and handle each val returned
  int val;
  while ((val = poptGetNextOpt(pc)) >= 0)
  {
  }

  // poptGetNextOpt returns -1 when the final argument has been parsed
  if (val != -1)
  {
    // handle error
    switch (val)
    {
      case POPT_ERROR_NOARG:
        printf("Argument expected but missing for an option.\n");
        return false;
      case POPT_ERROR_BADOPT:
        printf("Failed to parse argument.\n");
        return false;
      case POPT_ERROR_BADNUMBER:
      case POPT_ERROR_OVERFLOW:
        printf("Option could not be converted to number\n");
        return false;
      default:
        printf("Unknown error in option processing\n");
        return false;
    }
  }

  poptFreeContext(pc);
  return true;
}

// https://stackoverflow.com/questions/6855115/byte-array-to-int-c
uint32_t Utils::arrayToUInt32(const uint8_t* byteArray, int32_t offset)
{
  return *reinterpret_cast<const uint32_t*>(&byteArray[offset]);
}

char* Utils::getAsHex(const uint8_t* data, int len)
{
  char* hexStr = new char[len * 2 + 3];
  hexStr[0] = '0';
  hexStr[1] = 'x';
  for (int i = 0; i < len; i++)
    sprintf(&hexStr[i * 2 + 2], "%02x", data[i]);
  return hexStr;
}

bool Utils::isPowerOfTwo(std::size_t x)
{  // glibc method of checking
  return ((x != 0) && !(x & (x - 1)));
}

unsigned long Utils::decode64Estimation(unsigned long inSize)
{  // https://stackoverflow.com/questions/1533113/calculate-the-size-to-a-base-64-encoded-message
  return ((inSize * 4) / 3) + (inSize / 96) + 6;
}

// https://stackoverflow.com/questions/1494399/how-do-i-search-find-and-replace-in-a-standard-string
void Utils::stringReplace(std::string& str,
                          const std::string& find,
                          const std::string& replace)
{
  size_t pos = 0;
  while ((pos = str.find(find, pos)) != std::string::npos)
  {
    str.replace(pos, find.length(), replace);
    pos += replace.length();
  }
}

// https://stackoverflow.com/questions/874134/
bool Utils::strEndsWith(const std::string& str, const std::string& ending)
{
  if (str.length() >= ending.length())
    return (
        0 ==
        str.compare(str.length() - ending.length(), ending.length(), ending));
  else
    return false;
}

Botan::RSA_PublicKey* Utils::base64ToRSA(const std::string& base64)
{
  // decode public key
  unsigned long expectedSize = decode64Estimation(base64.length());
  uint8_t* keyBuffer = new uint8_t[expectedSize];
  size_t len = Botan::base64_decode(keyBuffer, base64, false);

  // interpret and parse into public RSA key
  std::istringstream iss(std::string(reinterpret_cast<char*>(keyBuffer), len));
  Botan::DataSource_Stream keyStream(iss);
  return dynamic_cast<Botan::RSA_PublicKey*>(Botan::X509::load_key(keyStream));
}

Botan::RSA_PrivateKey* Utils::loadKey(const std::string& filename)
{
  static Botan::AutoSeeded_RNG rng;

  try
  {
    // attempt reading key as standardized PKCS8 format
    Log::get().notice("Opening HS key... ");

    auto pvtKey = Botan::PKCS8::load_key(filename, rng);
    auto rsaKey = dynamic_cast<Botan::RSA_PrivateKey*>(pvtKey);
    if (!rsaKey)
      throw std::invalid_argument("The loaded key is not a RSA key!");

    Log::get().notice("Read PKCS8-formatted RSA key.");
    return rsaKey;
  }
  catch (Botan::Decoding_Error&)
  {
    Log::get().notice("Read OpenSSL-formatted RSA key.");
    return Utils::loadOpenSSLRSA(filename, rng);
  }

  Log::get().warn("Unable to read key!");
  return NULL;
}

// http://botan.randombit.net/faq.html#how-do-i-load-this-key-generated-by-openssl-into-botan
// http://lists.randombit.net/pipermail/botan-devel/2010-June/001157.html
// http://lists.randombit.net/pipermail/botan-devel/attachments/20100611/1d8d870a/attachment.cpp
Botan::RSA_PrivateKey* Utils::loadOpenSSLRSA(const std::string& filename,
                                             Botan::RandomNumberGenerator& rng)
{
  Botan::DataSource_Stream in(filename);

  Botan::DataSource_Memory key_bits(
      Botan::PEM_Code::decode_check_label(in, "RSA PRIVATE KEY"));

  // Botan::u32bit version;
  size_t version;
  Botan::BigInt n, e, d, p, q;

  Botan::BER_Decoder(key_bits)
      .start_cons(Botan::SEQUENCE)
      .decode(version)
      .decode(n)
      .decode(e)
      .decode(d)
      .decode(p)
      .decode(q);

  if (version != 0)
    return NULL;

  return new Botan::RSA_PrivateKey(rng, p, q, e, d, n);
}

// This function assumes src to be a zero terminated sanitized string with
// an even number of [0-9a-f] characters, and target to be sufficiently large
void Utils::hex2bin(const char* src, uint8_t* target)
{  // https://stackoverflow.com/questions/17261798/converting-a-hex-string-to-byte-array-in-c
  while (*src && src[1])
  {
    *(target++) = char2int(*src) * 16 + char2int(src[1]);
    src += 2;
  }
}

uint8_t Utils::char2int(const char c)
{
  if (c >= '0' && c <= '9')
    return c - '0';
  if (c >= 'A' && c <= 'F')
    return c - 'A' + 10;
  if (c >= 'a' && c <= 'f')
    return c - 'a' + 10;

  throw std::runtime_error("Invalid character");
}
<commit_msg>fix to allow no-argument execution<commit_after>
#include "Utils.hpp"
#include "Log.hpp"
#include <botan/pem.h>
#include <botan/base64.h>
#include <botan/auto_rng.h>
#include <cstdio>
#include <stdexcept>
#include <sstream>

bool Utils::parse(int argc, const poptContext& pc)
{  // http://privatemisc.blogspot.com/2012/12/popt-basic-example.html
  poptSetOtherOptionHelp(pc, "[ARG...]");

  // process options and handle each val returned
  int val;
  while ((val = poptGetNextOpt(pc)) >= 0)
  {
  }

  // poptGetNextOpt returns -1 when the final argument has been parsed
  if (val != -1)
  {
    poptPrintUsage(pc, stderr, 0);

    // handle error
    switch (val)
    {
      case POPT_ERROR_NOARG:
        printf("Argument expected but missing for an option.\n");
        return false;
      case POPT_ERROR_BADOPT:
        printf("Failed to parse argument.\n");
        return false;
      case POPT_ERROR_BADNUMBER:
      case POPT_ERROR_OVERFLOW:
        printf("Option could not be converted to number\n");
        return false;
      default:
        printf("Unknown error in option processing\n");
        return false;
    }
  }

  poptFreeContext(pc);
  return true;
}

// https://stackoverflow.com/questions/6855115/byte-array-to-int-c
uint32_t Utils::arrayToUInt32(const uint8_t* byteArray, int32_t offset)
{
  return *reinterpret_cast<const uint32_t*>(&byteArray[offset]);
}

char* Utils::getAsHex(const uint8_t* data, int len)
{
  char* hexStr = new char[len * 2 + 3];
  hexStr[0] = '0';
  hexStr[1] = 'x';
  for (int i = 0; i < len; i++)
    sprintf(&hexStr[i * 2 + 2], "%02x", data[i]);
  return hexStr;
}

bool Utils::isPowerOfTwo(std::size_t x)
{  // glibc method of checking
  return ((x != 0) && !(x & (x - 1)));
}

unsigned long Utils::decode64Estimation(unsigned long inSize)
{  // https://stackoverflow.com/questions/1533113/calculate-the-size-to-a-base-64-encoded-message
  return ((inSize * 4) / 3) + (inSize / 96) + 6;
}

// https://stackoverflow.com/questions/1494399/how-do-i-search-find-and-replace-in-a-standard-string
void Utils::stringReplace(std::string& str,
                          const std::string& find,
                          const std::string& replace)
{
  size_t pos = 0;
  while ((pos = str.find(find, pos)) != std::string::npos)
  {
    str.replace(pos, find.length(), replace);
    pos += replace.length();
  }
}

// https://stackoverflow.com/questions/874134/
bool Utils::strEndsWith(const std::string& str, const std::string& ending)
{
  if (str.length() >= ending.length())
    return (
        0 ==
        str.compare(str.length() - ending.length(), ending.length(), ending));
  else
    return false;
}

Botan::RSA_PublicKey* Utils::base64ToRSA(const std::string& base64)
{
  // decode public key
  unsigned long expectedSize = decode64Estimation(base64.length());
  uint8_t* keyBuffer = new uint8_t[expectedSize];
  size_t len = Botan::base64_decode(keyBuffer, base64, false);

  // interpret and parse into public RSA key
  std::istringstream iss(std::string(reinterpret_cast<char*>(keyBuffer), len));
  Botan::DataSource_Stream keyStream(iss);
  return dynamic_cast<Botan::RSA_PublicKey*>(Botan::X509::load_key(keyStream));
}

Botan::RSA_PrivateKey* Utils::loadKey(const std::string& filename)
{
  static Botan::AutoSeeded_RNG rng;

  try
  {
    // attempt reading key as standardized PKCS8 format
    Log::get().notice("Opening HS key... ");

    auto pvtKey = Botan::PKCS8::load_key(filename, rng);
    auto rsaKey = dynamic_cast<Botan::RSA_PrivateKey*>(pvtKey);
    if (!rsaKey)
      throw std::invalid_argument("The loaded key is not a RSA key!");

    Log::get().notice("Read PKCS8-formatted RSA key.");
    return rsaKey;
  }
  catch (Botan::Decoding_Error&)
  {
    Log::get().notice("Read OpenSSL-formatted RSA key.");
    return Utils::loadOpenSSLRSA(filename, rng);
  }

  Log::get().warn("Unable to read key!");
  return NULL;
}

// http://botan.randombit.net/faq.html#how-do-i-load-this-key-generated-by-openssl-into-botan
// http://lists.randombit.net/pipermail/botan-devel/2010-June/001157.html
// http://lists.randombit.net/pipermail/botan-devel/attachments/20100611/1d8d870a/attachment.cpp
Botan::RSA_PrivateKey* Utils::loadOpenSSLRSA(const std::string& filename,
                                             Botan::RandomNumberGenerator& rng)
{
  Botan::DataSource_Stream in(filename);

  Botan::DataSource_Memory key_bits(
      Botan::PEM_Code::decode_check_label(in, "RSA PRIVATE KEY"));

  // Botan::u32bit version;
  size_t version;
  Botan::BigInt n, e, d, p, q;

  Botan::BER_Decoder(key_bits)
      .start_cons(Botan::SEQUENCE)
      .decode(version)
      .decode(n)
      .decode(e)
      .decode(d)
      .decode(p)
      .decode(q);

  if (version != 0)
    return NULL;

  return new Botan::RSA_PrivateKey(rng, p, q, e, d, n);
}

// This function assumes src to be a zero terminated sanitized string with
// an even number of [0-9a-f] characters, and target to be sufficiently large
void Utils::hex2bin(const char* src, uint8_t* target)
{  // https://stackoverflow.com/questions/17261798/converting-a-hex-string-to-byte-array-in-c
  while (*src && src[1])
  {
    *(target++) = char2int(*src) * 16 + char2int(src[1]);
    src += 2;
  }
}

uint8_t Utils::char2int(const char c)
{
  if (c >= '0' && c <= '9')
    return c - '0';
  if (c >= 'A' && c <= 'F')
    return c - 'A' + 10;
  if (c >= 'a' && c <= 'f')
    return c - 'a' + 10;

  throw std::runtime_error("Invalid character");
}
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the Campcaster project.
    http://campcaster.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    Campcaster 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 2 of the License, or
    (at your option) any later version.

    Campcaster 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 Campcaster; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author$
    Version  : $Revision$
    Location : $URL$

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

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#define DEBUG_PREFIX "SchedulerThread"
#include "LiveSupport/Core/Debug.h"

#include "LiveSupport/Core/TimeConversion.h"

#include "SchedulerThread.h"

using namespace LiveSupport::Core;
using namespace LiveSupport::EventScheduler;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
SchedulerThread :: SchedulerThread(
                        Ptr<EventContainerInterface>::Ref   eventContainer,
                        Ptr<time_duration>::Ref             granularity)
                                                                    throw ()
{
    DEBUG_FUNC_INFO

    this->eventContainer = eventContainer;
    this->granularity    = granularity;
    this->shouldRun      = false;
}

/*------------------------------------------------------------------------------
 *  Get the next event from the eventContainer
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: getNextEvent(Ptr<ptime>::Ref     when)       throw ()
{
    DEBUG_FUNC_INFO

    nextEvent = eventContainer->getNextEvent(when);
    if (nextEvent.get()) {
        nextEventTime = nextEvent->getScheduledTime();
        nextInitTime.reset(new ptime(*nextEventTime
                                   - *granularity
                                   - *nextEvent->maxTimeToInitialize()));
        nextEventEnd.reset(new ptime(*nextEventTime
                                   + *nextEvent->eventLength()));
    }
}

/*------------------------------------------------------------------------------
 *  The main execution body of the thread.
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: nextStep(Ptr<ptime>::Ref     now)            throw ()
{
    if (nextEvent) {
        if (imminent(now, nextInitTime)) {
            debug() << "event init coming" << std::endl;
            try {
                nextEvent->initialize();
            } catch (std::exception &e) {
                // cancel event by getting the next event after this was
                // supposed to finish
                getNextEvent(nextEventEnd);
                // TODO: log error
                std::cerr << "event initialization error: " << e.what()
                          << std::endl;
            }
        } else if (imminent(now, nextEventTime)) {
            debug() << "event start coming" << std::endl;
            Ptr<time_duration>::Ref timeLeft(new time_duration(*nextEventTime
                                                             - *now));
            TimeConversion::sleep(timeLeft);
            nextEvent->start();
            currentEvent = nextEvent;
            currentEventEnd = nextEventEnd;
            getNextEvent(TimeConversion::now());
        }
    }

    if (currentEvent && imminent(now, nextEventEnd)) {
        debug() << "event end coming" << std::endl;
        Ptr<time_duration>::Ref timeLeft(new time_duration(*currentEventEnd
                                                         - *now));
        TimeConversion::sleep(timeLeft);
        currentEvent->stop();
        currentEvent->deInitialize();
        currentEvent.reset();
    }
}

/*------------------------------------------------------------------------------
 *  The main execution body of the thread.
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: run(void)                                    throw ()
{
    DEBUG_FUNC_INFO

    shouldRun = true;
    getNextEvent(TimeConversion::now());

    while (shouldRun) {
        Ptr<ptime>::Ref     start = TimeConversion::now();

        nextStep(start);

        // sleep until the next granularity
        Ptr<ptime>::Ref             end = TimeConversion::now();
        Ptr<time_duration>::Ref     diff(new time_duration(*end - *start));
        if (*diff <= *granularity) {
            Ptr<time_duration>::Ref sleepTime(new time_duration(*granularity
                                                              - *diff));
            TimeConversion::sleep(sleepTime);
        }
    }
}

/*------------------------------------------------------------------------------
 *  Accept a signal.
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: signal(int signalId)                         throw ()
{
    DEBUG_FUNC_INFO

    switch (signalId) {
        case UpdateSignal:
            getNextEvent(TimeConversion::now());
            break;

        default:
            break;
    }
}

<commit_msg>fixed a typo in [2694]<commit_after>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the Campcaster project.
    http://campcaster.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    Campcaster 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 2 of the License, or
    (at your option) any later version.

    Campcaster 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 Campcaster; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author$
    Version  : $Revision$
    Location : $URL$

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

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#define DEBUG_PREFIX "SchedulerThread"
#include "LiveSupport/Core/Debug.h"

#include "LiveSupport/Core/TimeConversion.h"

#include "SchedulerThread.h"

using namespace LiveSupport::Core;
using namespace LiveSupport::EventScheduler;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/* ===============================================  local function prototypes */

/* =============================================================  module code */

/*------------------------------------------------------------------------------
 *  Constructor.
 *----------------------------------------------------------------------------*/
SchedulerThread :: SchedulerThread(
                        Ptr<EventContainerInterface>::Ref   eventContainer,
                        Ptr<time_duration>::Ref             granularity)
                                                                    throw ()
{
    DEBUG_FUNC_INFO

    this->eventContainer = eventContainer;
    this->granularity    = granularity;
    this->shouldRun      = false;
}

/*------------------------------------------------------------------------------
 *  Get the next event from the eventContainer
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: getNextEvent(Ptr<ptime>::Ref     when)       throw ()
{
    DEBUG_FUNC_INFO

    nextEvent = eventContainer->getNextEvent(when);
    if (nextEvent.get()) {
        nextEventTime = nextEvent->getScheduledTime();
        nextInitTime.reset(new ptime(*nextEventTime
                                   - *granularity
                                   - *nextEvent->maxTimeToInitialize()));
        nextEventEnd.reset(new ptime(*nextEventTime
                                   + *nextEvent->eventLength()));
    }
}

/*------------------------------------------------------------------------------
 *  The main execution body of the thread.
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: nextStep(Ptr<ptime>::Ref     now)            throw ()
{
    if (nextEvent) {
        if (imminent(now, nextInitTime)) {
            debug() << "event init coming" << std::endl;
            try {
                nextEvent->initialize();
            } catch (std::exception &e) {
                // cancel event by getting the next event after this was
                // supposed to finish
                getNextEvent(nextEventEnd);
                // TODO: log error
                std::cerr << "event initialization error: " << e.what()
                          << std::endl;
            }
        } else if (imminent(now, nextEventTime)) {
            debug() << "event start coming" << std::endl;
            Ptr<time_duration>::Ref timeLeft(new time_duration(*nextEventTime
                                                             - *now));
            TimeConversion::sleep(timeLeft);
            nextEvent->start();
            currentEvent = nextEvent;
            currentEventEnd = nextEventEnd;
            getNextEvent(TimeConversion::now());
        }
    }

    if (currentEvent && imminent(now, currentEventEnd)) {
        debug() << "event end coming" << std::endl;
        Ptr<time_duration>::Ref timeLeft(new time_duration(*currentEventEnd
                                                         - *now));
        TimeConversion::sleep(timeLeft);
        currentEvent->stop();
        currentEvent->deInitialize();
        currentEvent.reset();
    }
}

/*------------------------------------------------------------------------------
 *  The main execution body of the thread.
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: run(void)                                    throw ()
{
    DEBUG_FUNC_INFO

    shouldRun = true;
    getNextEvent(TimeConversion::now());

    while (shouldRun) {
        Ptr<ptime>::Ref     start = TimeConversion::now();

        nextStep(start);

        // sleep until the next granularity
        Ptr<ptime>::Ref             end = TimeConversion::now();
        Ptr<time_duration>::Ref     diff(new time_duration(*end - *start));
        if (*diff <= *granularity) {
            Ptr<time_duration>::Ref sleepTime(new time_duration(*granularity
                                                              - *diff));
            TimeConversion::sleep(sleepTime);
        }
    }
}

/*------------------------------------------------------------------------------
 *  Accept a signal.
 *----------------------------------------------------------------------------*/
void
SchedulerThread :: signal(int signalId)                         throw ()
{
    DEBUG_FUNC_INFO

    switch (signalId) {
        case UpdateSignal:
            getNextEvent(TimeConversion::now());
            break;

        default:
            break;
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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 "src/trace_processor/counters_table.h"

#include "src/trace_processor/storage_columns.h"
#include "src/trace_processor/storage_cursor.h"
#include "src/trace_processor/table_utils.h"

namespace perfetto {
namespace trace_processor {

CountersTable::CountersTable(sqlite3*, const TraceStorage* storage)
    : storage_(storage) {
  ref_types_.resize(RefType::kRefMax);
  ref_types_[RefType::kRefNoRef] = "";
  ref_types_[RefType::kRefUtid] = "utid";
  ref_types_[RefType::kRefCpuId] = "cpu";
  ref_types_[RefType::kRefIrq] = "irq";
  ref_types_[RefType::kRefSoftIrq] = "softirq";
  ref_types_[RefType::kRefUpid] = "upid";
  ref_types_[RefType::kRefUtidLookupUpid] = "upid";
}

void CountersTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
  Table::Register<CountersTable>(db, storage, "counters");
}

Table::Schema CountersTable::CreateSchema(int, const char* const*) {
  const auto& counters = storage_->counters();
  std::unique_ptr<StorageColumn> cols[] = {
      IdColumnPtr("id", TableId::kCounters),
      NumericColumnPtr("ts", &counters.timestamps(), false /* hidden */,
                       true /* ordered */),
      StringColumnPtr("name", &counters.name_ids(), &storage_->string_pool()),
      NumericColumnPtr("value", &counters.values()),
      NumericColumnPtr("dur", &counters.durations()),
      TsEndPtr("ts_end", &counters.timestamps(), &counters.durations()),
      std::unique_ptr<RefColumn>(new RefColumn("ref", storage_)),
      StringColumnPtr("ref_type", &counters.types(), &ref_types_)};
  schema_ = StorageSchema({
      std::make_move_iterator(std::begin(cols)),
      std::make_move_iterator(std::end(cols)),
  });
  return schema_.ToTableSchema({"name", "ts", "ref"});
}

std::unique_ptr<Table::Cursor> CountersTable::CreateCursor(
    const QueryConstraints& qc,
    sqlite3_value** argv) {
  uint32_t count = static_cast<uint32_t>(storage_->counters().counter_count());
  auto it = table_utils::CreateBestRowIteratorForGenericSchema(schema_, count,
                                                               qc, argv);
  return std::unique_ptr<Table::Cursor>(
      new StorageCursor(std::move(it), schema_.mutable_columns()));
}

int CountersTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
  info->estimated_cost =
      static_cast<uint32_t>(storage_->counters().counter_count());

  // Only the string columns are handled by SQLite
  info->order_by_consumed = true;
  size_t name_index = schema_.ColumnIndexFromName("name");
  size_t ref_type_index = schema_.ColumnIndexFromName("ref_type");
  for (size_t i = 0; i < qc.constraints().size(); i++) {
    info->omit[i] =
        qc.constraints()[i].iColumn != static_cast<int>(name_index) &&
        qc.constraints()[i].iColumn != static_cast<int>(ref_type_index);
  }

  return SQLITE_OK;
}

CountersTable::RefColumn::RefColumn(std::string col_name,
                                    const TraceStorage* storage)
    : StorageColumn(col_name, false /* hidden */), storage_(storage) {}

void CountersTable::RefColumn::ReportResult(sqlite3_context* ctx,
                                            uint32_t row) const {
  auto ref = storage_->counters().refs()[row];
  auto type = storage_->counters().types()[row];
  if (type == RefType::kRefUtidLookupUpid) {
    auto upid = storage_->GetThread(static_cast<uint32_t>(ref)).upid;
    if (upid.has_value()) {
      sqlite_utils::ReportSqliteResult(ctx, upid.value());
    } else {
      sqlite3_result_null(ctx);
    }
  } else {
    sqlite_utils::ReportSqliteResult(ctx, ref);
  }
}

CountersTable::RefColumn::Bounds CountersTable::RefColumn::BoundFilter(
    int,
    sqlite3_value*) const {
  return Bounds{};
}

void CountersTable::RefColumn::Filter(int op,
                                      sqlite3_value* value,
                                      FilteredRowIndex* index) const {
  auto binary_op = sqlite_utils::GetPredicateForOp<int64_t>(op);
  int64_t extracted = sqlite_utils::ExtractSqliteValue<int64_t>(value);
  index->FilterRows([this, &binary_op, extracted](uint32_t row) {
    auto ref = storage_->counters().refs()[row];
    auto type = storage_->counters().types()[row];
    if (type == RefType::kRefUtidLookupUpid) {
      auto upid = storage_->GetThread(static_cast<uint32_t>(ref)).upid;
      // Trying to filter null with any operation we currently handle
      // should return false.
      return upid.has_value() && binary_op(upid.value(), extracted);
    }
    return binary_op(ref, extracted);
  });
}

CountersTable::RefColumn::Comparator CountersTable::RefColumn::Sort(
    const QueryConstraints::OrderBy& ob) const {
  if (ob.desc) {
    return [this](uint32_t f, uint32_t s) { return -CompareRefsAsc(f, s); };
  }
  return [this](uint32_t f, uint32_t s) { return CompareRefsAsc(f, s); };
}

int CountersTable::RefColumn::CompareRefsAsc(uint32_t f, uint32_t s) const {
  auto ref_f = storage_->counters().refs()[f];
  auto ref_s = storage_->counters().refs()[s];

  auto type_f = storage_->counters().types()[f];
  auto type_s = storage_->counters().types()[s];

  if (type_f == RefType::kRefUtidLookupUpid) {
    auto upid_f = storage_->GetThread(static_cast<uint32_t>(ref_f)).upid;
    if (type_s == RefType::kRefUtidLookupUpid) {
      auto upid_s = storage_->GetThread(static_cast<uint32_t>(ref_s)).upid;
      if (!upid_f.has_value() && !upid_s.has_value()) {
        return 0;
      } else if (!upid_f.has_value()) {
        return -1;
      } else if (!upid_s.has_value()) {
        return 1;
      }
      return sqlite_utils::CompareValuesAsc(upid_f.value(), upid_s.value());
    }
    if (!upid_f.has_value())
      return -1;
  }
  return sqlite_utils::CompareValuesAsc(ref_f, ref_s);
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix asymmetric upid sort breaking strict partitial ordering<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * 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 "src/trace_processor/counters_table.h"

#include "src/trace_processor/storage_columns.h"
#include "src/trace_processor/storage_cursor.h"
#include "src/trace_processor/table_utils.h"

namespace perfetto {
namespace trace_processor {

CountersTable::CountersTable(sqlite3*, const TraceStorage* storage)
    : storage_(storage) {
  ref_types_.resize(RefType::kRefMax);
  ref_types_[RefType::kRefNoRef] = "";
  ref_types_[RefType::kRefUtid] = "utid";
  ref_types_[RefType::kRefCpuId] = "cpu";
  ref_types_[RefType::kRefIrq] = "irq";
  ref_types_[RefType::kRefSoftIrq] = "softirq";
  ref_types_[RefType::kRefUpid] = "upid";
  ref_types_[RefType::kRefUtidLookupUpid] = "upid";
}

void CountersTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
  Table::Register<CountersTable>(db, storage, "counters");
}

Table::Schema CountersTable::CreateSchema(int, const char* const*) {
  const auto& counters = storage_->counters();
  std::unique_ptr<StorageColumn> cols[] = {
      IdColumnPtr("id", TableId::kCounters),
      NumericColumnPtr("ts", &counters.timestamps(), false /* hidden */,
                       true /* ordered */),
      StringColumnPtr("name", &counters.name_ids(), &storage_->string_pool()),
      NumericColumnPtr("value", &counters.values()),
      NumericColumnPtr("dur", &counters.durations()),
      TsEndPtr("ts_end", &counters.timestamps(), &counters.durations()),
      std::unique_ptr<RefColumn>(new RefColumn("ref", storage_)),
      StringColumnPtr("ref_type", &counters.types(), &ref_types_)};
  schema_ = StorageSchema({
      std::make_move_iterator(std::begin(cols)),
      std::make_move_iterator(std::end(cols)),
  });
  return schema_.ToTableSchema({"name", "ts", "ref"});
}

std::unique_ptr<Table::Cursor> CountersTable::CreateCursor(
    const QueryConstraints& qc,
    sqlite3_value** argv) {
  uint32_t count = static_cast<uint32_t>(storage_->counters().counter_count());
  auto it = table_utils::CreateBestRowIteratorForGenericSchema(schema_, count,
                                                               qc, argv);
  return std::unique_ptr<Table::Cursor>(
      new StorageCursor(std::move(it), schema_.mutable_columns()));
}

int CountersTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
  info->estimated_cost =
      static_cast<uint32_t>(storage_->counters().counter_count());

  // Only the string columns are handled by SQLite
  info->order_by_consumed = true;
  size_t name_index = schema_.ColumnIndexFromName("name");
  size_t ref_type_index = schema_.ColumnIndexFromName("ref_type");
  for (size_t i = 0; i < qc.constraints().size(); i++) {
    info->omit[i] =
        qc.constraints()[i].iColumn != static_cast<int>(name_index) &&
        qc.constraints()[i].iColumn != static_cast<int>(ref_type_index);
  }

  return SQLITE_OK;
}

CountersTable::RefColumn::RefColumn(std::string col_name,
                                    const TraceStorage* storage)
    : StorageColumn(col_name, false /* hidden */), storage_(storage) {}

void CountersTable::RefColumn::ReportResult(sqlite3_context* ctx,
                                            uint32_t row) const {
  auto ref = storage_->counters().refs()[row];
  auto type = storage_->counters().types()[row];
  if (type == RefType::kRefUtidLookupUpid) {
    auto upid = storage_->GetThread(static_cast<uint32_t>(ref)).upid;
    if (upid.has_value()) {
      sqlite_utils::ReportSqliteResult(ctx, upid.value());
    } else {
      sqlite3_result_null(ctx);
    }
  } else {
    sqlite_utils::ReportSqliteResult(ctx, ref);
  }
}

CountersTable::RefColumn::Bounds CountersTable::RefColumn::BoundFilter(
    int,
    sqlite3_value*) const {
  return Bounds{};
}

void CountersTable::RefColumn::Filter(int op,
                                      sqlite3_value* value,
                                      FilteredRowIndex* index) const {
  auto binary_op = sqlite_utils::GetPredicateForOp<int64_t>(op);
  int64_t extracted = sqlite_utils::ExtractSqliteValue<int64_t>(value);
  index->FilterRows([this, &binary_op, extracted](uint32_t row) {
    auto ref = storage_->counters().refs()[row];
    auto type = storage_->counters().types()[row];
    if (type == RefType::kRefUtidLookupUpid) {
      auto upid = storage_->GetThread(static_cast<uint32_t>(ref)).upid;
      // Trying to filter null with any operation we currently handle
      // should return false.
      return upid.has_value() && binary_op(upid.value(), extracted);
    }
    return binary_op(ref, extracted);
  });
}

CountersTable::RefColumn::Comparator CountersTable::RefColumn::Sort(
    const QueryConstraints::OrderBy& ob) const {
  if (ob.desc) {
    return [this](uint32_t f, uint32_t s) { return -CompareRefsAsc(f, s); };
  }
  return [this](uint32_t f, uint32_t s) { return CompareRefsAsc(f, s); };
}

int CountersTable::RefColumn::CompareRefsAsc(uint32_t f, uint32_t s) const {
  auto ref_f = storage_->counters().refs()[f];
  auto ref_s = storage_->counters().refs()[s];

  auto type_f = storage_->counters().types()[f];
  auto type_s = storage_->counters().types()[s];

  if (type_f == RefType::kRefUtidLookupUpid) {
    auto upid_f = storage_->GetThread(static_cast<uint32_t>(ref_f)).upid;
    if (type_s == RefType::kRefUtidLookupUpid) {
      auto upid_s = storage_->GetThread(static_cast<uint32_t>(ref_s)).upid;
      if (!upid_f.has_value() && !upid_s.has_value()) {
        return 0;
      } else if (!upid_f.has_value()) {
        return -1;
      } else if (!upid_s.has_value()) {
        return 1;
      }
      return sqlite_utils::CompareValuesAsc(upid_f.value(), upid_s.value());
    }
    if (!upid_f.has_value())
      return -1;
  } else if (type_s == RefType::kRefUtidLookupUpid) {
    auto upid_s = storage_->GetThread(static_cast<uint32_t>(ref_s)).upid;
    if (!upid_s.has_value())
      return 1;
  }
  return sqlite_utils::CompareValuesAsc(ref_f, ref_s);
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


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

#include "qwebsocketserver.h"
#include "qwebsocketserver_p.h"
#ifndef QT_NO_SSL
#include "qsslserver_p.h"
#endif
#include "qwebsocketprotocol.h"
#include "qwebsockethandshakerequest_p.h"
#include "qwebsockethandshakeresponse_p.h"
#include "qwebsocket.h"
#include "qwebsocket_p.h"
#include "qwebsocketcorsauthenticator.h"

#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QNetworkProxy>

QT_BEGIN_NAMESPACE

/*!
    \internal
 */
QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
                                                 QWebSocketServerPrivate::SslMode secureMode,
                                                 QWebSocketServer * const pWebSocketServer,
                                                 QObject *parent) :
    QObject(parent),
    q_ptr(pWebSocketServer),
    m_pTcpServer(Q_NULLPTR),
    m_serverName(serverName),
    m_secureMode(secureMode),
    m_pendingConnections(),
    m_error(QWebSocketProtocol::CloseCodeNormal),
    m_errorString()
{
    Q_ASSERT(pWebSocketServer);
    if (m_secureMode == NonSecureMode) {
        m_pTcpServer = new QTcpServer(this);
        if (Q_LIKELY(m_pTcpServer))
            connect(m_pTcpServer, &QTcpServer::newConnection,
                    this, &QWebSocketServerPrivate::onNewConnection);
        else
            qFatal("Could not allocate memory for tcp server.");
    } else {
#ifndef QT_NO_SSL
        QSslServer *pSslServer = new QSslServer(this);
        m_pTcpServer = pSslServer;
        if (Q_LIKELY(m_pTcpServer)) {
            connect(pSslServer, &QSslServer::newEncryptedConnection,
                    this, &QWebSocketServerPrivate::onNewConnection);
            connect(pSslServer, &QSslServer::peerVerifyError,
                    q_ptr, &QWebSocketServer::peerVerifyError);
            connect(pSslServer, &QSslServer::sslErrors,
                    q_ptr, &QWebSocketServer::sslErrors);
        }
#else
        qFatal("SSL not supported on this platform.");
#endif
    }
    connect(m_pTcpServer, &QTcpServer::acceptError, q_ptr, &QWebSocketServer::acceptError);
}

/*!
    \internal
 */
QWebSocketServerPrivate::~QWebSocketServerPrivate()
{
    close();
    m_pTcpServer->deleteLater();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::close()
{
    Q_Q(QWebSocketServer);
    m_pTcpServer->close();
    while (!m_pendingConnections.isEmpty()) {
        QWebSocket *pWebSocket = m_pendingConnections.dequeue();
        pWebSocket->close(QWebSocketProtocol::CloseCodeGoingAway, tr("Server closed."));
        pWebSocket->deleteLater();
    }
    //emit signal via the event queue, so the server gets time
    //to process any hanging events, like flushing buffers aso
    QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
}

/*!
    \internal
 */
QString QWebSocketServerPrivate::errorString() const
{
    if (m_errorString.isEmpty())
        return m_pTcpServer->errorString();
    else
        return m_errorString;
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::hasPendingConnections() const
{
    return !m_pendingConnections.isEmpty();
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::isListening() const
{
    return m_pTcpServer->isListening();
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
{
    return m_pTcpServer->listen(address, port);
}

/*!
    \internal
 */
int QWebSocketServerPrivate::maxPendingConnections() const
{
    return m_pTcpServer->maxPendingConnections();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
{
    if (m_pendingConnections.size() < maxPendingConnections())
        m_pendingConnections.enqueue(pWebSocket);
}

/*!
    \internal
 */
void QWebSocketServerPrivate::setErrorFromSocketError(QAbstractSocket::SocketError error,
                                                      const QString &errorDescription)
{
    Q_UNUSED(error);
    setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, errorDescription);
}

/*!
    \internal
 */
QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
{
    QWebSocket *pWebSocket = Q_NULLPTR;
    if (Q_LIKELY(!m_pendingConnections.isEmpty()))
        pWebSocket = m_pendingConnections.dequeue();
    return pWebSocket;
}

/*!
    \internal
 */
void QWebSocketServerPrivate::pauseAccepting()
{
    m_pTcpServer->pauseAccepting();
}

#ifndef QT_NO_NETWORKPROXY
/*!
    \internal
 */
QNetworkProxy QWebSocketServerPrivate::proxy() const
{
    return m_pTcpServer->proxy();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::setProxy(const QNetworkProxy &networkProxy)
{
    m_pTcpServer->setProxy(networkProxy);
}
#endif
/*!
    \internal
 */
void QWebSocketServerPrivate::resumeAccepting()
{
    m_pTcpServer->resumeAccepting();
}

/*!
    \internal
 */
QHostAddress QWebSocketServerPrivate::serverAddress() const
{
    return m_pTcpServer->serverAddress();
}

/*!
    \internal
 */
QWebSocketProtocol::CloseCode QWebSocketServerPrivate::serverError() const
{
    return m_error;
}

/*!
    \internal
 */
quint16 QWebSocketServerPrivate::serverPort() const
{
    return m_pTcpServer->serverPort();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
{
    m_pTcpServer->setMaxPendingConnections(numConnections);
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::setSocketDescriptor(qintptr socketDescriptor)
{
    return m_pTcpServer->setSocketDescriptor(socketDescriptor);
}

/*!
    \internal
 */
qintptr QWebSocketServerPrivate::socketDescriptor() const
{
    return m_pTcpServer->socketDescriptor();
}

/*!
    \internal
 */
QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
{
    QList<QWebSocketProtocol::Version> supportedVersions;
    supportedVersions << QWebSocketProtocol::currentVersion();	//we only support V13
    return supportedVersions;
}

/*!
    \internal
 */
QStringList QWebSocketServerPrivate::supportedProtocols() const
{
    QStringList supportedProtocols;
    return supportedProtocols;	//no protocols are currently supported
}

/*!
    \internal
 */
QStringList QWebSocketServerPrivate::supportedExtensions() const
{
    QStringList supportedExtensions;
    return supportedExtensions;	//no extensions are currently supported
}

/*!
  \internal
 */
void QWebSocketServerPrivate::setServerName(const QString &serverName)
{
    if (m_serverName != serverName)
        m_serverName = serverName;
}

/*!
  \internal
 */
QString QWebSocketServerPrivate::serverName() const
{
    return m_serverName;
}

/*!
  \internal
 */
QWebSocketServerPrivate::SslMode QWebSocketServerPrivate::secureMode() const
{
    return m_secureMode;
}

#ifndef QT_NO_SSL
void QWebSocketServerPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
{
    if (m_secureMode == SecureMode)
        qobject_cast<QSslServer *>(m_pTcpServer)->setSslConfiguration(sslConfiguration);
}

QSslConfiguration QWebSocketServerPrivate::sslConfiguration() const
{
    if (m_secureMode == SecureMode)
        return qobject_cast<QSslServer *>(m_pTcpServer)->sslConfiguration();
    else
        return QSslConfiguration::defaultConfiguration();
}
#endif

void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const QString &errorString)
{
    if ((m_error != code) || (m_errorString != errorString)) {
        Q_Q(QWebSocketServer);
        m_error = code;
        m_errorString = errorString;
        Q_EMIT q->serverError(code);
    }
}

/*!
    \internal
 */
void QWebSocketServerPrivate::onNewConnection()
{
    QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
    connect(pTcpSocket, &QTcpSocket::readyRead, this, &QWebSocketServerPrivate::handshakeReceived);
}

/*!
    \internal
 */
void QWebSocketServerPrivate::onCloseConnection()
{
    QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
    if (Q_LIKELY(pTcpSocket))
        pTcpSocket->close();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::handshakeReceived()
{
    Q_Q(QWebSocketServer);
    QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
    if (Q_LIKELY(pTcpSocket)) {
        bool success = false;
        bool isSecure = false;

        disconnect(pTcpSocket, &QTcpSocket::readyRead,
                   this, &QWebSocketServerPrivate::handshakeReceived);

        if (m_pendingConnections.length() >= maxPendingConnections()) {
            pTcpSocket->close();
            setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
                     tr("Too many pending connections."));
            return;
        }

        QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
        QTextStream textStream(pTcpSocket);
        request.readHandshake(textStream);

        if (request.isValid()) {
            QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
            Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);

            QWebSocketHandshakeResponse response(request,
                                                 m_serverName,
                                                 corsAuthenticator.allowed(),
                                                 supportedVersions(),
                                                 supportedProtocols(),
                                                 supportedExtensions());

            if (response.isValid()) {
                QTextStream httpStream(pTcpSocket);
                httpStream << response;
                httpStream.flush();

                if (response.canUpgrade()) {
                    QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
                                                                            request,
                                                                            response);
                    if (pWebSocket) {
                        pWebSocket->setParent(this);
                        addPendingConnection(pWebSocket);
                        Q_EMIT q->newConnection();
                        success = true;
                    } else {
                        setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
                                 tr("Upgrading to websocket failed."));
                    }
                }
                else {
                    setError(response.error(), response.errorString());
                }
            } else {
                setError(QWebSocketProtocol::CloseCodeProtocolError, tr("Invalid response received."));
            }
        }
        if (!success) {
            qWarning() << tr("Closing socket because of invalid or unsupported request.");
            pTcpSocket->close();
        }
    } else {
        qWarning() <<
            tr("Sender socket is NULL. This should not happen, otherwise it is a Qt bug!!!");
    }
}

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

#include "qwebsocketserver.h"
#include "qwebsocketserver_p.h"
#ifndef QT_NO_SSL
#include "qsslserver_p.h"
#endif
#include "qwebsocketprotocol.h"
#include "qwebsockethandshakerequest_p.h"
#include "qwebsockethandshakeresponse_p.h"
#include "qwebsocket.h"
#include "qwebsocket_p.h"
#include "qwebsocketcorsauthenticator.h"

#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QNetworkProxy>

QT_BEGIN_NAMESPACE

/*!
    \internal
 */
QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
                                                 QWebSocketServerPrivate::SslMode secureMode,
                                                 QWebSocketServer * const pWebSocketServer,
                                                 QObject *parent) :
    QObject(parent),
    q_ptr(pWebSocketServer),
    m_pTcpServer(Q_NULLPTR),
    m_serverName(serverName),
    m_secureMode(secureMode),
    m_pendingConnections(),
    m_error(QWebSocketProtocol::CloseCodeNormal),
    m_errorString()
{
    Q_ASSERT(pWebSocketServer);
    if (m_secureMode == NonSecureMode) {
        m_pTcpServer = new QTcpServer(this);
        if (Q_LIKELY(m_pTcpServer))
            connect(m_pTcpServer, &QTcpServer::newConnection,
                    this, &QWebSocketServerPrivate::onNewConnection);
        else
            qFatal("Could not allocate memory for tcp server.");
    } else {
#ifndef QT_NO_SSL
        QSslServer *pSslServer = new QSslServer(this);
        m_pTcpServer = pSslServer;
        if (Q_LIKELY(m_pTcpServer)) {
            connect(pSslServer, &QSslServer::newEncryptedConnection,
                    this, &QWebSocketServerPrivate::onNewConnection);
            connect(pSslServer, &QSslServer::peerVerifyError,
                    q_ptr, &QWebSocketServer::peerVerifyError);
            connect(pSslServer, &QSslServer::sslErrors,
                    q_ptr, &QWebSocketServer::sslErrors);
        }
#else
        qFatal("SSL not supported on this platform.");
#endif
    }
    connect(m_pTcpServer, &QTcpServer::acceptError, q_ptr, &QWebSocketServer::acceptError);
}

/*!
    \internal
 */
QWebSocketServerPrivate::~QWebSocketServerPrivate()
{
    close();
    m_pTcpServer->deleteLater();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::close()
{
    Q_Q(QWebSocketServer);
    m_pTcpServer->close();
    while (!m_pendingConnections.isEmpty()) {
        QWebSocket *pWebSocket = m_pendingConnections.dequeue();
        pWebSocket->close(QWebSocketProtocol::CloseCodeGoingAway, tr("Server closed."));
        pWebSocket->deleteLater();
    }
    //emit signal via the event queue, so the server gets time
    //to process any hanging events, like flushing buffers aso
    QMetaObject::invokeMethod(q, "closed", Qt::QueuedConnection);
}

/*!
    \internal
 */
QString QWebSocketServerPrivate::errorString() const
{
    if (m_errorString.isEmpty())
        return m_pTcpServer->errorString();
    else
        return m_errorString;
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::hasPendingConnections() const
{
    return !m_pendingConnections.isEmpty();
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::isListening() const
{
    return m_pTcpServer->isListening();
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::listen(const QHostAddress &address, quint16 port)
{
    bool success = m_pTcpServer->listen(address, port);
    if (!success)
        setErrorFromSocketError(m_pTcpServer->serverError(), m_pTcpServer->errorString());
    return success;
}

/*!
    \internal
 */
int QWebSocketServerPrivate::maxPendingConnections() const
{
    return m_pTcpServer->maxPendingConnections();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::addPendingConnection(QWebSocket *pWebSocket)
{
    if (m_pendingConnections.size() < maxPendingConnections())
        m_pendingConnections.enqueue(pWebSocket);
}

/*!
    \internal
 */
void QWebSocketServerPrivate::setErrorFromSocketError(QAbstractSocket::SocketError error,
                                                      const QString &errorDescription)
{
    Q_UNUSED(error);
    setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection, errorDescription);
}

/*!
    \internal
 */
QWebSocket *QWebSocketServerPrivate::nextPendingConnection()
{
    QWebSocket *pWebSocket = Q_NULLPTR;
    if (Q_LIKELY(!m_pendingConnections.isEmpty()))
        pWebSocket = m_pendingConnections.dequeue();
    return pWebSocket;
}

/*!
    \internal
 */
void QWebSocketServerPrivate::pauseAccepting()
{
    m_pTcpServer->pauseAccepting();
}

#ifndef QT_NO_NETWORKPROXY
/*!
    \internal
 */
QNetworkProxy QWebSocketServerPrivate::proxy() const
{
    return m_pTcpServer->proxy();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::setProxy(const QNetworkProxy &networkProxy)
{
    m_pTcpServer->setProxy(networkProxy);
}
#endif
/*!
    \internal
 */
void QWebSocketServerPrivate::resumeAccepting()
{
    m_pTcpServer->resumeAccepting();
}

/*!
    \internal
 */
QHostAddress QWebSocketServerPrivate::serverAddress() const
{
    return m_pTcpServer->serverAddress();
}

/*!
    \internal
 */
QWebSocketProtocol::CloseCode QWebSocketServerPrivate::serverError() const
{
    return m_error;
}

/*!
    \internal
 */
quint16 QWebSocketServerPrivate::serverPort() const
{
    return m_pTcpServer->serverPort();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::setMaxPendingConnections(int numConnections)
{
    m_pTcpServer->setMaxPendingConnections(numConnections);
}

/*!
    \internal
 */
bool QWebSocketServerPrivate::setSocketDescriptor(qintptr socketDescriptor)
{
    return m_pTcpServer->setSocketDescriptor(socketDescriptor);
}

/*!
    \internal
 */
qintptr QWebSocketServerPrivate::socketDescriptor() const
{
    return m_pTcpServer->socketDescriptor();
}

/*!
    \internal
 */
QList<QWebSocketProtocol::Version> QWebSocketServerPrivate::supportedVersions() const
{
    QList<QWebSocketProtocol::Version> supportedVersions;
    supportedVersions << QWebSocketProtocol::currentVersion();	//we only support V13
    return supportedVersions;
}

/*!
    \internal
 */
QStringList QWebSocketServerPrivate::supportedProtocols() const
{
    QStringList supportedProtocols;
    return supportedProtocols;	//no protocols are currently supported
}

/*!
    \internal
 */
QStringList QWebSocketServerPrivate::supportedExtensions() const
{
    QStringList supportedExtensions;
    return supportedExtensions;	//no extensions are currently supported
}

/*!
  \internal
 */
void QWebSocketServerPrivate::setServerName(const QString &serverName)
{
    if (m_serverName != serverName)
        m_serverName = serverName;
}

/*!
  \internal
 */
QString QWebSocketServerPrivate::serverName() const
{
    return m_serverName;
}

/*!
  \internal
 */
QWebSocketServerPrivate::SslMode QWebSocketServerPrivate::secureMode() const
{
    return m_secureMode;
}

#ifndef QT_NO_SSL
void QWebSocketServerPrivate::setSslConfiguration(const QSslConfiguration &sslConfiguration)
{
    if (m_secureMode == SecureMode)
        qobject_cast<QSslServer *>(m_pTcpServer)->setSslConfiguration(sslConfiguration);
}

QSslConfiguration QWebSocketServerPrivate::sslConfiguration() const
{
    if (m_secureMode == SecureMode)
        return qobject_cast<QSslServer *>(m_pTcpServer)->sslConfiguration();
    else
        return QSslConfiguration::defaultConfiguration();
}
#endif

void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const QString &errorString)
{
    if ((m_error != code) || (m_errorString != errorString)) {
        Q_Q(QWebSocketServer);
        m_error = code;
        m_errorString = errorString;
        Q_EMIT q->serverError(code);
    }
}

/*!
    \internal
 */
void QWebSocketServerPrivate::onNewConnection()
{
    QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
    connect(pTcpSocket, &QTcpSocket::readyRead, this, &QWebSocketServerPrivate::handshakeReceived);
}

/*!
    \internal
 */
void QWebSocketServerPrivate::onCloseConnection()
{
    QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
    if (Q_LIKELY(pTcpSocket))
        pTcpSocket->close();
}

/*!
    \internal
 */
void QWebSocketServerPrivate::handshakeReceived()
{
    Q_Q(QWebSocketServer);
    QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender());
    if (Q_LIKELY(pTcpSocket)) {
        bool success = false;
        bool isSecure = false;

        disconnect(pTcpSocket, &QTcpSocket::readyRead,
                   this, &QWebSocketServerPrivate::handshakeReceived);

        if (m_pendingConnections.length() >= maxPendingConnections()) {
            pTcpSocket->close();
            setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
                     tr("Too many pending connections."));
            return;
        }

        QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
        QTextStream textStream(pTcpSocket);
        request.readHandshake(textStream);

        if (request.isValid()) {
            QWebSocketCorsAuthenticator corsAuthenticator(request.origin());
            Q_EMIT q->originAuthenticationRequired(&corsAuthenticator);

            QWebSocketHandshakeResponse response(request,
                                                 m_serverName,
                                                 corsAuthenticator.allowed(),
                                                 supportedVersions(),
                                                 supportedProtocols(),
                                                 supportedExtensions());

            if (response.isValid()) {
                QTextStream httpStream(pTcpSocket);
                httpStream << response;
                httpStream.flush();

                if (response.canUpgrade()) {
                    QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
                                                                            request,
                                                                            response);
                    if (pWebSocket) {
                        pWebSocket->setParent(this);
                        addPendingConnection(pWebSocket);
                        Q_EMIT q->newConnection();
                        success = true;
                    } else {
                        setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
                                 tr("Upgrading to websocket failed."));
                    }
                }
                else {
                    setError(response.error(), response.errorString());
                }
            } else {
                setError(QWebSocketProtocol::CloseCodeProtocolError, tr("Invalid response received."));
            }
        }
        if (!success) {
            qWarning() << tr("Closing socket because of invalid or unsupported request.");
            pTcpSocket->close();
        }
    } else {
        qWarning() <<
            tr("Sender socket is NULL. This should not happen, otherwise it is a Qt bug!!!");
    }
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/session.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

void bind_session_settings()
{
    class_<session_settings>("session_settings")
        .def_readwrite("user_agent", &session_settings::user_agent)
        .def_readwrite("tracker_completion_timeout", &session_settings::tracker_completion_timeout)
        .def_readwrite("tracker_receive_timeout", &session_settings::tracker_receive_timeout)
        .def_readwrite("tracker_maximum_response_length", &session_settings::tracker_maximum_response_length)
        .def_readwrite("piece_timeout", &session_settings::piece_timeout)
        .def_readwrite("request_queue_time", &session_settings::request_queue_time)
        .def_readwrite("max_allowed_in_request_queue", &session_settings::max_allowed_in_request_queue)
        .def_readwrite("max_out_request_queue", &session_settings::max_out_request_queue)
        .def_readwrite("whole_pieces_threshold", &session_settings::whole_pieces_threshold)
        .def_readwrite("peer_timeout", &session_settings::peer_timeout)
        .def_readwrite("urlseed_timeout", &session_settings::urlseed_timeout)
        .def_readwrite("urlseed_pipeline_size", &session_settings::urlseed_pipeline_size)
        .def_readwrite("file_pool_size", &session_settings::file_pool_size)
        .def_readwrite("allow_multiple_connections_per_ip", &session_settings::allow_multiple_connections_per_ip)
        .def_readwrite("max_failcount", &session_settings::max_failcount)
        .def_readwrite("min_reconnect_time", &session_settings::min_reconnect_time)
        .def_readwrite("peer_connect_timeout", &session_settings::peer_connect_timeout)
        .def_readwrite("ignore_limits_on_local_network", &session_settings::ignore_limits_on_local_network)
        .def_readwrite("connection_speed", &session_settings::connection_speed)
        .def_readwrite("send_redundant_have", &session_settings::send_redundant_have)
        .def_readwrite("lazy_bitfields", &session_settings::lazy_bitfields)
        .def_readwrite("inactivity_timeout", &session_settings::inactivity_timeout)
        .def_readwrite("unchoke_interval", &session_settings::unchoke_interval)
        .def_readwrite("active_downloads", &session_settings::active_downloads)
        .def_readwrite("active_seeds", &session_settings::active_seeds)
        .def_readwrite("active_limit", &session_settings::active_limit)
        .def_readwrite("dont_count_slow_torrents", &session_settings::dont_count_slow_torrents)
        .def_readwrite("auto_manage_interval", &session_settings::auto_manage_interval)
        .def_readwrite("share_ratio_limit", &session_settings::share_ratio_limit)
        .def_readwrite("seed_time_ratio_limit", &session_settings::seed_time_ratio_limit)
        .def_readwrite("seed_time_limit", &session_settings::seed_time_limit)
        .def_readwrite("auto_scraped_interval", &session_settings::auto_scrape_interval)
        .def_readwrite("peer_tos", &session_settings::peer_tos)
#ifndef TORRENT_DISABLE_DHT
        .def_readwrite("use_dht_as_fallback", &session_settings::use_dht_as_fallback)
#endif
    ;

    enum_<proxy_settings::proxy_type>("proxy_type")
        .value("none", proxy_settings::none)
        .value("socks4", proxy_settings::socks4)
        .value("socks5", proxy_settings::socks5)
        .value("socks5_pw", proxy_settings::socks5_pw)
        .value("http", proxy_settings::http)
        .value("http_pw", proxy_settings::http_pw)
    ;
    class_<proxy_settings>("proxy_settings")
        .def_readwrite("hostname", &proxy_settings::hostname)
        .def_readwrite("port", &proxy_settings::port)
        .def_readwrite("password", &proxy_settings::password)
        .def_readwrite("username", &proxy_settings::username)
        .def_readwrite("type", &proxy_settings::type)
    ;

#ifndef TORRENT_DISABLE_ENCRYPTION
    enum_<pe_settings::enc_policy>("enc_policy")
        .value("forced", pe_settings::forced)
        .value("enabled", pe_settings::enabled)
        .value("disabled", pe_settings::disabled)
    ;

    enum_<pe_settings::enc_level>("enc_level")
        .value("rc4", pe_settings::rc4)
        .value("plaintext", pe_settings::plaintext)
        .value("both", pe_settings::both)
    ;

    class_<pe_settings>("pe_settings")
        .def_readwrite("out_enc_policy", &pe_settings::out_enc_policy)
        .def_readwrite("in_enc_policy", &pe_settings::in_enc_policy)
        .def_readwrite("allowed_enc_level", &pe_settings::allowed_enc_level)
        .def_readwrite("prefer_rc4", &pe_settings::prefer_rc4)
    ;
#endif

}

<commit_msg>Add session_settings::rate_limit_ip_overhead to the python bindings<commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/session.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

void bind_session_settings()
{
    class_<session_settings>("session_settings")
        .def_readwrite("user_agent", &session_settings::user_agent)
        .def_readwrite("tracker_completion_timeout", &session_settings::tracker_completion_timeout)
        .def_readwrite("tracker_receive_timeout", &session_settings::tracker_receive_timeout)
        .def_readwrite("tracker_maximum_response_length", &session_settings::tracker_maximum_response_length)
        .def_readwrite("piece_timeout", &session_settings::piece_timeout)
        .def_readwrite("request_queue_time", &session_settings::request_queue_time)
        .def_readwrite("max_allowed_in_request_queue", &session_settings::max_allowed_in_request_queue)
        .def_readwrite("max_out_request_queue", &session_settings::max_out_request_queue)
        .def_readwrite("whole_pieces_threshold", &session_settings::whole_pieces_threshold)
        .def_readwrite("peer_timeout", &session_settings::peer_timeout)
        .def_readwrite("urlseed_timeout", &session_settings::urlseed_timeout)
        .def_readwrite("urlseed_pipeline_size", &session_settings::urlseed_pipeline_size)
        .def_readwrite("file_pool_size", &session_settings::file_pool_size)
        .def_readwrite("allow_multiple_connections_per_ip", &session_settings::allow_multiple_connections_per_ip)
        .def_readwrite("max_failcount", &session_settings::max_failcount)
        .def_readwrite("min_reconnect_time", &session_settings::min_reconnect_time)
        .def_readwrite("peer_connect_timeout", &session_settings::peer_connect_timeout)
        .def_readwrite("ignore_limits_on_local_network", &session_settings::ignore_limits_on_local_network)
        .def_readwrite("connection_speed", &session_settings::connection_speed)
        .def_readwrite("send_redundant_have", &session_settings::send_redundant_have)
        .def_readwrite("lazy_bitfields", &session_settings::lazy_bitfields)
        .def_readwrite("inactivity_timeout", &session_settings::inactivity_timeout)
        .def_readwrite("unchoke_interval", &session_settings::unchoke_interval)
        .def_readwrite("active_downloads", &session_settings::active_downloads)
        .def_readwrite("active_seeds", &session_settings::active_seeds)
        .def_readwrite("active_limit", &session_settings::active_limit)
        .def_readwrite("dont_count_slow_torrents", &session_settings::dont_count_slow_torrents)
        .def_readwrite("auto_manage_interval", &session_settings::auto_manage_interval)
        .def_readwrite("share_ratio_limit", &session_settings::share_ratio_limit)
        .def_readwrite("seed_time_ratio_limit", &session_settings::seed_time_ratio_limit)
        .def_readwrite("seed_time_limit", &session_settings::seed_time_limit)
        .def_readwrite("auto_scraped_interval", &session_settings::auto_scrape_interval)
        .def_readwrite("peer_tos", &session_settings::peer_tos)
        .def_readwrite("rate_limit_ip_overhead", &session_settings::rate_limit_ip_overhead)
#ifndef TORRENT_DISABLE_DHT
        .def_readwrite("use_dht_as_fallback", &session_settings::use_dht_as_fallback)
#endif
    ;

    enum_<proxy_settings::proxy_type>("proxy_type")
        .value("none", proxy_settings::none)
        .value("socks4", proxy_settings::socks4)
        .value("socks5", proxy_settings::socks5)
        .value("socks5_pw", proxy_settings::socks5_pw)
        .value("http", proxy_settings::http)
        .value("http_pw", proxy_settings::http_pw)
    ;
    class_<proxy_settings>("proxy_settings")
        .def_readwrite("hostname", &proxy_settings::hostname)
        .def_readwrite("port", &proxy_settings::port)
        .def_readwrite("password", &proxy_settings::password)
        .def_readwrite("username", &proxy_settings::username)
        .def_readwrite("type", &proxy_settings::type)
    ;

#ifndef TORRENT_DISABLE_ENCRYPTION
    enum_<pe_settings::enc_policy>("enc_policy")
        .value("forced", pe_settings::forced)
        .value("enabled", pe_settings::enabled)
        .value("disabled", pe_settings::disabled)
    ;

    enum_<pe_settings::enc_level>("enc_level")
        .value("rc4", pe_settings::rc4)
        .value("plaintext", pe_settings::plaintext)
        .value("both", pe_settings::both)
    ;

    class_<pe_settings>("pe_settings")
        .def_readwrite("out_enc_policy", &pe_settings::out_enc_policy)
        .def_readwrite("in_enc_policy", &pe_settings::in_enc_policy)
        .def_readwrite("allowed_enc_level", &pe_settings::allowed_enc_level)
        .def_readwrite("prefer_rc4", &pe_settings::prefer_rc4)
    ;
#endif

}
<|endoftext|>


<commit_before>#include "EmoteInputItem.hpp"

namespace chatterino {

EmoteInputItem::EmoteInputItem(const EmotePtr &emote, const QString &text,
                               ActionCallback action)
    : emote_(emote)
    , text_(text)
    , action_(action)
{
}

void EmoteInputItem::action()
{
    if (this->action_ && this->emote_)
        this->action_(this->emote_->name.string);
}

void EmoteInputItem::paint(QPainter *painter, const QRect &rect) const
{
    if (this->emote_)
    {
        if (auto image = this->emote_->images.getImage(4))
        {
            if (auto pixmap = image->pixmapOrLoad())
            {
                painter->drawPixmap(QRect(rect.x(), rect.y(), ICON_SIZE.width(),
                                          ICON_SIZE.height()),
                                    *pixmap);
            }
        }
    }

    QRect iconRect(rect.topLeft(), ICON_SIZE);
    QRect textRect =
        QRect(iconRect.topRight(),
              QSize(rect.width() - iconRect.width(), iconRect.height()));
    painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, this->text_);
}

QSize EmoteInputItem::sizeHint(const QRect &rect) const
{
    return QSize(rect.width(), ICON_SIZE.height());
}

}  // namespace chatterino
<commit_msg>smooth pixmap transform in emote input item<commit_after>#include "EmoteInputItem.hpp"

namespace chatterino {

EmoteInputItem::EmoteInputItem(const EmotePtr &emote, const QString &text,
                               ActionCallback action)
    : emote_(emote)
    , text_(text)
    , action_(action)
{
}

void EmoteInputItem::action()
{
    if (this->action_ && this->emote_)
        this->action_(this->emote_->name.string);
}

void EmoteInputItem::paint(QPainter *painter, const QRect &rect) const
{
    painter->setRenderHint(QPainter::SmoothPixmapTransform);

    if (this->emote_)
    {
        if (auto image = this->emote_->images.getImage(4))
        {
            if (auto pixmap = image->pixmapOrLoad())
            {
                painter->drawPixmap(QRect(rect.x(), rect.y(), ICON_SIZE.width(),
                                          ICON_SIZE.height()),
                                    *pixmap);
            }
        }
    }

    QRect iconRect(rect.topLeft(), ICON_SIZE);
    QRect textRect =
        QRect(iconRect.topRight(),
              QSize(rect.width() - iconRect.width(), iconRect.height()));
    painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, this->text_);
}

QSize EmoteInputItem::sizeHint(const QRect &rect) const
{
    return QSize(rect.width(), ICON_SIZE.height());
}

}  // namespace chatterino
<|endoftext|>