<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/server/web_socket.h"

#include "base/base64.h"
#include "base/rand_util.h"
#include "base/logging.h"
#include "base/md5.h"
#include "base/sha1.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "net/server/http_connection.h"
#include "net/server/http_server_request_info.h"

#if defined(OS_WIN)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif

#include <limits>

namespace net {

namespace {

static uint32 WebSocketKeyFingerprint(const std::string& str) {
  std::string result;
  const char* p_char = str.c_str();
  int length = str.length();
  int spaces = 0;
  for (int i = 0; i < length; ++i) {
    if (p_char[i] >= '0' && p_char[i] <= '9')
      result.append(&p_char[i], 1);
    else if (p_char[i] == ' ')
      spaces++;
  }
  if (spaces == 0)
    return 0;
  int64 number = 0;
  if (!base::StringToInt64(result, &number))
    return 0;
  return htonl(static_cast<uint32>(number / spaces));
}

class WebSocketHixie76 : public net::WebSocket {
 public:
  static net::WebSocket* Create(HttpConnection* connection,
                                const HttpServerRequestInfo& request,
                                size_t* pos) {
    if (connection->recv_data().length() < *pos + kWebSocketHandshakeBodyLen)
      return NULL;
    return new WebSocketHixie76(connection, request, pos);
  }

  virtual void Accept(const HttpServerRequestInfo& request) {
    std::string key1 = request.GetHeaderValue("Sec-WebSocket-Key1");
    std::string key2 = request.GetHeaderValue("Sec-WebSocket-Key2");

    uint32 fp1 = WebSocketKeyFingerprint(key1);
    uint32 fp2 = WebSocketKeyFingerprint(key2);

    char data[16];
    memcpy(data, &fp1, 4);
    memcpy(data + 4, &fp2, 4);
    memcpy(data + 8, &key3_[0], 8);

    base::MD5Digest digest;
    base::MD5Sum(data, 16, &digest);

    std::string origin = request.GetHeaderValue("Origin");
    std::string host = request.GetHeaderValue("Host");
    std::string location = "ws://" + host + request.path;
    connection_->Send(base::StringPrintf(
        "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
        "Upgrade: WebSocket\r\n"
        "Connection: Upgrade\r\n"
        "Sec-WebSocket-Origin: %s\r\n"
        "Sec-WebSocket-Location: %s\r\n"
        "\r\n",
        origin.c_str(),
        location.c_str()));
    connection_->Send(reinterpret_cast<char*>(digest.a), 16);
  }

  virtual ParseResult Read(std::string* message) {
    DCHECK(message);
    const std::string& data = connection_->recv_data();
    if (data[0])
      return FRAME_ERROR;

    size_t pos = data.find('\377', 1);
    if (pos == std::string::npos)
      return FRAME_INCOMPLETE;

    std::string buffer(data.begin() + 1, data.begin() + pos);
    message->swap(buffer);
    connection_->Shift(pos + 1);

    return FRAME_OK;
  }

  virtual void Send(const std::string& message) {
    char message_start = 0;
    char message_end = -1;
    connection_->Send(&message_start, 1);
    connection_->Send(message);
    connection_->Send(&message_end, 1);
  }

 private:
  static const int kWebSocketHandshakeBodyLen;

  WebSocketHixie76(HttpConnection* connection,
                   const HttpServerRequestInfo& request,
                   size_t* pos) : WebSocket(connection) {
    std::string key1 = request.GetHeaderValue("Sec-WebSocket-Key1");
    std::string key2 = request.GetHeaderValue("Sec-WebSocket-Key2");

    if (key1.empty()) {
      connection->Send500("Invalid request format. "
                          "Sec-WebSocket-Key1 is empty or isn't specified.");
      return;
    }

    if (key2.empty()) {
      connection->Send500("Invalid request format. "
                          "Sec-WebSocket-Key2 is empty or isn't specified.");
      return;
    }

    key3_ = connection->recv_data().substr(
        *pos,
        *pos + kWebSocketHandshakeBodyLen);
    *pos += kWebSocketHandshakeBodyLen;
  }

  std::string key3_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketHixie76);
};

const int WebSocketHixie76::kWebSocketHandshakeBodyLen = 8;

// Constants for hybi-10 frame format.

typedef int OpCode;

const OpCode kOpCodeContinuation = 0x0;
const OpCode kOpCodeText = 0x1;
const OpCode kOpCodeBinary = 0x2;
const OpCode kOpCodeClose = 0x8;
const OpCode kOpCodePing = 0x9;
const OpCode kOpCodePong = 0xA;

const unsigned char kFinalBit = 0x80;
const unsigned char kReserved1Bit = 0x40;
const unsigned char kReserved2Bit = 0x20;
const unsigned char kReserved3Bit = 0x10;
const unsigned char kOpCodeMask = 0xF;
const unsigned char kMaskBit = 0x80;
const unsigned char kPayloadLengthMask = 0x7F;

const size_t kMaxSingleBytePayloadLength = 125;
const size_t kTwoBytePayloadLengthField = 126;
const size_t kEightBytePayloadLengthField = 127;
const size_t kMaskingKeyWidthInBytes = 4;

class WebSocketHybi10 : public WebSocket {
 public:
  static WebSocket* Create(HttpConnection* connection,
                           const HttpServerRequestInfo& request,
                           size_t* pos) {
    std::string version = request.GetHeaderValue("Sec-WebSocket-Version");
    if (version != "8")
      return NULL;

    std::string key = request.GetHeaderValue("Sec-WebSocket-Key");
    if (key.empty()) {
      connection->Send500("Invalid request format. "
              "Sec-WebSocket-Key is empty or isn't specified.");
      return NULL;
    }
    return new WebSocketHybi10(connection, request, pos);
  }

  virtual void Accept(const HttpServerRequestInfo& request) {
    static const char* const kWebSocketGuid =
        "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    std::string key = request.GetHeaderValue("Sec-WebSocket-Key");
    std::string data = base::StringPrintf("%s%s", key.c_str(), kWebSocketGuid);
    std::string encoded_hash;
    base::Base64Encode(base::SHA1HashString(data), &encoded_hash);

    std::string response = base::StringPrintf(
        "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
        "Upgrade: WebSocket\r\n"
        "Connection: Upgrade\r\n"
        "Sec-WebSocket-Accept: %s\r\n"
        "\r\n",
        encoded_hash.c_str());
    connection_->Send(response);
  }

  virtual ParseResult Read(std::string* message) {
    size_t data_length = connection_->recv_data().length();
    if (data_length < 2)
      return FRAME_INCOMPLETE;

    const char* p = connection_->recv_data().c_str();
    const char* buffer_end = p + data_length;

    unsigned char first_byte = *p++;
    unsigned char second_byte = *p++;

    final_ = first_byte & kFinalBit;
    reserved1_ = first_byte & kReserved1Bit;
    reserved2_ = first_byte & kReserved2Bit;
    reserved3_ = first_byte & kReserved3Bit;
    op_code_ = first_byte & kOpCodeMask;
    masked_ = second_byte & kMaskBit;

    switch (op_code_) {
    case kOpCodeClose:
      closed_ = true;
      break;
    case kOpCodeText:
      break;
    case kOpCodeBinary: // We don't support binary frames yet.
    case kOpCodeContinuation: // We don't support binary frames yet.
    case kOpCodePing: // We don't support binary frames yet.
    case kOpCodePong: // We don't support binary frames yet.
    default:
      return FRAME_ERROR;
    }

    uint64 payload_length64 = second_byte & kPayloadLengthMask;
    if (payload_length64 > kMaxSingleBytePayloadLength) {
      int extended_payload_length_size;
      if (payload_length64 == kTwoBytePayloadLengthField)
        extended_payload_length_size = 2;
      else {
        DCHECK(payload_length64 == kEightBytePayloadLengthField);
        extended_payload_length_size = 8;
      }
      if (buffer_end - p < extended_payload_length_size)
        return FRAME_INCOMPLETE;
      payload_length64 = 0;
      for (int i = 0; i < extended_payload_length_size; ++i) {
        payload_length64 <<= 8;
        payload_length64 |= static_cast<unsigned char>(*p++);
      }
    }

    static const uint64 max_payload_length = 0x7FFFFFFFFFFFFFFFull;
    size_t masking_key_length = masked_ ? kMaskingKeyWidthInBytes : 0;
    static size_t max_length = std::numeric_limits<size_t>::max();
    if (payload_length64 > max_payload_length ||
        payload_length64 + masking_key_length > max_length) {
      // WebSocket frame length too large.
      return FRAME_ERROR;
    }
    payload_length_ = static_cast<size_t>(payload_length64);

    size_t total_length = masking_key_length + payload_length_;
    if (static_cast<size_t>(buffer_end - p) < total_length)
      return FRAME_INCOMPLETE;

    if (masked_) {
      message->resize(payload_length_);
      const char* masking_key = p;
      char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
      for (size_t i = 0; i < payload_length_; ++i)  // Unmask the payload.
        (*message)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
    } else {
      std::string buffer(p, p + payload_length_);
      message->swap(buffer);
    }

    size_t pos = p + masking_key_length + payload_length_ -
        connection_->recv_data().c_str();
    connection_->Shift(pos);

    return closed_ ? FRAME_CLOSE : FRAME_OK;
  }

  virtual void Send(const std::string& message) {
    if (closed_)
      return;

    std::vector<char> frame;
    OpCode op_code = kOpCodeText;
    size_t data_length = message.length();

    frame.push_back(kFinalBit | op_code);
    if (data_length <= kMaxSingleBytePayloadLength)
      frame.push_back(kMaskBit | data_length);
    else if (data_length <= 0xFFFF) {
      frame.push_back(kMaskBit | kTwoBytePayloadLengthField);
      frame.push_back((data_length & 0xFF00) >> 8);
      frame.push_back(data_length & 0xFF);
    } else {
      frame.push_back(kMaskBit | kEightBytePayloadLengthField);
      char extended_payload_length[8];
      size_t remaining = data_length;
      // Fill the length into extended_payload_length in the network byte order.
      for (int i = 0; i < 8; ++i) {
        extended_payload_length[7 - i] = remaining & 0xFF;
        remaining >>= 8;
      }
      frame.insert(frame.end(),
                   extended_payload_length,
                   extended_payload_length + 8);
      DCHECK(!remaining);
    }

    // Mask the frame.
    size_t masking_key_start = frame.size();
    // Add placeholder for masking key. Will be overwritten.
    frame.resize(frame.size() + kMaskingKeyWidthInBytes);
    size_t payload_start = frame.size();
    const char* data = message.c_str();
    frame.insert(frame.end(), data, data + data_length);

    base::RandBytes(&frame[0] + masking_key_start,
                    kMaskingKeyWidthInBytes);
    for (size_t i = 0; i < data_length; ++i) {
      frame[payload_start + i] ^=
          frame[masking_key_start + i % kMaskingKeyWidthInBytes];
    }
    connection_->Send(&frame[0], frame.size());
  }

 private:
  WebSocketHybi10(HttpConnection* connection,
                  const HttpServerRequestInfo& request,
                  size_t* pos)
    : WebSocket(connection),
      op_code_(0),
      final_(false),
      reserved1_(false),
      reserved2_(false),
      reserved3_(false),
      masked_(false),
      payload_(0),
      payload_length_(0),
      frame_end_(0),
      closed_(false) {
  }

  OpCode op_code_;
  bool final_;
  bool reserved1_;
  bool reserved2_;
  bool reserved3_;
  bool masked_;
  const char* payload_;
  size_t payload_length_;
  const char* frame_end_;
  bool closed_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketHybi10);
};

}  // anonymous namespace

WebSocket* WebSocket::CreateWebSocket(HttpConnection* connection,
                                      const HttpServerRequestInfo& request,
                                      size_t* pos) {
  WebSocket* socket = WebSocketHybi10::Create(connection, request, pos);
  if (socket)
    return socket;

  return WebSocketHixie76::Create(connection, request, pos);
}

