<commit_before>#include "tnyosc-dispatch.hpp"
#include "tnyosc.hpp"

#include <algorithm>
#include <iostream>

#include <assert.h>
#include <arpa/inet.h>
#include <stdio.h>

using namespace tnyosc;

void print_bytes(const unsigned char* bytes, size_t size)
{
  size_t i;
	for (i = 0; i < size; ++i) {
		printf("%02x ", bytes[i]);
		if (i % 16 == 15) {
			printf("\n");
		} else if (i % 4 == 3) {
      printf(" ");
    }
  }
  if (i % 16 != 0) {
    printf("\n");
  }
  printf("\n");
}

bool compare_callback_timetag(const CallbackRef first, const CallbackRef second)
{
  if (first->timetag.tv_sec == second->timetag.tv_sec) {
    return first->timetag.tv_usec <= second->timetag.tv_usec;
  } else {
    return first->timetag.tv_sec < second->timetag.tv_sec;
  }
}

Argument::Argument()
{
  type = 0;
  size = 0;
  memset(&data, 0, sizeof(data));
}

Argument::Argument(const Argument& a)
{
  type = a.type;
  size = a.size;
  switch(type) {
    case 's':
    case 'S':
      data.s = strndup(a.data.s, a.size);
      break;
    case'b':
      data.b = malloc(sizeof(size));
      memcpy(data.b, a.data.b, size);
      break;
    default:
      data = a.data;
      break;
  }
}

Argument::~Argument()
{
  switch(type) {
    case 's':
    case 'S':
    case'b':
      free(data.s);
  }
}

Argument& Argument::operator=(const Argument& a)
{
  if (this == &a) return *this;
  switch (type) {
    case 's':
    case 'S':
    case 'b':
      free(data.s);
  }

  type = a.type;
  size = a.size;
  switch(type) {
    case 's':
    case 'S':
      data.s = strndup(a.data.s, a.size);
      break;
    case'b':
      data.b = malloc(sizeof(size));
      memcpy(data.b, a.data.b, size);
      break;
    default:
      data = a.data;
  }
  return *this;
}

Dispatcher::Dispatcher()
  : methods_(0)
{
}

Dispatcher::~Dispatcher()
{
}

void Dispatcher::add_method(const char* address, const char* types,
    osc_method method, void* user_data)
{
  MethodTemplate m;
  m.address = address == NULL ? "" : address;
  m.types = types == NULL ? "" : types;
  m.user_data = user_data;
  m.method = method;
  methods_.push_back(m);
}

std::list<CallbackRef> Dispatcher::match_methods(const unsigned char* data, size_t size)
{
  std::list<ParsedMessage> parsed_messages;
  std::list<CallbackRef> callback_list;
  if (!decode_data(data, size, parsed_messages)) return callback_list;
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": decode success" << std::endl;
#endif // TNYOSC_DEBUG
  assert(parsed_messages.size() > 0);

  // iterate through all the messages and find matches with registered methods
  std::list<ParsedMessage>::iterator msg_iter = parsed_messages.begin();
  for (; msg_iter != parsed_messages.end(); ++msg_iter) {
#if TNYOSC_DEBUG
    std::cerr << __FUNCTION__ << ": matching " << msg_iter->address << "\n";
#endif // TNYOSC_DEBUG
    std::list<MethodTemplate>::const_iterator method_iter = methods_.begin();
    for (; method_iter != methods_.end(); ++method_iter) {
      if (pattern_match(msg_iter->address, method_iter->address)) {
#if TNYOSC_DEBUG
        std::cerr << "   matched " << method_iter->address << "\n";
#endif // TNYOSC_DEBUG
        // if a method specifies a type, make sure it matches
        if (method_iter->types.empty() ||
            !msg_iter->types.compare(method_iter->types)) {
          CallbackRef callback = CallbackRef(new Callback());
          callback->timetag = msg_iter->timetag;
          callback->address = msg_iter->address;
          callback->argv = msg_iter->argv;
          callback->user_data = method_iter->user_data;
          callback->method = method_iter->method;
          callback_list.push_back(callback);
        }
      }
    }
  }

  callback_list.sort(compare_callback_timetag);

  return callback_list;
}

struct timeval ntp_to_unixtime(uint32_t sec, uint32_t frac)
{
  // time between 1-1-1900 and 1-1-1950
  static const uint64_t epoch = 2208988800UL;

  struct timeval tv;
  if (sec == 0 && frac == 1) {
    memset(&tv, 0, sizeof(tv));
  } else {
    tv.tv_sec = sec - epoch;
    tv.tv_usec = (double)frac * 0.0002328306437080;
  }

  return tv;
}

const struct timeval Dispatcher::kZeroTimetag = {0, 0};

bool Dispatcher::decode_data(const unsigned char* data, size_t size,
    std::list<ParsedMessage>& messages, struct timeval timetag)
{
  if (!memcmp(data, "#bundle\0", 8)) {
    // found a bundle
#if TNYOSC_DEBUG
    std::cerr << __FUNCTION__ << ": bundle" << std::endl;
#endif // TNYOSC_DEBUG
    data += 8; size -= 8;

    uint32_t sec, frac;
    memcpy(&sec, data, 4); data += 4; size -= 4;
    memcpy(&frac, data, 4); data += 4; size -= 4;
    sec = ntohl(sec);
    frac = ntohl(frac);

    struct timeval new_timetag = ntp_to_unixtime(sec, frac);

    while (size != 0) {
      uint32_t seg_size;
      memcpy(&seg_size, data, 4); data += 4; size -= 4;
      seg_size = ntohl(seg_size);
      if (seg_size > size) return false;
      if (!decode_data(data, seg_size, messages, new_timetag)) return false;
      data += seg_size; size -= seg_size;
    }
  } else {
#if TNYOSC_DEBUG
    std::cerr << __FUNCTION__ << ": osc" << std::endl;
#endif // TNYOSC_DEBUG
    if (!decode_osc(data, size, messages, timetag)) return false;
  }

  return true;
}

bool Dispatcher::decode_osc(const unsigned char* data, size_t size,
    std::list<ParsedMessage>& messages, struct timeval timetag)
{
  const unsigned char* head;
  const unsigned char* tail;
  unsigned int i = 0;
  size_t remain = size;

  ParsedMessage m;
  m.timetag = timetag;

  // extract address
  head = tail = data;
  while (tail[i] != '\0' && ++i < remain);
  if (i == remain) return false;
  m.address.resize(i);
  std::copy(head, head+i, m.address.begin());
  head += i + (4 - i % 4);
  remain = size - (head - data);
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": address = " << m.address << std::endl;
#endif // TNYOSC_DEBUG

  // extract types
  i = 0;
  tail = head;
  if (head[i++] != ',') return false;
  while (tail[i] != '\0' && ++i < remain);
  if (i == remain) return false;
  m.types.resize(i-1);
  std::copy(head+1, head+i, m.types.begin());
  head += i + (4 - i % 4);
  remain = size - (head - data);
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": types = " << m.types << std::endl;
#endif // TNYOSC_DEBUG

  // extract data
  uint32_t int32;
  uint64_t int64;
  m.argv.resize(m.types.size());
  for (unsigned int j = 0; j < m.types.size(); j++) {
    m.argv[j].type = m.types[j];
    switch (m.types[j]) {
      case 'i':
      case 'f':
      case 'r':
        memcpy(&int32, head, 4);
        int32 = htonl(int32);
        memcpy(&m.argv[j].data.i, &int32, 4);
        m.argv[j].size = 4;
        head += 4;
        remain -= 4;
        break;
      case 'b':
        memcpy(&int32, head, 4);
        head += 4;
        remain -= 4;
        int32 = htonl(int32);
        if (int32 > remain) return false;
        m.argv[j].data.b = malloc(int32);
        memcpy(m.argv[j].data.b, head, int32);
        m.argv[j].size = int32;
        head += int32;
        remain -= int32;
        break;
      case 's':
      case 'S':
        tail = head;
        i = 0;
        while (tail[i] != '\0' && ++i < remain);
        m.argv[j].data.s = (char*)calloc(1, i + 1);
        memcpy(m.argv[j].data.s, head, i);
        m.argv[j].size = i;
        i += 4 - i % 4;
        head += i;
        remain -= i;
        break;
      case 'h':
      case 'd':
      case 't':
        memcpy(&int64, head, 8);
        int64 = htonll(int64);
        memcpy(&m.argv[j].data.i, &int64, 8);
        m.argv[j].size = 8;
        head += 8;
        remain -= 8;
        break;
      case 'c':
        memcpy(&int32, head, 4);
        m.argv[j].data.c = (char)htonl(int32);
        m.argv[j].size = 1;
        head += 4;
        remain -= 8;
        break;
      case 'm':
        memcpy(&m.argv[j].data.m, head, 4);
        m.argv[j].size = 4;
        head += 4;
        remain -= 4;
        break;
    }
  }

  messages.push_back(m);
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": success" << std::endl;
#endif // TNYOSC_DEBUG
  return true;
}

