<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Achim Brandt
////////////////////////////////////////////////////////////////////////////////

#include "HttpResponse.h"

#include <velocypack/Builder.h>
#include <velocypack/Dumper.h>
#include <velocypack/Options.h>
#include <velocypack/velocypack-aliases.h>

#include "Basics/Exceptions.h"
#include "Basics/StringBuffer.h"
#include "Basics/StringUtils.h"
#include "Basics/VPackStringBufferAdapter.h"
#include "Basics/VelocyPackDumper.h"
#include "Basics/tri-strings.h"
#include "Meta/conversion.h"
#include "Rest/GeneralRequest.h"

using namespace arangodb;
using namespace arangodb::basics;

bool HttpResponse::HIDE_PRODUCT_HEADER = false;

HttpResponse::HttpResponse(ResponseCode code)
    : GeneralResponse(code),
      _isHeadResponse(false),
      _body(TRI_UNKNOWN_MEM_ZONE, false),
      _bodySize(0) {
  _generateBody = false;
  _contentType = ContentType::TEXT;
  _connectionType = rest::CONNECTION_KEEP_ALIVE;
  if (_body.c_str() == nullptr) {
    // no buffer could be reserved. out of memory!
    THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
  }
}

void HttpResponse::reset(ResponseCode code) {
  _responseCode = code;
  _headers.clear();
  _connectionType = rest::CONNECTION_KEEP_ALIVE;
  _contentType = ContentType::TEXT;
  _isHeadResponse = false;
  _body.clear();
  _bodySize = 0;
}

void HttpResponse::setCookie(std::string const& name, std::string const& value,
                             int lifeTimeSeconds, std::string const& path,
                             std::string const& domain, bool secure,
                             bool httpOnly) {
  std::unique_ptr<StringBuffer> buffer =
      std::make_unique<StringBuffer>(TRI_UNKNOWN_MEM_ZONE);

  std::string tmp = StringUtils::trim(name);
  buffer->appendText(tmp);
  buffer->appendChar('=');

  tmp = StringUtils::urlEncode(value);
  buffer->appendText(tmp);

  if (lifeTimeSeconds != 0) {
    time_t rawtime;

    time(&rawtime);
    if (lifeTimeSeconds > 0) {
      rawtime += lifeTimeSeconds;
    } else {
      rawtime = 1;
    }

    if (rawtime > 0) {
      struct tm* timeinfo;
      char buffer2[80];

      timeinfo = gmtime(&rawtime);
      strftime(buffer2, 80, "%a, %d-%b-%Y %H:%M:%S %Z", timeinfo);
      buffer->appendText(TRI_CHAR_LENGTH_PAIR("; expires="));
      buffer->appendText(buffer2);
    }
  }

  if (!path.empty()) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; path="));
    buffer->appendText(path);
  }

  if (!domain.empty()) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; domain="));
    buffer->appendText(domain);
  }

  if (secure) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; secure"));
  }

  if (httpOnly) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; HttpOnly"));
  }

  _cookies.emplace_back(buffer->c_str());
}

void HttpResponse::headResponse(size_t size) {
  _body.clear();
  _isHeadResponse = true;
  _bodySize = size;
}

size_t HttpResponse::bodySize() const {
  if (_isHeadResponse) {
    return _bodySize;
  }
  return _body.length();
}

void HttpResponse::writeHeader(StringBuffer* output) {
  output->appendText(TRI_CHAR_LENGTH_PAIR("HTTP/1.1 "));
  output->appendText(responseString(_responseCode));
  output->appendText("\r\n", 2);

  bool seenServerHeader = false;
  bool seenConnectionHeader = false;
  bool seenTransferEncodingHeader = false;
  std::string transferEncoding;

  for (auto const& it : _headers) {
    std::string const& key = it.first;
    size_t const keyLength = key.size();

    // ignore content-length
    if (keyLength == 14 && key[0] == 'c' &&
        memcmp(key.c_str(), "content-length", keyLength) == 0) {
      continue;
    }

    // save transfer encoding
    if (keyLength == 17 && key[0] == 't' &&
        memcmp(key.c_str(), "transfer-encoding", keyLength) == 0) {
      seenTransferEncodingHeader = true;
      transferEncoding = it.second;
      continue;
    }

    if (keyLength == 6 && key[0] == 's' &&
        memcmp(key.c_str(), "server", keyLength) == 0) {
      // this ensures we don't print two "Server" headers
      seenServerHeader = true;
      // go on and use the user-defined "Server" header value
    } else if (keyLength == 10 && key[0] == 'c' &&
               memcmp(key.c_str(), "connection", keyLength) == 0) {
      // this ensures we don't print two "Connection" headers
      seenConnectionHeader = true;
      // go on and use the user-defined "Connection" header value
    }

    // reserve enough space for header name + ": " + value + "\r\n"
    if (output->reserve(keyLength + 2 + it.second.size() + 2) !=
        TRI_ERROR_NO_ERROR) {
      THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
    }

    char const* p = key.c_str();
    char const* end = p + keyLength;
    int capState = 1;

    while (p < end) {
      if (capState == 1) {
        // upper case
        output->appendCharUnsafe(::toupper(*p));
        capState = 0;
      } else if (capState == 0) {
        // normal case
        output->appendCharUnsafe(::tolower(*p));
        if (*p == '-') {
          capState = 1;
        } else if (*p == ':') {
          capState = 2;
        }
      } else {
        // output as is
        output->appendCharUnsafe(*p);
      }
      ++p;
    }

    output->appendTextUnsafe(": ", 2);
    output->appendTextUnsafe(it.second);
    output->appendTextUnsafe("\r\n", 2);
  }

  // add "Server" response header
  if (!seenServerHeader && !HIDE_PRODUCT_HEADER) {
    output->appendText("Server: ArangoDB\r\n");
  }

  // add "Connection" response header
  if (!seenConnectionHeader) {
    switch (_connectionType) {
      case rest::ConnectionType::CONNECTION_KEEP_ALIVE:
        output->appendText(TRI_CHAR_LENGTH_PAIR("Connection: Keep-Alive\r\n"));
        break;
      case rest::ConnectionType::CONNECTION_CLOSE:
        output->appendText(TRI_CHAR_LENGTH_PAIR("Connection: Close\r\n"));
        break;
      case rest::ConnectionType::CONNECTION_NONE:
        output->appendText(TRI_CHAR_LENGTH_PAIR("Connection: \r\n"));
        break;
    }
  }

  // add "Content-Type" header
  switch (_contentType) {
    case ContentType::UNSET:
    case ContentType::JSON:
      output->appendText(TRI_CHAR_LENGTH_PAIR(
          "Content-Type: application/json; charset=utf-8\r\n"));
      break;
    case ContentType::VPACK:
      output->appendText(
          TRI_CHAR_LENGTH_PAIR("Content-Type: application/x-velocypack\r\n"));
      break;
    case ContentType::TEXT:
      output->appendText(
          TRI_CHAR_LENGTH_PAIR("Content-Type: text/plain; charset=utf-8\r\n"));
      break;
    case ContentType::HTML:
      output->appendText(
          TRI_CHAR_LENGTH_PAIR("Content-Type: text/html; charset=utf-8\r\n"));
      break;
    case ContentType::DUMP:
      output->appendText(TRI_CHAR_LENGTH_PAIR(
          "Content-Type: application/x-arango-dump; charset=utf-8\r\n"));
      break;
    case ContentType::CUSTOM: {
      // intentionally don't print anything here
      // the header should have been in _headers already, and should have been
      // handled above
    }
  }

  for (auto const& it : _cookies) {
    output->appendText(TRI_CHAR_LENGTH_PAIR("Set-Cookie: "));
    output->appendText(it);
    output->appendText("\r\n", 2);
  }

  if (seenTransferEncodingHeader && transferEncoding == "chunked") {
    output->appendText(
        TRI_CHAR_LENGTH_PAIR("Transfer-Encoding: chunked\r\n\r\n"));
  } else {
    if (seenTransferEncodingHeader) {
      output->appendText(TRI_CHAR_LENGTH_PAIR("Transfer-Encoding: "));
      output->appendText(transferEncoding);
      output->appendText("\r\n", 2);
    }

    output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Length: "));

    if (_isHeadResponse) {
      // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
      //
      // 14.13 Content-Length
      //
      // The Content-Length entity-header field indicates the size of the
      // entity-body,
      // in decimal number of OCTETs, sent to the recipient or, in the case of
      // the HEAD method,
      // the size of the entity-body that would have been sent had the request
      // been a GET.
      output->appendInteger(_bodySize);
    } else {
      output->appendInteger(_body.length());
    }

    output->appendText("\r\n\r\n", 4);
  }
  // end of header, body to follow
}

void HttpResponse::addPayloadPostHook(
    VPackSlice const& slice,
    VPackOptions const* options = &VPackOptions::Options::Defaults,
    bool resolveExternals = true, bool bodySkipped = false) {

  VPackSlice const* slicePtr;
  VPackSlice tmpSlice;

  if (!bodySkipped) {
    // we have Probably resolved externals
    TRI_ASSERT(!_vpackPayloads.empty());
    tmpSlice = VPackSlice(_vpackPayloads.front().data());
    slicePtr = &tmpSlice;
  } else {
    slicePtr = &slice;
  }

  switch (_contentType) {
    case rest::ContentType::VPACK: {
      size_t length = static_cast<size_t>(slicePtr->byteSize());
      if (_generateBody) {
        _body.appendText(slicePtr->startAs<const char>(), length);
      } else {
        headResponse(length);
      }
      break;
    }
    default: {
      setContentType(rest::ContentType::JSON);
      if (_generateBody) {
        arangodb::basics::VelocyPackDumper dumper(&_body, options);
        dumper.dumpValue(*slicePtr);
      } else {
        // TODO can we optimize this?
        // Just dump some where else to find real length
        StringBuffer tmp(TRI_UNKNOWN_MEM_ZONE, false);

        // convert object to string
        VPackStringBufferAdapter buffer(tmp.stringBuffer());

        // usual dumping -  but not to the response body
        VPackDumper dumper(&buffer, options);
        dumper.dump(*slicePtr);

        headResponse(tmp.length());
      }
    }
  }
}
<commit_msg>make use of requested content type<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Achim Brandt
////////////////////////////////////////////////////////////////////////////////