WebSocket::WebSocket(HttpConnection* connection) : connection_(connection) {
}

}  // namespace net
<commit_msg>Expected version of WebSocket was adjusted for hybi17 that was introduced at wk r97249. Now the server implementation of websocket accepts v.8 and v.13<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/server/web_socket.h"

#include "base/base64.h"
#include "base/rand_util.h"
#include "base/logging.h"
#include "base/md5.h"
#include "base/sha1.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "net/server/http_connection.h"
#include "net/server/http_server_request_info.h"

#if defined(OS_WIN)
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif

#include <limits>

namespace net {

namespace {

static uint32 WebSocketKeyFingerprint(const std::string& str) {
  std::string result;
  const char* p_char = str.c_str();
  int length = str.length();
  int spaces = 0;
  for (int i = 0; i < length; ++i) {
    if (p_char[i] >= '0' && p_char[i] <= '9')
      result.append(&p_char[i], 1);
    else if (p_char[i] == ' ')
      spaces++;
  }
  if (spaces == 0)
    return 0;
  int64 number = 0;
  if (!base::StringToInt64(result, &number))
    return 0;
  return htonl(static_cast<uint32>(number / spaces));
}

class WebSocketHixie76 : public net::WebSocket {
 public:
  static net::WebSocket* Create(HttpConnection* connection,
                                const HttpServerRequestInfo& request,
                                size_t* pos) {
    if (connection->recv_data().length() < *pos + kWebSocketHandshakeBodyLen)
      return NULL;
    return new WebSocketHixie76(connection, request, pos);
  }

  virtual void Accept(const HttpServerRequestInfo& request) {
    std::string key1 = request.GetHeaderValue("Sec-WebSocket-Key1");
    std::string key2 = request.GetHeaderValue("Sec-WebSocket-Key2");

    uint32 fp1 = WebSocketKeyFingerprint(key1);
    uint32 fp2 = WebSocketKeyFingerprint(key2);

    char data[16];
    memcpy(data, &fp1, 4);
    memcpy(data + 4, &fp2, 4);
    memcpy(data + 8, &key3_[0], 8);

    base::MD5Digest digest;
    base::MD5Sum(data, 16, &digest);

    std::string origin = request.GetHeaderValue("Origin");
    std::string host = request.GetHeaderValue("Host");
    std::string location = "ws://" + host + request.path;
    connection_->Send(base::StringPrintf(
        "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
        "Upgrade: WebSocket\r\n"
        "Connection: Upgrade\r\n"
        "Sec-WebSocket-Origin: %s\r\n"
        "Sec-WebSocket-Location: %s\r\n"
        "\r\n",
        origin.c_str(),
        location.c_str()));
    connection_->Send(reinterpret_cast<char*>(digest.a), 16);
  }

  virtual ParseResult Read(std::string* message) {
    DCHECK(message);
    const std::string& data = connection_->recv_data();
    if (data[0])
      return FRAME_ERROR;

    size_t pos = data.find('\377', 1);
    if (pos == std::string::npos)
      return FRAME_INCOMPLETE;

    std::string buffer(data.begin() + 1, data.begin() + pos);
    message->swap(buffer);
    connection_->Shift(pos + 1);

    return FRAME_OK;
  }

  virtual void Send(const std::string& message) {
    char message_start = 0;
    char message_end = -1;
    connection_->Send(&message_start, 1);
    connection_->Send(message);
    connection_->Send(&message_end, 1);
  }

 private:
  static const int kWebSocketHandshakeBodyLen;

  WebSocketHixie76(HttpConnection* connection,
                   const HttpServerRequestInfo& request,
                   size_t* pos) : WebSocket(connection) {
    std::string key1 = request.GetHeaderValue("Sec-WebSocket-Key1");
    std::string key2 = request.GetHeaderValue("Sec-WebSocket-Key2");

    if (key1.empty()) {
      connection->Send500("Invalid request format. "
                          "Sec-WebSocket-Key1 is empty or isn't specified.");
      return;
    }

    if (key2.empty()) {
      connection->Send500("Invalid request format. "
                          "Sec-WebSocket-Key2 is empty or isn't specified.");
      return;
    }

    key3_ = connection->recv_data().substr(
        *pos,
        *pos + kWebSocketHandshakeBodyLen);
    *pos += kWebSocketHandshakeBodyLen;
  }

  std::string key3_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketHixie76);
};

const int WebSocketHixie76::kWebSocketHandshakeBodyLen = 8;

// Constants for hybi-10 frame format.

typedef int OpCode;

const OpCode kOpCodeContinuation = 0x0;
const OpCode kOpCodeText = 0x1;
const OpCode kOpCodeBinary = 0x2;
const OpCode kOpCodeClose = 0x8;
const OpCode kOpCodePing = 0x9;
const OpCode kOpCodePong = 0xA;

const unsigned char kFinalBit = 0x80;
const unsigned char kReserved1Bit = 0x40;
const unsigned char kReserved2Bit = 0x20;
const unsigned char kReserved3Bit = 0x10;
const unsigned char kOpCodeMask = 0xF;
const unsigned char kMaskBit = 0x80;
const unsigned char kPayloadLengthMask = 0x7F;

const size_t kMaxSingleBytePayloadLength = 125;
const size_t kTwoBytePayloadLengthField = 126;
const size_t kEightBytePayloadLengthField = 127;
const size_t kMaskingKeyWidthInBytes = 4;

class WebSocketHybi10 : public WebSocket {
 public:
  static WebSocket* Create(HttpConnection* connection,
                           const HttpServerRequestInfo& request,
                           size_t* pos) {
    std::string version = request.GetHeaderValue("Sec-WebSocket-Version");
    if (version != "8" && version != "13")
      return NULL;

    std::string key = request.GetHeaderValue("Sec-WebSocket-Key");
    if (key.empty()) {
      connection->Send500("Invalid request format. "
              "Sec-WebSocket-Key is empty or isn't specified.");
      return NULL;
    }
    return new WebSocketHybi10(connection, request, pos);
  }

  virtual void Accept(const HttpServerRequestInfo& request) {
    static const char* const kWebSocketGuid =
        "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    std::string key = request.GetHeaderValue("Sec-WebSocket-Key");
    std::string data = base::StringPrintf("%s%s", key.c_str(), kWebSocketGuid);
    std::string encoded_hash;
    base::Base64Encode(base::SHA1HashString(data), &encoded_hash);

    std::string response = base::StringPrintf(
        "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
        "Upgrade: WebSocket\r\n"
        "Connection: Upgrade\r\n"
        "Sec-WebSocket-Accept: %s\r\n"
        "\r\n",
        encoded_hash.c_str());
    connection_->Send(response);
  }

  virtual ParseResult Read(std::string* message) {
    size_t data_length = connection_->recv_data().length();
    if (data_length < 2)
      return FRAME_INCOMPLETE;

    const char* p = connection_->recv_data().c_str();
    const char* buffer_end = p + data_length;

    unsigned char first_byte = *p++;
    unsigned char second_byte = *p++;

    final_ = first_byte & kFinalBit;
    reserved1_ = first_byte & kReserved1Bit;
    reserved2_ = first_byte & kReserved2Bit;
    reserved3_ = first_byte & kReserved3Bit;
    op_code_ = first_byte & kOpCodeMask;
    masked_ = second_byte & kMaskBit;

    switch (op_code_) {
    case kOpCodeClose:
      closed_ = true;
      break;
    case kOpCodeText:
      break;
    case kOpCodeBinary: // We don't support binary frames yet.
    case kOpCodeContinuation: // We don't support binary frames yet.
    case kOpCodePing: // We don't support binary frames yet.
    case kOpCodePong: // We don't support binary frames yet.
    default:
      return FRAME_ERROR;
    }

    uint64 payload_length64 = second_byte & kPayloadLengthMask;
    if (payload_length64 > kMaxSingleBytePayloadLength) {
      int extended_payload_length_size;
      if (payload_length64 == kTwoBytePayloadLengthField)
        extended_payload_length_size = 2;
      else {
        DCHECK(payload_length64 == kEightBytePayloadLengthField);
        extended_payload_length_size = 8;
      }
      if (buffer_end - p < extended_payload_length_size)
        return FRAME_INCOMPLETE;
      payload_length64 = 0;
      for (int i = 0; i < extended_payload_length_size; ++i) {
        payload_length64 <<= 8;
        payload_length64 |= static_cast<unsigned char>(*p++);
      }
    }

    static const uint64 max_payload_length = 0x7FFFFFFFFFFFFFFFull;
    size_t masking_key_length = masked_ ? kMaskingKeyWidthInBytes : 0;
    static size_t max_length = std::numeric_limits<size_t>::max();
    if (payload_length64 > max_payload_length ||
        payload_length64 + masking_key_length > max_length) {
      // WebSocket frame length too large.
      return FRAME_ERROR;
    }
    payload_length_ = static_cast<size_t>(payload_length64);

    size_t total_length = masking_key_length + payload_length_;
    if (static_cast<size_t>(buffer_end - p) < total_length)
      return FRAME_INCOMPLETE;

    if (masked_) {
      message->resize(payload_length_);
      const char* masking_key = p;
      char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
      for (size_t i = 0; i < payload_length_; ++i)  // Unmask the payload.
        (*message)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
    } else {
      std::string buffer(p, p + payload_length_);
      message->swap(buffer);
    }

    size_t pos = p + masking_key_length + payload_length_ -
        connection_->recv_data().c_str();
    connection_->Shift(pos);

    return closed_ ? FRAME_CLOSE : FRAME_OK;
  }

  virtual void Send(const std::string& message) {
    if (closed_)
      return;

    std::vector<char> frame;
    OpCode op_code = kOpCodeText;
    size_t data_length = message.length();

    frame.push_back(kFinalBit | op_code);
    if (data_length <= kMaxSingleBytePayloadLength)
      frame.push_back(kMaskBit | data_length);
    else if (data_length <= 0xFFFF) {
      frame.push_back(kMaskBit | kTwoBytePayloadLengthField);
      frame.push_back((data_length & 0xFF00) >> 8);
      frame.push_back(data_length & 0xFF);
    } else {
      frame.push_back(kMaskBit | kEightBytePayloadLengthField);
      char extended_payload_length[8];
      size_t remaining = data_length;
      // Fill the length into extended_payload_length in the network byte order.
      for (int i = 0; i < 8; ++i) {
        extended_payload_length[7 - i] = remaining & 0xFF;
        remaining >>= 8;
      }
      frame.insert(frame.end(),
                   extended_payload_length,
                   extended_payload_length + 8);
      DCHECK(!remaining);
    }

    // Mask the frame.
    size_t masking_key_start = frame.size();
    // Add placeholder for masking key. Will be overwritten.
    frame.resize(frame.size() + kMaskingKeyWidthInBytes);
    size_t payload_start = frame.size();
    const char* data = message.c_str();
    frame.insert(frame.end(), data, data + data_length);

    base::RandBytes(&frame[0] + masking_key_start,
                    kMaskingKeyWidthInBytes);
    for (size_t i = 0; i < data_length; ++i) {
      frame[payload_start + i] ^=
          frame[masking_key_start + i % kMaskingKeyWidthInBytes];
    }
    connection_->Send(&frame[0], frame.size());
  }

 private:
  WebSocketHybi10(HttpConnection* connection,
                  const HttpServerRequestInfo& request,
                  size_t* pos)
    : WebSocket(connection),
      op_code_(0),
      final_(false),
      reserved1_(false),
      reserved2_(false),
      reserved3_(false),
      masked_(false),
      payload_(0),
      payload_length_(0),
      frame_end_(0),
      closed_(false) {
  }

  OpCode op_code_;
  bool final_;
  bool reserved1_;
  bool reserved2_;
  bool reserved3_;
  bool masked_;
  const char* payload_;
  size_t payload_length_;
  const char* frame_end_;
  bool closed_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketHybi10);
};

}  // anonymous namespace