// pattern_match compares two strings and returns true or false depending on if
// they match according to OSC's pattern matching guideline
//
// OSC Pattern Matching Guideline:
//
//   1. '?' in the OSC Address Pattern matches any single character.
//   2. '*' in the OSC Address Pattern matches any sequence of zero or more
//      characters.
//   3. A string of characters in square brackets (e.g., "[string]") in the
//      OSC Address Pattern matches any character in the string. Inside square
//      brackets, the minus sign (-) and exclamation point (!) have special
//      meanings:
//        o two characters separated by a minus sign indicate the range of
//          characters between the given two in ASCII collating sequence. (A
//          minus sign at the end of the string has no special meaning.)
//        o An exclamation point at the beginning of a bracketed string
//          negates the sense of the list, meaning that the list matches any
//          character not in the list. (An exclamation point anywhere besides
//          the first character after the open bracket has no special meaning.)
//   4. A comma-separated list of strings enclosed in curly braces
//      (e.g., "{foo,bar}") in the OSC Address Pattern matches any of the
//      strings in the list.
//   5. Any other character in an OSC Address Pattern can match only the same
//      character.
//
// @param lhs incoming OSC address pattern to match it with rhs's pattern
// @param rhs method address pattern that may contain special characters
bool Dispatcher::pattern_match(const std::string& lhs, const std::string& rhs)
{
  bool negate = false;
  bool mismatched = false;
  std::string::const_iterator seq_tmp;
  std::string::const_iterator seq = lhs.begin();
  std::string::const_iterator seq_end = lhs.end();
  std::string::const_iterator pattern = rhs.begin();
  std::string::const_iterator pattern_end = rhs.end();
  while (seq != seq_end && pattern != pattern_end) {
    switch (*pattern) {
      case '?':
        break;
      case '*':
        // if * is the last pattern, return true
        if (++pattern == pattern_end) return true;
        while (*seq != *pattern && seq != seq_end) ++seq;
        // if seq reaches to the end without matching pattern
        if (seq == seq_end) return false;
        break;
      case '[':
        negate = false;
        mismatched = false;
        if (*(++pattern) == '!') {
          negate = true;
          ++pattern;
        }
        if (*(pattern+1) == '-') {
          // range matching
          char c_start = *pattern; ++pattern;
          //assert(*pattern == '-');
          char c_end = *(++pattern); ++pattern;
          //assert(*pattern == ']');
          // swap c_start and c_end if c_start is larger
          if (c_start > c_end) {
            char tmp = c_start;
            c_end = c_start;
            c_start = tmp;
          }
          mismatched = (c_start <= *seq && *seq <= c_end) ? negate : !negate;
          if (mismatched) return false;
        } else {
          // literal matching
          while (*pattern != ']') {
            if (*seq == *pattern) {
              mismatched = negate;
              break;
            }
            ++pattern;
          }
          if (mismatched) return false;
          while (*pattern != ']') ++pattern;
        }
        break;
      case '{':
        seq_tmp = seq;
        mismatched = true;
        while (*(++pattern) != '}') {
          // this assumes that there's no sequence like "{,a}" where ',' is
          // follows immediately after '{', which is illegal.
          if (*pattern == ',') {
            mismatched = false;
            break;
          } else if (*seq != *pattern) {
            // fast forward to the next ',' or '}'
            while (*(++pattern) != ',' && *pattern != '}');
            if (*pattern == '}') return false;
            // redo seq matching
            seq = seq_tmp;
            mismatched = true;
          } else {
            // matched
            ++seq;
            mismatched = false;
          }
        }
        if (mismatched) return false;
        while (*pattern != '}') ++pattern;
        --seq;
        break;
      default: // non-special character
        if (*seq != *pattern) return false;
        break;
    }
    ++seq; ++pattern;
  }
  if (seq == seq_end && pattern == pattern_end) return true;
  else return false;
}

<commit_msg>Use strndup instead of calloc/memcpy<commit_after>#include "tnyosc-dispatch.hpp"
#include "tnyosc.hpp"

#include <algorithm>
#include <iostream>

#include <assert.h>
#include <arpa/inet.h>
#include <stdio.h>

using namespace tnyosc;

void print_bytes(const unsigned char* bytes, size_t size)
{
  size_t i;
	for (i = 0; i < size; ++i) {
		printf("%02x ", bytes[i]);
		if (i % 16 == 15) {
			printf("\n");
		} else if (i % 4 == 3) {
      printf(" ");
    }
  }
  if (i % 16 != 0) {
    printf("\n");
  }
  printf("\n");
}

bool compare_callback_timetag(const CallbackRef first, const CallbackRef second)
{
  if (first->timetag.tv_sec == second->timetag.tv_sec) {
    return first->timetag.tv_usec <= second->timetag.tv_usec;
  } else {
    return first->timetag.tv_sec < second->timetag.tv_sec;
  }
}

Argument::Argument()
{
  type = 0;
  size = 0;
  memset(&data, 0, sizeof(data));
}

Argument::Argument(const Argument& a)
{
  type = a.type;
  size = a.size;
  switch(type) {
    case 's':
    case 'S':
      data.s = strndup(a.data.s, a.size);
      break;
    case'b':
      data.b = malloc(sizeof(size));
      memcpy(data.b, a.data.b, size);
      break;
    default:
      data = a.data;
      break;
  }
}

Argument::~Argument()
{
  switch(type) {
    case 's':
    case 'S':
    case'b':
      free(data.s);
  }
}

Argument& Argument::operator=(const Argument& a)
{
  if (this == &a) return *this;
  switch (type) {
    case 's':
    case 'S':
    case 'b':
      free(data.s);
  }

  type = a.type;
  size = a.size;
  switch(type) {
    case 's':
    case 'S':
      data.s = strndup(a.data.s, a.size);
      break;
    case'b':
      data.b = malloc(sizeof(size));
      memcpy(data.b, a.data.b, size);
      break;
    default:
      data = a.data;
  }
  return *this;
}

Dispatcher::Dispatcher()
  : methods_(0)
{
}

Dispatcher::~Dispatcher()
{
}

void Dispatcher::add_method(const char* address, const char* types,
    osc_method method, void* user_data)
{
  MethodTemplate m;
  m.address = address == NULL ? "" : address;
  m.types = types == NULL ? "" : types;
  m.user_data = user_data;
  m.method = method;
  methods_.push_back(m);
}

std::list<CallbackRef> Dispatcher::match_methods(const unsigned char* data, size_t size)
{
  std::list<ParsedMessage> parsed_messages;
  std::list<CallbackRef> callback_list;
  if (!decode_data(data, size, parsed_messages)) return callback_list;
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": decode success" << std::endl;
#endif // TNYOSC_DEBUG
  assert(parsed_messages.size() > 0);

  // iterate through all the messages and find matches with registered methods
  std::list<ParsedMessage>::iterator msg_iter = parsed_messages.begin();
  for (; msg_iter != parsed_messages.end(); ++msg_iter) {
#if TNYOSC_DEBUG
    std::cerr << __FUNCTION__ << ": matching " << msg_iter->address << "\n";
#endif // TNYOSC_DEBUG
    std::list<MethodTemplate>::const_iterator method_iter = methods_.begin();
    for (; method_iter != methods_.end(); ++method_iter) {
      if (pattern_match(msg_iter->address, method_iter->address)) {
#if TNYOSC_DEBUG
        std::cerr << "   matched " << method_iter->address << "\n";
#endif // TNYOSC_DEBUG
        // if a method specifies a type, make sure it matches
        if (method_iter->types.empty() ||
            !msg_iter->types.compare(method_iter->types)) {
          CallbackRef callback = CallbackRef(new Callback());
          callback->timetag = msg_iter->timetag;
          callback->address = msg_iter->address;
          callback->argv = msg_iter->argv;
          callback->user_data = method_iter->user_data;
          callback->method = method_iter->method;
          callback_list.push_back(callback);
        }
      }
    }
  }

  callback_list.sort(compare_callback_timetag);

  return callback_list;
}

struct timeval ntp_to_unixtime(uint32_t sec, uint32_t frac)
{
  // time between 1-1-1900 and 1-1-1950
  static const uint64_t epoch = 2208988800UL;

  struct timeval tv;
  if (sec == 0 && frac == 1) {
    memset(&tv, 0, sizeof(tv));
  } else {
    tv.tv_sec = sec - epoch;
    tv.tv_usec = (double)frac * 0.0002328306437080;
  }

  return tv;
}

const struct timeval Dispatcher::kZeroTimetag = {0, 0};

bool Dispatcher::decode_data(const unsigned char* data, size_t size,
    std::list<ParsedMessage>& messages, struct timeval timetag)
{
  if (!memcmp(data, "#bundle\0", 8)) {
    // found a bundle
#if TNYOSC_DEBUG
    std::cerr << __FUNCTION__ << ": bundle" << std::endl;
#endif // TNYOSC_DEBUG
    data += 8; size -= 8;

    uint32_t sec, frac;
    memcpy(&sec, data, 4); data += 4; size -= 4;
    memcpy(&frac, data, 4); data += 4; size -= 4;
    sec = ntohl(sec);
    frac = ntohl(frac);

    struct timeval new_timetag = ntp_to_unixtime(sec, frac);

    while (size != 0) {
      uint32_t seg_size;
      memcpy(&seg_size, data, 4); data += 4; size -= 4;
      seg_size = ntohl(seg_size);
      if (seg_size > size) return false;
      if (!decode_data(data, seg_size, messages, new_timetag)) return false;
      data += seg_size; size -= seg_size;
    }
  } else {
#if TNYOSC_DEBUG
    std::cerr << __FUNCTION__ << ": osc" << std::endl;
#endif // TNYOSC_DEBUG
    if (!decode_osc(data, size, messages, timetag)) return false;
  }

  return true;
}

bool Dispatcher::decode_osc(const unsigned char* data, size_t size,
    std::list<ParsedMessage>& messages, struct timeval timetag)
{
  const unsigned char* head;
  const unsigned char* tail;
  unsigned int i = 0;
  size_t remain = size;

  ParsedMessage m;
  m.timetag = timetag;

  // extract address
  head = tail = data;
  while (tail[i] != '\0' && ++i < remain);
  if (i == remain) return false;
  m.address.resize(i);
  std::copy(head, head+i, m.address.begin());
  head += i + (4 - i % 4);
  remain = size - (head - data);
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": address = " << m.address << std::endl;
#endif // TNYOSC_DEBUG

  // extract types
  i = 0;
  tail = head;
  if (head[i++] != ',') return false;
  while (tail[i] != '\0' && ++i < remain);
  if (i == remain) return false;
  m.types.resize(i-1);
  std::copy(head+1, head+i, m.types.begin());
  head += i + (4 - i % 4);
  remain = size - (head - data);
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": types = " << m.types << std::endl;
#endif // TNYOSC_DEBUG

  // extract data
  uint32_t int32;
  uint64_t int64;
  m.argv.resize(m.types.size());
  for (unsigned int j = 0; j < m.types.size(); j++) {
    m.argv[j].type = m.types[j];
    switch (m.types[j]) {
      case 'i':
      case 'f':
      case 'r':
        memcpy(&int32, head, 4);
        int32 = htonl(int32);
        memcpy(&m.argv[j].data.i, &int32, 4);
        m.argv[j].size = 4;
        head += 4;
        remain -= 4;
        break;
      case 'b':
        memcpy(&int32, head, 4);
        head += 4;
        remain -= 4;
        int32 = htonl(int32);
        if (int32 > remain) return false;
        m.argv[j].data.b = malloc(int32);
        memcpy(m.argv[j].data.b, head, int32);
        m.argv[j].size = int32;
        head += int32;
        remain -= int32;
        break;
      case 's':
      case 'S':
        tail = head;
        i = 0;
        while (tail[i] != '\0' && ++i < remain);
        m.argv[j].data.s = strndup((char*)head, i);
        m.argv[j].size = i;
        i += 4 - i % 4;
        head += i;
        remain -= i;
        break;
      case 'h':
      case 'd':
      case 't':
        memcpy(&int64, head, 8);
        int64 = htonll(int64);
        memcpy(&m.argv[j].data.i, &int64, 8);
        m.argv[j].size = 8;
        head += 8;
        remain -= 8;
        break;
      case 'c':
        memcpy(&int32, head, 4);
        m.argv[j].data.c = (char)htonl(int32);
        m.argv[j].size = 1;
        head += 4;
        remain -= 8;
        break;
      case 'm':
        memcpy(&m.argv[j].data.m, head, 4);
        m.argv[j].size = 4;
        head += 4;
        remain -= 4;
        break;
    }
  }

  messages.push_back(m);
#if TNYOSC_DEBUG
  std::cerr << __FUNCTION__ << ": success" << std::endl;
#endif // TNYOSC_DEBUG
  return true;
}