#include "HttpResponse.h"

#include <velocypack/Builder.h>
#include <velocypack/Dumper.h>
#include <velocypack/Options.h>
#include <velocypack/velocypack-aliases.h>

#include "Basics/Exceptions.h"
#include "Basics/StringBuffer.h"
#include "Basics/StringUtils.h"
#include "Basics/VPackStringBufferAdapter.h"
#include "Basics/VelocyPackDumper.h"
#include "Basics/tri-strings.h"
#include "Meta/conversion.h"
#include "Rest/GeneralRequest.h"

using namespace arangodb;
using namespace arangodb::basics;

bool HttpResponse::HIDE_PRODUCT_HEADER = false;

HttpResponse::HttpResponse(ResponseCode code)
    : GeneralResponse(code),
      _isHeadResponse(false),
      _body(TRI_UNKNOWN_MEM_ZONE, false),
      _bodySize(0) {
  _generateBody = false;
  _contentType = ContentType::TEXT;
  _connectionType = rest::CONNECTION_KEEP_ALIVE;
  if (_body.c_str() == nullptr) {
    // no buffer could be reserved. out of memory!
    THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
  }
}

void HttpResponse::reset(ResponseCode code) {
  _responseCode = code;
  _headers.clear();
  _connectionType = rest::CONNECTION_KEEP_ALIVE;
  _contentType = ContentType::TEXT;
  _isHeadResponse = false;
  _body.clear();
  _bodySize = 0;
}

void HttpResponse::setCookie(std::string const& name, std::string const& value,
                             int lifeTimeSeconds, std::string const& path,
                             std::string const& domain, bool secure,
                             bool httpOnly) {
  std::unique_ptr<StringBuffer> buffer =
      std::make_unique<StringBuffer>(TRI_UNKNOWN_MEM_ZONE);

  std::string tmp = StringUtils::trim(name);
  buffer->appendText(tmp);
  buffer->appendChar('=');

  tmp = StringUtils::urlEncode(value);
  buffer->appendText(tmp);

  if (lifeTimeSeconds != 0) {
    time_t rawtime;

    time(&rawtime);
    if (lifeTimeSeconds > 0) {
      rawtime += lifeTimeSeconds;
    } else {
      rawtime = 1;
    }

    if (rawtime > 0) {
      struct tm* timeinfo;
      char buffer2[80];

      timeinfo = gmtime(&rawtime);
      strftime(buffer2, 80, "%a, %d-%b-%Y %H:%M:%S %Z", timeinfo);
      buffer->appendText(TRI_CHAR_LENGTH_PAIR("; expires="));
      buffer->appendText(buffer2);
    }
  }

  if (!path.empty()) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; path="));
    buffer->appendText(path);
  }

  if (!domain.empty()) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; domain="));
    buffer->appendText(domain);
  }

  if (secure) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; secure"));
  }

  if (httpOnly) {
    buffer->appendText(TRI_CHAR_LENGTH_PAIR("; HttpOnly"));
  }

  _cookies.emplace_back(buffer->c_str());
}

void HttpResponse::headResponse(size_t size) {
  _body.clear();
  _isHeadResponse = true;
  _bodySize = size;
}

size_t HttpResponse::bodySize() const {
  if (_isHeadResponse) {
    return _bodySize;
  }
  return _body.length();
}

void HttpResponse::writeHeader(StringBuffer* output) {
  output->appendText(TRI_CHAR_LENGTH_PAIR("HTTP/1.1 "));
  output->appendText(responseString(_responseCode));
  output->appendText("\r\n", 2);

  bool seenServerHeader = false;
  bool seenConnectionHeader = false;
  bool seenTransferEncodingHeader = false;
  std::string transferEncoding;

  for (auto const& it : _headers) {
    std::string const& key = it.first;
    size_t const keyLength = key.size();

    // ignore content-length
    if (keyLength == 14 && key[0] == 'c' &&
        memcmp(key.c_str(), "content-length", keyLength) == 0) {
      continue;
    }

    // save transfer encoding
    if (keyLength == 17 && key[0] == 't' &&
        memcmp(key.c_str(), "transfer-encoding", keyLength) == 0) {
      seenTransferEncodingHeader = true;
      transferEncoding = it.second;
      continue;
    }

    if (keyLength == 6 && key[0] == 's' &&
        memcmp(key.c_str(), "server", keyLength) == 0) {
      // this ensures we don't print two "Server" headers
      seenServerHeader = true;
      // go on and use the user-defined "Server" header value
    } else if (keyLength == 10 && key[0] == 'c' &&
               memcmp(key.c_str(), "connection", keyLength) == 0) {
      // this ensures we don't print two "Connection" headers
      seenConnectionHeader = true;
      // go on and use the user-defined "Connection" header value
    }

    // reserve enough space for header name + ": " + value + "\r\n"
    if (output->reserve(keyLength + 2 + it.second.size() + 2) !=
        TRI_ERROR_NO_ERROR) {
      THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
    }

    char const* p = key.c_str();
    char const* end = p + keyLength;
    int capState = 1;

    while (p < end) {
      if (capState == 1) {
        // upper case
        output->appendCharUnsafe(::toupper(*p));
        capState = 0;
      } else if (capState == 0) {
        // normal case
        output->appendCharUnsafe(::tolower(*p));
        if (*p == '-') {
          capState = 1;
        } else if (*p == ':') {
          capState = 2;
        }
      } else {
        // output as is
        output->appendCharUnsafe(*p);
      }
      ++p;
    }

    output->appendTextUnsafe(": ", 2);
    output->appendTextUnsafe(it.second);
    output->appendTextUnsafe("\r\n", 2);
  }

  // add "Server" response header
  if (!seenServerHeader && !HIDE_PRODUCT_HEADER) {
    output->appendText("Server: ArangoDB\r\n");
  }

  // add "Connection" response header
  if (!seenConnectionHeader) {
    switch (_connectionType) {
      case rest::ConnectionType::CONNECTION_KEEP_ALIVE:
        output->appendText(TRI_CHAR_LENGTH_PAIR("Connection: Keep-Alive\r\n"));
        break;
      case rest::ConnectionType::CONNECTION_CLOSE:
        output->appendText(TRI_CHAR_LENGTH_PAIR("Connection: Close\r\n"));
        break;
      case rest::ConnectionType::CONNECTION_NONE:
        output->appendText(TRI_CHAR_LENGTH_PAIR("Connection: \r\n"));
        break;
    }
  }

  // add "Content-Type" header
  switch (_contentType) {
    case ContentType::UNSET:
    case ContentType::JSON:
      output->appendText(TRI_CHAR_LENGTH_PAIR(
          "Content-Type: application/json; charset=utf-8\r\n"));
      break;
    case ContentType::VPACK:
      output->appendText(
          TRI_CHAR_LENGTH_PAIR("Content-Type: application/x-velocypack\r\n"));
      break;
    case ContentType::TEXT:
      output->appendText(
          TRI_CHAR_LENGTH_PAIR("Content-Type: text/plain; charset=utf-8\r\n"));
      break;
    case ContentType::HTML:
      output->appendText(
          TRI_CHAR_LENGTH_PAIR("Content-Type: text/html; charset=utf-8\r\n"));
      break;
    case ContentType::DUMP:
      output->appendText(TRI_CHAR_LENGTH_PAIR(
          "Content-Type: application/x-arango-dump; charset=utf-8\r\n"));
      break;
    case ContentType::CUSTOM: {
      // intentionally don't print anything here
      // the header should have been in _headers already, and should have been
      // handled above
    }
  }

  for (auto const& it : _cookies) {
    output->appendText(TRI_CHAR_LENGTH_PAIR("Set-Cookie: "));
    output->appendText(it);
    output->appendText("\r\n", 2);
  }

  if (seenTransferEncodingHeader && transferEncoding == "chunked") {
    output->appendText(
        TRI_CHAR_LENGTH_PAIR("Transfer-Encoding: chunked\r\n\r\n"));
  } else {
    if (seenTransferEncodingHeader) {
      output->appendText(TRI_CHAR_LENGTH_PAIR("Transfer-Encoding: "));
      output->appendText(transferEncoding);
      output->appendText("\r\n", 2);
    }

    output->appendText(TRI_CHAR_LENGTH_PAIR("Content-Length: "));

    if (_isHeadResponse) {
      // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
      //
      // 14.13 Content-Length
      //
      // The Content-Length entity-header field indicates the size of the
      // entity-body,
      // in decimal number of OCTETs, sent to the recipient or, in the case of
      // the HEAD method,
      // the size of the entity-body that would have been sent had the request
      // been a GET.
      output->appendInteger(_bodySize);
    } else {
      output->appendInteger(_body.length());
    }

    output->appendText("\r\n\r\n", 4);
  }
  // end of header, body to follow
}

void HttpResponse::addPayloadPostHook(
    VPackSlice const& slice,
    VPackOptions const* options = &VPackOptions::Options::Defaults,
    bool resolveExternals = true, bool bodySkipped = false) {
  VPackSlice const* slicePtr;
  VPackSlice tmpSlice;

  if (!bodySkipped) {
    // we have Probably resolved externals
    TRI_ASSERT(!_vpackPayloads.empty());
    tmpSlice = VPackSlice(_vpackPayloads.front().data());
    slicePtr = &tmpSlice;
  } else {
    slicePtr = &slice;
  }

  if (_contentType == rest::ContentType::JSON &&
      _contentTypeRequested == rest::ContentType::VPACK) {
    // content type was set by a handler to Json but the client wants VPACK
    // as we have a slice at had we are able to reply with VPACK
    _contentType = rest::ContentType::VPACK;
  }

  switch (_contentType) {
    case rest::ContentType::VPACK: {
      size_t length = static_cast<size_t>(slicePtr->byteSize());
      if (_generateBody) {
        _body.appendText(slicePtr->startAs<const char>(), length);
      } else {
        headResponse(length);
      }
      break;
    }
    default: {
      setContentType(rest::ContentType::JSON);
      if (_generateBody) {
        arangodb::basics::VelocyPackDumper dumper(&_body, options);
        dumper.dumpValue(*slicePtr);
      } else {
        // TODO can we optimize this?
        // Just dump some where else to find real length
        StringBuffer tmp(TRI_UNKNOWN_MEM_ZONE, false);

        // convert object to string
        VPackStringBufferAdapter buffer(tmp.stringBuffer());

        // usual dumping -  but not to the response body
        VPackDumper dumper(&buffer, options);
        dumper.dump(*slicePtr);

        headResponse(tmp.length());
      }
    }
  }
}
<|endoftext|>