WebSocket* WebSocket::CreateWebSocket(HttpConnection* connection,
                                      const HttpServerRequestInfo& request,
                                      size_t* pos) {
  WebSocket* socket = WebSocketHybi10::Create(connection, request, pos);
  if (socket)
    return socket;

  return WebSocketHixie76::Create(connection, request, pos);
}

WebSocket::WebSocket(HttpConnection* connection) : connection_(connection) {
}

}  // namespace net
<|endoftext|>


<commit_before>#include "algebra/NDSS.h"
#include "utils/FHEUtils.hpp"
#include "utils/timer.hpp"
#include "fhe/EncryptedArray.h"
#include "fhe/NumbTh.h"
#include "utils/FileUtils.hpp"
#define TIMING_THIS(codes_block)                           \
    do {                                                   \
        MDL::Timer timer;                                  \
        timer.start();                                     \
        codes_block                                        \
        timer.end();                                       \
        printf("This codes run %f sec\n", timer.second()); \
    } while (0)

int main(int argc, char *argv[]) {
    long m, p, r, L;
    ArgMapping argmap;
    MDL::Timer keyTimer, totalTimer;

    argmap.arg("m", m, "m");
    argmap.arg("L", L, "L");
    argmap.arg("p", p, "p");
    argmap.arg("r", r, "r");
    argmap.parse(argc, argv);
    MDL::Matrix<long> mat = load_csv("covariance3.data");
    long dimension = mat.cols();
    MDL::Vector<long> vec(dimension), vec2(dimension);
    printf("Dimension %ld\n", dimension);

    for (size_t i = 0; i < dimension; i++) vec[i] = NTL::RandomBnd(3);
    std::cout << mat.maxEigenValue() << std::endl;
    totalTimer.start();
    keyTimer.start();
    FHEcontext context(m, p, r);
    buildModChain(context, L);
    FHESecKey  sk(context);
    sk.GenSecKey(64);
    addSome1DMatrices(sk);
    FHEPubKey pk = sk;
    auto G = context.alMod.getFactorsOverZZ()[0];
    keyTimer.end();
    printf("KeyGen %f\n", keyTimer.second());

    EncryptedArray ea(context, G);
        MDL::EncMatrix encMat(pk);
    MDL::EncVector encVec(pk), encVec2(pk);
    TIMING_THIS(
        encMat.pack(mat, ea);
        encVec.pack(vec, ea);
        );

    TIMING_THIS(encVec  = encMat.column_dot(encVec, ea, dimension); );
    TIMING_THIS(encVec  = encMat.column_dot(encVec, ea, dimension); );
    TIMING_THIS(encVec  = encMat.column_dot(encVec, ea, dimension); );
    TIMING_THIS(encVec2 = encMat.column_dot(encVec, ea, dimension); );

    {
        MDL::Vector<NTL::ZZX> vec(dimension), vec2(dimension);
        TIMING_THIS(
            encVec.unpack(vec, sk, ea);
            encVec2.unpack(vec2, sk, ea);
            );
        std::cout << vec2.L2() / vec.L2() << std::endl;
    }
    totalTimer.end();
    printf("total %f\n", totalTimer.second());
}
<commit_msg>print PCA timing<commit_after>#include "algebra/NDSS.h"
#include "utils/FHEUtils.hpp"
#include "utils/timer.hpp"
#include "fhe/EncryptedArray.h"
#include "fhe/NumbTh.h"
#include "utils/FileUtils.hpp"
#define TIMING_THIS(codes_block)                           \
    do {                                                   \
        MDL::Timer timer;                                  \
        timer.start();                                     \
        codes_block                                        \
        timer.end();                                       \
        printf("This codes run %f sec\n", timer.second()); \
    } while (0)

int main(int argc, char *argv[]) {
    long m, p, r, L, f;
    ArgMapping argmap;
    MDL::Timer keyTimer, totalTimer;
	std::string file;
    argmap.arg("m", m, "m");
    argmap.arg("L", L, "L");
    argmap.arg("p", p, "p");
    argmap.arg("r", r, "r");
    argmap.arg("f", f, "file");
    argmap.parse(argc, argv);

	switch (f) {
	case 0: file = "covariance.data"; break;
	case 1: file = "covariance2.data"; break;
	case 2: file = "covariance3.data"; break;
	default: file = "covariance.data"; break;
	}

    MDL::Matrix<long> mat = load_csv(file);
    long dimension = mat.cols();
    MDL::Vector<long> vec(dimension), vec2(dimension);
    printf("Dimension %ld\n", dimension);

    for (size_t i = 0; i < dimension; i++) vec[i] = NTL::RandomBnd(3);
    std::cout << mat.maxEigenValue() << std::endl;

    totalTimer.start();

    keyTimer.start();
    FHEcontext context(m, p, r);
    buildModChain(context, L);
    FHESecKey  sk(context);
    sk.GenSecKey(64);
    addSome1DMatrices(sk);
    FHEPubKey pk = sk;
    auto G = context.alMod.getFactorsOverZZ()[0];
    keyTimer.end();

    EncryptedArray ea(context, G);
    MDL::EncMatrix encMat(pk);
    MDL::EncVector encVec(pk), encVec2(pk);
	MDL::Timer encTimer, evalTimer;

	encTimer.start();
    encMat.pack(mat, ea);
    encVec.pack(vec, ea);
	encTimer.end();

	evalTimer.start();
    encVec  = encMat.column_dot(encVec, ea, dimension);
    encVec  = encMat.column_dot(encVec, ea, dimension);
	if (f < 2) {
		encVec  = encMat.column_dot(encVec, ea, dimension);
	}
    encVec2 = encMat.column_dot(encVec, ea, dimension);
	evalTimer.end();

    {
        MDL::Vector<NTL::ZZX> vec(dimension), vec2(dimension);
        encVec.unpack(vec, sk, ea);
        encVec2.unpack(vec2, sk, ea);
        std::cout << vec2.L2() / vec.L2() << std::endl;
    }

    totalTimer.end();
    printf("keygen %f enc %f eval %f total %f\n",
		   keyTimer.second(), encTimer.second(),
		   evalTimer.second(), totalTimer.second());
	return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Common/Harness.hh>
#include <Lex/Token.hh>

TADPOLE_TEST(TadpoleToken) {
  using TK = Tadpole::Lex::TokenKind;
}
<commit_msg>:white_check_mark: test(token): add test case for token module<commit_after>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Common/Harness.hh>
#include <Lex/Token.hh>

TADPOLE_TEST(TadpoleToken) {
  using TK = Tadpole::Lex::TokenKind;
#define NEWTK2(k, s)    Tadpole::Lex::Token(k, s, 0)
#define NEWTK3(k, s, l) Tadpole::Lex::Token(k, s, l)
#define TESTEQ(a, b)    TADPOLE_CHECK_EQ(a, b)
#define TESTTK(k, s)    do {\
  auto t = NEWTK2(k, s);\
  TESTEQ(t.kind(), k);\
  TESTEQ(t.literal(), s);\
  TESTEQ(t.lineno(),  0);\
} while (false)
#define TESTID(id)      TESTTK(TK::TK_IDENTIFIER, id)
#define TESTNUM(n)      do {\
  auto t = NEWTK2(TK::TK_NUMERIC, #n);\
  TESTEQ(t.kind(), TK::TK_NUMERIC);\
  TESTEQ(t.as_numeric(), n);\
  TESTEQ(t.lineno(), 0);\
} while (false)
#define TESTSTR(s, l)   do {\
  auto t = NEWTK3(TK::TK_STRING, s, l);\
  TESTEQ(t.kind(), TK::TK_STRING);\
  TESTEQ(t.as_string(), s);\
  TESTEQ(a.lineno(), l);\
} while (false)

#undef TESTSTR
#undef TESTNUM
#undef TESTID
#undef TESTTK
#undef TESTEQ
#undef NEWTK3
#undef NEWTK2
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Winsock2.h>
#include <iostream>

#define UNUSED(x) ((void)x)

struct _EventFd_t {
  int writer{};
  int reader{};

  bool is_valid(void) const {
    return writer > 0 && reader > 0;
  }

  _EventFd_t& operator=(std::nullptr_t) {
    writer = 0;
    reader = 0;
  }
};

void eventfd_close(_EventFd_t eventfd) {
  if (eventfd.reader > 0)
    closesocket(eventfd.reader);
  if (eventfd.writer > 0)
    closesocket(eventfd.writer);
}

_EventFd_t eventfd_create(void) {
  struct sockaddr_in addr{};
  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  addr.sin_family = AF_INET;

  bool has_error = false;
  _EventFd_t eventfd{};
  int listener = socket(AF_INET, SOCK_STREAM, 0);
  if (listener < 0)
    return eventfd;

  int r = bind(listener, (const struct sockaddr*)&addr, sizeof(addr));
  if (0 == r) {
    int addrlen = sizeof(addr);
    r = getsockname(listener, (struct sockaddr*)&addr, &addrlen);
  }
  if (0 == r)
    r = listen(listener, 1);

  eventfd.writer = socket(AF_INET, SOCK_STREAM, 0);
  if (eventfd.writer < 0)
    goto Exit;
  if (0 == r)
    r = connect(eventfd.writer, (struct sockaddr*)&addr, sizeof(addr));
  if (0 == r)
    eventfd.reader = accept(listener, nullptr, nullptr);
  if (eventfd.reader <= 0)
    has_error = true;

Exit:
  if (has_error)
    eventfd_close(eventfd);
  if (listener > 0)
    closesocket(listener);

  return eventfd;
}

int eventfd_read(_EventFd_t eventfd, char* buf, size_t len) {
  return recv(eventfd.reader, buf, len, 0);
}

int eventfd_write(_EventFd_t eventfd, const char* buf, size_t len) {
  return send(eventfd.writer, buf, len, 0);
}

int main(int argc, char* argv[]) {
  UNUSED(argc);
  UNUSED(argv);
  WSADATA wd;
  WSAStartup(MAKEWORD(2, 2), &wd);

  static const int RUN_TIMES = 100;
  _EventFd_t eventfd = eventfd_create();

  for (int i = 0; i < RUN_TIMES; ++i) {
    char wbuf[8] = "Wakeup!";
    eventfd_write(eventfd, wbuf, sizeof(wbuf));

    char rbuf[8] = {0};
    eventfd_read(eventfd, rbuf, sizeof(rbuf));
    std::cout << "[" << i+1 << "] read buffer is : " << rbuf << std::endl;
  }

  eventfd_close(eventfd);

  WSACleanup();
  return 0;
}
<commit_msg>:construction: chore(eventfd): add building command for eventfd for windows<commit_after>// Copyright (c) 2017 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <Winsock2.h>
#include <iostream>

// build command:
// \> cl.exe /Fe"a.exe" main.cc /EHsc ws2_32.lib

#define UNUSED(x) ((void)x)

struct _EventFd_t {
  int writer{};
  int reader{};

  bool is_valid(void) const {
    return writer > 0 && reader > 0;
  }

  _EventFd_t& operator=(std::nullptr_t) {
    writer = 0;
    reader = 0;
  }
};

void eventfd_close(_EventFd_t eventfd) {
  if (eventfd.reader > 0)
    closesocket(eventfd.reader);
  if (eventfd.writer > 0)
    closesocket(eventfd.writer);
}

_EventFd_t eventfd_create(void) {
  struct sockaddr_in addr{};
  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  addr.sin_family = AF_INET;

  bool has_error = false;
  _EventFd_t eventfd{};
  int listener = socket(AF_INET, SOCK_STREAM, 0);
  if (listener < 0)
    return eventfd;

  int r = bind(listener, (const struct sockaddr*)&addr, sizeof(addr));
  if (0 == r) {
    int addrlen = sizeof(addr);
    r = getsockname(listener, (struct sockaddr*)&addr, &addrlen);
  }
  if (0 == r)
    r = listen(listener, 1);

  eventfd.writer = socket(AF_INET, SOCK_STREAM, 0);
  if (eventfd.writer < 0)
    goto Exit;
  if (0 == r)
    r = connect(eventfd.writer, (struct sockaddr*)&addr, sizeof(addr));
  if (0 == r)
    eventfd.reader = accept(listener, nullptr, nullptr);
  if (eventfd.reader <= 0)
    has_error = true;

Exit:
  if (has_error)
    eventfd_close(eventfd);
  if (listener > 0)
    closesocket(listener);

  return eventfd;
}