// pattern_match compares two strings and returns true or false depending on if
// they match according to OSC's pattern matching guideline
//
// OSC Pattern Matching Guideline:
//
//   1. '?' in the OSC Address Pattern matches any single character.
//   2. '*' in the OSC Address Pattern matches any sequence of zero or more
//      characters.
//   3. A string of characters in square brackets (e.g., "[string]") in the
//      OSC Address Pattern matches any character in the string. Inside square
//      brackets, the minus sign (-) and exclamation point (!) have special
//      meanings:
//        o two characters separated by a minus sign indicate the range of
//          characters between the given two in ASCII collating sequence. (A
//          minus sign at the end of the string has no special meaning.)
//        o An exclamation point at the beginning of a bracketed string
//          negates the sense of the list, meaning that the list matches any
//          character not in the list. (An exclamation point anywhere besides
//          the first character after the open bracket has no special meaning.)
//   4. A comma-separated list of strings enclosed in curly braces
//      (e.g., "{foo,bar}") in the OSC Address Pattern matches any of the
//      strings in the list.
//   5. Any other character in an OSC Address Pattern can match only the same
//      character.
//
// @param lhs incoming OSC address pattern to match it with rhs's pattern
// @param rhs method address pattern that may contain special characters
bool Dispatcher::pattern_match(const std::string& lhs, const std::string& rhs)
{
  bool negate = false;
  bool mismatched = false;
  std::string::const_iterator seq_tmp;
  std::string::const_iterator seq = lhs.begin();
  std::string::const_iterator seq_end = lhs.end();
  std::string::const_iterator pattern = rhs.begin();
  std::string::const_iterator pattern_end = rhs.end();
  while (seq != seq_end && pattern != pattern_end) {
    switch (*pattern) {
      case '?':
        break;
      case '*':
        // if * is the last pattern, return true
        if (++pattern == pattern_end) return true;
        while (*seq != *pattern && seq != seq_end) ++seq;
        // if seq reaches to the end without matching pattern
        if (seq == seq_end) return false;
        break;
      case '[':
        negate = false;
        mismatched = false;
        if (*(++pattern) == '!') {
          negate = true;
          ++pattern;
        }
        if (*(pattern+1) == '-') {
          // range matching
          char c_start = *pattern; ++pattern;
          //assert(*pattern == '-');
          char c_end = *(++pattern); ++pattern;
          //assert(*pattern == ']');
          // swap c_start and c_end if c_start is larger
          if (c_start > c_end) {
            char tmp = c_start;
            c_end = c_start;
            c_start = tmp;
          }
          mismatched = (c_start <= *seq && *seq <= c_end) ? negate : !negate;
          if (mismatched) return false;
        } else {
          // literal matching
          while (*pattern != ']') {
            if (*seq == *pattern) {
              mismatched = negate;
              break;
            }
            ++pattern;
          }
          if (mismatched) return false;
          while (*pattern != ']') ++pattern;
        }
        break;
      case '{':
        seq_tmp = seq;
        mismatched = true;
        while (*(++pattern) != '}') {
          // this assumes that there's no sequence like "{,a}" where ',' is
          // follows immediately after '{', which is illegal.
          if (*pattern == ',') {
            mismatched = false;
            break;
          } else if (*seq != *pattern) {
            // fast forward to the next ',' or '}'
            while (*(++pattern) != ',' && *pattern != '}');
            if (*pattern == '}') return false;
            // redo seq matching
            seq = seq_tmp;
            mismatched = true;
          } else {
            // matched
            ++seq;
            mismatched = false;
          }
        }
        if (mismatched) return false;
        while (*pattern != '}') ++pattern;
        --seq;
        break;
      default: // non-special character
        if (*seq != *pattern) return false;
        break;
    }
    ++seq; ++pattern;
  }
  if (seq == seq_end && pattern == pattern_end) return true;
  else return false;
}

<|endoftext|>


<commit_before>/** @file
 *
 *  Basic implementation of RFC 4122, see
 *      https://www.ietf.org/rfc/rfc4122.txt
 *
 *  @section license License
 *
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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 <openssl/rand.h>

#include "tscore/ink_error.h"
#include "tscore/ink_uuid.h"

void
ATSUuid::initialize(TSUuidVersion v)
{
  switch (v) {
  case TS_UUID_UNDEFINED:
    ink_abort("Don't initialize to undefined UUID variant!");
    break;
  case TS_UUID_V1:
  case TS_UUID_V2:
  case TS_UUID_V3:
  case TS_UUID_V5:
    ink_zero(_uuid.data); // Not properly implemented yet, so set it to the Nil UUID
    break;
  case TS_UUID_V4:
    RAND_bytes(_uuid.data, sizeof(_uuid.data));
    _uuid.clockSeqAndReserved = (uint8_t)((_uuid.clockSeqAndReserved & 0x3F) | 0x80);
    _uuid.timeHighAndVersion  = (uint16_t)((_uuid.timeHighAndVersion & 0x0FFF) | 0x4000);

    break;
  }

  _version = _toString(_string) ? v : TS_UUID_UNDEFINED;
}

// Copy assignment
ATSUuid &
ATSUuid::operator=(const ATSUuid &other)
{
  memcpy(_uuid.data, other._uuid.data, sizeof(_uuid.data));
  memcpy(_string, other._string, sizeof(_string));
  _version = other._version;

  return *this;
}

bool
ATSUuid::parseString(const char *str)
{
  int cnt = sscanf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &_uuid.timeLow, &_uuid.timeMid,
                   &_uuid.timeHighAndVersion, &_uuid.clockSeqAndReserved, &_uuid.clockSeqLow, &_uuid.node[0], &_uuid.node[1],
                   &_uuid.node[2], &_uuid.node[3], &_uuid.node[4], &_uuid.node[5]);

  if ((11 == cnt) && _toString(_string)) {
    switch (_uuid.timeHighAndVersion >> 12) {
    case 1:
      _version = TS_UUID_V1;
      break;
    case 2:
      _version = TS_UUID_V2;
      break;
    case 3:
      _version = TS_UUID_V3;
      break;
    case 4:
      _version = TS_UUID_V4;
      break;
    case 5:
      _version = TS_UUID_V5;
      break;
    default:
      _version = TS_UUID_UNDEFINED;
      break;
    }
  } else {
    _version = TS_UUID_UNDEFINED;
  }

  return (TS_UUID_UNDEFINED != _version);
}
<commit_msg>Don't assign if this and other are the same object<commit_after>/** @file
 *
 *  Basic implementation of RFC 4122, see
 *      https://www.ietf.org/rfc/rfc4122.txt
 *
 *  @section license License
 *
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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 <openssl/rand.h>

#include "tscore/ink_error.h"
#include "tscore/ink_uuid.h"

void
ATSUuid::initialize(TSUuidVersion v)
{
  switch (v) {
  case TS_UUID_UNDEFINED:
    ink_abort("Don't initialize to undefined UUID variant!");
    break;
  case TS_UUID_V1:
  case TS_UUID_V2:
  case TS_UUID_V3:
  case TS_UUID_V5:
    ink_zero(_uuid.data); // Not properly implemented yet, so set it to the Nil UUID
    break;
  case TS_UUID_V4:
    RAND_bytes(_uuid.data, sizeof(_uuid.data));
    _uuid.clockSeqAndReserved = (uint8_t)((_uuid.clockSeqAndReserved & 0x3F) | 0x80);
    _uuid.timeHighAndVersion  = (uint16_t)((_uuid.timeHighAndVersion & 0x0FFF) | 0x4000);

    break;
  }

  _version = _toString(_string) ? v : TS_UUID_UNDEFINED;
}

// Copy assignment
ATSUuid &
ATSUuid::operator=(const ATSUuid &other)
{
  if (this != &other) { // Self assignment guard
    memcpy(_uuid.data, other._uuid.data, sizeof(_uuid.data));
    memcpy(_string, other._string, sizeof(_string));
    _version = other._version;
  }

  return *this;
}

bool
ATSUuid::parseString(const char *str)
{
  int cnt = sscanf(str, "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", &_uuid.timeLow, &_uuid.timeMid,
                   &_uuid.timeHighAndVersion, &_uuid.clockSeqAndReserved, &_uuid.clockSeqLow, &_uuid.node[0], &_uuid.node[1],
                   &_uuid.node[2], &_uuid.node[3], &_uuid.node[4], &_uuid.node[5]);

  if ((11 == cnt) && _toString(_string)) {
    switch (_uuid.timeHighAndVersion >> 12) {
    case 1:
      _version = TS_UUID_V1;
      break;
    case 2:
      _version = TS_UUID_V2;
      break;
    case 3:
      _version = TS_UUID_V3;
      break;
    case 4:
      _version = TS_UUID_V4;
      break;
    case 5:
      _version = TS_UUID_V5;
      break;
    default:
      _version = TS_UUID_UNDEFINED;
      break;
    }
  } else {
    _version = TS_UUID_UNDEFINED;
  }

  return (TS_UUID_UNDEFINED != _version);
}
<|endoftext|>


<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2013 Istituto Italiano di Tecnologia
*  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 Willow Garage 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.
*********************************************************************/