<commit_before>

#include "Pickle.h"

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <cstring>

namespace KBase{

// static
const int Pickle::kPayloadUnit = 64;
static const size_t kCapacityReadOnly = static_cast<size_t>(-1);

PickleIterator::PickleIterator(const Pickle& pickle)
    : read_ptr_(pickle.payload()), read_end_ptr_(pickle.end_of_payload())
{}

bool PickleIterator::ReadBool(bool* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadInt(int* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadUInt32(uint32_t* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadInt64(int64_t* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadUInt64(uint64_t* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadFloat(float* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadDouble(double* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadString(std::string* result)
{
    int str_length;
    if (!ReadInt(&str_length)) {
        return false;
    }

    const char* read_from = GetReadPointerAndAdvance(str_length);
    if (!read_from) {
        return false;
    }

    result->assign(read_from, str_length);
    return true;
}

bool PickleIterator::ReadWString(std::wstring* result)
{
    int str_length;
    if (!ReadInt(&str_length)) {
        return false;
    }

    const char* read_from = GetReadPointerAndAdvance(str_length, sizeof(wchar_t));
    if (!read_from) {
        return false;
    }

    result->assign(reinterpret_cast<const wchar_t*>(read_from), str_length);
    return true;
}

bool PickleIterator::ReadBytes(const char** data, int length)
{
    assert(data);
    const char* read_from = GetReadPointerAndAdvance(length);
    if (!read_from) {
        *data = nullptr;
        return false;
    }

    *data = read_from;
    return true;
}

// sizeof comparison in if statement causes constant expression warning
// disable the warning temporarily
#pragma warning(push)
#pragma warning(disable:4127)

template<typename T>
inline bool PickleIterator::ReadBuiltIninType(T* result)
{
    const char* read_from = GetReadPointerAndAdvance<T>();

    if (!read_from) {
        return false;
    }

    if (sizeof(T) > sizeof(uint32_t)) {
        memcpy_s(result, sizeof(*result), read_from, sizeof(*result));
    } else {
        *result = *reinterpret_cast<const T*>(read_from);
    }

    return true;
}

template<typename T>
inline const char* PickleIterator::GetReadPointerAndAdvance()
{
    const char* curr_read_ptr = read_ptr_;

    if (read_ptr_ + sizeof(T) > read_end_ptr_) {
        return nullptr;
    }

    // skip the memory hole if size of the type is less than uint32
    if (sizeof(T) < sizeof(uint32_t)) {
        read_ptr_ += Pickle::AlignInt(sizeof(T), sizeof(uint32_t));
    } else {
        read_ptr_ += sizeof(T);
    }

    return curr_read_ptr;
}

#pragma warning(pop)

const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes)
{
    const char* curr_read_ptr = read_ptr_;

    if (num_bytes < 0 || read_ptr_ + num_bytes > read_end_ptr_) {
        return nullptr;
    }

    read_ptr_ += Pickle::AlignInt(num_bytes, sizeof(uint32_t));

    return curr_read_ptr;
}

/*
 @ brief
    when the size of element doesn't equal to sizeof(char), use this function
    for safety consieration. this function runs overflow check on int32 num_bytes.
*/
const char* PickleIterator::GetReadPointerAndAdvance(int num_elements, size_t element_size)
{
    int64_t num_bytes = static_cast<int64_t>(num_elements) * element_size;
    int num_bytes32 = static_cast<int>(num_bytes);
    if (num_bytes != static_cast<int64_t>(num_bytes32)) {
        return nullptr;
    }

    return GetReadPointerAndAdvance(num_bytes32);
}

// payload is uint32 aligned

Pickle::Pickle() : header_(nullptr), capacity_(0), buffer_offset_(0)
{
    Resize(kPayloadUnit);
    header_->payload_size = 0;
}

Pickle::Pickle(const char* data, int)
    : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
      capacity_(kCapacityReadOnly),
      buffer_offset_(0)
{}

/*
 @ brief
    a deep copy of an Pickle object
*/
Pickle::Pickle(const Pickle& other) : header_(nullptr), capacity_(0),
                                      buffer_offset_(other.buffer_offset_)
{
    // if [other] is constructed from a const buffer, its capacity value is
    // kCapacityReadOnly. therefore, calculate its capacity on hand.
    size_t capacity = sizeof(Header) + other.header_->payload_size;
    bool resized = Resize(capacity);
    assert(resized);

    memcpy_s(header_, capacity_, other.header_, capacity);
}

Pickle::~Pickle()
{
    if (capacity_ != kCapacityReadOnly) {
        free(header_);
    }
}

Pickle& Pickle::operator=(const Pickle& rhs)
{
    if (this == &rhs) {
        assert(false);
        return *this;
    }

    if (capacity_ == kCapacityReadOnly) {
        header_ = nullptr;
        capacity_ = 0;
    }

    size_t capacity = sizeof(Header) + rhs.header_->payload_size;
    bool resized = Resize(capacity);
    assert(resized);

    memcpy_s(header_, capacity_, rhs.header_, capacity);
    buffer_offset_ = rhs.buffer_offset_;

    return *this;
}

/*
 @ brief
    resize the capacity of internal buffer. this function internally rounds the
    [new_capacity] up to the next multiple of predefined alignment
 @ params
    new_capacity[in] new capacity of internal buffer and will be aligned internally.
    be wary of that, the new_capacity actually includes internal header size.
    e.g. new_capacity = header_size + your_desired_payload_size
*/
bool Pickle::Resize(size_t new_capacity)
{
    assert(capacity_ != kCapacityReadOnly);
    new_capacity = AlignInt(new_capacity, kPayloadUnit);

    void* p = realloc(header_, new_capacity);
    if (!p) {
        return false;
    }

    header_ = static_cast<Header*>(p);
    capacity_ = new_capacity;

    return true;
}

// static
size_t Pickle::AlignInt(size_t i, int alignment)
{
    return i + (alignment - i % alignment) % alignment;
}

bool Pickle::WriteString(const std::string& value)
{
    if (!WriteInt(static_cast<int>(value.size()))) {
        return false;
    }

    return WriteByte(value.data(), static_cast<int>(value.size()));
}

bool Pickle::WriteWString(const std::wstring& value)
{
    if (!WriteInt(static_cast<int>(value.size()))) {
        return false;
    }

    return WriteByte(value.data(), static_cast<int>(value.size() * sizeof(wchar_t)));
}

/*
 @ brief
    serialize data in byte with specified length. PoD types only
    the function guarantees the internal data remains unchanged if this
    funtion fails.
*/
bool Pickle::WriteByte(const void* data, int data_len)
{
    if (capacity_ == kCapacityReadOnly) {
        assert(false);
        return false;
    }

    char* dest = BeginWrite(data_len);
    if (!dest) {
        return false;
    }

    size_t extra_size = capacity_ - (dest - reinterpret_cast<char*>(header_));
    memcpy_s(dest, extra_size, data, data_len);
    EndWrite(dest, data_len);

    return true;
}

/*
 @ brief
    locate to the next uint32-aligned offset. and resize internal buffer if
    necessary.
 @ return
    the location that the data should be written at, or
    nullptr if an error occured.
*/
char* Pickle::BeginWrite(size_t length)
{
    // write at a uint32-aligned offset from the begining of head
    size_t offset = AlignInt(header_->payload_size, sizeof(uint32_t));
    size_t required_size = offset + length;
    size_t total_required_size = required_size + sizeof(Header);

    if (total_required_size > capacity_ &&
        !Resize(std::max(capacity_ << 1, total_required_size))) {
        return nullptr;
    }

    header_->payload_size = static_cast<uint32_t>(required_size);

    return mutable_payload() + offset;
}

/*
 @ brief
    zero pading memory; otherwise some memory detectors may complain about
    uninitialized memory.
*/
void Pickle::EndWrite(char* dest, size_t length)
{
    if (length % sizeof(uint32_t)) {
        memset(dest + length, 0, sizeof(uint32_t) - (length % sizeof(uint32_t)));
    }
}

}
<commit_msg>Pickle: add Read/WriteData() and SkipBytes<commit_after>

#include "Pickle.h"

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <cstring>

namespace KBase{

// static
const int Pickle::kPayloadUnit = 64;
static const size_t kCapacityReadOnly = static_cast<size_t>(-1);

PickleIterator::PickleIterator(const Pickle& pickle)
    : read_ptr_(pickle.payload()), read_end_ptr_(pickle.end_of_payload())
{}

bool PickleIterator::ReadBool(bool* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadInt(int* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadUInt32(uint32_t* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadInt64(int64_t* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadUInt64(uint64_t* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadFloat(float* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadDouble(double* result)
{
    return ReadBuiltIninType(result);
}

bool PickleIterator::ReadString(std::string* result)
{
    int str_length;
    if (!ReadInt(&str_length)) {
        return false;
    }

    const char* read_from = GetReadPointerAndAdvance(str_length);
    if (!read_from) {
        return false;
    }

    result->assign(read_from, str_length);
    return true;
}

bool PickleIterator::ReadWString(std::wstring* result)
{
    int str_length;
    if (!ReadInt(&str_length)) {
        return false;
    }

    const char* read_from = GetReadPointerAndAdvance(str_length, sizeof(wchar_t));
    if (!read_from) {
        return false;
    }

    result->assign(reinterpret_cast<const wchar_t*>(read_from), str_length);
    return true;
}

bool PickleIterator::ReadBytes(const char** data, int length)
{
    assert(data);
    const char* read_from = GetReadPointerAndAdvance(length);
    if (!read_from) {
        *data = nullptr;
        return false;
    }

    *data = read_from;
    return true;
}

bool PickleIterator::ReadData(const char** data, int* read_length)
{
    assert(data);

    if (!ReadInt(read_length)) {
        *data = nullptr;
        *read_length = 0;
        return false;
    }

    return ReadBytes(data, *read_length);
}

bool PickleIterator::SkipBytes(int num_bytes)
{
    return !!GetReadPointerAndAdvance(num_bytes);
}

// sizeof comparison in if statement causes constant expression warning
// disable the warning temporarily
#pragma warning(push)
#pragma warning(disable:4127)

template<typename T>
inline bool PickleIterator::ReadBuiltIninType(T* result)
{
    const char* read_from = GetReadPointerAndAdvance<T>();

    if (!read_from) {
        return false;
    }

    if (sizeof(T) > sizeof(uint32_t)) {
        memcpy_s(result, sizeof(*result), read_from, sizeof(*result));
    } else {
        *result = *reinterpret_cast<const T*>(read_from);
    }

    return true;
}

template<typename T>
inline const char* PickleIterator::GetReadPointerAndAdvance()
{
    const char* curr_read_ptr = read_ptr_;

    if (read_ptr_ + sizeof(T) > read_end_ptr_) {
        return nullptr;
    }

    // skip the memory hole if size of the type is less than uint32
    if (sizeof(T) < sizeof(uint32_t)) {
        read_ptr_ += Pickle::AlignInt(sizeof(T), sizeof(uint32_t));
    } else {
        read_ptr_ += sizeof(T);
    }

    return curr_read_ptr;
}

#pragma warning(pop)

const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes)
{
    const char* curr_read_ptr = read_ptr_;

    if (num_bytes < 0 || read_ptr_ + num_bytes > read_end_ptr_) {
        return nullptr;
    }

    read_ptr_ += Pickle::AlignInt(num_bytes, sizeof(uint32_t));

    return curr_read_ptr;
}

/*
 @ brief
    when the size of element doesn't equal to sizeof(char), use this function
    for safety consieration. this function runs overflow check on int32 num_bytes.
*/
const char* PickleIterator::GetReadPointerAndAdvance(int num_elements, size_t element_size)
{
    int64_t num_bytes = static_cast<int64_t>(num_elements) * element_size;
    int num_bytes32 = static_cast<int>(num_bytes);
    if (num_bytes != static_cast<int64_t>(num_bytes32)) {
        return nullptr;
    }

    return GetReadPointerAndAdvance(num_bytes32);
}

// payload is uint32 aligned

Pickle::Pickle() : header_(nullptr), capacity_(0), buffer_offset_(0)
{
    Resize(kPayloadUnit);
    header_->payload_size = 0;
}

Pickle::Pickle(const char* data, int)
    : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
      capacity_(kCapacityReadOnly),
      buffer_offset_(0)
{}

/*
 @ brief
    a deep copy of an Pickle object
*/
Pickle::Pickle(const Pickle& other) : header_(nullptr), capacity_(0),
                                      buffer_offset_(other.buffer_offset_)
{
    // if [other] is constructed from a const buffer, its capacity value is
    // kCapacityReadOnly. therefore, calculate its capacity on hand.
    size_t capacity = sizeof(Header) + other.header_->payload_size;
    bool resized = Resize(capacity);
    assert(resized);

    memcpy_s(header_, capacity_, other.header_, capacity);
}

Pickle::~Pickle()
{
    if (capacity_ != kCapacityReadOnly) {
        free(header_);
    }
}

Pickle& Pickle::operator=(const Pickle& rhs)
{
    if (this == &rhs) {
        assert(false);
        return *this;
    }

    if (capacity_ == kCapacityReadOnly) {
        header_ = nullptr;
        capacity_ = 0;
    }

    size_t capacity = sizeof(Header) + rhs.header_->payload_size;
    bool resized = Resize(capacity);
    assert(resized);

    memcpy_s(header_, capacity_, rhs.header_, capacity);
    buffer_offset_ = rhs.buffer_offset_;

    return *this;
}

/*
 @ brief
    resize the capacity of internal buffer. this function internally rounds the
    [new_capacity] up to the next multiple of predefined alignment
 @ params
    new_capacity[in] new capacity of internal buffer and will be aligned internally.
    be wary of that, the new_capacity actually includes internal header size.
    e.g. new_capacity = header_size + your_desired_payload_size
*/
bool Pickle::Resize(size_t new_capacity)
{
    assert(capacity_ != kCapacityReadOnly);
    new_capacity = AlignInt(new_capacity, kPayloadUnit);

    void* p = realloc(header_, new_capacity);
    if (!p) {
        return false;
    }

    header_ = static_cast<Header*>(p);
    capacity_ = new_capacity;

    return true;
}

// static
size_t Pickle::AlignInt(size_t i, int alignment)
{
    return i + (alignment - i % alignment) % alignment;
}

bool Pickle::WriteString(const std::string& value)
{
    if (!WriteInt(static_cast<int>(value.size()))) {
        return false;
    }

    return WriteByte(value.data(), static_cast<int>(value.size()));
}

bool Pickle::WriteWString(const std::wstring& value)
{
    if (!WriteInt(static_cast<int>(value.size()))) {
        return false;
    }

    return WriteByte(value.data(), static_cast<int>(value.size() * sizeof(wchar_t)));
}

/*
 @ brief
    serialize data in byte with specified length. PoD types only
    the function guarantees the internal data remains unchanged if this
    funtion fails.
*/
bool Pickle::WriteByte(const void* data, int data_len)
{
    if (capacity_ == kCapacityReadOnly) {
        assert(false);
        return false;
    }

    char* dest = BeginWrite(data_len);
    if (!dest) {
        return false;
    }

    size_t extra_size = capacity_ - (dest - reinterpret_cast<char*>(header_));
    memcpy_s(dest, extra_size, data, data_len);
    EndWrite(dest, data_len);

    return true;
}

bool Pickle::WriteData(const char* data, int length)
{
    return length >= 0 && WriteInt(length) && WriteByte(data, length);
}

/*
 @ brief
    locate to the next uint32-aligned offset. and resize internal buffer if
    necessary.
 @ return
    the location that the data should be written at, or
    nullptr if an error occured.
*/
char* Pickle::BeginWrite(size_t length)
{
    // write at a uint32-aligned offset from the begining of head
    size_t offset = AlignInt(header_->payload_size, sizeof(uint32_t));
    size_t required_size = offset + length;
    size_t total_required_size = required_size + sizeof(Header);

    if (total_required_size > capacity_ &&
        !Resize(std::max(capacity_ << 1, total_required_size))) {
        return nullptr;
    }

    header_->payload_size = static_cast<uint32_t>(required_size);

    return mutable_payload() + offset;
}

/*
 @ brief
    zero pading memory; otherwise some memory detectors may complain about
    uninitialized memory.
*/
void Pickle::EndWrite(char* dest, size_t length)
{
    if (length % sizeof(uint32_t)) {
        memset(dest + length, 0, sizeof(uint32_t) - (length % sizeof(uint32_t)));
    }
}

}
<|endoftext|>


<commit_before>/*
 * libjingle
 * Copyright 2004--2005, Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>  // NOLINT

#include "talk/base/thread.h"
#include "talk/p2p/base/relayserver.h"
#include "talk/examples/natty/natty_server.h"
#include "talk/app/webrtc/portallocatorfactory.h"
#include "talk/base/crc32.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
#include "talk/base/natserver.h"
#include "talk/base/natsocketfactory.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/socketaddress.h"
#include "talk/base/ssladapter.h"
#include "talk/examples/natty/natty_socket.h"
#include "talk/base/flags.h"
#include "talk/p2p/base/basicpacketsocketfactory.h"
#include "talk/p2p/base/portproxy.h"
#include "talk/p2p/base/relayport.h"
#include "talk/p2p/base/stunport.h"
#include "talk/p2p/base/tcpport.h"
#include "talk/p2p/base/testrelayserver.h"
#include "talk/p2p/base/teststunserver.h"
#include "talk/p2p/base/testturnserver.h"
#include "talk/p2p/base/transport.h"
#include "talk/p2p/base/turnport.h"

#define LOG2(fmt, ...) printf("%s:%d: \n" fmt, __FILE__, __LINE__, __VA_ARGS__);

typedef std::vector<NattySocket*> SocketArray;
typedef talk_base::BasicPacketSocketFactory NattySocketFactory;

using talk_base::PacketSocketFactory;
using talk_base::SocketAddress;
using talk_base::AsyncPacketSocket;
using talk_base::scoped_ptr;
using talk_base::Socket;
using talk_base::ByteBuffer;
using namespace cricket;

static const SocketAddress kLocalAddr1("192.168.1.2", 0);
static const SocketAddress kLocalAddr2("192.168.1.3", 0);

class FakePacketSocketFactory : public talk_base::PacketSocketFactory {
 public:
  FakePacketSocketFactory()
      : next_udp_socket_(NULL),
        next_server_tcp_socket_(NULL),
        next_client_tcp_socket_(NULL) {
  }
  virtual ~FakePacketSocketFactory() { }

  virtual AsyncPacketSocket* CreateUdpSocket(
      const SocketAddress& address, int min_port, int max_port) {
    //EXPECT_TRUE(next_udp_socket_ != NULL);
    AsyncPacketSocket* result = next_udp_socket_;
    next_udp_socket_ = NULL;
    return result;
  }

  virtual AsyncPacketSocket* CreateServerTcpSocket(
      const SocketAddress& local_address, int min_port, int max_port,
      int opts) {
    //EXPECT_TRUE(next_server_tcp_socket_ != NULL);
    AsyncPacketSocket* result = next_server_tcp_socket_;
    next_server_tcp_socket_ = NULL;
    return result;
  }

  // TODO: |proxy_info| and |user_agent| should be set
  // per-factory and not when socket is created.
  virtual AsyncPacketSocket* CreateClientTcpSocket(
      const SocketAddress& local_address, const SocketAddress& remote_address,
      const talk_base::ProxyInfo& proxy_info,
      const std::string& user_agent, int opts) {
    //EXPECT_TRUE(next_client_tcp_socket_ != NULL);
    AsyncPacketSocket* result = next_client_tcp_socket_;
    next_client_tcp_socket_ = NULL;
    return result;
  }

  void set_next_udp_socket(AsyncPacketSocket* next_udp_socket) {
    next_udp_socket_ = next_udp_socket;
  }
  void set_next_server_tcp_socket(AsyncPacketSocket* next_server_tcp_socket) {
    next_server_tcp_socket_ = next_server_tcp_socket;
  }
  void set_next_client_tcp_socket(AsyncPacketSocket* next_client_tcp_socket) {
    next_client_tcp_socket_ = next_client_tcp_socket;
  }
  talk_base::AsyncResolverInterface* CreateAsyncResolver() {
    return NULL;
  }

 private:
  AsyncPacketSocket* next_udp_socket_;
  AsyncPacketSocket* next_server_tcp_socket_;
  AsyncPacketSocket* next_client_tcp_socket_;
};

class FakeAsyncPacketSocket : public AsyncPacketSocket {
 public:
  // Returns current local address. Address may be set to NULL if the
  // socket is not bound yet (GetState() returns STATE_BINDING).
  virtual SocketAddress GetLocalAddress() const {
    return SocketAddress();
  }

  // Returns remote address. Returns zeroes if this is not a client TCP socket.
  virtual SocketAddress GetRemoteAddress() const {
    return SocketAddress();
  }

  // Send a packet.
  virtual int Send(const void *pv, size_t cb,
                   const talk_base::PacketOptions& options) {
    return static_cast<int>(cb);
  }
  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
                     const talk_base::PacketOptions& options) {
    return static_cast<int>(cb);
  }
  virtual int Close() {
    return 0;
  }

  virtual State GetState() const { return state_; }
  virtual int GetOption(Socket::Option opt, int* value) { return 0; }
  virtual int SetOption(Socket::Option opt, int value) { return 0; }
  virtual int GetError() const { return 0; }
  virtual void SetError(int error) { }

  void set_state(State state) { state_ = state; }

 private:
  State state_;
};

static Candidate GetCandidate(Port* port) {
  assert(port->Candidates().size() == 1);
  return port->Candidates()[0];
}

static IceMessage* CopyStunMessage(const IceMessage* src) {
  IceMessage* dst = new IceMessage();
  ByteBuffer buf;
  src->Write(&buf);
  dst->Read(&buf);
  return dst;
}

class TestChannel : public sigslot::has_slots<> {
 public:
  // Takes ownership of |p1| (but not |p2|).
  TestChannel(Port* p1, Port* p2)
      : ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0),
	conn_(NULL), remote_request_(), nominated_(false) {
    src_->SignalPortComplete.connect(
        this, &TestChannel::OnPortComplete);
    src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress);
    src_->SignalDestroyed.connect(this, &TestChannel::OnSrcPortDestroyed);
  }

  int complete_count() { return complete_count_; }
  Connection* conn() { return conn_; }
  const SocketAddress& remote_address() { return remote_address_; }
  const std::string remote_fragment() { return remote_frag_; }

  void Start() {
    src_->PrepareAddress();
  }
  void CreateConnection() {
    conn_ = src_->CreateConnection(GetCandidate(dst_), Port::ORIGIN_MESSAGE);
    IceMode remote_ice_mode =
        (ice_mode_ == ICEMODE_FULL) ? ICEMODE_LITE : ICEMODE_FULL;
    conn_->set_remote_ice_mode(remote_ice_mode);
    conn_->set_use_candidate_attr(remote_ice_mode == ICEMODE_FULL);
    conn_->SignalStateChange.connect(
        this, &TestChannel::OnConnectionStateChange);
  }
  void OnConnectionStateChange(Connection* conn) {
    if (conn->write_state() == Connection::STATE_WRITABLE) {
      conn->set_use_candidate_attr(true);
      nominated_ = true;
    }
  }
  void AcceptConnection() {
    //ASSERT_TRUE(remote_request_.get() != NULL);
    Candidate c = GetCandidate(dst_);
    c.set_address(remote_address_);
    conn_ = src_->CreateConnection(c, Port::ORIGIN_MESSAGE);
    src_->SendBindingResponse(remote_request_.get(), remote_address_);
    remote_request_.reset();
  }
  void Ping() {
    Ping(0);
  }
  void Ping(uint32 now) {
    conn_->Ping(now);
  }
  void Stop() {
    conn_->SignalDestroyed.connect(this, &TestChannel::OnDestroyed);
    conn_->Destroy();
  }

  void OnPortComplete(Port* port) {
    complete_count_++;
  }
  void SetIceMode(IceMode ice_mode) {
    ice_mode_ = ice_mode;
  }

  void OnUnknownAddress(PortInterface* port, const SocketAddress& addr,
                        ProtocolType proto,
                        IceMessage* msg, const std::string& rf,
                        bool /*port_muxed*/) {
    //ASSERT_EQ(src_.get(), port);
    if (!remote_address_.IsNil()) {
      //ASSERT_EQ(remote_address_, addr);
    }
    // MI and PRIORITY attribute should be present in ping requests when port
    // is in ICEPROTO_RFC5245 mode.
    const cricket::StunUInt32Attribute* priority_attr =
        msg->GetUInt32(STUN_ATTR_PRIORITY);
    const cricket::StunByteStringAttribute* mi_attr =
        msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
    const cricket::StunUInt32Attribute* fingerprint_attr =
        msg->GetUInt32(STUN_ATTR_FINGERPRINT);
    if (src_->IceProtocol() == cricket::ICEPROTO_RFC5245) {
      //EXPECT_TRUE(priority_attr != NULL);
      //EXPECT_TRUE(mi_attr != NULL);
      //EXPECT_TRUE(fingerprint_attr != NULL);
    } else {
      //EXPECT_TRUE(priority_attr == NULL);
      //EXPECT_TRUE(mi_attr == NULL);
      //EXPECT_TRUE(fingerprint_attr == NULL);
    }
    remote_address_ = addr;
    remote_request_.reset(CopyStunMessage(msg));
    remote_frag_ = rf;
  }

  void OnDestroyed(Connection* conn) {
    //ASSERT_EQ(conn_, conn);
    conn_ = NULL;
  }

  void OnSrcPortDestroyed(PortInterface* port) {
    Port* destroyed_src = src_.release();
    //ASSERT_EQ(destroyed_src, port);
  }

  bool nominated() const { return nominated_; }

 private:
  IceMode ice_mode_;
  talk_base::scoped_ptr<Port> src_;
  Port* dst_;

  int complete_count_;
  Connection* conn_;
  SocketAddress remote_address_;
  talk_base::scoped_ptr<StunMessage> remote_request_;
  std::string remote_frag_;
  bool nominated_;
};

void cleanConnections(SocketArray *sockets) {
  for (SocketArray::iterator i = sockets->begin(); i != sockets->end(); ++i)
    delete (*i);
  sockets->clear();
}

void acceptConnections(ListeningSocket *listener) {
  SocketArray sockets;
  bool quit = false;
  while (!quit) {
    fd_set socket_set;
    FD_ZERO(&socket_set);
    if (listener->valid())
      FD_SET(listener->socket(), &socket_set);
    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
      FD_SET((*i)->socket(), &socket_set);

    struct timeval timeout = { 10, 0 };
    if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
      printf("select failed\n");
      break;
    }

    if (FD_ISSET(listener->socket(), &socket_set)) {
      NattySocket* s = listener->Accept();
      sockets.push_back(s);
      printf("New connection made!\n");
    }
  }
  printf("Exiting accept connections loop\n");
  cleanConnections(&sockets);
}

UDPPort* CreateUdpPort(const SocketAddress& addr,
    PacketSocketFactory* socket_factory,
    talk_base::Network *network
    ) {
  std::string username_ = talk_base::CreateRandomString(ICE_UFRAG_LENGTH);
  std::string password_ = talk_base::CreateRandomString(ICE_PWD_LENGTH);
  //std::cout << "username : " << username_;
  //std::cout << "password : " << password_;
  UDPPort* port = UDPPort::Create(talk_base::Thread::Current(), socket_factory, network,
      addr.ipaddr(), 0, 3000, "", "");
  port->SetIceProtocolType(cricket::ICEPROTO_GOOGLE);
  port->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
  port->PrepareAddress();

  return NULL;
  //return port;
}

int main(int argc, char **argv) {
  FakeAsyncPacketSocket *s1 = new FakeAsyncPacketSocket();
  FakePacketSocketFactory socket_factory;

  socket_factory.set_next_udp_socket(s1);
  talk_base::Network *network = new talk_base::Network("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32);
  printf("HEY.\n");
  //network->AddIP(talk_base::IPAddress(INADDR_ANY));
  //Port* p1 = CreateUdpPort(kLocalAddr1, &socket_factory, network);

  /*
  //socket_factory.set_next_udp_socket(s2);
    Port* p2 = CreateUdpPort(kLocalAddr2, &socket_factory, network);
  //TestChannel ch1(p1, p2);
//  TestConnectivity("udp", port1, "udp", port2, true, true, true, true);

  delete network;
  delete s1;
  //delete p1;
    */
  //delete network;
  delete s1;
  //delete network;
  /*ListeningSocket listener;
  if (!listener.Create()) {
    printf("Failed to create server socket\n");
    return -1;
  } else if (!listener.Listen(8888)) {
    printf("Failed to listen on server socket\n");
    return -1;
  }
  printf("listening for connections\n");
  acceptConnections(&listener);
    */

  return 0;
}
<commit_msg>initial application structure and natty ninja/gyp build files<commit_after>/*
 * libjingle
 * Copyright 2004--2005, Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <iostream>  // NOLINT

#include "talk/base/thread.h"
#include "talk/p2p/base/relayserver.h"
#include "talk/examples/natty/natty_server.h"
#include "talk/app/webrtc/portallocatorfactory.h"
#include "talk/base/crc32.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
#include "talk/base/natserver.h"
#include "talk/base/natsocketfactory.h"
#include "talk/base/physicalsocketserver.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/socketaddress.h"
#include "talk/base/ssladapter.h"
#include "talk/examples/natty/natty_socket.h"
#include "talk/base/flags.h"
#include "talk/p2p/base/basicpacketsocketfactory.h"
#include "talk/p2p/base/portproxy.h"
#include "talk/p2p/base/relayport.h"
#include "talk/p2p/base/stunport.h"
#include "talk/p2p/base/tcpport.h"
#include "talk/p2p/base/testrelayserver.h"
#include "talk/p2p/base/teststunserver.h"
#include "talk/p2p/base/testturnserver.h"
#include "talk/p2p/base/transport.h"
#include "talk/p2p/base/turnport.h"

#define LOG2(fmt, ...) printf("%s:%d: \n" fmt, __FILE__, __LINE__, __VA_ARGS__);

typedef std::vector<NattySocket*> SocketArray;
typedef talk_base::BasicPacketSocketFactory NattySocketFactory;

using talk_base::PacketSocketFactory;
using talk_base::SocketAddress;
using talk_base::AsyncPacketSocket;
using talk_base::scoped_ptr;
using talk_base::Socket;
using talk_base::ByteBuffer;
using namespace cricket;

static const SocketAddress kLocalAddr1("192.168.1.2", 0);
static const SocketAddress kLocalAddr2("192.168.1.3", 0);

class FakePacketSocketFactory : public talk_base::PacketSocketFactory {
 public:
  FakePacketSocketFactory()
      : next_udp_socket_(NULL),
        next_server_tcp_socket_(NULL),
        next_client_tcp_socket_(NULL) {
  }
  virtual ~FakePacketSocketFactory() { }

  virtual AsyncPacketSocket* CreateUdpSocket(
      const SocketAddress& address, int min_port, int max_port) {
    //EXPECT_TRUE(next_udp_socket_ != NULL);
    AsyncPacketSocket* result = next_udp_socket_;
    next_udp_socket_ = NULL;
    return result;
  }

  virtual AsyncPacketSocket* CreateServerTcpSocket(
      const SocketAddress& local_address, int min_port, int max_port,
      int opts) {
    //EXPECT_TRUE(next_server_tcp_socket_ != NULL);
    AsyncPacketSocket* result = next_server_tcp_socket_;
    next_server_tcp_socket_ = NULL;
    return result;
  }

  // TODO: |proxy_info| and |user_agent| should be set
  // per-factory and not when socket is created.
  virtual AsyncPacketSocket* CreateClientTcpSocket(
      const SocketAddress& local_address, const SocketAddress& remote_address,
      const talk_base::ProxyInfo& proxy_info,
      const std::string& user_agent, int opts) {
    //EXPECT_TRUE(next_client_tcp_socket_ != NULL);
    AsyncPacketSocket* result = next_client_tcp_socket_;
    next_client_tcp_socket_ = NULL;
    return result;
  }

  void set_next_udp_socket(AsyncPacketSocket* next_udp_socket) {
    next_udp_socket_ = next_udp_socket;
  }
  void set_next_server_tcp_socket(AsyncPacketSocket* next_server_tcp_socket) {
    next_server_tcp_socket_ = next_server_tcp_socket;
  }
  void set_next_client_tcp_socket(AsyncPacketSocket* next_client_tcp_socket) {
    next_client_tcp_socket_ = next_client_tcp_socket;
  }
  talk_base::AsyncResolverInterface* CreateAsyncResolver() {
    return NULL;
  }

 private:
  AsyncPacketSocket* next_udp_socket_;
  AsyncPacketSocket* next_server_tcp_socket_;
  AsyncPacketSocket* next_client_tcp_socket_;
};

class FakeAsyncPacketSocket : public AsyncPacketSocket {
 public:
  // Returns current local address. Address may be set to NULL if the
  // socket is not bound yet (GetState() returns STATE_BINDING).
  virtual SocketAddress GetLocalAddress() const {
    return SocketAddress();
  }

  // Returns remote address. Returns zeroes if this is not a client TCP socket.
  virtual SocketAddress GetRemoteAddress() const {
    return SocketAddress();
  }

  // Send a packet.
  virtual int Send(const void *pv, size_t cb,
                   const talk_base::PacketOptions& options) {
    return static_cast<int>(cb);
  }
  virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
                     const talk_base::PacketOptions& options) {
    return static_cast<int>(cb);
  }
  virtual int Close() {
    return 0;
  }

  virtual State GetState() const { return state_; }
  virtual int GetOption(Socket::Option opt, int* value) { return 0; }
  virtual int SetOption(Socket::Option opt, int value) { return 0; }
  virtual int GetError() const { return 0; }
  virtual void SetError(int error) { }

  void set_state(State state) { state_ = state; }

 private:
  State state_;
};

static Candidate GetCandidate(Port* port) {
  assert(port->Candidates().size() == 1);
  return port->Candidates()[0];
}

static IceMessage* CopyStunMessage(const IceMessage* src) {
  IceMessage* dst = new IceMessage();
  ByteBuffer buf;
  src->Write(&buf);
  dst->Read(&buf);
  return dst;
}

class TestChannel : public sigslot::has_slots<> {
 public:
  // Takes ownership of |p1| (but not |p2|).
  TestChannel(Port* p1, Port* p2)
      : ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0),
	conn_(NULL), remote_request_(), nominated_(false) {
    src_->SignalPortComplete.connect(
        this, &TestChannel::OnPortComplete);
    src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress);
    src_->SignalDestroyed.connect(this, &TestChannel::OnSrcPortDestroyed);
  }

  int complete_count() { return complete_count_; }
  Connection* conn() { return conn_; }
  const SocketAddress& remote_address() { return remote_address_; }
  const std::string remote_fragment() { return remote_frag_; }

  void Start() {
    src_->PrepareAddress();
  }
  void CreateConnection() {
    conn_ = src_->CreateConnection(GetCandidate(dst_), Port::ORIGIN_MESSAGE);
    IceMode remote_ice_mode =
        (ice_mode_ == ICEMODE_FULL) ? ICEMODE_LITE : ICEMODE_FULL;
    conn_->set_remote_ice_mode(remote_ice_mode);
    conn_->set_use_candidate_attr(remote_ice_mode == ICEMODE_FULL);
    conn_->SignalStateChange.connect(
        this, &TestChannel::OnConnectionStateChange);
  }
  void OnConnectionStateChange(Connection* conn) {
    if (conn->write_state() == Connection::STATE_WRITABLE) {
      conn->set_use_candidate_attr(true);
      nominated_ = true;
    }
  }
  void AcceptConnection() {
    //ASSERT_TRUE(remote_request_.get() != NULL);
    Candidate c = GetCandidate(dst_);
    c.set_address(remote_address_);
    conn_ = src_->CreateConnection(c, Port::ORIGIN_MESSAGE);
    src_->SendBindingResponse(remote_request_.get(), remote_address_);
    remote_request_.reset();
  }
  void Ping() {
    Ping(0);
  }
  void Ping(uint32 now) {
    conn_->Ping(now);
  }
  void Stop() {
    conn_->SignalDestroyed.connect(this, &TestChannel::OnDestroyed);
    conn_->Destroy();
  }

  void OnPortComplete(Port* port) {
    complete_count_++;
  }
  void SetIceMode(IceMode ice_mode) {
    ice_mode_ = ice_mode;
  }

  void OnUnknownAddress(PortInterface* port, const SocketAddress& addr,
                        ProtocolType proto,
                        IceMessage* msg, const std::string& rf,
                        bool /*port_muxed*/) {
    //ASSERT_EQ(src_.get(), port);
    if (!remote_address_.IsNil()) {
      //ASSERT_EQ(remote_address_, addr);
    }
    // MI and PRIORITY attribute should be present in ping requests when port
    // is in ICEPROTO_RFC5245 mode.
    const cricket::StunUInt32Attribute* priority_attr =
        msg->GetUInt32(STUN_ATTR_PRIORITY);
    const cricket::StunByteStringAttribute* mi_attr =
        msg->GetByteString(STUN_ATTR_MESSAGE_INTEGRITY);
    const cricket::StunUInt32Attribute* fingerprint_attr =
        msg->GetUInt32(STUN_ATTR_FINGERPRINT);
    if (src_->IceProtocol() == cricket::ICEPROTO_RFC5245) {
      //EXPECT_TRUE(priority_attr != NULL);
      //EXPECT_TRUE(mi_attr != NULL);
      //EXPECT_TRUE(fingerprint_attr != NULL);
    } else {
      //EXPECT_TRUE(priority_attr == NULL);
      //EXPECT_TRUE(mi_attr == NULL);
      //EXPECT_TRUE(fingerprint_attr == NULL);
    }
    remote_address_ = addr;
    remote_request_.reset(CopyStunMessage(msg));
    remote_frag_ = rf;
  }

  void OnDestroyed(Connection* conn) {
    //ASSERT_EQ(conn_, conn);
    conn_ = NULL;
  }

  void OnSrcPortDestroyed(PortInterface* port) {
    Port* destroyed_src = src_.release();
    //ASSERT_EQ(destroyed_src, port);
  }

  bool nominated() const { return nominated_; }

 private:
  IceMode ice_mode_;
  talk_base::scoped_ptr<Port> src_;
  Port* dst_;

  int complete_count_;
  Connection* conn_;
  SocketAddress remote_address_;
  talk_base::scoped_ptr<StunMessage> remote_request_;
  std::string remote_frag_;
  bool nominated_;
};

void cleanConnections(SocketArray *sockets) {
  for (SocketArray::iterator i = sockets->begin(); i != sockets->end(); ++i)
    delete (*i);
  sockets->clear();
}

void acceptConnections(ListeningSocket *listener) {
  SocketArray sockets;
  bool quit = false;
  while (!quit) {
    fd_set socket_set;
    FD_ZERO(&socket_set);
    if (listener->valid())
      FD_SET(listener->socket(), &socket_set);
    for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
      FD_SET((*i)->socket(), &socket_set);

    struct timeval timeout = { 10, 0 };
    if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
      printf("select failed\n");
      break;
    }

    if (FD_ISSET(listener->socket(), &socket_set)) {
      NattySocket* s = listener->Accept();
      sockets.push_back(s);
      printf("New connection made!\n");
    }
  }
  printf("Exiting accept connections loop\n");
  cleanConnections(&sockets);
}

UDPPort* CreateUdpPort(const SocketAddress& addr,
    PacketSocketFactory* socket_factory,
    talk_base::Network *network
    ) {
  std::string username_ = talk_base::CreateRandomString(ICE_UFRAG_LENGTH);
  std::string password_ = talk_base::CreateRandomString(ICE_PWD_LENGTH);
  //std::cout << "username : " << username_;
  //std::cout << "password : " << password_;
  UDPPort* port = UDPPort::Create(talk_base::Thread::Current(), socket_factory, network,
      addr.ipaddr(), 0, 3000, "", "");
  port->SetIceProtocolType(cricket::ICEPROTO_GOOGLE);
  port->set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
  port->PrepareAddress();

  return NULL;
  //return port;
}

int main(int argc, char **argv) {
  FakeAsyncPacketSocket *s1 = new FakeAsyncPacketSocket();
  FakePacketSocketFactory socket_factory;

  socket_factory.set_next_udp_socket(s1);
  talk_base::Network *network = new talk_base::Network("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32);

  delete network;

  return 0;
}
<|endoftext|>


<commit_before>#ifndef _RATIONAL_H
#define _RATIONAL_H

#include <cmath>
#include <cstddef>
#include <stdexcept>
#include <type_traits>

#ifndef RATIONAL_NCONSTEXPR
#define CONSTEXPR constexpr
#else
#define CONSTEXPR /* not supported */
#endif

namespace rational {

    struct NoReduceTag {};

    struct DivideByZeroException : public std::runtime_error {
        DivideByZeroException() noexcept :
            runtime_error("Division by zero is undefined.")
        {  }
    };

    struct OverflowException : public std::runtime_error {
        OverflowException() noexcept :
            runtime_error("Arithmetic operation resulted in an overflow.")
        {  }
    };

    namespace detail {

        template<class T>
        inline CONSTEXPR T cpow(const T base, unsigned const exponent) noexcept
        {
            return (exponent == 0) ? 1 : (base * pow(base, exponent-1));
        }

        template<class T>
        inline T gcd(T a, T b) noexcept {
            if(a < 0) a = -a;
            if(b < 0) b = -b;
            while(b != 0) {
                a %= b;
                if(a == 0) {
                    return b;
                }
                b %= a;
            }
            return a;
        }

    } // namespace detail

    template<class T>
    struct Ratio {
    public:

        static_assert(std::is_integral<T>::value, "Ratio<T>: T must meet the requirements of Integral");

        const T numer;
        const T denom;

        inline CONSTEXPR Ratio() noexcept :
            numer(0),
            denom(1)
        {  }

        inline CONSTEXPR Ratio(const T& numer) noexcept :
            numer(numer),
            denom(1)
        {
        }

        inline Ratio(const T& numer, const T& denom) :
            numer(numer),
            denom(denom)
        {
            if(denom == 0) {
                throw DivideByZeroException();
            }
            *this = reduce(*this);
        }

        inline CONSTEXPR Ratio(const T& numer, const T& denom, NoReduceTag) noexcept :
            numer(numer),
            denom(denom)
        {  }

        inline CONSTEXPR Ratio(const Ratio& r) noexcept :
            numer(r.numer),
            denom(r.denom)
        {  }

        inline Ratio& operator=(const Ratio& r) noexcept
        {
            new (this) Ratio<T>(r);
            return *this;
        }

        template<class U>
        inline CONSTEXPR Ratio(const Ratio<U>& r) noexcept :
            numer(r.numer),
            denom(r.denom)
        {
            static_assert(std::is_convertible<U, T>::value,
                "Ratio<T>::Ratio<U>(const Ratio<U>&): U must meet the requirements of ImplicitlyConvertible to T.");
        }

        template<class U>
        inline Ratio& operator=(const Ratio<U>& r) noexcept
        {
            static_assert(std::is_convertible<U, T>::value,
                "Ratio<T>::operator=<U>(const Ratio<U>&): U must meet the requirements of ImplicitlyConvertible to T.");
            new (this) Ratio<T>(r.numer, r.denom, NoReduceTag());
            return *this;
        }

        inline static CONSTEXPR T to_integer(const Ratio& r) noexcept
        {
            return T(r.numer / r.denom);
        }

        template<class Float = float>
        inline static CONSTEXPR Float to_float(const Ratio& r) noexcept
        {
            static_assert(std::is_constructible<Float, T>::value,
                "Ratio<T>::to_floating<Float>(): T must meet the requirements of Convertible to Float.");
            return Float(Float(r.numer) / Float(r.denom));
        }

        template<class Float = float>
        inline static Ratio from_float(const Float& u, const unsigned prec)
        {
            const Ratio r (T(u * detail::cpow(10, prec)), T(detail::cpow(10, prec)));
            if((u > 0 && u > r.numer)
                || (u < 0 && u < r.numer)) {
                throw OverflowException();
            }
            return r;
        }

        inline static CONSTEXPR Ratio zero() noexcept
        {
            return Ratio(0, 1, NoReduceTag());
        }

        inline static CONSTEXPR Ratio one() noexcept
        {
            return Ratio(1, 1, NoReduceTag());
        }

        inline static CONSTEXPR Ratio pi() noexcept
        {
            return Ratio(6283, 2000, NoReduceTag());
        }

        template<class U>
        inline explicit CONSTEXPR operator Ratio<U>() const noexcept
        {
            static_assert(std::is_convertible<U, T>::value,
                "Ratio<T>::operator Ratio<U>(): T must meet the requirements of ImplicitlyConvertible to U.");
            return Ratio<U>(U(this->numer), U(this->denom), NoReduceTag());
        }

        inline friend Ratio<T> operator+(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom) + (lhs.denom * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator-(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom) - (lhs.denom * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator%(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom) % (lhs.denom * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator*(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator/(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom), (lhs.denom * rhs.numer));
        }

        inline friend Ratio<T> operator+=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs + rhs;
        }

        inline friend Ratio<T> operator-=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs - rhs;
        }

        inline friend Ratio<T> operator*=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs * rhs;
        }

        inline friend Ratio<T> operator/=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs / rhs;
        }

        inline friend Ratio<T> operator%=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs % rhs;
        }

        inline friend bool operator==(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return (lhs.numer * lhs.denom) == (rhs.numer * rhs.denom);
        }

        inline friend bool operator!=(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return !(lhs == rhs);
        }

        inline friend bool operator>(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return (lhs.numer * lhs.denom) > (rhs.numer * rhs.denom);
        }

        inline friend bool operator<(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return (rhs > lhs);
        }

        inline friend bool operator<=(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return !(lhs > rhs);
        }

        inline friend bool operator>=(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return !(lhs < rhs);
        }

    };

    template<class T>
    inline Ratio<T> operator+(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(r);
    }

    template<class T>
    inline Ratio<T> operator-(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(-r.numer, r.denom, NoReduceTag());
    }

    template<class T>
    inline Ratio<T>& operator++(Ratio<T>& r) noexcept
    {
        return r = Ratio<T>(r.numer + r.denom, r.denom);
    }

    template<class T>
    inline Ratio<T>& operator--(Ratio<T>& r) noexcept
    {
        return r = Ratio<T>(r.numer - r.denom, r.denom);
    }

    template<class T>
    inline Ratio<T> operator++(Ratio<T>& r, int) noexcept
    {
        const Ratio<T> cpy = r;
        ++r;
        return cpy;
    }

    template<class T>
    inline Ratio<T> operator--(Ratio<T>& r, int) noexcept
    {
        const Ratio<T> cpy = r;
        --r;
        return cpy;
    }

    template<class T>
    inline bool is_integer(const Ratio<T>& r) noexcept
    {
        return r.denom == T(1);
    }
    template<class T>
    inline bool is_zero(const Ratio<T>& r) noexcept
    {
        return (r.numer == 0);
    }

    template<class T>
    inline bool is_positive(const Ratio<T>& r) noexcept
    {
        return (r.numer > 0);
    }

    template<class T>
    inline bool is_negative(const Ratio<T>& r) noexcept
    {
        return (r.numer < 0);
    }

    template<class T>
    inline Ratio<T> reduce(const Ratio<T>& r) noexcept
    {
        T numer = r.numer;
        T denom = r.denom;

        const T g = detail::gcd(numer, denom);

        numer /= g;
        denom /= g;

        if(denom < T(0)) {
            return Ratio<T>(-numer, -denom, NoReduceTag());
        } else {
            return Ratio<T>(numer, denom, NoReduceTag());
        }
    }

    template<class T>
    inline Ratio<T> floor(const Ratio<T>& r) noexcept
    {
        const T numer = r.numer;
        const T denom = r.denom;

        if(is_negative(r)) {
            return Ratio<T>((numer - denom + T(1)) / denom);
        } else {
            return Ratio<T>(numer / denom);
        }
    }

    template<class T>
    inline Ratio<T> ceil(const Ratio<T>& r) noexcept
    {
        const T numer = r.numer;
        const T denom = r.denom;

        if(is_negative(r)) {
            return Ratio<T>(numer / denom);
        } else {
            return Ratio<T>((numer + denom - T(1)) / denom);
        }
    }

    template<class T>
    inline Ratio<T> round(const Ratio<T>& r) noexcept
    {
        const Ratio<T> zero = Ratio<T>::zero();
        const T one(1);
        const T two(one + one);

        Ratio<T> fractional = r.fract();
        if(fractional < zero) {
            fractional = zero - fractional;
        }

        const bool half_or_larger;
        if(fractional.denom % 2 == 0) {
            half_or_larger = fractional.numer >= fractional.denom / two;
        } else {
            half_or_larger = fractional.numer >= (fractional.denom / two) + one;
        }

        if(half_or_larger) {
            if(is_positive(r)) {
                return r.trunc() + Ratio<T>::one();
            } else {
                return r.trunc() - Ratio<T>::one();
            }
        } else {
            return r.trunc();
        }
    }

    template<class T>
    inline Ratio<T> trunc(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(r.numer / r.denom);
    }

    template<class T>
    inline Ratio<T> fract(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(r.numer % r.denom, r.denom, NoReduceTag());
    }

    template<class T>
    inline Ratio<T> pow(const Ratio<T>& r, int expon) noexcept
    {
        if(expon == 0) {
            return Ratio<T>(1);
        } else if(expon < 0) {
            return std::pow(recip(r), -expon);
        } else {
            return Ratio<T>(std::pow(r.numer, expon), std::pow(r.numer, expon));
        }
    }

    template<class T>
    inline Ratio<T> abs(const Ratio<T>& r) noexcept
    {
        return (r.is_positive() || r.is_zero() ? r : -r);
    }

    template<class T>
    inline Ratio<T> abs_sub(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
    {
        return abs(lhs - rhs);
    }

    template<class T>
    inline Ratio<T> signum(const Ratio<T>& r) noexcept
    {
        if(is_zero(r)) {
            return Ratio<T>(0);
        } else if(is_positive(r)) {
            return Ratio<T>(1);
        } else {
            return Ratio<T>(-1);
        }
    }

    typedef Ratio<std::ptrdiff_t> Rational;
    typedef Ratio<std::int32_t> Rational32;
    typedef Ratio<std::int64_t> Rational64;

} // namespace rational

#endif<commit_msg>Fully switched from member to global functions.<commit_after>#ifndef _RATIONAL_H
#define _RATIONAL_H

#include <cmath>
#include <cstddef>
#include <stdexcept>
#include <type_traits>

#ifndef RATIONAL_NCONSTEXPR
#define CONSTEXPR constexpr
#else
#define CONSTEXPR /* not supported */
#endif

namespace rational {

    struct NoReduceTag {};

    struct DivideByZeroException : public std::runtime_error {
        DivideByZeroException() noexcept :
            runtime_error("Division by zero is undefined.")
        {  }
    };

    struct OverflowException : public std::runtime_error {
        OverflowException() noexcept :
            runtime_error("Arithmetic operation resulted in an overflow.")
        {  }
    };

    namespace detail {

        template<class T>
        inline CONSTEXPR T cpow(const T base, unsigned const exponent) noexcept
        {
            return (exponent == 0) ? 1 : (base * pow(base, exponent-1));
        }

        template<class T>
        inline T gcd(T a, T b) noexcept {
            if(a < 0) a = -a;
            if(b < 0) b = -b;
            while(b != 0) {
                a %= b;
                if(a == 0) {
                    return b;
                }
                b %= a;
            }
            return a;
        }

    } // namespace detail

    template<class T>
    struct Ratio {
    public:

        static_assert(std::is_integral<T>::value, "Ratio<T>: T must meet the requirements of Integral");

        const T numer;
        const T denom;

        inline CONSTEXPR Ratio() noexcept :
            numer(0),
            denom(1)
        {  }

        inline CONSTEXPR Ratio(const T& numer) noexcept :
            numer(numer),
            denom(1)
        {
        }

        inline Ratio(const T& numer, const T& denom) :
            numer(numer),
            denom(denom)
        {
            if(denom == 0) {
                throw DivideByZeroException();
            }
            *this = reduce(*this);
        }

        inline CONSTEXPR Ratio(const T& numer, const T& denom, NoReduceTag) noexcept :
            numer(numer),
            denom(denom)
        {  }

        inline CONSTEXPR Ratio(const Ratio& r) noexcept :
            numer(r.numer),
            denom(r.denom)
        {  }

        inline Ratio& operator=(const Ratio& r) noexcept
        {
            new (this) Ratio<T>(r);
            return *this;
        }

        inline static CONSTEXPR T to_integer(const Ratio& r) noexcept
        {
            return T(r.numer / r.denom);
        }

        template<class Float = float>
        inline static CONSTEXPR Float to_float(const Ratio& r) noexcept
        {
            return Float(Float(r.numer) / Float(r.denom));
        }

        template<class Float = float>
        inline static Ratio from_float(const Float& u, const unsigned prec)
        {
            const Ratio r (T(u * detail::cpow(10, prec)), T(detail::cpow(10, prec)));
            if((u > 0 && u > r.numer)
                || (u < 0 && u < r.numer)) {
                throw OverflowException();
            }
            return r;
        }

        inline static CONSTEXPR Ratio zero() noexcept
        {
            return Ratio(0, 1, NoReduceTag());
        }

        inline static CONSTEXPR Ratio one() noexcept
        {
            return Ratio(1, 1, NoReduceTag());
        }

        inline static CONSTEXPR Ratio pi() noexcept
        {
            return Ratio(6283, 2000, NoReduceTag());
        }

        template<class U>
        inline explicit CONSTEXPR operator Ratio<U>() const noexcept
        {
            return Ratio<U>(U(this->numer), U(this->denom), NoReduceTag());
        }

        inline friend Ratio<T> operator+(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom) + (lhs.denom * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator-(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom) - (lhs.denom * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator%(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom) % (lhs.denom * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator*(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.numer), (lhs.denom * rhs.denom));
        }

        inline friend Ratio<T> operator/(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return Ratio<T>((lhs.numer * rhs.denom), (lhs.denom * rhs.numer));
        }

        inline friend Ratio<T> operator+=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs + rhs;
        }

        inline friend Ratio<T> operator-=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs - rhs;
        }

        inline friend Ratio<T> operator*=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs * rhs;
        }

        inline friend Ratio<T> operator/=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs / rhs;
        }

        inline friend Ratio<T> operator%=(Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return lhs = lhs % rhs;
        }

        inline friend bool operator==(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return (lhs.numer * lhs.denom) == (rhs.numer * rhs.denom);
        }

        inline friend bool operator!=(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return !(lhs == rhs);
        }

        inline friend bool operator>(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return (lhs.numer * lhs.denom) > (rhs.numer * rhs.denom);
        }

        inline friend bool operator<(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return (rhs > lhs);
        }

        inline friend bool operator<=(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return !(lhs > rhs);
        }

        inline friend bool operator>=(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
        {
            return !(lhs < rhs);
        }

        template<class U>
        constexpr explicit operator Ratio<U>() const noexcept
        {
            return Ratio<U>(U(this->numer), U(this->denom));
        }

    };

    template<class T>
    inline Ratio<T> operator+(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(r);
    }

    template<class T>
    inline Ratio<T> operator-(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(-r.numer, r.denom, NoReduceTag());
    }

    template<class T>
    inline Ratio<T>& operator++(Ratio<T>& r) noexcept
    {
        return r = Ratio<T>(r.numer + r.denom, r.denom);
    }

    template<class T>
    inline Ratio<T>& operator--(Ratio<T>& r) noexcept
    {
        return r = Ratio<T>(r.numer - r.denom, r.denom);
    }

    template<class T>
    inline Ratio<T> operator++(Ratio<T>& r, int) noexcept
    {
        const Ratio<T> cpy = r;
        ++r;
        return cpy;
    }

    template<class T>
    inline Ratio<T> operator--(Ratio<T>& r, int) noexcept
    {
        const Ratio<T> cpy = r;
        --r;
        return cpy;
    }

    template<class T>
    inline bool is_integer(const Ratio<T>& r) noexcept
    {
        return r.denom == T(1);
    }
    template<class T>
    inline bool is_zero(const Ratio<T>& r) noexcept
    {
        return (r.numer == 0);
    }

    template<class T>
    inline bool is_positive(const Ratio<T>& r) noexcept
    {
        return (r.numer > 0);
    }

    template<class T>
    inline bool is_negative(const Ratio<T>& r) noexcept
    {
        return (r.numer < 0);
    }

    template<class T>
    inline Ratio<T> reduce(const Ratio<T>& r) noexcept
    {
        T numer = r.numer;
        T denom = r.denom;

        const T g = detail::gcd(numer, denom);

        numer /= g;
        denom /= g;

        if(denom < T(0)) {
            return Ratio<T>(-numer, -denom, NoReduceTag());
        } else {
            return Ratio<T>(numer, denom, NoReduceTag());
        }
    }

    template<class T>
    inline Ratio<T> floor(const Ratio<T>& r) noexcept
    {
        const T numer = r.numer;
        const T denom = r.denom;

        if(is_negative(r)) {
            return Ratio<T>((numer - denom + T(1)) / denom);
        } else {
            return Ratio<T>(numer / denom);
        }
    }

    template<class T>
    inline Ratio<T> ceil(const Ratio<T>& r) noexcept
    {
        const T numer = r.numer;
        const T denom = r.denom;

        if(is_negative(r)) {
            return Ratio<T>(numer / denom);
        } else {
            return Ratio<T>((numer + denom - T(1)) / denom);
        }
    }

    template<class T>
    inline Ratio<T> round(const Ratio<T>& r) noexcept
    {
        const Ratio<T> zero = Ratio<T>::zero();
        const T one(1);
        const T two(one + one);

        Ratio<T> fractional = fract(r);
        if(fractional < zero) {
            fractional = zero - fractional;
        }

        const bool half_or_larger;
        if(fractional.denom % 2 == 0) {
            half_or_larger = fractional.numer >= fractional.denom / two;
        } else {
            half_or_larger = fractional.numer >= (fractional.denom / two) + one;
        }

        if(half_or_larger) {
            if(is_positive(r)) {
                return trunc(r) + Ratio<T>::one();
            } else {
                return trunc(r) - Ratio<T>::one();
            }
        } else {
            return trunc(r);
        }
    }

    template<class T>
    inline Ratio<T> trunc(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(r.numer / r.denom);
    }

    template<class T>
    inline Ratio<T> fract(const Ratio<T>& r) noexcept
    {
        return Ratio<T>(r.numer % r.denom, r.denom, NoReduceTag());
    }

    template<class T>
    inline Ratio<T> pow(const Ratio<T>& r, int expon) noexcept
    {
        if(expon == 0) {
            return Ratio<T>(1);
        } else if(expon < 0) {
            return std::pow(recip(r), -expon);
        } else {
            return Ratio<T>(std::pow(r.numer, expon), std::pow(r.numer, expon));
        }
    }

    template<class T>
    inline Ratio<T> abs(const Ratio<T>& r) noexcept
    {
        return (is_negative(r) ? -r : r);
    }

    template<class T>
    inline Ratio<T> abs_sub(const Ratio<T>& lhs, const Ratio<T>& rhs) noexcept
    {
        return abs(lhs - rhs);
    }

    template<class T>
    inline Ratio<T> signum(const Ratio<T>& r) noexcept
    {
        if(is_zero(r)) {
            return Ratio<T>(0);
        } else if(is_positive(r)) {
            return Ratio<T>(1);
        } else {
            return Ratio<T>(-1);
        }
    }

    typedef Ratio<std::ptrdiff_t> Rational;
    typedef Ratio<std::int32_t> Rational32;
    typedef Ratio<std::int64_t> Rational64;

} // namespace rational

#endif<|endoftext|>