int eventfd_read(_EventFd_t eventfd, char* buf, size_t len) {
  return recv(eventfd.reader, buf, len, 0);
}

int eventfd_write(_EventFd_t eventfd, const char* buf, size_t len) {
  return send(eventfd.writer, buf, len, 0);
}

int main(int argc, char* argv[]) {
  UNUSED(argc);
  UNUSED(argv);
  WSADATA wd;
  WSAStartup(MAKEWORD(2, 2), &wd);

  static const int RUN_TIMES = 100;
  _EventFd_t eventfd = eventfd_create();

  for (int i = 0; i < RUN_TIMES; ++i) {
    char wbuf[8] = "Wakeup!";
    eventfd_write(eventfd, wbuf, sizeof(wbuf));

    char rbuf[8] = {0};
    eventfd_read(eventfd, rbuf, sizeof(rbuf));
    std::cout << "[" << i+1 << "] read buffer is : " << rbuf << std::endl;
  }

  eventfd_close(eventfd);

  WSACleanup();
  return 0;
}
<|endoftext|>


<commit_before>#include "kitPluginManager.h"

#include <QtCore/QFileInfo>
#include <QtCore/QCoreApplication>

#include <qrkernel/exception/exception.h>

#include <qrutils/pluginManagers/interfaceWrapper.h>

using namespace interpreterCore;
using namespace qReal;

KitPluginManager::KitPluginManager(QString const &pluginDirectory)
	: mPluginsDir(QCoreApplication::applicationDirPath() + "/" + pluginDirectory)
{
	mCommonPluginManager = new CommonPluginManager(QCoreApplication::applicationDirPath(), pluginDirectory);
	tryToLoadGeneratorPlugin();
	tryToLoadInterpreterPlugin();
}

KitPluginManager::~KitPluginManager()
{
	mCommonPluginManager->deleteAllLoaders();
	delete(mCommonPluginManager);
}

QList<QString> KitPluginManager::kitIds() const
{
	return mPluginInterfaces.keys();
}

QList<interpreterBase::KitPluginInterface *> KitPluginManager::kitsById(QString const &kitId) const
{
	if (!mPluginInterfaces.contains(kitId)) {
		throw qReal::Exception("Requesting non-existing kit plugin");
	}

	return mPluginInterfaces.values(kitId);
}

QList<generatorBase::GeneratorKitPluginInterface *> KitPluginManager::generatorsById(QString const &kitId) const
{
	// There can be no generators for the given kit id, so we do not filter out non-existing case here.
	return mGenerators.values(kitId);
}

QList<interpreterBase::robotModel::RobotModelInterface *> KitPluginManager::allRobotModels() const
{
	QList<interpreterBase::robotModel::RobotModelInterface *> result;
	for (interpreterBase::KitPluginInterface * const kit : mPluginInterfaces) {
		result += kit->robotModels();
	}

	return result;
}

void KitPluginManager::tryToLoadInterpreterPlugin()
{
	QList<interpreterBase::KitPluginInterface *> loadedInterpreterPlugins =
			InterfaceWrapper<interpreterBase::KitPluginInterface>::listOfInterfaces(mCommonPluginManager->allLoadedPlugins());

	foreach (interpreterBase::KitPluginInterface * const kitPlugin, loadedInterpreterPlugins) {
		mPluginInterfaces.insertMulti(kitPlugin->kitId(), kitPlugin);
	}
}

void KitPluginManager::tryToLoadGeneratorPlugin()
{
	QList<generatorBase::GeneratorKitPluginInterface *> loadedGeneratorPlugins =
			InterfaceWrapper<generatorBase::GeneratorKitPluginInterface>::listOfInterfaces(mCommonPluginManager->allLoadedPlugins());

	foreach (generatorBase::GeneratorKitPluginInterface * const generatorPlugin, loadedGeneratorPlugins) {
		mGenerators.insertMulti(generatorPlugin->kitId(), generatorPlugin);
	}
}
<commit_msg>trying to fix build<commit_after>#include "kitPluginManager.h"

#include <QtCore/QFileInfo>
#include <QtCore/QCoreApplication>

#include <qrkernel/exception/exception.h>

#include <qrutils/pluginManagers/interfaceWrapper.h>

using namespace interpreterCore;
using namespace qReal;

KitPluginManager::KitPluginManager(QString const &pluginDirectory)
	: mPluginsDir(QCoreApplication::applicationDirPath() + "/" + pluginDirectory)
{
	mCommonPluginManager = new CommonPluginManager(QCoreApplication::applicationDirPath(), pluginDirectory);
	tryToLoadGeneratorPlugin();
	tryToLoadInterpreterPlugin();
}

KitPluginManager::~KitPluginManager()
{
	mCommonPluginManager->deleteAllLoaders();
//	delete(mCommonPluginManager);
}

QList<QString> KitPluginManager::kitIds() const
{
	return mPluginInterfaces.keys();
}

QList<interpreterBase::KitPluginInterface *> KitPluginManager::kitsById(QString const &kitId) const
{
	if (!mPluginInterfaces.contains(kitId)) {
		throw qReal::Exception("Requesting non-existing kit plugin");
	}

	return mPluginInterfaces.values(kitId);
}

QList<generatorBase::GeneratorKitPluginInterface *> KitPluginManager::generatorsById(QString const &kitId) const
{
	// There can be no generators for the given kit id, so we do not filter out non-existing case here.
	return mGenerators.values(kitId);
}

QList<interpreterBase::robotModel::RobotModelInterface *> KitPluginManager::allRobotModels() const
{
	QList<interpreterBase::robotModel::RobotModelInterface *> result;
	for (interpreterBase::KitPluginInterface * const kit : mPluginInterfaces) {
		result += kit->robotModels();
	}

	return result;
}

void KitPluginManager::tryToLoadInterpreterPlugin()
{
	QList<interpreterBase::KitPluginInterface *> loadedInterpreterPlugins =
			InterfaceWrapper<interpreterBase::KitPluginInterface>::listOfInterfaces(mCommonPluginManager->allLoadedPlugins());

	foreach (interpreterBase::KitPluginInterface * const kitPlugin, loadedInterpreterPlugins) {
		mPluginInterfaces.insertMulti(kitPlugin->kitId(), kitPlugin);
	}
}

void KitPluginManager::tryToLoadGeneratorPlugin()
{
	QList<generatorBase::GeneratorKitPluginInterface *> loadedGeneratorPlugins =
			InterfaceWrapper<generatorBase::GeneratorKitPluginInterface>::listOfInterfaces(mCommonPluginManager->allLoadedPlugins());

	foreach (generatorBase::GeneratorKitPluginInterface * const generatorPlugin, loadedGeneratorPlugins) {
		mGenerators.insertMulti(generatorPlugin->kitId(), generatorPlugin);
	}
}
<|endoftext|>


<commit_before>extern const char groupName[] = "LADSPA";

#include "LADSPA.hpp"

#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
#include <QDir>

extern "C" QList< Block * > createBlocks()
{
	QStringList possibleDirs = QStringList() << qApp->property( "DSPBlocksDir" ).toString() + "/ladspa" << QDir::cleanPath( getenv( "LADSPA_PATH" ) );
#ifdef Q_OS_UNIX
	possibleDirs << ( sizeof( void * ) == 8 ? "/usr/lib64/ladspa" : "/usr/lib/ladspa" );
#endif

	QString ladspa_path;
	foreach ( const QString &dir, possibleDirs )
		if ( QFileInfo( dir ).isDir() )
		{
			ladspa_path = dir;
			break;
		}

	QList< Block * > ladspaBlocks;
	if ( !ladspa_path.isEmpty() )
	{
		QStringList libFilter;
#ifndef Q_OS_WIN
	#ifdef Q_OS_MAC
		libFilter << "*.dylib";
	#endif
		libFilter << "*.so";
#else
		libFilter << "*.dll";
#endif
		foreach ( const QString &fName, QDir( ladspa_path ).entryList( libFilter ) )
		{
			QLibrary lib( ladspa_path + "/" + fName );
			if ( lib.load() )
			{
				LADSPA_Descriptor_Function ladspa_descriptor = ( LADSPA_Descriptor_Function )lib.resolve( "ladspa_descriptor" );
				if ( !ladspa_descriptor )
					lib.unload();
				else for ( unsigned long i = 0 ;; ++i )
				{
					const LADSPA_Descriptor *ld = ladspa_descriptor( i );
					if ( !ld )
						break;
					int inputs = 0, outputs = 0;
					for ( unsigned long p = 0 ; p < ld->PortCount ; ++p )
						if ( LADSPA_IS_PORT_AUDIO( ld->PortDescriptors[ p ] ) )
						{
							if ( LADSPA_IS_PORT_INPUT( ld->PortDescriptors[ p ] ) )
								++inputs;
							else if ( LADSPA_IS_PORT_OUTPUT( ld->PortDescriptors[ p ] ) )
								++outputs;
						}
					if ( inputs > 0 && outputs > 0 )
						ladspaBlocks << new LADSPA( ld->Name, inputs, outputs, *ld );
				}
			}
		}
	}
	return ladspaBlocks;
}
<commit_msg>Show error if LADSPA plugin cannot be loaded<commit_after>extern const char groupName[] = "LADSPA";

#include "LADSPA.hpp"

#include <QCoreApplication>
#include <QLibrary>
#include <QDebug>
#include <QDir>

extern "C" QList< Block * > createBlocks()
{
	QStringList possibleDirs = QStringList() << qApp->property( "DSPBlocksDir" ).toString() + "/ladspa" << QDir::cleanPath( getenv( "LADSPA_PATH" ) );
#ifdef Q_OS_UNIX
	possibleDirs << ( sizeof( void * ) == 8 ? "/usr/lib64/ladspa" : "/usr/lib/ladspa" );
#endif

	QString ladspa_path;
	foreach ( const QString &dir, possibleDirs )
		if ( QFileInfo( dir ).isDir() )
		{
			ladspa_path = dir;
			break;
		}

	QList< Block * > ladspaBlocks;
	if ( !ladspa_path.isEmpty() )
	{
		QStringList libFilter;
#ifndef Q_OS_WIN
	#ifdef Q_OS_MAC
		libFilter << "*.dylib";
	#endif
		libFilter << "*.so";
#else
		libFilter << "*.dll";
#endif
		foreach ( const QString &fName, QDir( ladspa_path ).entryList( libFilter ) )
		{
			QLibrary lib( ladspa_path + "/" + fName );
			if ( !lib.load() )
				qDebug() << lib.errorString();
			else
			{
				LADSPA_Descriptor_Function ladspa_descriptor = ( LADSPA_Descriptor_Function )lib.resolve( "ladspa_descriptor" );
				if ( !ladspa_descriptor )
					lib.unload();
				else for ( unsigned long i = 0 ;; ++i )
				{
					const LADSPA_Descriptor *ld = ladspa_descriptor( i );
					if ( !ld )
						break;
					int inputs = 0, outputs = 0;
					for ( unsigned long p = 0 ; p < ld->PortCount ; ++p )
						if ( LADSPA_IS_PORT_AUDIO( ld->PortDescriptors[ p ] ) )
						{
							if ( LADSPA_IS_PORT_INPUT( ld->PortDescriptors[ p ] ) )
								++inputs;
							else if ( LADSPA_IS_PORT_OUTPUT( ld->PortDescriptors[ p ] ) )
								++outputs;
						}
					if ( inputs > 0 && outputs > 0 )
						ladspaBlocks << new LADSPA( ld->Name, inputs, outputs, *ld );
				}
			}
		}
	}
	return ladspaBlocks;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2020 The ZCash developers
// Copyright (c) 2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sapling/saplingscriptpubkeyman.h"

//! TODO: Should be Sapling address format, SaplingPaymentAddress
// Generate a new Sapling spending key and return its public payment address
libzcash::SaplingPaymentAddress SaplingScriptPubKeyMan::GenerateNewSaplingZKey()
{
    LOCK(wallet->cs_wallet); // mapSaplingZKeyMetadata

    // Try to get the seed
    CKey seedKey;
    if (!wallet->GetKey(hdChain.GetID(), seedKey))
        throw std::runtime_error(std::string(__func__) + ": HD seed not found");

    HDSeed seed(seedKey.GetPrivKey());
    auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);

    // We use a fixed keypath scheme of m/32'/coin_type'/account'
    // Derive m/32'
    auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
    // Derive m/32'/coin_type'
    auto m_32h_cth = m_32h.Derive(119 | ZIP32_HARDENED_KEY_LIMIT);

    // Derive account key at next index, skip keys already known to the wallet
    libzcash::SaplingExtendedSpendingKey xsk;
    do {
        xsk = m_32h_cth.Derive(hdChain.nExternalChainCounter | ZIP32_HARDENED_KEY_LIMIT);
        hdChain.nExternalChainCounter++; // Increment childkey index
    } while (wallet->HaveSaplingSpendingKey(xsk.expsk.full_viewing_key()));

    // Update the chain model in the database
    if (wallet->fFileBacked && !CWalletDB(wallet->strWalletFile).WriteHDChain(hdChain))
        throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");

    // Create new metadata
    int64_t nCreationTime = GetTime();
    auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
    mapSaplingZKeyMetadata[ivk] = CKeyMetadata(nCreationTime);

    auto addr = xsk.DefaultAddress();
    if (!AddSaplingZKey(xsk, addr)) {
        throw std::runtime_error(std::string(__func__) + ": AddSaplingZKey failed");
    }
    // return default sapling payment address.
    return addr;
}