/* Author: Silvio Traversaro */

#include <cstdlib>

#include "kdl_format_io/symoro_par_model.hpp"
#include "kdl_format_io/symoro_par_import.hpp"

#include "kdl_format_io/urdf_export.hpp"

using namespace KDL;
using namespace std;
using namespace kdl_format_io;

int main(int argc, char** argv)
{
  if (argc != 3){
    std::cerr << "Usage: par2urdf robot.par robot.urdf" << std::endl;
    return -1;
  }

  symoro_par_model mdl;

  if( !parModelFromFile(argv[1],mdl) ) {cerr << "Could not parse SYMORO par robot model" << endl; return EXIT_FAILURE;}

  std::cout << "Extracted par file" << std::endl;
  std::cout << mdl.toString() << std::endl;

  Tree my_tree;
  if (!treeFromSymoroParFile(argv[1],my_tree,true))
  {cerr << "Could not generate robot model and extract kdl tree" << endl; return EXIT_FAILURE;}

  if( !treeToUrdfFile(argv[2],my_tree,"par_file_robot") )
  {cerr << "Could not export KDL::Tree to URDF file" << endl; return EXIT_FAILURE;}

  return EXIT_SUCCESS;
}

<commit_msg>Added missing include<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2013 Istituto Italiano di Tecnologia
*  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 Willow Garage 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.
*********************************************************************/

/* Author: Silvio Traversaro */

#include <cstdlib>

#include "kdl_format_io/symoro_par_model.hpp"
#include "kdl_format_io/symoro_par_import.hpp"

#include "kdl_format_io/urdf_export.hpp"
#include <kdl/tree.hpp>

using namespace KDL;
using namespace std;
using namespace kdl_format_io;

int main(int argc, char** argv)
{
  if (argc != 3){
    std::cerr << "Usage: par2urdf robot.par robot.urdf" << std::endl;
    return -1;
  }

  symoro_par_model mdl;

  if( !parModelFromFile(argv[1],mdl) ) {cerr << "Could not parse SYMORO par robot model" << endl; return EXIT_FAILURE;}

  std::cout << "Extracted par file" << std::endl;
  std::cout << mdl.toString() << std::endl;

  Tree my_tree;
  if (!treeFromSymoroParFile(argv[1],my_tree,true))
  {cerr << "Could not generate robot model and extract kdl tree" << endl; return EXIT_FAILURE;}

  if( !treeToUrdfFile(argv[2],my_tree,"par_file_robot") )
  {cerr << "Could not export KDL::Tree to URDF file" << endl; return EXIT_FAILURE;}

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>/*
 * WebRadio web-based Software Defined Radio
 *
 * Copyright (C) 2013 Mike Stirling
 *
 * This file is part of WebRadio (http://www.mike-stirling.com/webradio)
 *
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <sstream>

#include "httpserver.h"
#include "debug.h"

#define DEFAULT_URL_SCHEME		"http://"

using namespace std;

int HttpRequestHandler::populate_args(void *self, enum MHD_ValueKind kind,
	const char *key, const char *value)
{
	switch (kind) {
	case MHD_HEADER_KIND:
		((HttpRequestHandler*)self)->_requestHeaders[key] = value;
		break;
	case MHD_COOKIE_KIND:
		((HttpRequestHandler*)self)->_requestCookies[key] = value;
		break;
	case MHD_GET_ARGUMENT_KIND:
		((HttpRequestHandler*)self)->_requestArgs[key] = value;
		break;
	default:
		return MHD_NO;
	}
	return MHD_YES;
}

void HttpRequestHandler::doError(unsigned short status)
{
	stringstream ss;
	string errorstr;

	switch (status) {
	case 400: errorstr = "Bad request"; break;
	case 401: errorstr = "Unauthorized"; break;
	case 403: errorstr = "Forbidden"; break;
	case 404: errorstr = "Not found"; break;
	case 405: errorstr = "Method not allowed"; break;
	case 406: errorstr = "Not acceptable"; break;
	default:
		errorstr = "An error occurred";
	}

	ss << "<!DOCTYPE html>\n" <<
		"\n" <<
		"<title>Error " << status << "</title>\n" <<
		"\n" <<
		"
Error " << status << "
\n" <<
		"
" << errorstr << "
\n" <<
		"\n" <<
		"\n";

	string response = ss.str();
	_data.insert(_data.end(), response.begin(), response.end());
	_contentType = "text/html";
}

/*******************************/

int HttpServer::handlerCallback(void *arg,
		struct MHD_Connection *conn,
		const char *path,
		const char *method,
		const char *version,
		const char *upload_data,
		size_t *upload_data_size,
		void **ptr)
{
	HttpServer *self = (HttpServer*)arg;
	HttpRequestHandler *handler = NULL;
	struct MHD_Response *response;
	int rc;
	unsigned short status = MHD_HTTP_OK;
	const char *host;
	vector<char> *upload_buffer;
	vector<string> url_wildcards;

	/* Create vector for upload buffer if required */
	if (*ptr == NULL) {
		*ptr = new vector<char>;
		return MHD_YES;
	}
	upload_buffer = (vector<char>*)*ptr;

	/* Get POST data if present */
	if (*upload_data_size > 0) {
		LOG_DEBUG("adding %lu bytes\n", *upload_data_size);
		/* Append to upload_buffer */
		upload_buffer->insert(upload_buffer->end(),
			upload_data, upload_data + *upload_data_size);
		*upload_data_size = 0;
		return MHD_YES;
	}

	/* Sanity checks - we expect a Host header */
	host = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "Host");
	if (host == NULL) {
		LOG_ERROR("Missing HTTP Host header\n");
		status = MHD_HTTP_BAD_REQUEST;
	}

	/* FIXME: Check Accept header (for GET) - return 406 Not Acceptable,
	 * Check Content-type header (for POST) - return 415 Unsupported Media Type */

	LOG_DEBUG("%s %s\n", method, path);
	if (status == MHD_HTTP_OK) {
		/* Look up handler for requested URL */
		handler = self->findHandler(path, url_wildcards);
		if (handler == NULL)
			status = MHD_HTTP_NOT_FOUND;
	}

	if (handler == NULL) {
		/* Use default handler */
		handler = HttpRequestHandler::factory();
	}

	/* Populate query parameters for request handler */
	MHD_get_connection_values(conn, MHD_HEADER_KIND,
			HttpRequestHandler::populate_args, handler);
	MHD_get_connection_values(conn, MHD_COOKIE_KIND,
			HttpRequestHandler::populate_args, handler);
	MHD_get_connection_values(conn, MHD_GET_ARGUMENT_KIND,
			HttpRequestHandler::populate_args, handler);

	/* Don't call the handler if a method already occurred */
	if (status == MHD_HTTP_OK) {
		string strmethod(method);
		if (strmethod == "GET")
			status = handler->doGet(url_wildcards, *upload_buffer);
		else if (strmethod == "PUT")
			status = handler->doPut(url_wildcards, *upload_buffer);
		else if (strmethod == "POST")
			status = handler->doPost(url_wildcards, *upload_buffer);
		else if (strmethod == "DELETE")
			status = handler->doDelete(url_wildcards, *upload_buffer);
		else
			status = MHD_HTTP_METHOD_NOT_ALLOWED;
	}

	if (status >= 300) {
		/* Generate error page instead */
		handler->doError(status);
	}

	/* Build response */
	LOG_DEBUG("status = %u\n", status);
	if (handler->isPersistent()) {
		/* The handler wants to be called back (streaming) */
		response = MHD_create_response_from_callback(
				MHD_SIZE_UNKNOWN, 512,
				&HttpRequestHandler::contentReaderCallback,
				(void*)handler,
				&HttpRequestHandler::freeContentReaderCallback);
	} else {
		/* Send static response */
		response = MHD_create_response_from_buffer(
				handler->response().size(),
				(void*)handler->response().data(),
				MHD_RESPMEM_MUST_COPY); /* FIXME: Can we keep the handler object for a while? */
	}

	/* Handle redirects */
	if (!handler->location().empty()) {
		string redirect_url;

		/* Only add Location: header if the handler returned something */
		LOG_DEBUG("Handler supplied location: %s\n", handler->location().c_str());

		/* Assemble the full URL */
		redirect_url = string(DEFAULT_URL_SCHEME) + string(host) + handler->location();
		LOG_DEBUG("Full URL for redirect: %s\n", redirect_url.c_str());
		MHD_add_response_header(response, MHD_HTTP_HEADER_LOCATION, redirect_url.c_str());
	}

	/* Add any other handler-specific headers */
	map<string, string> extra_headers = handler->responseHeaders();
	map<string, string>::iterator iter;
	for (iter = extra_headers.begin(); iter != extra_headers.end(); iter++) {
		LOG_DEBUG("Extra header %s: %s\n", iter->first.c_str(), iter->second.c_str());
		MHD_add_response_header(response, iter->first.c_str(), iter->second.c_str());
	}

	/* Add generic headers */
	MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, handler->contentType().c_str());
	MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
	{
		char keepalive[32];
		snprintf(keepalive, 32, "timeout=%d; max=%d", HTTP_CONNECTION_TIMEOUT, HTTP_CONNECTION_LIMIT);
		MHD_add_response_header(response, "Keep-Alive", keepalive);
	}
	MHD_add_response_header(response, MHD_HTTP_HEADER_CONNECTION, "keep-alive");
	MHD_add_response_header(response, MHD_HTTP_HEADER_SERVER, HTTP_SERVER_NAME);

	/* If we return 405 then we have to include an Allows: header */
	if (status == MHD_HTTP_METHOD_NOT_ALLOWED)
		MHD_add_response_header(response, MHD_HTTP_HEADER_ALLOW, handler->allows(url_wildcards).c_str());

	/* Clean up */
	if (!handler->isPersistent())
		delete handler; // Handler can ask to stick around (for streaming), else we delete it
	if (upload_buffer)
		delete upload_buffer;
	*ptr = NULL;

	/* Send the response */
	rc = MHD_queue_response(conn, status, response);
	MHD_destroy_response(response);
	return rc;
}

HttpServer::HttpServer(const int _port) : port(_port), d(NULL)
{

}

HttpServer::~HttpServer()
{
	if (d) {
		LOG_INFO("Stopping HTTP server\n");
		MHD_stop_daemon(d);
	}
}