// Add spending key to keystore
bool SaplingScriptPubKeyMan::AddSaplingZKey(
        const libzcash::SaplingExtendedSpendingKey &sk,
        const libzcash::SaplingPaymentAddress &defaultAddr)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata

    if (!AddSaplingSpendingKey(sk, defaultAddr)) {
        return false;
    }

    if (!wallet->fFileBacked) {
        return true;
    }

    if (!wallet->IsCrypted()) {
        auto ivk = sk.expsk.full_viewing_key().in_viewing_key();
        return CWalletDB(wallet->strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]);
    }

    return true;
}

bool SaplingScriptPubKeyMan::AddSaplingSpendingKey(
        const libzcash::SaplingExtendedSpendingKey &sk,
        const libzcash::SaplingPaymentAddress &defaultAddr)
{
    {
        LOCK(wallet->cs_KeyStore);
        if (!wallet->IsCrypted()) {
            return wallet->AddSaplingSpendingKey(sk, defaultAddr); // keystore
        }

        if (wallet->IsLocked()) {
            return false;
        }

        std::vector<unsigned char> vchCryptedSecret;
        CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << sk;
        CKeyingMaterial vchSecret(ss.begin(), ss.end());
        auto address = sk.DefaultAddress();
        auto extfvk = sk.ToXFVK();
        if (!EncryptSecret(wallet->GetEncryptionKey(), vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
            return false;
        }

        if (!AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret, defaultAddr)) {
            return false;
        }
    }
    return true;
}

// Add payment address -> incoming viewing key map entry
bool SaplingScriptPubKeyMan::AddSaplingIncomingViewingKey(
        const libzcash::SaplingIncomingViewingKey &ivk,
        const libzcash::SaplingPaymentAddress &addr)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata

    if (!wallet->AddSaplingIncomingViewingKey(ivk, addr)) {
        return false;
    }

    if (!wallet->fFileBacked) {
        return true;
    }

    if (!wallet->IsCrypted()) {
        return CWalletDB(wallet->strWalletFile).WriteSaplingPaymentAddress(addr, ivk);
    }

    return true;
}

bool SaplingScriptPubKeyMan::EncryptSaplingKeys(CKeyingMaterial& vMasterKeyIn)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingSpendingKeys

    for (SaplingSpendingKeyMap::value_type& mSaplingSpendingKey : wallet->mapSaplingSpendingKeys) {
        const libzcash::SaplingExtendedSpendingKey &sk = mSaplingSpendingKey.second;
        CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << sk;
        CKeyingMaterial vchSecret(ss.begin(), ss.end());
        auto extfvk = sk.ToXFVK();
        std::vector<unsigned char> vchCryptedSecret;
        if (!EncryptSecret(vMasterKeyIn, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
            return false;
        }
        if (!AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret, sk.DefaultAddress())) {
            return false;
        }
    }
    wallet->mapSaplingSpendingKeys.clear();
    return true;
}

bool SaplingScriptPubKeyMan::AddCryptedSaplingSpendingKeyDB(const libzcash::SaplingExtendedFullViewingKey &extfvk,
                                           const std::vector<unsigned char> &vchCryptedSecret,
                                           const libzcash::SaplingPaymentAddress &defaultAddr)
{
    if (!wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr))
        return false;
    if (!wallet->fFileBacked)
        return true;
    {
        LOCK(wallet->cs_wallet);
        if (wallet->pwalletdbEncryption) {
            return wallet->pwalletdbEncryption->WriteCryptedSaplingZKey(extfvk,
                                                                vchCryptedSecret,
                                                                mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
        } else {
            return CWalletDB(wallet->strWalletFile).WriteCryptedSaplingZKey(extfvk,
                                                                    vchCryptedSecret,
                                                                    mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
        }
    }
    return false;
}

bool SaplingScriptPubKeyMan::HaveSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &zaddr) const
{
    libzcash::SaplingIncomingViewingKey ivk;
    libzcash::SaplingFullViewingKey fvk;

    return wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
           wallet->GetSaplingFullViewingKey(ivk, fvk) &&
           wallet->HaveSaplingSpendingKey(fvk);
}

///////////////////// Load ////////////////////////////////////////

bool SaplingScriptPubKeyMan::LoadCryptedSaplingZKey(
        const libzcash::SaplingExtendedFullViewingKey &extfvk,
        const std::vector<unsigned char> &vchCryptedSecret)
{
    return wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, extfvk.DefaultAddress());
}

bool SaplingScriptPubKeyMan::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata
    mapSaplingZKeyMetadata[ivk] = meta;
    return true;
}

bool SaplingScriptPubKeyMan::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
{
    return wallet->AddSaplingSpendingKey(key, key.DefaultAddress());
}

bool SaplingScriptPubKeyMan::LoadSaplingPaymentAddress(
        const libzcash::SaplingPaymentAddress &addr,
        const libzcash::SaplingIncomingViewingKey &ivk)
{
    return wallet->AddSaplingIncomingViewingKey(ivk, addr);
}

///////////////////// Setup ///////////////////////////////////////

bool SaplingScriptPubKeyMan::SetupGeneration(const CKeyID& keyID, bool force)
{
    SetHDSeed(keyID, force);
    return true;
}

void SaplingScriptPubKeyMan::SetHDSeed(const CPubKey& seed, bool force, bool memonly)
{
    SetHDSeed(seed.GetID(), force, memonly);
}

void SaplingScriptPubKeyMan::SetHDSeed(const CKeyID& keyID, bool force, bool memonly)
{
    if (!hdChain.IsNull() && !force)
        throw std::runtime_error(std::string(__func__) + ": sapling trying to set a hd seed on an already created chain");

    LOCK(wallet->cs_wallet);
    // store the keyid (hash160) together with
    // the child index counter in the database
    // as a hdChain object
    CHDChain newHdChain(HDChain::ChainCounterType::Sapling);
    if (!newHdChain.SetSeed(keyID) ) {
        throw std::runtime_error(std::string(__func__) + ": set sapling hd seed failed");
    }

    SetHDChain(newHdChain, memonly);
}

void SaplingScriptPubKeyMan::SetHDChain(CHDChain& chain, bool memonly)
{
    LOCK(wallet->cs_wallet);
    if (chain.chainType != HDChain::ChainCounterType::Sapling)
        throw std::runtime_error(std::string(__func__) + ": trying to store an invalid chain type");

    if (!memonly && !CWalletDB(wallet->strWalletFile).WriteHDChain(chain))
        throw std::runtime_error(std::string(__func__) + ": writing sapling chain failed");

    hdChain = chain;

    // Sanity check
    if (!wallet->HaveKey(hdChain.GetID()))
        throw std::runtime_error(std::string(__func__) + ": Not found sapling seed in wallet");
}<commit_msg>Store seed id & path metadata in Sapling keys.<commit_after>// Copyright (c) 2016-2020 The ZCash developers
// Copyright (c) 2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sapling/saplingscriptpubkeyman.h"

//! TODO: Should be Sapling address format, SaplingPaymentAddress
// Generate a new Sapling spending key and return its public payment address
libzcash::SaplingPaymentAddress SaplingScriptPubKeyMan::GenerateNewSaplingZKey()
{
    LOCK(wallet->cs_wallet); // mapSaplingZKeyMetadata

    // Try to get the seed
    CKey seedKey;
    if (!wallet->GetKey(hdChain.GetID(), seedKey))
        throw std::runtime_error(std::string(__func__) + ": HD seed not found");

    HDSeed seed(seedKey.GetPrivKey());
    auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);

    // We use a fixed keypath scheme of m/32'/coin_type'/account'
    // Derive m/32'
    auto m_32h = m.Derive(32 | ZIP32_HARDENED_KEY_LIMIT);
    // Derive m/32'/coin_type'
    auto m_32h_cth = m_32h.Derive(119 | ZIP32_HARDENED_KEY_LIMIT);

    // Derive account key at next index, skip keys already known to the wallet
    libzcash::SaplingExtendedSpendingKey xsk;
    do {
        xsk = m_32h_cth.Derive(hdChain.nExternalChainCounter | ZIP32_HARDENED_KEY_LIMIT);
        hdChain.nExternalChainCounter++; // Increment childkey index
    } while (wallet->HaveSaplingSpendingKey(xsk.expsk.full_viewing_key()));

    // Update the chain model in the database
    if (wallet->fFileBacked && !CWalletDB(wallet->strWalletFile).WriteHDChain(hdChain))
        throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");

    // Create new metadata
    int64_t nCreationTime = GetTime();
    auto ivk = xsk.expsk.full_viewing_key().in_viewing_key();
    CKeyMetadata metadata(nCreationTime);
    metadata.key_origin.path.push_back(32 | BIP32_HARDENED_KEY_LIMIT);
    metadata.key_origin.path.push_back(119 | BIP32_HARDENED_KEY_LIMIT);
    metadata.key_origin.path.push_back(hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
    metadata.hd_seed_id = hdChain.GetID();
    mapSaplingZKeyMetadata[ivk] = metadata;

    auto addr = xsk.DefaultAddress();
    if (!AddSaplingZKey(xsk, addr)) {
        throw std::runtime_error(std::string(__func__) + ": AddSaplingZKey failed");
    }
    // return default sapling payment address.
    return addr;
}

// Add spending key to keystore
bool SaplingScriptPubKeyMan::AddSaplingZKey(
        const libzcash::SaplingExtendedSpendingKey &sk,
        const libzcash::SaplingPaymentAddress &defaultAddr)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata

    if (!AddSaplingSpendingKey(sk, defaultAddr)) {
        return false;
    }

    if (!wallet->fFileBacked) {
        return true;
    }

    if (!wallet->IsCrypted()) {
        auto ivk = sk.expsk.full_viewing_key().in_viewing_key();
        return CWalletDB(wallet->strWalletFile).WriteSaplingZKey(ivk, sk, mapSaplingZKeyMetadata[ivk]);
    }

    return true;
}

bool SaplingScriptPubKeyMan::AddSaplingSpendingKey(
        const libzcash::SaplingExtendedSpendingKey &sk,
        const libzcash::SaplingPaymentAddress &defaultAddr)
{
    {
        LOCK(wallet->cs_KeyStore);
        if (!wallet->IsCrypted()) {
            return wallet->AddSaplingSpendingKey(sk, defaultAddr); // keystore
        }

        if (wallet->IsLocked()) {
            return false;
        }

        std::vector<unsigned char> vchCryptedSecret;
        CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << sk;
        CKeyingMaterial vchSecret(ss.begin(), ss.end());
        auto address = sk.DefaultAddress();
        auto extfvk = sk.ToXFVK();
        if (!EncryptSecret(wallet->GetEncryptionKey(), vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
            return false;
        }

        if (!AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret, defaultAddr)) {
            return false;
        }
    }
    return true;
}

// Add payment address -> incoming viewing key map entry
bool SaplingScriptPubKeyMan::AddSaplingIncomingViewingKey(
        const libzcash::SaplingIncomingViewingKey &ivk,
        const libzcash::SaplingPaymentAddress &addr)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata

    if (!wallet->AddSaplingIncomingViewingKey(ivk, addr)) {
        return false;
    }

    if (!wallet->fFileBacked) {
        return true;
    }

    if (!wallet->IsCrypted()) {
        return CWalletDB(wallet->strWalletFile).WriteSaplingPaymentAddress(addr, ivk);
    }

    return true;
}

bool SaplingScriptPubKeyMan::EncryptSaplingKeys(CKeyingMaterial& vMasterKeyIn)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingSpendingKeys

    for (SaplingSpendingKeyMap::value_type& mSaplingSpendingKey : wallet->mapSaplingSpendingKeys) {
        const libzcash::SaplingExtendedSpendingKey &sk = mSaplingSpendingKey.second;
        CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
        ss << sk;
        CKeyingMaterial vchSecret(ss.begin(), ss.end());
        auto extfvk = sk.ToXFVK();
        std::vector<unsigned char> vchCryptedSecret;
        if (!EncryptSecret(vMasterKeyIn, vchSecret, extfvk.fvk.GetFingerprint(), vchCryptedSecret)) {
            return false;
        }
        if (!AddCryptedSaplingSpendingKeyDB(extfvk, vchCryptedSecret, sk.DefaultAddress())) {
            return false;
        }
    }
    wallet->mapSaplingSpendingKeys.clear();
    return true;
}

bool SaplingScriptPubKeyMan::AddCryptedSaplingSpendingKeyDB(const libzcash::SaplingExtendedFullViewingKey &extfvk,
                                           const std::vector<unsigned char> &vchCryptedSecret,
                                           const libzcash::SaplingPaymentAddress &defaultAddr)
{
    if (!wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, defaultAddr))
        return false;
    if (!wallet->fFileBacked)
        return true;
    {
        LOCK(wallet->cs_wallet);
        if (wallet->pwalletdbEncryption) {
            return wallet->pwalletdbEncryption->WriteCryptedSaplingZKey(extfvk,
                                                                vchCryptedSecret,
                                                                mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
        } else {
            return CWalletDB(wallet->strWalletFile).WriteCryptedSaplingZKey(extfvk,
                                                                    vchCryptedSecret,
                                                                    mapSaplingZKeyMetadata[extfvk.fvk.in_viewing_key()]);
        }
    }
    return false;
}

bool SaplingScriptPubKeyMan::HaveSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &zaddr) const
{
    libzcash::SaplingIncomingViewingKey ivk;
    libzcash::SaplingFullViewingKey fvk;

    return wallet->GetSaplingIncomingViewingKey(zaddr, ivk) &&
           wallet->GetSaplingFullViewingKey(ivk, fvk) &&
           wallet->HaveSaplingSpendingKey(fvk);
}

///////////////////// Load ////////////////////////////////////////

bool SaplingScriptPubKeyMan::LoadCryptedSaplingZKey(
        const libzcash::SaplingExtendedFullViewingKey &extfvk,
        const std::vector<unsigned char> &vchCryptedSecret)
{
    return wallet->AddCryptedSaplingSpendingKey(extfvk, vchCryptedSecret, extfvk.DefaultAddress());
}

bool SaplingScriptPubKeyMan::LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta)
{
    AssertLockHeld(wallet->cs_wallet); // mapSaplingZKeyMetadata
    mapSaplingZKeyMetadata[ivk] = meta;
    return true;
}

bool SaplingScriptPubKeyMan::LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key)
{
    return wallet->AddSaplingSpendingKey(key, key.DefaultAddress());
}

bool SaplingScriptPubKeyMan::LoadSaplingPaymentAddress(
        const libzcash::SaplingPaymentAddress &addr,
        const libzcash::SaplingIncomingViewingKey &ivk)
{
    return wallet->AddSaplingIncomingViewingKey(ivk, addr);
}

///////////////////// Setup ///////////////////////////////////////

bool SaplingScriptPubKeyMan::SetupGeneration(const CKeyID& keyID, bool force)
{
    SetHDSeed(keyID, force);
    return true;
}

void SaplingScriptPubKeyMan::SetHDSeed(const CPubKey& seed, bool force, bool memonly)
{
    SetHDSeed(seed.GetID(), force, memonly);
}

void SaplingScriptPubKeyMan::SetHDSeed(const CKeyID& keyID, bool force, bool memonly)
{
    if (!hdChain.IsNull() && !force)
        throw std::runtime_error(std::string(__func__) + ": sapling trying to set a hd seed on an already created chain");

    LOCK(wallet->cs_wallet);
    // store the keyid (hash160) together with
    // the child index counter in the database
    // as a hdChain object
    CHDChain newHdChain(HDChain::ChainCounterType::Sapling);
    if (!newHdChain.SetSeed(keyID) ) {
        throw std::runtime_error(std::string(__func__) + ": set sapling hd seed failed");
    }

    SetHDChain(newHdChain, memonly);
}

void SaplingScriptPubKeyMan::SetHDChain(CHDChain& chain, bool memonly)
{
    LOCK(wallet->cs_wallet);
    if (chain.chainType != HDChain::ChainCounterType::Sapling)
        throw std::runtime_error(std::string(__func__) + ": trying to store an invalid chain type");

    if (!memonly && !CWalletDB(wallet->strWalletFile).WriteHDChain(chain))
        throw std::runtime_error(std::string(__func__) + ": writing sapling chain failed");

    hdChain = chain;

    // Sanity check
    if (!wallet->HaveKey(hdChain.GetID()))
        throw std::runtime_error(std::string(__func__) + ": Not found sapling seed in wallet");
}<|endoftext|>


<commit_before>/**
*  Copyright (C) 2018 3D Repo Ltd
*
*  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 <OdaCommon.h>
#include <OdString.h>

#include <toString.h>
#include <DgLevelTableRecord.h>

#include "geometry_dumper.h"
#include "../../../../core/model/bson/repo_bson_factory.h"
using namespace repo::manipulator::modelconvertor::odaHelper;

void GeometryDumper::triangleOut(const OdInt32* p3Vertices, const OdGeVector3d* pNormal)
{
	const OdGePoint3d*  pVertexDataList = vertexDataList();
	const OdGeVector3d* pNormals = NULL;

	if ((pVertexDataList + p3Vertices[0]) != (pVertexDataList + p3Vertices[1]) &&
		(pVertexDataList + p3Vertices[0]) != (pVertexDataList + p3Vertices[2]) &&
		(pVertexDataList + p3Vertices[1]) != (pVertexDataList + p3Vertices[2]))
	{
		std::vector<repo::lib::RepoVector3D64> vertices;
		for (int i = 0; i < 3; ++i)
		{
			vertices.push_back({ pVertexDataList[p3Vertices[i]].x , pVertexDataList[p3Vertices[i]].y, pVertexDataList[p3Vertices[i]].z });
		}
		collector->addFace(vertices);
	}
}

double GeometryDumper::deviation(
	const OdGiDeviationType deviationType,
	const OdGePoint3d& pointOnCurve) const {
	return 0;
}

VectoriseDevice* GeometryDumper::device()
{
	return static_cast<VectoriseDevice*>(OdGsBaseVectorizeView::device());
}

bool GeometryDumper::doDraw(OdUInt32 i, const OdGiDrawable* pDrawable)
{
	OdDgElementPtr pElm = OdDgElement::cast(pDrawable);

	OdString sClassName = toString(pElm->isA());
	OdString sHandle = pElm->isDBRO() ? toString(pElm->elementId().getHandle()) : toString(OD_T("non-DbResident"));

	std::stringstream ss;
	ss << sHandle;
	collector->setNextMeshName(ss.str());

	OdGiSubEntityTraitsData traits = effectiveTraits();
	OdDgElementId idLevel = traits.layer();
	if (!idLevel.isNull())
	{
		OdDgLevelTableRecordPtr pLevel = idLevel.openObject(OdDg::kForRead);
		OdUInt32 iLevelEntry = pLevel->getEntryId();

		std::stringstream ss;
		ss << pLevel->getName();
		auto layerName = ss.str();
		collector->setLayer(layerName);
	}
	return OdGsBaseMaterialView::doDraw(i, pDrawable);
}

OdCmEntityColor GeometryDumper::fixByACI(const ODCOLORREF *ids, const OdCmEntityColor &color)
{
	if (color.isByACI() || color.isByDgnIndex())
	{
		return OdCmEntityColor(ODGETRED(ids[color.colorIndex()]), ODGETGREEN(ids[color.colorIndex()]), ODGETBLUE(ids[color.colorIndex()]));
	}
	else if (!color.isByColor())
	{
		return OdCmEntityColor(0, 0, 0);
	}
	return color;
}

OdGiMaterialItemPtr GeometryDumper::fillMaterialCache(
	OdGiMaterialItemPtr prevCache,
	OdDbStub* materialId,
	const OdGiMaterialTraitsData & materialData
) {

	auto id = (OdUInt64)(OdIntPtr)materialId;

	OdGiMaterialColor diffuseColor; OdGiMaterialMap diffuseMap;
	OdGiMaterialColor ambientColor;
	OdGiMaterialColor specularColor; OdGiMaterialMap specularMap; double glossFactor;
	double opacityPercentage; OdGiMaterialMap opacityMap;
	double refrIndex; OdGiMaterialMap refrMap;

	materialData.diffuse(diffuseColor, diffuseMap);
	materialData.ambient(ambientColor);
	materialData.specular(specularColor, specularMap, glossFactor);
	materialData.opacity(opacityPercentage, opacityMap);
	materialData.refraction(refrIndex, refrMap);

	OdGiMaterialMap bumpMap;
	materialData.bump(bumpMap);

	ODCOLORREF colorDiffuse(0), colorAmbient(0), colorSpecular(0);
	if (diffuseColor.color().colorMethod() == OdCmEntityColor::kByColor)
	{
		colorDiffuse = ODTOCOLORREF(diffuseColor.color());
	}
	else if (diffuseColor.color().colorMethod() == OdCmEntityColor::kByACI)
	{
		colorDiffuse = OdCmEntityColor::lookUpRGB((OdUInt8)diffuseColor.color().colorIndex());
	}
	if (ambientColor.color().colorMethod() == OdCmEntityColor::kByColor)
	{
		colorAmbient = ODTOCOLORREF(ambientColor.color());
	}
	else if (ambientColor.color().colorMethod() == OdCmEntityColor::kByACI)
	{
		colorAmbient = OdCmEntityColor::lookUpRGB((OdUInt8)ambientColor.color().colorIndex());
	}
	if (specularColor.color().colorMethod() == OdCmEntityColor::kByColor)
	{
		colorSpecular = ODTOCOLORREF(specularColor.color());
	}
	else if (specularColor.color().colorMethod() == OdCmEntityColor::kByACI)
	{
		colorSpecular = OdCmEntityColor::lookUpRGB((OdUInt8)specularColor.color().colorIndex());
	}

	OdCmEntityColor color = fixByACI(this->device()->getPalette(), effectiveTraits().trueColor());
	repo_material_t material;
	// diffuse
	if (diffuseColor.method() == OdGiMaterialColor::kOverride)
		material.diffuse = { ODGETRED(colorDiffuse) / 255.0f, ODGETGREEN(colorDiffuse) / 255.0f, ODGETBLUE(colorDiffuse) / 255.0f, 1.0f };
	else
		material.diffuse = { color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, 1.0f };
	/*
	TODO: texture support
	mData.bDiffuseChannelEnabled = (GETBIT(materialData.channelFlags(), OdGiMaterialTraits::kUseDiffuse)) ? true : false;
	if (mData.bDiffuseChannelEnabled && diffuseMap.source() == OdGiMaterialMap::kFile && !diffuseMap.sourceFileName().isEmpty())
	{
	mData.bDiffuseHasTexture = true;
	mData.sDiffuseFileSource = diffuseMap.sourceFileName();
	}*/

	// specular
	if (specularColor.method() == OdGiMaterialColor::kOverride)
		material.specular = { ODGETRED(colorSpecular) / 255.0f, ODGETGREEN(colorSpecular) / 255.0f, ODGETBLUE(colorSpecular) / 255.0f, 1.0f };
	else
		material.specular = { color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, 1.0f };

	material.shininessStrength = 1 - glossFactor;
	material.shininess = materialData.reflectivity();

	// opacity
	material.opacity = opacityPercentage;

	// refraction
	/*mData.bRefractionChannelEnabled = (GETBIT(materialData.channelFlags(), OdGiMaterialTraits::kUseRefraction)) ? 1 : 0;
	mData.dRefractionIndex = materialData.reflectivity();*/

	// transclucence
	//mData.dTranslucence = materialData.translucence();

	collector->setCurrentMaterial(material);
	collector->stopMeshEntry();
	collector->startMeshEntry();

	return OdGiMaterialItemPtr();
}