bool HttpServer::start()
{
	struct MHD_OptionItem opts[] = {
		{ MHD_OPTION_CONNECTION_LIMIT,		HTTP_CONNECTION_LIMIT,		NULL },
		{ MHD_OPTION_CONNECTION_TIMEOUT,	HTTP_CONNECTION_TIMEOUT,	NULL },
		{ MHD_OPTION_END, 0, NULL }
	};

	d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
		port,
		NULL, /* access control callback */
		NULL, /* argument to above */
 		&handlerCallback, /* default handler */
		this, /* argument to above */
		MHD_OPTION_ARRAY, opts,
		MHD_OPTION_END);
	if (d == NULL) {
		LOG_ERROR("Couldn't start http daemon\n");
		return false;
	}
	LOG_INFO("HTTP interface started on port %hu\n", port);
	return true;
}

void HttpServer::registerHandler(const string &pattern, HttpRequestHandlerFactory factory, void *arg)
{
	istringstream iss(pattern);
	string part;
	HttpUrlTree *node = &handlerTree;

	/* Split path on slashes and build node tree */
	while (std::getline(iss, part, '/'))
		node = &node->next[part];
	node->setHandler(factory, arg);
	LOG_DEBUG("Registered handler for URL: %s\n", pattern.c_str());
}

HttpRequestHandler* HttpServer::findHandler(const string &path, vector<string> &wildcards)
{
	istringstream iss(path);
	string part;
	HttpUrlTree *node = &handlerTree;

	wildcards.clear();

	/* Split requested URL on slashes and walk tree for a match */
	while (std::getline(iss, part, '/')) {
		if (part.empty())
			continue; // skip null path components

		if (node->next.count(part) == 0) {
			if (node->next.count("*") == 0) {
				if (node->next.count("**") == 0) {
					return NULL; // No match
				} else {
					/* Double wildcard matches the rest of the URL.
					 * Stop scanning and return the remainder as the final
					 * wildcard component. */
					string remainder;
					getline(iss, remainder);
					if (remainder.empty())
						/* No further path components after this one - trailing
						 * slash is suppressed */
						wildcards.push_back(part);
					else
						wildcards.push_back(part + "/" + remainder);
					node = &node->next.at("**");
					break;
				}
			} else {
				// Matches on wildcard
				wildcards.push_back(part);
				node = &node->next.at("*");
			}
		} else {
			// Matches on specific pattern
			node = &node->next.at(part);
		}
	}

	HttpRequestHandler *handler = NULL;
	if (node->factory()) {
		/* Instantiate a handler using the factory and set its argument
		 * for those handlers that use it */
		handler = (node->factory())();
		handler->setArg(node->arg());
	}

	return handler;
}
<commit_msg>Don't assume size_t will be 64-bits wide<commit_after>/*
 * WebRadio web-based Software Defined Radio
 *
 * Copyright (C) 2013 Mike Stirling
 *
 * This file is part of WebRadio (http://www.mike-stirling.com/webradio)
 *
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <sstream>

#include "httpserver.h"
#include "debug.h"

#define DEFAULT_URL_SCHEME		"http://"

using namespace std;

int HttpRequestHandler::populate_args(void *self, enum MHD_ValueKind kind,
	const char *key, const char *value)
{
	switch (kind) {
	case MHD_HEADER_KIND:
		((HttpRequestHandler*)self)->_requestHeaders[key] = value;
		break;
	case MHD_COOKIE_KIND:
		((HttpRequestHandler*)self)->_requestCookies[key] = value;
		break;
	case MHD_GET_ARGUMENT_KIND:
		((HttpRequestHandler*)self)->_requestArgs[key] = value;
		break;
	default:
		return MHD_NO;
	}
	return MHD_YES;
}

void HttpRequestHandler::doError(unsigned short status)
{
	stringstream ss;
	string errorstr;

	switch (status) {
	case 400: errorstr = "Bad request"; break;
	case 401: errorstr = "Unauthorized"; break;
	case 403: errorstr = "Forbidden"; break;
	case 404: errorstr = "Not found"; break;
	case 405: errorstr = "Method not allowed"; break;
	case 406: errorstr = "Not acceptable"; break;
	default:
		errorstr = "An error occurred";
	}

	ss << "<!DOCTYPE html>\n" <<
		"\n" <<
		"<title>Error " << status << "</title>\n" <<
		"\n" <<
		"
Error " << status << "
\n" <<
		"
" << errorstr << "
\n" <<
		"\n" <<
		"\n";

	string response = ss.str();
	_data.insert(_data.end(), response.begin(), response.end());
	_contentType = "text/html";
}

/*******************************/

int HttpServer::handlerCallback(void *arg,
		struct MHD_Connection *conn,
		const char *path,
		const char *method,
		const char *version,
		const char *upload_data,
		size_t *upload_data_size,
		void **ptr)
{
	HttpServer *self = (HttpServer*)arg;
	HttpRequestHandler *handler = NULL;
	struct MHD_Response *response;
	int rc;
	unsigned short status = MHD_HTTP_OK;
	const char *host;
	vector<char> *upload_buffer;
	vector<string> url_wildcards;

	/* Create vector for upload buffer if required */
	if (*ptr == NULL) {
		*ptr = new vector<char>;
		return MHD_YES;
	}
	upload_buffer = (vector<char>*)*ptr;

	/* Get POST data if present */
	if (*upload_data_size > 0) {
		LOG_DEBUG("adding %u bytes\n", (unsigned int)*upload_data_size);
		/* Append to upload_buffer */
		upload_buffer->insert(upload_buffer->end(),
			upload_data, upload_data + *upload_data_size);
		*upload_data_size = 0;
		return MHD_YES;
	}

	/* Sanity checks - we expect a Host header */
	host = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "Host");
	if (host == NULL) {
		LOG_ERROR("Missing HTTP Host header\n");
		status = MHD_HTTP_BAD_REQUEST;
	}

	/* FIXME: Check Accept header (for GET) - return 406 Not Acceptable,
	 * Check Content-type header (for POST) - return 415 Unsupported Media Type */

	LOG_DEBUG("%s %s\n", method, path);
	if (status == MHD_HTTP_OK) {
		/* Look up handler for requested URL */
		handler = self->findHandler(path, url_wildcards);
		if (handler == NULL)
			status = MHD_HTTP_NOT_FOUND;
	}

	if (handler == NULL) {
		/* Use default handler */
		handler = HttpRequestHandler::factory();
	}

	/* Populate query parameters for request handler */
	MHD_get_connection_values(conn, MHD_HEADER_KIND,
			HttpRequestHandler::populate_args, handler);
	MHD_get_connection_values(conn, MHD_COOKIE_KIND,
			HttpRequestHandler::populate_args, handler);
	MHD_get_connection_values(conn, MHD_GET_ARGUMENT_KIND,
			HttpRequestHandler::populate_args, handler);

	/* Don't call the handler if a method already occurred */
	if (status == MHD_HTTP_OK) {
		string strmethod(method);
		if (strmethod == "GET")
			status = handler->doGet(url_wildcards, *upload_buffer);
		else if (strmethod == "PUT")
			status = handler->doPut(url_wildcards, *upload_buffer);
		else if (strmethod == "POST")
			status = handler->doPost(url_wildcards, *upload_buffer);
		else if (strmethod == "DELETE")
			status = handler->doDelete(url_wildcards, *upload_buffer);
		else
			status = MHD_HTTP_METHOD_NOT_ALLOWED;
	}

	if (status >= 300) {
		/* Generate error page instead */
		handler->doError(status);
	}

	/* Build response */
	LOG_DEBUG("status = %u\n", status);
	if (handler->isPersistent()) {
		/* The handler wants to be called back (streaming) */
		response = MHD_create_response_from_callback(
				MHD_SIZE_UNKNOWN, 512,
				&HttpRequestHandler::contentReaderCallback,
				(void*)handler,
				&HttpRequestHandler::freeContentReaderCallback);
	} else {
		/* Send static response */
		response = MHD_create_response_from_buffer(
				handler->response().size(),
				(void*)handler->response().data(),
				MHD_RESPMEM_MUST_COPY); /* FIXME: Can we keep the handler object for a while? */
	}

	/* Handle redirects */
	if (!handler->location().empty()) {
		string redirect_url;

		/* Only add Location: header if the handler returned something */
		LOG_DEBUG("Handler supplied location: %s\n", handler->location().c_str());

		/* Assemble the full URL */
		redirect_url = string(DEFAULT_URL_SCHEME) + string(host) + handler->location();
		LOG_DEBUG("Full URL for redirect: %s\n", redirect_url.c_str());
		MHD_add_response_header(response, MHD_HTTP_HEADER_LOCATION, redirect_url.c_str());
	}

	/* Add any other handler-specific headers */
	map<string, string> extra_headers = handler->responseHeaders();
	map<string, string>::iterator iter;
	for (iter = extra_headers.begin(); iter != extra_headers.end(); iter++) {
		LOG_DEBUG("Extra header %s: %s\n", iter->first.c_str(), iter->second.c_str());
		MHD_add_response_header(response, iter->first.c_str(), iter->second.c_str());
	}

	/* Add generic headers */
	MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, handler->contentType().c_str());
	MHD_add_response_header(response, "Access-Control-Allow-Origin", "*");
	{
		char keepalive[32];
		snprintf(keepalive, 32, "timeout=%d; max=%d", HTTP_CONNECTION_TIMEOUT, HTTP_CONNECTION_LIMIT);
		MHD_add_response_header(response, "Keep-Alive", keepalive);
	}
	MHD_add_response_header(response, MHD_HTTP_HEADER_CONNECTION, "keep-alive");
	MHD_add_response_header(response, MHD_HTTP_HEADER_SERVER, HTTP_SERVER_NAME);

	/* If we return 405 then we have to include an Allows: header */
	if (status == MHD_HTTP_METHOD_NOT_ALLOWED)
		MHD_add_response_header(response, MHD_HTTP_HEADER_ALLOW, handler->allows(url_wildcards).c_str());

	/* Clean up */
	if (!handler->isPersistent())
		delete handler; // Handler can ask to stick around (for streaming), else we delete it
	if (upload_buffer)
		delete upload_buffer;
	*ptr = NULL;

	/* Send the response */
	rc = MHD_queue_response(conn, status, response);
	MHD_destroy_response(response);
	return rc;
}