void GeometryDumper::init(GeometryCollector *const geoCollector) {
	collector = geoCollector;
}

void GeometryDumper::beginViewVectorization()
{
	OdGsBaseMaterialView::beginViewVectorization();
	setEyeToOutputTransform(getEyeToWorldTransform());

	OdGiGeometrySimplifier::setDrawContext(OdGsBaseMaterialView::drawContext());
	output().setDestGeometry((OdGiGeometrySimplifier&)*this);
}

void GeometryDumper::endViewVectorization()
{
	collector->stopMeshEntry();
	OdGsBaseMaterialView::endViewVectorization();
}

void GeometryDumper::setMode(OdGsView::RenderMode mode)
{
	OdGsBaseVectorizeView::m_renderMode = kGouraudShaded;
	m_regenerationType = kOdGiRenderCommand;
	OdGiGeometrySimplifier::m_renderMode = OdGsBaseVectorizeView::m_renderMode;
}<commit_msg>ISSUE #271 try fix travis via char conversion<commit_after>/**
*  Copyright (C) 2018 3D Repo Ltd
*
*  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 <OdaCommon.h>
#include <OdString.h>

#include <toString.h>
#include <DgLevelTableRecord.h>

#include "geometry_dumper.h"
#include "../../../../core/model/bson/repo_bson_factory.h"
using namespace repo::manipulator::modelconvertor::odaHelper;

void GeometryDumper::triangleOut(const OdInt32* p3Vertices, const OdGeVector3d* pNormal)
{
	const OdGePoint3d*  pVertexDataList = vertexDataList();
	const OdGeVector3d* pNormals = NULL;

	if ((pVertexDataList + p3Vertices[0]) != (pVertexDataList + p3Vertices[1]) &&
		(pVertexDataList + p3Vertices[0]) != (pVertexDataList + p3Vertices[2]) &&
		(pVertexDataList + p3Vertices[1]) != (pVertexDataList + p3Vertices[2]))
	{
		std::vector<repo::lib::RepoVector3D64> vertices;
		for (int i = 0; i < 3; ++i)
		{
			vertices.push_back({ pVertexDataList[p3Vertices[i]].x , pVertexDataList[p3Vertices[i]].y, pVertexDataList[p3Vertices[i]].z });
		}
		collector->addFace(vertices);
	}
}

double GeometryDumper::deviation(
	const OdGiDeviationType deviationType,
	const OdGePoint3d& pointOnCurve) const {
	return 0;
}

VectoriseDevice* GeometryDumper::device()
{
	return static_cast<VectoriseDevice*>(OdGsBaseVectorizeView::device());
}

bool GeometryDumper::doDraw(OdUInt32 i, const OdGiDrawable* pDrawable)
{
	OdDgElementPtr pElm = OdDgElement::cast(pDrawable);

	OdString sClassName = toString(pElm->isA());
	OdString sHandle = pElm->isDBRO() ? toString(pElm->elementId().getHandle()) : toString(OD_T("non-DbResident"));

	std::stringstream ss;
	ss << sHandle;
	collector->setNextMeshName(ss.str());

	OdGiSubEntityTraitsData traits = effectiveTraits();
	OdDgElementId idLevel = traits.layer();
	if (!idLevel.isNull())
	{
		OdDgLevelTableRecordPtr pLevel = idLevel.openObject(OdDg::kForRead);
		OdUInt32 iLevelEntry = pLevel->getEntryId();

		std::stringstream ss;
		ss << pLevel->getName().c_str();
		auto layerName = ss.str();
		collector->setLayer(layerName);
	}
	return OdGsBaseMaterialView::doDraw(i, pDrawable);
}

OdCmEntityColor GeometryDumper::fixByACI(const ODCOLORREF *ids, const OdCmEntityColor &color)
{
	if (color.isByACI() || color.isByDgnIndex())
	{
		return OdCmEntityColor(ODGETRED(ids[color.colorIndex()]), ODGETGREEN(ids[color.colorIndex()]), ODGETBLUE(ids[color.colorIndex()]));
	}
	else if (!color.isByColor())
	{
		return OdCmEntityColor(0, 0, 0);
	}
	return color;
}

OdGiMaterialItemPtr GeometryDumper::fillMaterialCache(
	OdGiMaterialItemPtr prevCache,
	OdDbStub* materialId,
	const OdGiMaterialTraitsData & materialData
) {

	auto id = (OdUInt64)(OdIntPtr)materialId;

	OdGiMaterialColor diffuseColor; OdGiMaterialMap diffuseMap;
	OdGiMaterialColor ambientColor;
	OdGiMaterialColor specularColor; OdGiMaterialMap specularMap; double glossFactor;
	double opacityPercentage; OdGiMaterialMap opacityMap;
	double refrIndex; OdGiMaterialMap refrMap;

	materialData.diffuse(diffuseColor, diffuseMap);
	materialData.ambient(ambientColor);
	materialData.specular(specularColor, specularMap, glossFactor);
	materialData.opacity(opacityPercentage, opacityMap);
	materialData.refraction(refrIndex, refrMap);

	OdGiMaterialMap bumpMap;
	materialData.bump(bumpMap);

	ODCOLORREF colorDiffuse(0), colorAmbient(0), colorSpecular(0);
	if (diffuseColor.color().colorMethod() == OdCmEntityColor::kByColor)
	{
		colorDiffuse = ODTOCOLORREF(diffuseColor.color());
	}
	else if (diffuseColor.color().colorMethod() == OdCmEntityColor::kByACI)
	{
		colorDiffuse = OdCmEntityColor::lookUpRGB((OdUInt8)diffuseColor.color().colorIndex());
	}
	if (ambientColor.color().colorMethod() == OdCmEntityColor::kByColor)
	{
		colorAmbient = ODTOCOLORREF(ambientColor.color());
	}
	else if (ambientColor.color().colorMethod() == OdCmEntityColor::kByACI)
	{
		colorAmbient = OdCmEntityColor::lookUpRGB((OdUInt8)ambientColor.color().colorIndex());
	}
	if (specularColor.color().colorMethod() == OdCmEntityColor::kByColor)
	{
		colorSpecular = ODTOCOLORREF(specularColor.color());
	}
	else if (specularColor.color().colorMethod() == OdCmEntityColor::kByACI)
	{
		colorSpecular = OdCmEntityColor::lookUpRGB((OdUInt8)specularColor.color().colorIndex());
	}

	OdCmEntityColor color = fixByACI(this->device()->getPalette(), effectiveTraits().trueColor());
	repo_material_t material;
	// diffuse
	if (diffuseColor.method() == OdGiMaterialColor::kOverride)
		material.diffuse = { ODGETRED(colorDiffuse) / 255.0f, ODGETGREEN(colorDiffuse) / 255.0f, ODGETBLUE(colorDiffuse) / 255.0f, 1.0f };
	else
		material.diffuse = { color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, 1.0f };
	/*
	TODO: texture support
	mData.bDiffuseChannelEnabled = (GETBIT(materialData.channelFlags(), OdGiMaterialTraits::kUseDiffuse)) ? true : false;
	if (mData.bDiffuseChannelEnabled && diffuseMap.source() == OdGiMaterialMap::kFile && !diffuseMap.sourceFileName().isEmpty())
	{
	mData.bDiffuseHasTexture = true;
	mData.sDiffuseFileSource = diffuseMap.sourceFileName();
	}*/

	// specular
	if (specularColor.method() == OdGiMaterialColor::kOverride)
		material.specular = { ODGETRED(colorSpecular) / 255.0f, ODGETGREEN(colorSpecular) / 255.0f, ODGETBLUE(colorSpecular) / 255.0f, 1.0f };
	else
		material.specular = { color.red() / 255.0f, color.green() / 255.0f, color.blue() / 255.0f, 1.0f };

	material.shininessStrength = 1 - glossFactor;
	material.shininess = materialData.reflectivity();

	// opacity
	material.opacity = opacityPercentage;

	// refraction
	/*mData.bRefractionChannelEnabled = (GETBIT(materialData.channelFlags(), OdGiMaterialTraits::kUseRefraction)) ? 1 : 0;
	mData.dRefractionIndex = materialData.reflectivity();*/

	// transclucence
	//mData.dTranslucence = materialData.translucence();

	collector->setCurrentMaterial(material);
	collector->stopMeshEntry();
	collector->startMeshEntry();

	return OdGiMaterialItemPtr();
}

void GeometryDumper::init(GeometryCollector *const geoCollector) {
	collector = geoCollector;
}

void GeometryDumper::beginViewVectorization()
{
	OdGsBaseMaterialView::beginViewVectorization();
	setEyeToOutputTransform(getEyeToWorldTransform());

	OdGiGeometrySimplifier::setDrawContext(OdGsBaseMaterialView::drawContext());
	output().setDestGeometry((OdGiGeometrySimplifier&)*this);
}

void GeometryDumper::endViewVectorization()
{
	collector->stopMeshEntry();
	OdGsBaseMaterialView::endViewVectorization();
}

void GeometryDumper::setMode(OdGsView::RenderMode mode)
{
	OdGsBaseVectorizeView::m_renderMode = kGouraudShaded;
	m_regenerationType = kOdGiRenderCommand;
	OdGiGeometrySimplifier::m_renderMode = OdGsBaseVectorizeView::m_renderMode;
}<|endoftext|>


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

#include <thrift/lib/cpp/async/TAsyncUDPSocket.h>

#include <thrift/lib/cpp/async/TEventBase.h>

#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
using apache::thrift::transport::TTransportException;