HttpServer::HttpServer(const int _port) : port(_port), d(NULL)
{

}

HttpServer::~HttpServer()
{
	if (d) {
		LOG_INFO("Stopping HTTP server\n");
		MHD_stop_daemon(d);
	}
}

bool HttpServer::start()
{
	struct MHD_OptionItem opts[] = {
		{ MHD_OPTION_CONNECTION_LIMIT,		HTTP_CONNECTION_LIMIT,		NULL },
		{ MHD_OPTION_CONNECTION_TIMEOUT,	HTTP_CONNECTION_TIMEOUT,	NULL },
		{ MHD_OPTION_END, 0, NULL }
	};

	d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
		port,
		NULL, /* access control callback */
		NULL, /* argument to above */
 		&handlerCallback, /* default handler */
		this, /* argument to above */
		MHD_OPTION_ARRAY, opts,
		MHD_OPTION_END);
	if (d == NULL) {
		LOG_ERROR("Couldn't start http daemon\n");
		return false;
	}
	LOG_INFO("HTTP interface started on port %hu\n", port);
	return true;
}

void HttpServer::registerHandler(const string &pattern, HttpRequestHandlerFactory factory, void *arg)
{
	istringstream iss(pattern);
	string part;
	HttpUrlTree *node = &handlerTree;

	/* Split path on slashes and build node tree */
	while (std::getline(iss, part, '/'))
		node = &node->next[part];
	node->setHandler(factory, arg);
	LOG_DEBUG("Registered handler for URL: %s\n", pattern.c_str());
}

HttpRequestHandler* HttpServer::findHandler(const string &path, vector<string> &wildcards)
{
	istringstream iss(path);
	string part;
	HttpUrlTree *node = &handlerTree;

	wildcards.clear();

	/* Split requested URL on slashes and walk tree for a match */
	while (std::getline(iss, part, '/')) {
		if (part.empty())
			continue; // skip null path components

		if (node->next.count(part) == 0) {
			if (node->next.count("*") == 0) {
				if (node->next.count("**") == 0) {
					return NULL; // No match
				} else {
					/* Double wildcard matches the rest of the URL.
					 * Stop scanning and return the remainder as the final
					 * wildcard component. */
					string remainder;
					getline(iss, remainder);
					if (remainder.empty())
						/* No further path components after this one - trailing
						 * slash is suppressed */
						wildcards.push_back(part);
					else
						wildcards.push_back(part + "/" + remainder);
					node = &node->next.at("**");
					break;
				}
			} else {
				// Matches on wildcard
				wildcards.push_back(part);
				node = &node->next.at("*");
			}
		} else {
			// Matches on specific pattern
			node = &node->next.at(part);
		}
	}

	HttpRequestHandler *handler = NULL;
	if (node->factory()) {
		/* Instantiate a handler using the factory and set its argument
		 * for those handlers that use it */
		handler = (node->factory())();
		handler->setArg(node->arg());
	}

	return handler;
}
<|endoftext|>


<commit_before>#include <world/world.hpp>

namespace MCPP {

	bool BlockID::operator == (const BlockID & other) const noexcept {

		return (
			(X==other.X) &&
			(Y==other.Y) &&
			(Z==other.Z) &&
			(Dimension==other.Dimension)
		);

	}

	bool BlockID::operator != (const BlockID & other) const noexcept {

		return !(*this==other);

	}

	ColumnID BlockID::GetContaining () const noexcept {

		ColumnID retr{
			X/16,
			Z/16,
			Dimension
		};

		if (
			(X<0) &&
			((X%16)!=0)
		) --retr.X;
		if (
			(Z<0) &&
			((Z%16)!=0)
		) --retr.Z;

		return retr;

	}

	Word BlockID::GetOffset () const noexcept {

		Int32 x=X%16;
		if (X<0) x=16-(x*-1);
		Int32 z=Z%16;
		if (Z<0) z=16-(z*-1);

		return static_cast<Word>(x)+(static_cast<Word>(z)*16)+(static_cast<Word>(Y)*16*16);

	}

	bool BlockID::IsContainedBy (const ColumnID & column) const noexcept {

		Int32 x=X/16;
		if (X<0) --x;

		if (column.X!=x) return false;

		Int32 z=Z/16;
		if (Z<0) --z;

		return !(
			(column.Z==z) &&
			(column.Dimension==Dimension)
		);

	}

}
<commit_msg>BlockID Tweak<commit_after>#include <world/world.hpp>

namespace MCPP {

	bool BlockID::operator == (const BlockID & other) const noexcept {

		return (
			(X==other.X) &&
			(Y==other.Y) &&
			(Z==other.Z) &&
			(Dimension==other.Dimension)
		);

	}

	bool BlockID::operator != (const BlockID & other) const noexcept {

		return !(*this==other);

	}

	ColumnID BlockID::GetContaining () const noexcept {

		ColumnID retr{
			X/16,
			Z/16,
			Dimension
		};

		if (
			(X<0) &&
			((X%16)!=0)
		) --retr.X;
		if (
			(Z<0) &&
			((Z%16)!=0)
		) --retr.Z;

		return retr;

	}

	Word BlockID::GetOffset () const noexcept {

		Int32 x=X%16;
		if (X<0) x=16-(x*-1);
		Int32 z=Z%16;
		if (Z<0) z=16-(z*-1);

		return static_cast<Word>(x)+(static_cast<Word>(z)*16)+(static_cast<Word>(Y)*16*16);

	}

	bool BlockID::IsContainedBy (const ColumnID & column) const noexcept {

		if (column.Dimension!=Dimension) return false;

		Int32 x=X/16;
		if (X<0) --x;

		if (column.X!=x) return false;

		Int32 z=Z/16;
		if (Z<0) --z;

		return column.Z==z;

	}

}
<|endoftext|>


<commit_before>#include <Beacon.h>
#include <sys/time.h>
#include "HCIDumpParser.h"

// Uncomment to publish the raw byte[] for the beacon, otherwise, properties are sent
//#define SEND_BINARY_DATA

static int64_t currentMilliseconds() {
    timeval now;
    gettimeofday(&now, nullptr);

    int64_t nowMS = now.tv_sec;
    nowMS *= 1000;
    nowMS += now.tv_usec/1000;
    return nowMS;
}

void HCIDumpParser::processHCI(HCIDumpCommand& parseCommand) {
    HCIDumpParser::parseCommand = &parseCommand;
    string clientID(parseCommand.getClientID());
    if(clientID.empty())
        clientID = parseCommand.getScannerID();
    publisher = MsgPublisher::create(parseCommand.getPubType(), parseCommand.getBrokerURL(), clientID, "", "");
    if(parseCommand.isAnalyzeMode()) {
        begin = currentMilliseconds();
        end = begin + parseCommand.getAnalyzeWindow();
        printf("Running in analyze mode, window=%d seconds, begin=%lld\n", parseCommand.getAnalyzeWindow(), begin);
    }
    else if(!parseCommand.isSkipPublish()) {
        publisher->setUseTopics(!parseCommand.isUseQueues());
        publisher->setDestinationName(parseCommand.getDestinationName());
        if(batchCount > 0) {
            publisher->setUseTransactions(true);
            printf("Enabled transactions\n");
        }
        publisher->start(parseCommand.isAsyncMode());
    }
    else {
        printf("Skipping publish of parsed beacons\n");
    }

    char cdev = parseCommand.getHciDev().at(parseCommand.getHciDev().size()-1);
    int device = cdev - '0';
    scan_frames(device,  beacon_event_callback);
}

void HCIDumpParser::beaconEvent(const beacon_info *info) {
    Beacon beacon(parseCommand->getScannerID(), info->uuid, info->code, info->manufacturer, info->major, info->minor,
            info->power, info->calibrated_power, info->rssi, info->time);
    vector<byte> msg = beacon.toByteMsg();
    // Check for heartbeat
    bool isHeartbeat = scannerUUID.compare(info->uuid) == 0;
    if(isHeartbeat)
        beacon.setMessageType(BeconEventType::SCANNER_HEARTBEAT);
    if(parseCommand->isAnalyzeMode()) {
        updateBeaconCounts(info);
    }
    else if(!parseCommand->isSkipPublish()) {
        if(batchCount > 0) {
            // Overwrite last event if it is a heartbeat and this is as well
            if(isHeartbeat && events.size() > 0 && events.back().getMessageType() == BeconEventType::SCANNER_HEARTBEAT)
                events.pop_back();
            events.push_back(beacon);
            if(shouldSendMessages()) {
#ifdef PRINT_DEBUG
printf("Sending msg batch, size=%d\n", events.size());
#endif
                publisher->publish(events);
                events.clear();
            } else {
#ifdef PRINT_DEBUG
printf("Batched msg, size=%d\n", events.size());
#endif
            }
        } else if(isHeartbeat) {
#ifdef PRINT_DEBUG
printf("Sending heartbeat, %s\n", !parseCommand->isSkipHeartbeat());
#endif
            if(!parseCommand->isSkipHeartbeat())
                publisher->publishStatus(beacon);
        } else {
#ifdef PRINT_DEBUG
printf("Sending msg\n");
#endif
#ifdef SEND_BINARY_DATA
            publisher->publish("", MqttQOS::AT_MOST_ONCE, msg.data(), msg.size());
#else
            publisher->publish("", beacon);
#endif
        }
    }
    else {
        const char *info = isHeartbeat ? "heartbeat" : "event";
        if(!isHeartbeat || (isHeartbeat && !parseCommand->isSkipHeartbeat()))
            printf("Parsed(%s): %s\n", info, beacon.toString().c_str());
    }
}

void HCIDumpParser::cleanup() {
    if(publisher != nullptr)
        publisher->stop();
    publisher = nullptr;
}