namespace apache { namespace thrift { namespace async {

TAsyncUDPSocket::TAsyncUDPSocket(TEventBase* evb)
    : TEventHandler(CHECK_NOTNULL(evb)),
      eventBase_(evb),
      fd_(-1),
      readCallback_(nullptr) {
  DCHECK(evb->isInEventBaseThread());
}

TAsyncUDPSocket::~TAsyncUDPSocket() {
  if (fd_ != -1) {
    close();
  }
}

void TAsyncUDPSocket::bind(const folly::SocketAddress& address) {
  int socket = ::socket(address.getFamily(), SOCK_DGRAM, IPPROTO_UDP);
  if (socket == -1) {
    throw TTransportException(TTransportException::NOT_OPEN,
                              "error creating async udp socket",
                              errno);
  }

  auto g = folly::makeGuard([&] { ::close(socket); });

  // put the socket in non-blocking mode
  int ret = fcntl(socket, F_SETFL, O_NONBLOCK);
  if (ret != 0) {
    throw TTransportException(TTransportException::NOT_OPEN,
                              "failed to put socket in non-blocking mode",
                              errno);
  }

  // put the socket in reuse mode
  int value = 1;
  if (setsockopt(socket,
                 SOL_SOCKET,
                 SO_REUSEADDR,
                 &value,
                 sizeof(value)) != 0) {
    throw TTransportException(TTransportException::NOT_OPEN,
                              "failed to put socket in reuse mode",
                              errno);
  }

  // bind to the address
  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
  if (::bind(socket, saddr, address.getActualSize()) != 0) {
    throw TTransportException(
        TTransportException::NOT_OPEN,
        "failed to bind the async udp socket for:" + address.describe(),
        errno);
  }

  // success
  g.dismiss();
  fd_ = socket;
  ownership_ = FDOwnership::OWNS;

  // attach to TEventHandler
  TEventHandler::changeHandlerFD(fd_);

  if (address.getPort() != 0) {
    localAddress_ = address;
  } else {
    localAddress_.setFromLocalAddress(fd_);
  }
}

void TAsyncUDPSocket::setFD(int fd, FDOwnership ownership) {
  CHECK_EQ(-1, fd_) << "Already bound to another FD";

  fd_ = fd;
  ownership_ = ownership;

  TEventHandler::changeHandlerFD(fd_);
  localAddress_.setFromLocalAddress(fd_);
}

ssize_t TAsyncUDPSocket::write(const folly::SocketAddress& address,
                               const std::unique_ptr<folly::IOBuf>& buf) {
  CHECK_NE(-1, fd_) << "Socket not yet bound";

  // XXX: Use `sendmsg` instead of coalescing here
  buf->coalesce();

  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);

  return ::sendto(fd_,
                  buf->data(),
                  buf->length(),
                  MSG_DONTWAIT,
                  saddr,
                  address.getActualSize());
}

void TAsyncUDPSocket::resumeRead(ReadCallback* cob) {
  CHECK(!readCallback_) << "Another read callback already installed";
  CHECK_NE(-1, fd_) << "UDP server socket not yet bind to an address";

  readCallback_ = CHECK_NOTNULL(cob);
  if (!updateRegistration()) {
    TTransportException ex(TTransportException::NOT_OPEN,
                           "failed to register for accept events");

    readCallback_ = nullptr;
    cob->onReadError(ex);
    return;
  }
}

void TAsyncUDPSocket::pauseRead() {
  // It is ok to pause an already paused socket
  readCallback_ = nullptr;
  updateRegistration();
}

void TAsyncUDPSocket::close() {
  DCHECK(eventBase_->isInEventBaseThread());

  if (readCallback_) {
    auto cob = readCallback_;
    readCallback_ = nullptr;

    cob->onReadClosed();
  }

  // Unregister any events we are registered for
  unregisterHandler();

  if (fd_ != -1 && ownership_ == FDOwnership::OWNS) {
    ::close(fd_);
  }

  fd_ = -1;
}

void TAsyncUDPSocket::handlerReady(uint16_t events) noexcept {
  if (events & TEventHandler::READ) {
    DCHECK(readCallback_);
    handleRead();
  }
}

void TAsyncUDPSocket::handleRead() noexcept {
  void* buf{nullptr};
  size_t len{0};

  readCallback_->getReadBuffer(&buf, &len);
  if (buf == nullptr || len == 0) {
    TTransportException ex(
        TTransportException::BAD_ARGS,
        "TAsyncUDPSocket::getReadBuffer() returned empty buffer");

    auto cob = readCallback_;
    readCallback_ = nullptr;

    cob->onReadError(ex);
    updateRegistration();
    return;
  }

  sockaddr_storage addrStorage;
  struct sockaddr* rawAddr = reinterpret_cast<sockaddr*>(&addrStorage);
  rawAddr->sa_family = localAddress_.getFamily();
  socklen_t addrLen = sizeof(*rawAddr);

  ssize_t bytesRead = ::recvfrom(fd_, buf, len, MSG_TRUNC, rawAddr, &addrLen);
  if (bytesRead >= 0) {
    clientAddress_.setFromSockaddr(rawAddr, addrLen);

    if (bytesRead > 0) {
      bool truncated = false;
      if (bytesRead > len) {
        truncated = true;
        bytesRead = len;
      }

      readCallback_->onDataAvailable(clientAddress_, bytesRead, truncated);
    }
  } else {
    if (errno == EAGAIN || errno == EWOULDBLOCK) {
      // No data could be read without blocking the socket
      return;
    }

    TTransportException ex(TTransportException::INTERNAL_ERROR,
                           "::recvfrom() failed",
                           errno);

    // In case of UDP we can continue reading from the socket
    // even if the current request fails. We notify the user
    // so that he can do some logging/stats collection if he wants.
    auto cob = readCallback_;
    readCallback_ = nullptr;

    cob->onReadError(ex);
    updateRegistration();
  }
}

bool TAsyncUDPSocket::updateRegistration() noexcept {
  uint16_t flags = NONE;

  if (readCallback_) {
    flags |= READ;
  }

  return registerHandler(flags | PERSIST);
}

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

#include <thrift/lib/cpp/async/TAsyncUDPSocket.h>

#include <thrift/lib/cpp/async/TEventBase.h>

#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
using apache::thrift::transport::TTransportException;

namespace apache { namespace thrift { namespace async {

TAsyncUDPSocket::TAsyncUDPSocket(TEventBase* evb)
    : TEventHandler(CHECK_NOTNULL(evb)),
      eventBase_(evb),
      fd_(-1),
      readCallback_(nullptr) {
  DCHECK(evb->isInEventBaseThread());
}

TAsyncUDPSocket::~TAsyncUDPSocket() {
  if (fd_ != -1) {
    close();
  }
}

void TAsyncUDPSocket::bind(const folly::SocketAddress& address) {
  int socket = ::socket(address.getFamily(), SOCK_DGRAM, IPPROTO_UDP);
  if (socket == -1) {
    throw TTransportException(TTransportException::NOT_OPEN,
                              "error creating async udp socket",
                              errno);
  }

  auto g = folly::makeGuard([&] { ::close(socket); });

  // put the socket in non-blocking mode
  int ret = fcntl(socket, F_SETFL, O_NONBLOCK);
  if (ret != 0) {
    throw TTransportException(TTransportException::NOT_OPEN,
                              "failed to put socket in non-blocking mode",
                              errno);
  }

  // put the socket in reuse mode
  int value = 1;
  if (setsockopt(socket,
                 SOL_SOCKET,
                 SO_REUSEADDR,
                 &value,
                 sizeof(value)) != 0) {
    throw TTransportException(TTransportException::NOT_OPEN,
                              "failed to put socket in reuse mode",
                              errno);
  }

  // bind to the address
  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
  if (::bind(socket, saddr, address.getActualSize()) != 0) {
    throw TTransportException(
        TTransportException::NOT_OPEN,
        "failed to bind the async udp socket for:" + address.describe(),
        errno);
  }

  // success
  g.dismiss();
  fd_ = socket;
  ownership_ = FDOwnership::OWNS;

  // attach to TEventHandler
  TEventHandler::changeHandlerFD(fd_);

  if (address.getPort() != 0) {
    localAddress_ = address;
  } else {
    localAddress_.setFromLocalAddress(fd_);
  }
}

void TAsyncUDPSocket::setFD(int fd, FDOwnership ownership) {
  CHECK_EQ(-1, fd_) << "Already bound to another FD";

  fd_ = fd;
  ownership_ = ownership;

  TEventHandler::changeHandlerFD(fd_);
  localAddress_.setFromLocalAddress(fd_);
}

ssize_t TAsyncUDPSocket::write(const folly::SocketAddress& address,
                               const std::unique_ptr<folly::IOBuf>& buf) {
  CHECK_NE(-1, fd_) << "Socket not yet bound";

  // XXX: Use `sendmsg` instead of coalescing here
  buf->coalesce();

  sockaddr_storage addrStorage;
  address.getAddress(&addrStorage);
  sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);

  return ::sendto(fd_,
                  buf->data(),
                  buf->length(),
                  MSG_DONTWAIT,
                  saddr,
                  address.getActualSize());
}

void TAsyncUDPSocket::resumeRead(ReadCallback* cob) {
  CHECK(!readCallback_) << "Another read callback already installed";
  CHECK_NE(-1, fd_) << "UDP server socket not yet bind to an address";

  readCallback_ = CHECK_NOTNULL(cob);
  if (!updateRegistration()) {
    TTransportException ex(TTransportException::NOT_OPEN,
                           "failed to register for accept events");

    readCallback_ = nullptr;
    cob->onReadError(ex);
    return;
  }
}

void TAsyncUDPSocket::pauseRead() {
  // It is ok to pause an already paused socket
  readCallback_ = nullptr;
  updateRegistration();
}

void TAsyncUDPSocket::close() {
  DCHECK(eventBase_->isInEventBaseThread());

  if (readCallback_) {
    auto cob = readCallback_;
    readCallback_ = nullptr;

    cob->onReadClosed();
  }

  // Unregister any events we are registered for
  unregisterHandler();

  if (fd_ != -1 && ownership_ == FDOwnership::OWNS) {
    ::close(fd_);
  }

  fd_ = -1;
}

void TAsyncUDPSocket::handlerReady(uint16_t events) noexcept {
  if (events & TEventHandler::READ) {
    DCHECK(readCallback_);
    handleRead();
  }
}

void TAsyncUDPSocket::handleRead() noexcept {
  void* buf{nullptr};
  size_t len{0};

  readCallback_->getReadBuffer(&buf, &len);
  if (buf == nullptr || len == 0) {
    TTransportException ex(
        TTransportException::BAD_ARGS,
        "TAsyncUDPSocket::getReadBuffer() returned empty buffer");

    auto cob = readCallback_;
    readCallback_ = nullptr;

    cob->onReadError(ex);
    updateRegistration();
    return;
  }

  struct sockaddr_storage addrStorage;
  socklen_t addrLen = sizeof(addrStorage);
  memset(&addrStorage, 0, addrLen);
  struct sockaddr* rawAddr = reinterpret_cast<sockaddr*>(&addrStorage);
  rawAddr->sa_family = localAddress_.getFamily();

  ssize_t bytesRead = ::recvfrom(fd_, buf, len, MSG_TRUNC, rawAddr, &addrLen);
  if (bytesRead >= 0) {
    clientAddress_.setFromSockaddr(rawAddr, addrLen);

    if (bytesRead > 0) {
      bool truncated = false;
      if (bytesRead > len) {
        truncated = true;
        bytesRead = len;
      }

      readCallback_->onDataAvailable(clientAddress_, bytesRead, truncated);
    }
  } else {
    if (errno == EAGAIN || errno == EWOULDBLOCK) {
      // No data could be read without blocking the socket
      return;
    }

    TTransportException ex(TTransportException::INTERNAL_ERROR,
                           "::recvfrom() failed",
                           errno);

    // In case of UDP we can continue reading from the socket
    // even if the current request fails. We notify the user
    // so that he can do some logging/stats collection if he wants.
    auto cob = readCallback_;
    readCallback_ = nullptr;

    cob->onReadError(ex);
    updateRegistration();
  }
}

bool TAsyncUDPSocket::updateRegistration() noexcept {
  uint16_t flags = NONE;

  if (readCallback_) {
    flags |= READ;
  }

  return registerHandler(flags | PERSIST);
}

}}}
<|endoftext|>