void HCIDumpParser::updateBeaconCounts(beacon_info const *info) {
#ifdef PRINT_DEBUG
    printf("updateBeaconCounts(%d); begin=%lld, end=%lld, info.time=%lld\n", beaconCounts.size(), begin, end, info->time);
#endif
    if(info->time < end) {
        // Update the beacon event counts
        beaconCounts[info->minor] ++;
    } else {
        char timestr[256];
        struct timeval tv;
        tv.tv_sec = begin/1000;
        tv.tv_usec = 0;
        struct tm tm;
        localtime_r(&tv.tv_sec, &tm);
        strftime(timestr, 128, "%r", &tm);
        // Report the stats for this time window and then reset
        printf("+++ Beacon counts for window(%d,%d): %s\n", beaconCounts.size(), parseCommand->getAnalyzeWindow(), timestr);
        for(map<int32_t, int32_t>::iterator iter = beaconCounts.begin(); iter != beaconCounts.end(); iter++) {
            printf("\t%2d: %2d\n", iter->first, iter->second);
        }
        begin = end;
        end += 1000*parseCommand->getAnalyzeWindow();
        beaconCounts.clear();
    }
}
<commit_msg>Make the analyze output more compact<commit_after>#include <Beacon.h>
#include <sys/time.h>
#include "HCIDumpParser.h"

// Uncomment to publish the raw byte[] for the beacon, otherwise, properties are sent
//#define SEND_BINARY_DATA

static int64_t currentMilliseconds() {
    timeval now;
    gettimeofday(&now, nullptr);

    int64_t nowMS = now.tv_sec;
    nowMS *= 1000;
    nowMS += now.tv_usec/1000;
    return nowMS;
}

void HCIDumpParser::processHCI(HCIDumpCommand& parseCommand) {
    HCIDumpParser::parseCommand = &parseCommand;
    string clientID(parseCommand.getClientID());
    if(clientID.empty())
        clientID = parseCommand.getScannerID();
    publisher = MsgPublisher::create(parseCommand.getPubType(), parseCommand.getBrokerURL(), clientID, "", "");
    if(parseCommand.isAnalyzeMode()) {
        begin = currentMilliseconds();
        end = begin + parseCommand.getAnalyzeWindow();
        printf("Running in analyze mode, window=%d seconds, begin=%lld\n", parseCommand.getAnalyzeWindow(), begin);
    }
    else if(!parseCommand.isSkipPublish()) {
        publisher->setUseTopics(!parseCommand.isUseQueues());
        publisher->setDestinationName(parseCommand.getDestinationName());
        if(batchCount > 0) {
            publisher->setUseTransactions(true);
            printf("Enabled transactions\n");
        }
        publisher->start(parseCommand.isAsyncMode());
    }
    else {
        printf("Skipping publish of parsed beacons\n");
    }

    char cdev = parseCommand.getHciDev().at(parseCommand.getHciDev().size()-1);
    int device = cdev - '0';
    scan_frames(device,  beacon_event_callback);
}

void HCIDumpParser::beaconEvent(const beacon_info *info) {
    Beacon beacon(parseCommand->getScannerID(), info->uuid, info->code, info->manufacturer, info->major, info->minor,
            info->power, info->calibrated_power, info->rssi, info->time);
    vector<byte> msg = beacon.toByteMsg();
    // Check for heartbeat
    bool isHeartbeat = scannerUUID.compare(info->uuid) == 0;
    if(isHeartbeat)
        beacon.setMessageType(BeconEventType::SCANNER_HEARTBEAT);
    if(parseCommand->isAnalyzeMode()) {
        updateBeaconCounts(info);
    }
    else if(!parseCommand->isSkipPublish()) {
        if(batchCount > 0) {
            // Overwrite last event if it is a heartbeat and this is as well
            if(isHeartbeat && events.size() > 0 && events.back().getMessageType() == BeconEventType::SCANNER_HEARTBEAT)
                events.pop_back();
            events.push_back(beacon);
            if(shouldSendMessages()) {
#ifdef PRINT_DEBUG
printf("Sending msg batch, size=%d\n", events.size());
#endif
                publisher->publish(events);
                events.clear();
            } else {
#ifdef PRINT_DEBUG
printf("Batched msg, size=%d\n", events.size());
#endif
            }
        } else if(isHeartbeat) {
#ifdef PRINT_DEBUG
printf("Sending heartbeat, %s\n", !parseCommand->isSkipHeartbeat());
#endif
            if(!parseCommand->isSkipHeartbeat())
                publisher->publishStatus(beacon);
        } else {
#ifdef PRINT_DEBUG
printf("Sending msg\n");
#endif
#ifdef SEND_BINARY_DATA
            publisher->publish("", MqttQOS::AT_MOST_ONCE, msg.data(), msg.size());
#else
            publisher->publish("", beacon);
#endif
        }
    }
    else {
        const char *info = isHeartbeat ? "heartbeat" : "event";
        if(!isHeartbeat || (isHeartbeat && !parseCommand->isSkipHeartbeat()))
            printf("Parsed(%s): %s\n", info, beacon.toString().c_str());
    }
}

void HCIDumpParser::cleanup() {
    if(publisher != nullptr)
        publisher->stop();
    publisher = nullptr;
}

void HCIDumpParser::updateBeaconCounts(beacon_info const *info) {
#ifdef PRINT_DEBUG
    printf("updateBeaconCounts(%d); begin=%lld, end=%lld, info.time=%lld\n", beaconCounts.size(), begin, end, info->time);
#endif
    if(info->time < end) {
        // Update the beacon event counts
        beaconCounts[info->minor] ++;
    } else {
        char timestr[256];
        struct timeval tv;
        tv.tv_sec = begin/1000;
        tv.tv_usec = 0;
        struct tm tm;
        localtime_r(&tv.tv_sec, &tm);
        strftime(timestr, 128, "%r", &tm);
        // Report the stats for this time window and then reset
        printf("+++ Beacon counts for window(%d,%d): %s\n", beaconCounts.size(), parseCommand->getAnalyzeWindow(), timestr);
        printf("\t");
        for(map<int32_t, int32_t>::iterator iter = beaconCounts.begin(); iter != beaconCounts.end(); iter++) {
            printf("+%2d: %2d; ", iter->first, iter->second);
        }
        printf("\n");
        begin = end;
        end += 1000*parseCommand->getAnalyzeWindow();
        beaconCounts.clear();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

#include <vector>
#include <functional>

#include "core/future-util.hh"
#include "core/pipe.hh"

#include "sstables.hh"
#include "compaction.hh"
#include "mutation_reader.hh"

namespace sstables {

// compact_sstables compacts the given list of sstables creating one
// (currently) or more (in the future) new sstables. The new sstables
// are created using the "sstable_creator" object passed by the caller.
future<> compact_sstables(std::vector<shared_sstable> sstables,
        schema_ptr schema, std::function<shared_sstable()> creator) {
    std::vector<::mutation_reader> readers;
    uint64_t estimated_partitions = 0;

    for (auto sst : sstables) {
        // We also capture the sstable, so we keep it alive while the read isn't done
        readers.emplace_back([sst, r = make_lw_shared(sst->read_rows(schema))] () mutable { return r->read(); });
        // FIXME: If the sstables have cardinality estimation bitmaps, use that
        // for a better estimate for the number of partitions in the merged
        // sstable than just adding up the lengths of individual sstables.
        estimated_partitions += sst->get_estimated_key_count();
    }
    auto combined_reader = make_combined_reader(std::move(readers));

    // We use a fixed-sized pipe between the producer fiber (which reads the
    // individual sstables and merges them) and the consumer fiber (which
    // only writes to the sstable). Things would have worked without this
    // pipe (the writing fiber would have also performed the reads), but we
    // prefer to do less work in the writer (which is a seastar::thread),
    // and also want the extra buffer to ensure we do fewer context switches
    // to that seastar::thread.
    // TODO: better tuning for the size of the pipe. Perhaps should take into
    // account the size of the individual mutations?
    seastar::pipe<mutation> output{16};
    auto output_reader = make_lw_shared<seastar::pipe_reader<mutation>>(std::move(output.reader));
    auto output_writer = make_lw_shared<seastar::pipe_writer<mutation>>(std::move(output.writer));

    auto done = make_lw_shared<bool>(false);
    future<> read_done = do_until([done] { return *done; }, [done, output_writer, combined_reader = std::move(combined_reader)] {
        return combined_reader().then([done = std::move(done), output_writer = std::move(output_writer)] (auto mopt) {
            if (mopt) {
                return output_writer->write(std::move(*mopt));
            } else {
                *done = true;
                return make_ready_future<>();
            }
        });
    });

    ::mutation_reader mutation_queue_reader = [output_reader] () {
        return output_reader->read();
    };
    auto newtab = creator();
    future<> write_done = newtab->write_components(
            std::move(mutation_queue_reader), estimated_partitions, schema).then([newtab] {
        return newtab->load().then([newtab] {});
    });

    // Wait for both read_done and write_done fibers to finish.
    // FIXME: if write_done throws an exception, we get a broken pipe
    // exception on read_done, and then we don't handle write_done's
    // exception, causing a warning message of "ignored exceptional future".
    return read_done.then([write_done = std::move(write_done)] () mutable { return std::move(write_done); });
}

}
<commit_msg>sstables: keep track of compacted sstable's ancestors<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

#include <vector>
#include <functional>

#include "core/future-util.hh"
#include "core/pipe.hh"

#include "sstables.hh"
#include "compaction.hh"
#include "mutation_reader.hh"

namespace sstables {

// compact_sstables compacts the given list of sstables creating one
// (currently) or more (in the future) new sstables. The new sstables
// are created using the "sstable_creator" object passed by the caller.
future<> compact_sstables(std::vector<shared_sstable> sstables,
        schema_ptr schema, std::function<shared_sstable()> creator) {
    std::vector<::mutation_reader> readers;
    uint64_t estimated_partitions = 0;
    auto newtab = creator();

    for (auto sst : sstables) {
        // We also capture the sstable, so we keep it alive while the read isn't done
        readers.emplace_back([sst, r = make_lw_shared(sst->read_rows(schema))] () mutable { return r->read(); });
        // FIXME: If the sstables have cardinality estimation bitmaps, use that
        // for a better estimate for the number of partitions in the merged
        // sstable than just adding up the lengths of individual sstables.
        estimated_partitions += sst->get_estimated_key_count();
        // Compacted sstable keeps track of its ancestors.
        newtab->add_ancestor(sst->generation());
    }
    auto combined_reader = make_combined_reader(std::move(readers));

    // We use a fixed-sized pipe between the producer fiber (which reads the
    // individual sstables and merges them) and the consumer fiber (which
    // only writes to the sstable). Things would have worked without this
    // pipe (the writing fiber would have also performed the reads), but we
    // prefer to do less work in the writer (which is a seastar::thread),
    // and also want the extra buffer to ensure we do fewer context switches
    // to that seastar::thread.
    // TODO: better tuning for the size of the pipe. Perhaps should take into
    // account the size of the individual mutations?
    seastar::pipe<mutation> output{16};
    auto output_reader = make_lw_shared<seastar::pipe_reader<mutation>>(std::move(output.reader));
    auto output_writer = make_lw_shared<seastar::pipe_writer<mutation>>(std::move(output.writer));

    auto done = make_lw_shared<bool>(false);
    future<> read_done = do_until([done] { return *done; }, [done, output_writer, combined_reader = std::move(combined_reader)] {
        return combined_reader().then([done = std::move(done), output_writer = std::move(output_writer)] (auto mopt) {
            if (mopt) {
                return output_writer->write(std::move(*mopt));
            } else {
                *done = true;
                return make_ready_future<>();
            }
        });
    });

    ::mutation_reader mutation_queue_reader = [output_reader] () {
        return output_reader->read();
    };

    future<> write_done = newtab->write_components(
            std::move(mutation_queue_reader), estimated_partitions, schema).then([newtab] {
        return newtab->load().then([newtab] {});
    });

    // Wait for both read_done and write_done fibers to finish.
    // FIXME: if write_done throws an exception, we get a broken pipe
    // exception on read_done, and then we don't handle write_done's
    // exception, causing a warning message of "ignored exceptional future".
    return read_done.then([write_done = std::move(write_done)] () mutable { return std::move(write_done); });
}

}
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * This library 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         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; if not, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

#ifndef _BINSOCKETMESSAGE_INL_
#define _BINSOCKETMESSAGE_INL_

OSG_BEGIN_NAMESPACE

/*---------------------------------------------------------------------*/
/*                      write message                                  */

inline void BinaryMessage::putUInt32(const UInt32  value)
{
    UInt32 net = osgHostToNet<UInt32>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putInt32 (const Int32  value)
{
    Int32 net = osgHostToNet<Int32>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putUInt16(const UInt16  value)
{
    UInt16 net = osgHostToNet<UInt16>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putInt16 (const Int16  value)
{
    Int16 net = osgHostToNet<Int16>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putUInt8 (const UInt8   value)
{
    _buffer.push_back(value);
}

inline void BinaryMessage::putInt8  (const Int8   value)
{
    UInt8 v = static_cast<const UInt8>(value);
    _buffer.push_back(v);
}

inline void BinaryMessage::putString(const std::string &value)
{
    putUInt32(value.size());
    if(value.size())
    {
        const UInt8 *s = reinterpret_cast<const UInt8*>(value.c_str());
        const UInt8 *e = s + value.size();
        _buffer.insert(_buffer.end(), s, e);
    }
}

inline void BinaryMessage::putReal32(const Real32  value)
{
    Real32 net = osgHostToNet(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

/*---------------------------------------------------------------------*/
/*                      read message                                   */

inline void BinaryMessage::getUInt32(UInt32  &value)
{
    UInt32 net = *reinterpret_cast<UInt32*>(&_buffer[_pos]);
    value = osgNetToHost<UInt32>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getInt32 (Int32  &value)
{
    Int32 net = *reinterpret_cast<Int32*>(&_buffer[_pos]);
    value = osgNetToHost<Int32>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getUInt16(UInt16  &value)
{
    UInt16 net = *reinterpret_cast<UInt16*>(&_buffer[_pos]);
    value = osgNetToHost<UInt16>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getInt16 (Int16  &value)
{
    Int16 net = *reinterpret_cast<Int16*>(&_buffer[_pos]);
    value = osgNetToHost<Int16>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getUInt8 (UInt8   &value)
{
    value = _buffer[_pos++];
}

inline void BinaryMessage::getInt8  (Int8   &value)
{
    value = _buffer[_pos++];
}

inline void BinaryMessage::getString(std::string &value)
{
    UInt32 size;
    getUInt32(size);

    if(size)
    {
        value.assign(reinterpret_cast<char*>(&_buffer[_pos       ]),
                     reinterpret_cast<char*>(&_buffer[_pos + size]) );
        _pos += size;
    }
    else
    {
        value.erase();
    }
}

inline void BinaryMessage::getReal32(Real32  &value)
{
    Real32 net = *reinterpret_cast<Real32*>(&_buffer[_pos]);
    value = osgNetToHost(net);
    _pos += sizeof(net);
}

inline UInt32 BinaryMessage::getUInt32(void)
{
    UInt32 value;
    getUInt32(value);
    return value;
}

inline Int32  BinaryMessage::getInt32 (void)
{
    Int32 value;
    getInt32(value);
    return value;
}

inline UInt16 BinaryMessage::getUInt16(void)
{
    UInt16 value;
    getUInt16(value);
    return value;
}

inline Int16  BinaryMessage::getInt16 (void)
{
    Int16 value;
    getInt16(value);
    return value;
}

inline UInt8  BinaryMessage::getUInt8 (void)
{
    UInt8 value;
    getUInt8(value);
    return value;
}

inline Int8   BinaryMessage::getInt8  (void)
{
    Int8 value;
    getInt8(value);
    return value;
}

inline std::string BinaryMessage::getString(void)
{
    std::string value;
    getString(value);
    return value;
}

inline Real32 BinaryMessage::getReal32(void)
{
    Real32 value;
    getReal32(value);
    return value;
}

OSG_END_NAMESPACE

#endif
<commit_msg>fixed  : out of bounds error<commit_after>/*---------------------------------------------------------------------------*\
 *                                OpenSG                                     *
 *                                                                           *
 *                                                                           *
 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
 *                                                                           *
 *                            www.opensg.org                                 *
 *                                                                           *
 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                License                                    *
 *                                                                           *
 * This library is free software; you can redistribute it and/or modify it   *
 * under the terms of the GNU Library General Public License as published    *
 * by the Free Software Foundation, version 2.                               *
 *                                                                           *
 * This library 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         *
 * Library General Public License for more details.                          *
 *                                                                           *
 * You should have received a copy of the GNU Library General Public         *
 * License along with this library; if not, write to the Free Software       *
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
 *                                                                           *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
 *                                Changes                                    *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
\*---------------------------------------------------------------------------*/

#ifndef _BINSOCKETMESSAGE_INL_
#define _BINSOCKETMESSAGE_INL_

OSG_BEGIN_NAMESPACE

/*---------------------------------------------------------------------*/
/*                      write message                                  */

inline void BinaryMessage::putUInt32(const UInt32  value)
{
    UInt32 net = osgHostToNet<UInt32>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putInt32 (const Int32  value)
{
    Int32 net = osgHostToNet<Int32>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putUInt16(const UInt16  value)
{
    UInt16 net = osgHostToNet<UInt16>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putInt16 (const Int16  value)
{
    Int16 net = osgHostToNet<Int16>(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

inline void BinaryMessage::putUInt8 (const UInt8   value)
{
    _buffer.push_back(value);
}

inline void BinaryMessage::putInt8  (const Int8   value)
{
    UInt8 v = static_cast<const UInt8>(value);
    _buffer.push_back(v);
}

inline void BinaryMessage::putString(const std::string &value)
{
    putUInt32(value.size());
    if(value.size())
    {
        const UInt8 *s = reinterpret_cast<const UInt8*>(value.c_str());
        const UInt8 *e = s + value.size();
        _buffer.insert(_buffer.end(), s, e);
    }
}

inline void BinaryMessage::putReal32(const Real32  value)
{
    Real32 net = osgHostToNet(value);
    _buffer.insert(_buffer.end(),
                   reinterpret_cast<UInt8*>(&net),
                   reinterpret_cast<UInt8*>(&net) + sizeof(net));
}

/*---------------------------------------------------------------------*/
/*                      read message                                   */

inline void BinaryMessage::getUInt32(UInt32  &value)
{
    UInt32 net = *reinterpret_cast<UInt32*>(&_buffer[_pos]);
    value = osgNetToHost<UInt32>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getInt32 (Int32  &value)
{
    Int32 net = *reinterpret_cast<Int32*>(&_buffer[_pos]);
    value = osgNetToHost<Int32>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getUInt16(UInt16  &value)
{
    UInt16 net = *reinterpret_cast<UInt16*>(&_buffer[_pos]);
    value = osgNetToHost<UInt16>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getInt16 (Int16  &value)
{
    Int16 net = *reinterpret_cast<Int16*>(&_buffer[_pos]);
    value = osgNetToHost<Int16>(net);
    _pos += sizeof(net);
}

inline void BinaryMessage::getUInt8 (UInt8   &value)
{
    value = _buffer[_pos++];
}

inline void BinaryMessage::getInt8  (Int8   &value)
{
    value = _buffer[_pos++];
}

inline void BinaryMessage::getString(std::string &value)
{
    UInt32 size;
    getUInt32(size);

    if(size)
    {
// error if [] checks index
//        value.assign(reinterpret_cast<char*>(&_buffer[_pos       ]),
//                     reinterpret_cast<char*>(&_buffer[_pos + size]) );

        value.assign(reinterpret_cast<char*>(&(_buffer[_pos])), size);

        _pos += size;
    }
    else
    {
        value.erase();
    }
}

inline void BinaryMessage::getReal32(Real32  &value)
{
    Real32 net = *reinterpret_cast<Real32*>(&_buffer[_pos]);
    value = osgNetToHost(net);
    _pos += sizeof(net);
}

inline UInt32 BinaryMessage::getUInt32(void)
{
    UInt32 value;
    getUInt32(value);
    return value;
}

inline Int32  BinaryMessage::getInt32 (void)
{
    Int32 value;
    getInt32(value);
    return value;
}

inline UInt16 BinaryMessage::getUInt16(void)
{
    UInt16 value;
    getUInt16(value);
    return value;
}

inline Int16  BinaryMessage::getInt16 (void)
{
    Int16 value;
    getInt16(value);
    return value;
}

inline UInt8  BinaryMessage::getUInt8 (void)
{
    UInt8 value;
    getUInt8(value);
    return value;
}

inline Int8   BinaryMessage::getInt8  (void)
{
    Int8 value;
    getInt8(value);
    return value;
}

inline std::string BinaryMessage::getString(void)
{
    std::string value;
    getString(value);
    return value;
}

inline Real32 BinaryMessage::getReal32(void)
{
    Real32 value;
    getReal32(value);
    return value;
}

OSG_END_NAMESPACE

#endif
<|endoftext|>