<commit_before>// Copyright (c) 2009 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/tools/flip_server/http_interface.h"

#include "net/tools/dump_cache/url_utilities.h"
#include "net/tools/flip_server/balsa_frame.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/spdy_util.h"

namespace net {

HttpSM::HttpSM(SMConnection* connection,
               SMInterface* sm_spdy_interface,
               EpollServer* epoll_server,
               MemoryCache* memory_cache,
               FlipAcceptor* acceptor)
    : seq_num_(0),
      http_framer_(new BalsaFrame),
      stream_id_(0),
      server_idx_(-1),
      connection_(connection),
      sm_spdy_interface_(sm_spdy_interface),
      output_list_(connection->output_list()),
      output_ordering_(connection),
      memory_cache_(connection->memory_cache()),
      acceptor_(acceptor) {
  http_framer_->set_balsa_visitor(this);
  http_framer_->set_balsa_headers(&headers_);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
    http_framer_->set_is_request(false);
}
HttpSM::~HttpSM() {
  Reset();
  delete http_framer_;
}

void HttpSM::ProcessBodyData(const char *input, size_t size) {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream "
            << stream_id_ << ": size " << size;
    sm_spdy_interface_->SendDataFrame(stream_id_, input, size, 0, false);
  }
}

void HttpSM::ProcessHeaders(const BalsaHeaders& headers) {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
    std::string host =
      UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string());
    std::string method = headers.request_method().as_string();
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Received Request: "
            << headers.request_uri().as_string() << " " << method;
    std::string filename = EncodeURL(headers.request_uri().as_string(),
                                host, method);
    NewStream(stream_id_, 0, filename);
    stream_id_ += 2;
  } else {
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from "
            << connection_->server_ip_ << ":"
            << connection_->server_port_ << " ";
    sm_spdy_interface_->SendSynReply(stream_id_, headers);
  }
}

void HttpSM::MessageDone() {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: "
            << "stream " << stream_id_;
    sm_spdy_interface_->SendEOF(stream_id_);
  } else {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone.";
  }
}

void HttpSM::HandleHeaderError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleChunkingError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleBodyError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleError() {
  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
}

void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
  output_ordering_.AddToOutputOrder(mci);
}

void HttpSM::SendOKResponse(uint32 stream_id, std::string* output) {
  SendOKResponseImpl(stream_id, output);
}

void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
                             int32 server_idx) {
  sm_spdy_interface_ = sm_spdy_interface;
  server_idx_ = server_idx;
}

void HttpSM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
                              SMInterface* sm_interface,
                              EpollServer* epoll_server,
                              int fd,
                              std::string server_ip,
                              std::string server_port,
                              std::string remote_ip,
                              bool use_ssl) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server "
          << "connection.";
  connection_->InitSMConnection(connection_pool,
                                sm_interface,
                                epoll_server,
                                fd,
                                server_ip,
                                server_port,
                                remote_ip,
                                use_ssl);
}

size_t HttpSM::ProcessReadInput(const char* data, size_t len) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process read input: stream "
          << stream_id_;
  return http_framer_->ProcessInput(data, len);
}

size_t HttpSM::ProcessWriteInput(const char* data, size_t len) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size "
          << len << ": stream " << stream_id_;
  char * dataPtr = new char[len];
  memcpy(dataPtr, data, len);
  DataFrame* data_frame = new DataFrame;
  data_frame->data = (const char *)dataPtr;
  data_frame->size = len;
  data_frame->delete_when_done = true;
  connection_->EnqueueDataFrame(data_frame);
  return len;
}

bool HttpSM::MessageFullyRead() const {
  return http_framer_->MessageFullyRead();
}

void HttpSM::SetStreamID(uint32 stream_id) {
  stream_id_ = stream_id;
}

bool HttpSM::Error() const {
  return http_framer_->Error();
}

const char* HttpSM::ErrorAsString() const {
  return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
}

void HttpSM::Reset() {
  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream "
          << stream_id_;
  http_framer_->Reset();
}

void HttpSM::ResetForNewConnection() {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
      << "to: " << connection_->server_ip_ << ":"
      << connection_->server_port_ << " ";
  }
  seq_num_ = 0;
  output_ordering_.Reset();
  http_framer_->Reset();
  if (sm_spdy_interface_) {
    sm_spdy_interface_->ResetForNewInterface(server_idx_);
  }
}

void HttpSM::Cleanup() {
  if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) {
    VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_;
    connection_->Cleanup("request complete");
  }
}

int HttpSM::PostAcceptHook() {
  return 1;
}

void HttpSM::NewStream(uint32 stream_id, uint32 priority,
                       const std::string& filename) {
  MemCacheIter mci;
  mci.stream_id = stream_id;
  mci.priority = priority;
  if (!memory_cache_->AssignFileData(filename, &mci)) {
    // error creating new stream.
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
    SendErrorNotFound(stream_id);
  } else {
    AddToOutputOrder(mci);
  }
}

void HttpSM::SendEOF(uint32 stream_id) {
  SendEOFImpl(stream_id);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    sm_spdy_interface_->ResetForNewInterface(server_idx_);
  }
}

void HttpSM::SendErrorNotFound(uint32 stream_id) {
  SendErrorNotFoundImpl(stream_id);
}

size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
  return 0;
}

size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
  return SendSynReplyImpl(stream_id, headers);
}

void HttpSM::SendDataFrame(uint32 stream_id, const char* data, int64 len,
                   uint32 flags, bool compress) {
  SendDataFrameImpl(stream_id, data, len, flags, compress);
}

void HttpSM::SendEOFImpl(uint32 stream_id) {
  DataFrame* df = new DataFrame;
  df->data = "0\r\n\r\n";
  df->size = 5;
  df->delete_when_done = false;
  EnqueueDataFrame(df);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
    Reset();
  }
}

void HttpSM::SendErrorNotFoundImpl(uint32 stream_id) {
  BalsaHeaders my_headers;
  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
  my_headers.RemoveAllOfHeader("content-length");
  my_headers.AppendHeader("transfer-encoding", "chunked");
  SendSynReplyImpl(stream_id, my_headers);
  SendDataFrame(stream_id, "page not found", 14, 0, false);
  SendEOFImpl(stream_id);
  output_ordering_.RemoveStreamId(stream_id);
}

void HttpSM::SendOKResponseImpl(uint32 stream_id, std::string* output) {
  BalsaHeaders my_headers;
  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
  my_headers.RemoveAllOfHeader("content-length");
  my_headers.AppendHeader("transfer-encoding", "chunked");
  SendSynReplyImpl(stream_id, my_headers);
  SendDataFrame(stream_id, output->c_str(), output->size(), 0, false);
  SendEOFImpl(stream_id);
  output_ordering_.RemoveStreamId(stream_id);
}

size_t HttpSM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
  SimpleBuffer sb;
  headers.WriteHeaderAndEndingToBuffer(&sb);
  DataFrame* df = new DataFrame;
  df->size = sb.ReadableBytes();
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  sb.Read(buffer, df->size);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
          << stream_id_;
  size_t df_size = df->size;
  EnqueueDataFrame(df);
  return df_size;
}

size_t HttpSM::SendSynStreamImpl(uint32 stream_id,
                                 const BalsaHeaders& headers) {
  SimpleBuffer sb;
  headers.WriteHeaderAndEndingToBuffer(&sb);
  DataFrame* df = new DataFrame;
  df->size = sb.ReadableBytes();
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  sb.Read(buffer, df->size);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
          << stream_id_;
  size_t df_size = df->size;
  EnqueueDataFrame(df);
  return df_size;
}

void HttpSM::SendDataFrameImpl(uint32 stream_id, const char* data, int64 len,
                       uint32 flags, bool compress) {
  char chunk_buf[128];
  snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len);
  std::string chunk_description(chunk_buf);
  DataFrame* df = new DataFrame;
  df->size = chunk_description.size() + len + 2;
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  memcpy(buffer, chunk_description.data(), chunk_description.size());
  memcpy(buffer + chunk_description.size(), data, len);
  memcpy(buffer + chunk_description.size() + len, "\r\n", 2);
  EnqueueDataFrame(df);
}

void HttpSM::EnqueueDataFrame(DataFrame* df) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
          << stream_id_;
  connection_->EnqueueDataFrame(df);
}

void HttpSM::GetOutput() {
  MemCacheIter* mci = output_ordering_.GetIter();
  if (mci == NULL) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to "
            << "output!?: stream " << stream_id_;
    return;
  }
  if (!mci->transformed_header) {
    mci->bytes_sent = SendSynReply(mci->stream_id,
                                   *(mci->file_data->headers));
    mci->transformed_header = true;
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed "
            << "header stream_id: [" << mci->stream_id << "]";
    return;
  }
  if (mci->body_bytes_consumed >= mci->file_data->body.size()) {
    SendEOF(mci->stream_id);
    output_ordering_.RemoveStreamId(mci->stream_id);
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: ["
            << mci->stream_id << "]";
    return;
  }
  size_t num_to_write =
    mci->file_data->body.size() - mci->body_bytes_consumed;
  if (num_to_write > mci->max_segment_size)
    num_to_write = mci->max_segment_size;

  SendDataFrame(mci->stream_id,
                mci->file_data->body.data() + mci->body_bytes_consumed,
                num_to_write, 0, true);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame["
          << mci->stream_id << "]: " << num_to_write;
  mci->body_bytes_consumed += num_to_write;
  mci->bytes_sent += num_to_write;
}

}  // namespace net

<commit_msg>Responses using connection close to signal end of message were failing to render because we didn't close out the SPDY stream.<commit_after>// Copyright (c) 2009 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/tools/flip_server/http_interface.h"

#include "net/tools/dump_cache/url_utilities.h"
#include "net/tools/flip_server/balsa_frame.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/spdy_util.h"

namespace net {

HttpSM::HttpSM(SMConnection* connection,
               SMInterface* sm_spdy_interface,
               EpollServer* epoll_server,
               MemoryCache* memory_cache,
               FlipAcceptor* acceptor)
    : seq_num_(0),
      http_framer_(new BalsaFrame),
      stream_id_(0),
      server_idx_(-1),
      connection_(connection),
      sm_spdy_interface_(sm_spdy_interface),
      output_list_(connection->output_list()),
      output_ordering_(connection),
      memory_cache_(connection->memory_cache()),
      acceptor_(acceptor) {
  http_framer_->set_balsa_visitor(this);
  http_framer_->set_balsa_headers(&headers_);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY)
    http_framer_->set_is_request(false);
}
HttpSM::~HttpSM() {
  Reset();
  delete http_framer_;
}

void HttpSM::ProcessBodyData(const char *input, size_t size) {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process Body Data: stream "
            << stream_id_ << ": size " << size;
    sm_spdy_interface_->SendDataFrame(stream_id_, input, size, 0, false);
  }
}

void HttpSM::ProcessHeaders(const BalsaHeaders& headers) {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
    std::string host =
      UrlUtilities::GetUrlHost(headers.GetHeader("Host").as_string());
    std::string method = headers.request_method().as_string();
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Received Request: "
            << headers.request_uri().as_string() << " " << method;
    std::string filename = EncodeURL(headers.request_uri().as_string(),
                                host, method);
    NewStream(stream_id_, 0, filename);
    stream_id_ += 2;
  } else {
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Received Response from "
            << connection_->server_ip_ << ":"
            << connection_->server_port_ << " ";
    sm_spdy_interface_->SendSynReply(stream_id_, headers);
  }
}

void HttpSM::MessageDone() {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone. Sending EOF: "
            << "stream " << stream_id_;
    sm_spdy_interface_->SendEOF(stream_id_);
  } else {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: MessageDone.";
  }
}

void HttpSM::HandleHeaderError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleChunkingError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleBodyError(BalsaFrame* framer) {
  HandleError();
}

void HttpSM::HandleError() {
  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "Error detected";
}

void HttpSM::AddToOutputOrder(const MemCacheIter& mci) {
  output_ordering_.AddToOutputOrder(mci);
}

void HttpSM::SendOKResponse(uint32 stream_id, std::string* output) {
  SendOKResponseImpl(stream_id, output);
}

void HttpSM::InitSMInterface(SMInterface* sm_spdy_interface,
                             int32 server_idx) {
  sm_spdy_interface_ = sm_spdy_interface;
  server_idx_ = server_idx;
}

void HttpSM::InitSMConnection(SMConnectionPoolInterface* connection_pool,
                              SMInterface* sm_interface,
                              EpollServer* epoll_server,
                              int fd,
                              std::string server_ip,
                              std::string server_port,
                              std::string remote_ip,
                              bool use_ssl) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Initializing server "
          << "connection.";
  connection_->InitSMConnection(connection_pool,
                                sm_interface,
                                epoll_server,
                                fd,
                                server_ip,
                                server_port,
                                remote_ip,
                                use_ssl);
}

size_t HttpSM::ProcessReadInput(const char* data, size_t len) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process read input: stream "
          << stream_id_;
  return http_framer_->ProcessInput(data, len);
}

size_t HttpSM::ProcessWriteInput(const char* data, size_t len) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Process write input: size "
          << len << ": stream " << stream_id_;
  char * dataPtr = new char[len];
  memcpy(dataPtr, data, len);
  DataFrame* data_frame = new DataFrame;
  data_frame->data = (const char *)dataPtr;
  data_frame->size = len;
  data_frame->delete_when_done = true;
  connection_->EnqueueDataFrame(data_frame);
  return len;
}

bool HttpSM::MessageFullyRead() const {
  return http_framer_->MessageFullyRead();
}

void HttpSM::SetStreamID(uint32 stream_id) {
  stream_id_ = stream_id;
}

bool HttpSM::Error() const {
  return http_framer_->Error();
}

const char* HttpSM::ErrorAsString() const {
  return BalsaFrameEnums::ErrorCodeToString(http_framer_->ErrorCode());
}

void HttpSM::Reset() {
  VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Reset: stream "
          << stream_id_;
  http_framer_->Reset();
}

void HttpSM::ResetForNewConnection() {
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    VLOG(1) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Server connection closing "
      << "to: " << connection_->server_ip_ << ":"
      << connection_->server_port_ << " ";
  }
  // Message has not been fully read, either it is incomplete or the
  // server is closing the connection to signal message end.
  if (!MessageFullyRead()) {
    VLOG(2) << "HTTP response closed before end of file detected. "
            << "Sending EOF to spdy.";
    sm_spdy_interface_->SendEOF(stream_id_);
  }
  seq_num_ = 0;
  output_ordering_.Reset();
  http_framer_->Reset();
  if (sm_spdy_interface_) {
    sm_spdy_interface_->ResetForNewInterface(server_idx_);
  }
}

void HttpSM::Cleanup() {
  if (!(acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER)) {
    VLOG(2) << "HttpSM Request Fully Read; stream_id: " << stream_id_;
    connection_->Cleanup("request complete");
  }
}

int HttpSM::PostAcceptHook() {
  return 1;
}

void HttpSM::NewStream(uint32 stream_id, uint32 priority,
                       const std::string& filename) {
  MemCacheIter mci;
  mci.stream_id = stream_id;
  mci.priority = priority;
  if (!memory_cache_->AssignFileData(filename, &mci)) {
    // error creating new stream.
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending ErrorNotFound";
    SendErrorNotFound(stream_id);
  } else {
    AddToOutputOrder(mci);
  }
}

void HttpSM::SendEOF(uint32 stream_id) {
  SendEOFImpl(stream_id);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_PROXY) {
    sm_spdy_interface_->ResetForNewInterface(server_idx_);
  }
}

void HttpSM::SendErrorNotFound(uint32 stream_id) {
  SendErrorNotFoundImpl(stream_id);
}

size_t HttpSM::SendSynStream(uint32 stream_id, const BalsaHeaders& headers) {
  return 0;
}

size_t HttpSM::SendSynReply(uint32 stream_id, const BalsaHeaders& headers) {
  return SendSynReplyImpl(stream_id, headers);
}

void HttpSM::SendDataFrame(uint32 stream_id, const char* data, int64 len,
                   uint32 flags, bool compress) {
  SendDataFrameImpl(stream_id, data, len, flags, compress);
}

void HttpSM::SendEOFImpl(uint32 stream_id) {
  DataFrame* df = new DataFrame;
  df->data = "0\r\n\r\n";
  df->size = 5;
  df->delete_when_done = false;
  EnqueueDataFrame(df);
  if (acceptor_->flip_handler_type_ == FLIP_HANDLER_HTTP_SERVER) {
    Reset();
  }
}

void HttpSM::SendErrorNotFoundImpl(uint32 stream_id) {
  BalsaHeaders my_headers;
  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "404", "Not Found");
  my_headers.RemoveAllOfHeader("content-length");
  my_headers.AppendHeader("transfer-encoding", "chunked");
  SendSynReplyImpl(stream_id, my_headers);
  SendDataFrame(stream_id, "page not found", 14, 0, false);
  SendEOFImpl(stream_id);
  output_ordering_.RemoveStreamId(stream_id);
}

void HttpSM::SendOKResponseImpl(uint32 stream_id, std::string* output) {
  BalsaHeaders my_headers;
  my_headers.SetFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
  my_headers.RemoveAllOfHeader("content-length");
  my_headers.AppendHeader("transfer-encoding", "chunked");
  SendSynReplyImpl(stream_id, my_headers);
  SendDataFrame(stream_id, output->c_str(), output->size(), 0, false);
  SendEOFImpl(stream_id);
  output_ordering_.RemoveStreamId(stream_id);
}

size_t HttpSM::SendSynReplyImpl(uint32 stream_id, const BalsaHeaders& headers) {
  SimpleBuffer sb;
  headers.WriteHeaderAndEndingToBuffer(&sb);
  DataFrame* df = new DataFrame;
  df->size = sb.ReadableBytes();
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  sb.Read(buffer, df->size);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
          << stream_id_;
  size_t df_size = df->size;
  EnqueueDataFrame(df);
  return df_size;
}

size_t HttpSM::SendSynStreamImpl(uint32 stream_id,
                                 const BalsaHeaders& headers) {
  SimpleBuffer sb;
  headers.WriteHeaderAndEndingToBuffer(&sb);
  DataFrame* df = new DataFrame;
  df->size = sb.ReadableBytes();
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  sb.Read(buffer, df->size);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "Sending HTTP Reply header "
          << stream_id_;
  size_t df_size = df->size;
  EnqueueDataFrame(df);
  return df_size;
}

void HttpSM::SendDataFrameImpl(uint32 stream_id, const char* data, int64 len,
                       uint32 flags, bool compress) {
  char chunk_buf[128];
  snprintf(chunk_buf, sizeof(chunk_buf), "%x\r\n", (unsigned int)len);
  std::string chunk_description(chunk_buf);
  DataFrame* df = new DataFrame;
  df->size = chunk_description.size() + len + 2;
  char* buffer = new char[df->size];
  df->data = buffer;
  df->delete_when_done = true;
  memcpy(buffer, chunk_description.data(), chunk_description.size());
  memcpy(buffer + chunk_description.size(), data, len);
  memcpy(buffer + chunk_description.size() + len, "\r\n", 2);
  EnqueueDataFrame(df);
}

void HttpSM::EnqueueDataFrame(DataFrame* df) {
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: Enqueue data frame: stream "
          << stream_id_;
  connection_->EnqueueDataFrame(df);
}

void HttpSM::GetOutput() {
  MemCacheIter* mci = output_ordering_.GetIter();
  if (mci == NULL) {
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput: nothing to "
            << "output!?: stream " << stream_id_;
    return;
  }
  if (!mci->transformed_header) {
    mci->bytes_sent = SendSynReply(mci->stream_id,
                                   *(mci->file_data->headers));
    mci->transformed_header = true;
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput transformed "
            << "header stream_id: [" << mci->stream_id << "]";
    return;
  }
  if (mci->body_bytes_consumed >= mci->file_data->body.size()) {
    SendEOF(mci->stream_id);
    output_ordering_.RemoveStreamId(mci->stream_id);
    VLOG(2) << ACCEPTOR_CLIENT_IDENT << "GetOutput remove_stream_id: ["
            << mci->stream_id << "]";
    return;
  }
  size_t num_to_write =
    mci->file_data->body.size() - mci->body_bytes_consumed;
  if (num_to_write > mci->max_segment_size)
    num_to_write = mci->max_segment_size;

  SendDataFrame(mci->stream_id,
                mci->file_data->body.data() + mci->body_bytes_consumed,
                num_to_write, 0, true);
  VLOG(2) << ACCEPTOR_CLIENT_IDENT << "HttpSM: GetOutput SendDataFrame["
          << mci->stream_id << "]: " << num_to_write;
  mci->body_bytes_consumed += num_to_write;
  mci->bytes_sent += num_to_write;
}

}  // namespace net

<|endoftext|>


<commit_before>// RUN: %clangxx -frtti -fsanitize=null,vptr -fno-sanitize-recover=null,vptr -g %s -O3 -o %t -mllvm -enable-tail-merge=false
// RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
// RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
// RUN: %run %t rS && %run %t rV && %run %t oV
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --check-prefix=CHECK-%os-MEMBER --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --check-prefix=CHECK-%os-MEMBER --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --check-prefix=CHECK-%os-OFFSET --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
// RUN: not %run %t nN 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMFUN --strict-whitespace

// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mS
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t fS
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t cS
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mV
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t fV
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t cV
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t oU

// RUN: echo "vptr_check:S" > %t.loc-supp
// RUN: %env_ubsan_opts=suppressions='"%t.loc-supp"' not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS

// REQUIRES: stable-runtime, cxxabi
// UNSUPPORTED: win32
#include <new>
#include <assert.h>
#include <stdio.h>

struct S {
  S() : a(0) {}
  ~S() {}
  int a;
  int f() { return 0; }
  virtual int v() { return 0; }
};

struct T : S {
  T() : b(0) {}
  int b;
  int g() { return 0; }
  virtual int v() { return 1; }
};

struct U : S, T { virtual int v() { return 2; } };

struct V : S {};

// Make p global so that lsan does not complain.
T *p = 0;

volatile void *sink1, *sink2;

int access_p(T *p, char type);

int main(int argc, char **argv) {
  assert(argc > 1);
  fprintf(stderr, "Test case: %s\n", argv[1]);
  T t;
  (void)t.a;
  (void)t.b;
  (void)t.f();
  (void)t.g();
  (void)t.v();
  (void)t.S::v();

  U u;
  (void)u.T::a;
  (void)u.b;
  (void)u.T::f();
  (void)u.g();
  (void)u.v();
  (void)u.T::v();
  (void)((T&)u).S::v();

  char Buffer[sizeof(U)] = {};
  char TStorage[sizeof(T)];
  // Allocate two dummy objects so that the real object
  // is not on the boundary of mapped memory. Otherwise ubsan
  // will not be able to describe the vptr in detail.
  sink1 = new T;
  sink2 = new U;
  switch (argv[1][1]) {
  case '0':
    p = reinterpret_cast<T*>(Buffer);
    break;
  case 'S':
    // Make sure p points to the memory chunk of sufficient size to prevent ASan
    // reports about out-of-bounds access.
    p = reinterpret_cast<T*>(new(TStorage) S);
    break;
  case 'T':
    p = new T;
    break;
  case 'U':
    p = new U;
    break;
  case 'V':
    p = reinterpret_cast<T*>(new U);
    break;
  case 'N':
    p = 0;
    break;
  }

  access_p(p, argv[1][0]);
  return 0;
}

int access_p(T *p, char type) {
  switch (type) {
  case 'r':
    // Binding a reference to storage of appropriate size and alignment is OK.
    {T &r = *p;}
    return 0;

  case 'x':
    for (int i = 0; i < 2; i++) {
      // Check that the first iteration ("S") succeeds, while the second ("V") fails.
      p = reinterpret_cast<T*>((i == 0) ? new S : new V);
      // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:10: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
      // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
      // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
      // CHECK-LOC-SUPPRESS-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
      // CHECK-LOC-SUPPRESS-NEXT: {{^              vptr for 'V'}}
      p->g();
    }
    return 0;

  case 'm':
    // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
    // CHECK-MEMBER-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
    // CHECK-Linux-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
    return p->b;

    // CHECK-INVALID-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-INVALID-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
    // CHECK-INVALID-MEMBER-NEXT: {{^  ?.. .. .. ..  ?00 00 00 00  ?00 00 00 00  ?}}
    // CHECK-INVALID-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-INVALID-MEMBER-NEXT: {{^              invalid vptr}}
    // CHECK-Linux-NULL-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE-7]]

  case 'f':
    // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:15: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
    // CHECK-MEMFUN-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
    // TODO: Add check for stacktrace here.
    return p->g();

  case 'o':
    // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:37: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
    // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
    // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
    // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} 'T' base class of [[DYN_TYPE]]
    // CHECK-Linux-OFFSET: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
    return reinterpret_cast<U*>(p)->v() - 2;

  case 'c':
    // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:11: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
    // CHECK-DOWNCAST-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-DOWNCAST-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-DOWNCAST-NEXT: {{^              vptr for}} [[DYN_TYPE]]
    // CHECK-Linux-DOWNCAST: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
    (void)static_cast<T*>(reinterpret_cast<S*>(p));
    return 0;

  case 'n':
    // CHECK-NULL-MEMFUN: vptr.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'T'
    return p->g();
  }
  return 0;
}
<commit_msg>[ubsan] Disable one test on Android.<commit_after>// RUN: %clangxx -frtti -fsanitize=null,vptr -fno-sanitize-recover=null,vptr -g %s -O3 -o %t -mllvm -enable-tail-merge=false
// RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
// RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
// RUN: %run %t rS && %run %t rV && %run %t oV
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --check-prefix=CHECK-%os-MEMBER --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --check-prefix=CHECK-%os-MEMBER --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --check-prefix=CHECK-%os-DOWNCAST --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --check-prefix=CHECK-%os-OFFSET --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-MEMBER --check-prefix=CHECK-%os-NULL-MEMBER --strict-whitespace
// RUN: not %run %t nN 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMFUN --strict-whitespace

// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mS
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t fS
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t cS
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t mV
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t fV
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t cV
// RUN: %env_ubsan_opts=suppressions='"%t.supp"' %run %t oU

// RUN: echo "vptr_check:S" > %t.loc-supp
// RUN: %env_ubsan_opts=suppressions='"%t.loc-supp"' not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS

// REQUIRES: stable-runtime, cxxabi
// UNSUPPORTED: win32
// Suppressions file not pushed to the device.
// UNSUPPORTED: android
#include <new>
#include <assert.h>
#include <stdio.h>

struct S {
  S() : a(0) {}
  ~S() {}
  int a;
  int f() { return 0; }
  virtual int v() { return 0; }
};

struct T : S {
  T() : b(0) {}
  int b;
  int g() { return 0; }
  virtual int v() { return 1; }
};

struct U : S, T { virtual int v() { return 2; } };

struct V : S {};

// Make p global so that lsan does not complain.
T *p = 0;

volatile void *sink1, *sink2;

int access_p(T *p, char type);

int main(int argc, char **argv) {
  assert(argc > 1);
  fprintf(stderr, "Test case: %s\n", argv[1]);
  T t;
  (void)t.a;
  (void)t.b;
  (void)t.f();
  (void)t.g();
  (void)t.v();
  (void)t.S::v();

  U u;
  (void)u.T::a;
  (void)u.b;
  (void)u.T::f();
  (void)u.g();
  (void)u.v();
  (void)u.T::v();
  (void)((T&)u).S::v();

  char Buffer[sizeof(U)] = {};
  char TStorage[sizeof(T)];
  // Allocate two dummy objects so that the real object
  // is not on the boundary of mapped memory. Otherwise ubsan
  // will not be able to describe the vptr in detail.
  sink1 = new T;
  sink2 = new U;
  switch (argv[1][1]) {
  case '0':
    p = reinterpret_cast<T*>(Buffer);
    break;
  case 'S':
    // Make sure p points to the memory chunk of sufficient size to prevent ASan
    // reports about out-of-bounds access.
    p = reinterpret_cast<T*>(new(TStorage) S);
    break;
  case 'T':
    p = new T;
    break;
  case 'U':
    p = new U;
    break;
  case 'V':
    p = reinterpret_cast<T*>(new U);
    break;
  case 'N':
    p = 0;
    break;
  }

  access_p(p, argv[1][0]);
  return 0;
}

int access_p(T *p, char type) {
  switch (type) {
  case 'r':
    // Binding a reference to storage of appropriate size and alignment is OK.
    {T &r = *p;}
    return 0;

  case 'x':
    for (int i = 0; i < 2; i++) {
      // Check that the first iteration ("S") succeeds, while the second ("V") fails.
      p = reinterpret_cast<T*>((i == 0) ? new S : new V);
      // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:10: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
      // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
      // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
      // CHECK-LOC-SUPPRESS-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
      // CHECK-LOC-SUPPRESS-NEXT: {{^              vptr for 'V'}}
      p->g();
    }
    return 0;

  case 'm':
    // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
    // CHECK-MEMBER-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-MEMBER-NEXT: {{^              vptr for}} [[DYN_TYPE]]
    // CHECK-Linux-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
    return p->b;

    // CHECK-INVALID-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-INVALID-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
    // CHECK-INVALID-MEMBER-NEXT: {{^  ?.. .. .. ..  ?00 00 00 00  ?00 00 00 00  ?}}
    // CHECK-INVALID-MEMBER-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-INVALID-MEMBER-NEXT: {{^              invalid vptr}}
    // CHECK-Linux-NULL-MEMBER: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE-7]]

  case 'f':
    // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:15: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
    // CHECK-MEMFUN-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-MEMFUN-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-MEMFUN-NEXT: {{^              vptr for}} [[DYN_TYPE]]
    // TODO: Add check for stacktrace here.
    return p->g();

  case 'o':
    // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:37: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
    // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
    // CHECK-OFFSET-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-OFFSET-NEXT: {{^              \^                        (                         ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
    // CHECK-OFFSET-NEXT: {{^                                       (                         )?vptr for}} 'T' base class of [[DYN_TYPE]]
    // CHECK-Linux-OFFSET: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
    return reinterpret_cast<U*>(p)->v() - 2;

  case 'c':
    // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:11: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
    // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
    // CHECK-DOWNCAST-NEXT: {{^ .. .. .. ..  .. .. .. .. .. .. .. ..  }}
    // CHECK-DOWNCAST-NEXT: {{^              \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
    // CHECK-DOWNCAST-NEXT: {{^              vptr for}} [[DYN_TYPE]]
    // CHECK-Linux-DOWNCAST: #0 {{.*}}access_p{{.*}}vptr.cpp:[[@LINE+1]]
    (void)static_cast<T*>(reinterpret_cast<S*>(p));
    return 0;

  case 'n':
    // CHECK-NULL-MEMFUN: vptr.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'T'
    return p->g();
  }
  return 0;
}
<|endoftext|>


<commit_before>
#include	"package.h"

package* package_handler::create_package(int32_t cmd, const void* data, size_t size, uint32_t flag) {
    package*	pkg	= new package;

    pkg->cmd	= cmd;
    pkg->flag	= flag;

    if(NULL != data && size > 0) {
        pkg->data	= new char[(size/16 + 1) * 16];
        pkg->size	= size;

        memcpy(pkg->data, data, size);
    } else {
        pkg->data	= NULL;
        pkg->size	= 0;
    }

    return	pkg;
}

void package_handler::destroy_package(package* pkg) {
    if(NULL != pkg) {
        delete	pkg->data;
        delete	pkg;
    }
}

<commit_msg>fix package.cpp compile errors.<commit_after>
#include	<string.h>
#include	"package.h"

package* package_handler::create_package(int32_t cmd, const void* data, size_t size, uint32_t flag) {
    package*	pkg	= new package;

    pkg->cmd	= cmd;
    pkg->flag	= flag;

    if(0 != data && size > 0) {
        pkg->data	= new char[(size/16 + 1) * 16];
        pkg->size	= size;

        memcpy(pkg->data, data, size);
    } else {
        pkg->data	= 0;
        pkg->size	= 0;
    }

    return	pkg;
}

void package_handler::destroy_package(package* pkg) {
    if(0 != pkg) {
        delete	pkg->data;
        delete	pkg;
    }
}

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////////////////////
///
/// @file
/// @author     Kuba Sejdak
/// @date       21.07.2016
///
/// @copyright  This file is a part of cosmos OS. All rights reserved.
///
////////////////////////////////////////////////////////////////////////////////////////////////

#include "buddy_allocator.h"
#include "pagepool_dynamic.h"
#include "pagepool_static.h"

#include <hal/mmu.h>
#include <os/assert.h>

using namespace HAL;

namespace Memory {

static const uint32_t MEMORY_CHUNK_MAGIC = 0x08081990;

MemoryChunk::MemoryChunk()
    : m_magic(0)
    , m_virtualAddress(0)
    , m_size(0)
    , m_parentPage(nullptr)
{
}

bool MemoryChunk::checkMagic()
{
    return (m_magic == MEMORY_CHUNK_MAGIC);
}

uint32_t MemoryChunk::virtualAddress()
{
    return m_virtualAddress;
}

void* MemoryChunk::data()
{
    return reinterpret_cast<void*>(m_virtualAddress + sizeof(MemoryChunk));
}

uint16_t MemoryChunk::size()
{
    return m_size;
}

Page* MemoryChunk::parentPage()
{
    return m_parentPage;
}

void MemoryChunk::init(Page* parentPage)
{
    m_magic = MEMORY_CHUNK_MAGIC;
    m_parentPage = parentPage;
}

void MemoryChunk::setVirtualAddress(uint32_t virtualAddress)
{
    m_virtualAddress = virtualAddress;
}

void MemoryChunk::setSize(uint32_t size)
{
    m_size = size;
}

os::pair<MemoryChunk, MemoryChunk> MemoryChunk::split()
{
    uint32_t newSize = m_size / 2;

    MemoryChunk* first = reinterpret_cast<MemoryChunk*>(m_virtualAddress);
    first->init(m_parentPage);
    first->setVirtualAddress(m_virtualAddress);
    first->setSize(newSize);

    MemoryChunk* second = reinterpret_cast<MemoryChunk*>(m_virtualAddress + newSize);
    second->init(m_parentPage);
    first->setVirtualAddress(m_virtualAddress + newSize);
    second->setSize(newSize);

    return os::pair<MemoryChunk, MemoryChunk>(first, second);
}

void IAllocator::init()
{
    static PagePool pagePool;
    pagePool.init();
    static BuddyAllocator buddyAllocator(&pagePool);
    kernelAllocator = &buddyAllocator;
}

BuddyAllocator::BuddyAllocator(PagePool* pagePool)
    : IAllocator(pagePool)
{
}

void* BuddyAllocator::allocate(uint32_t size)
{
    if (size == 0)
        return nullptr;

    uint32_t requiredSize = size + sizeof(MemoryChunk);
    int factor = sizeToFactor(requiredSize);

    while (true) {
        // Find proper chunk from the free chunks list.
        bool chunkAvailable = false;

        for (int i = factor; i < MEMORY_CHUNK_FACTOR; ++i) {
            if (m_freeChunks[i].size() == 0) {
                // There is no chunk with given factor.
                continue;
            }

            if (factorToSize(i) / 2 >= requiredSize) {
                // Smallest suitable chunk can be splitted to avoid fragmentation.
                splitChunk(m_freeChunks[i].front());
                chunkAvailable = true;
                break;
            }

            // Proper chunk found.
            return m_freeChunks[i].pop_front()->data();
        }

        if (chunkAvailable)
            continue;

        // No suitable chunk was found. Allocate new page.
        if (!allocatePage())
            return nullptr;
    }

    return nullptr;
}

void BuddyAllocator::release(void *memoryChunk)
{
    if (memoryChunk == nullptr)
        return;

    MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>((char*) memoryChunk - sizeof(MemoryChunk));
    assert(chunk->checkMagic());
}

bool BuddyAllocator::allocatePage()
{
    auto page = m_pagePool->allocatePages(1);
    if (page.size() == 0)
        return false;

    /// @todo Map this page into kernel address space.
    // void* pageVirtualAddress = IMMU::map(page.front());
    void* pageVirtualAddress = reinterpret_cast<void*>(page.front()->physicalAddress());

    MemoryChunk* newChunk = reinterpret_cast<MemoryChunk*>(pageVirtualAddress);
    newChunk->init(page.front());
    newChunk->setVirtualAddress((uint32_t) pageVirtualAddress);
    newChunk->setSize(IMMU::pageSize());

    // Insert this chunk to the list of free chunks.
    m_freeChunks[sizeToFactor(newChunk->size())].push_back(newChunk);

    return true;
}

int BuddyAllocator::sizeToFactor(uint32_t size)
{
    for (int i = 0; i < MEMORY_CHUNK_FACTOR; ++i) {
        if (factorToSize(i) >= size)
            return i;
    }

    return -1;
}

uint32_t BuddyAllocator::factorToSize(int factor)
{
    return (1 << factor);
}

void BuddyAllocator::splitChunk(MemoryChunk* chunk)
{
    int factor = sizeToFactor(chunk->size());
    int index = m_freeChunks[factor].indexOf(chunk);
    assert(index != -1);

    auto chunkHalfs = chunk->split();
    m_freeChunks[factor].remove(index);
    m_freeChunks[factor - 1].push_back(chunkHalfs.first());
    m_freeChunks[factor - 1].push_back(chunkHalfs.second());
}

} // namespace Memory
<commit_msg>Move initializing page pool to allocator.<commit_after>////////////////////////////////////////////////////////////////////////////////////////////////
///
/// @file
/// @author     Kuba Sejdak
/// @date       21.07.2016
///
/// @copyright  This file is a part of cosmos OS. All rights reserved.
///
////////////////////////////////////////////////////////////////////////////////////////////////

#include "buddy_allocator.h"

#include <hal/mmu.h>
#include <os/assert.h>

using namespace HAL;

namespace Memory {

static const uint32_t MEMORY_CHUNK_MAGIC = 0x08081990;

MemoryChunk::MemoryChunk()
    : m_magic(0)
    , m_virtualAddress(0)
    , m_size(0)
    , m_parentPage(nullptr)
{
}

bool MemoryChunk::checkMagic()
{
    return (m_magic == MEMORY_CHUNK_MAGIC);
}

uint32_t MemoryChunk::virtualAddress()
{
    return m_virtualAddress;
}

void* MemoryChunk::data()
{
    return reinterpret_cast<void*>(m_virtualAddress + sizeof(MemoryChunk));
}

uint16_t MemoryChunk::size()
{
    return m_size;
}

Page* MemoryChunk::parentPage()
{
    return m_parentPage;
}

void MemoryChunk::init(Page* parentPage)
{
    m_magic = MEMORY_CHUNK_MAGIC;
    m_parentPage = parentPage;
}

void MemoryChunk::setVirtualAddress(uint32_t virtualAddress)
{
    m_virtualAddress = virtualAddress;
}

void MemoryChunk::setSize(uint32_t size)
{
    m_size = size;
}

os::pair<MemoryChunk, MemoryChunk> MemoryChunk::split()
{
    uint32_t newSize = m_size / 2;

    MemoryChunk* first = reinterpret_cast<MemoryChunk*>(m_virtualAddress);
    first->init(m_parentPage);
    first->setVirtualAddress(m_virtualAddress);
    first->setSize(newSize);

    MemoryChunk* second = reinterpret_cast<MemoryChunk*>(m_virtualAddress + newSize);
    second->init(m_parentPage);
    first->setVirtualAddress(m_virtualAddress + newSize);
    second->setSize(newSize);

    return os::pair<MemoryChunk, MemoryChunk>(first, second);
}

void IAllocator::init()
{
    static PagePool pagePool;
    static BuddyAllocator buddyAllocator(&pagePool);
    kernelAllocator = &buddyAllocator;
}

BuddyAllocator::BuddyAllocator(PagePool* pagePool)
    : IAllocator(pagePool)
{
    m_pagePool->init();
}

void* BuddyAllocator::allocate(uint32_t size)
{
    if (size == 0)
        return nullptr;

    uint32_t requiredSize = size + sizeof(MemoryChunk);
    int factor = sizeToFactor(requiredSize);

    while (true) {
        // Find proper chunk from the free chunks list.
        bool chunkAvailable = false;

        for (int i = factor; i < MEMORY_CHUNK_FACTOR; ++i) {
            if (m_freeChunks[i].size() == 0) {
                // There is no chunk with given factor.
                continue;
            }

            if (factorToSize(i) / 2 >= requiredSize) {
                // Smallest suitable chunk can be splitted to avoid fragmentation.
                splitChunk(m_freeChunks[i].front());
                chunkAvailable = true;
                break;
            }

            // Proper chunk found.
            return m_freeChunks[i].pop_front()->data();
        }

        if (chunkAvailable)
            continue;

        // No suitable chunk was found. Allocate new page.
        if (!allocatePage())
            return nullptr;
    }

    return nullptr;
}

void BuddyAllocator::release(void *memoryChunk)
{
    if (memoryChunk == nullptr)
        return;

    MemoryChunk* chunk = reinterpret_cast<MemoryChunk*>((char*) memoryChunk - sizeof(MemoryChunk));
    assert(chunk->checkMagic());
}

bool BuddyAllocator::allocatePage()
{
    auto page = m_pagePool->allocatePages(1);
    if (page.size() == 0)
        return false;

    /// @todo Map this page into kernel address space.
    // void* pageVirtualAddress = IMMU::map(page.front());
    void* pageVirtualAddress = reinterpret_cast<void*>(page.front()->physicalAddress());

    MemoryChunk* newChunk = reinterpret_cast<MemoryChunk*>(pageVirtualAddress);
    newChunk->init(page.front());
    newChunk->setVirtualAddress((uint32_t) pageVirtualAddress);
    newChunk->setSize(IMMU::pageSize());

    // Insert this chunk to the list of free chunks.
    m_freeChunks[sizeToFactor(newChunk->size())].push_back(newChunk);

    return true;
}

int BuddyAllocator::sizeToFactor(uint32_t size)
{
    for (int i = 0; i < MEMORY_CHUNK_FACTOR; ++i) {
        if (factorToSize(i) >= size)
            return i;
    }

    return -1;
}

uint32_t BuddyAllocator::factorToSize(int factor)
{
    return (1 << factor);
}

void BuddyAllocator::splitChunk(MemoryChunk* chunk)
{
    int factor = sizeToFactor(chunk->size());
    int index = m_freeChunks[factor].indexOf(chunk);
    assert(index != -1);

    auto chunkHalfs = chunk->split();
    m_freeChunks[factor].remove(index);
    m_freeChunks[factor - 1].push_back(chunkHalfs.first());
    m_freeChunks[factor - 1].push_back(chunkHalfs.second());
}

} // namespace Memory
<|endoftext|>


<commit_before>/*
 * SchemeSmobAV.c
 *
 * Scheme small objects (SMOBS) for attention values.
 *
 * Copyright (c) 2008,2009 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include <libguile.h>

#include <opencog/atomspace/AttentionValue.h>
#include <opencog/guile/SchemeSmob.h>

using namespace opencog;

/* ============================================================== */
/**
 * Search for an attention value in a list of values.
 * Return the attention value if found, else return null.
 * Throw errors if the list is not stictly just key-value pairs
 */
AttentionValue * SchemeSmob::get_av_from_list(SCM slist)
{
	while (scm_is_pair(slist))
	{
		SCM sval = SCM_CAR(slist);
		if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, sval))
		{
			scm_t_bits misctype = SCM_SMOB_FLAGS(sval);
			switch (misctype)
			{
				case COG_AV:
					return (AttentionValue *) SCM_SMOB_DATA(sval);
				default:
					break;
			}
		}

		slist = SCM_CDR(slist);
	}

	return NULL;
}

/* ============================================================== */

std::string SchemeSmob::av_to_string(const AttentionValue *av)
{
#define BUFLEN 120
	char buff[BUFLEN];

	snprintf(buff, BUFLEN, "(av %d %d %d)",
		av->getSTI(), av->getLTI(), av->getVLTI());
	std::string ret = buff;
	return ret;
}

/* ============================================================== */
/**
 * Take over memory management of an attention value
 */
SCM SchemeSmob::take_av (AttentionValue *av)
{
	scm_gc_register_collectable_memory (av,
	                 sizeof(*av), "opencog av");

	SCM smob;
	SCM_NEWSMOB (smob, cog_misc_tag, av);
	SCM_SET_SMOB_FLAGS(smob, COG_AV);
	return smob;
}

/* ============================================================== */
/**
 * Create a new attention value, with indicated sti/lti/vlti
 */
SCM SchemeSmob::ss_new_av (SCM ssti, SCM slti, SCM svlti)
{
	sti_t sti = scm_to_short(ssti);
	lti_t lti = scm_to_short(slti);
	vlti_t vlti = scm_to_short(svlti);

	AttentionValue *av = new AttentionValue(sti, lti, vlti);
	return take_av(av);
}

/* ============================================================== */
/**
 * Return true if the scm is an attention value
 */
SCM SchemeSmob::ss_av_p (SCM s)
{
	if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, s))
	{
		scm_t_bits misctype = SCM_SMOB_FLAGS(s);
		switch (misctype)
		{
			case COG_AV:
				return SCM_BOOL_T;

			default:
				return SCM_BOOL_F;
		}
	}
	return SCM_BOOL_F;
}

/* ============================================================== */

AttentionValue * SchemeSmob::verify_av(SCM sav, const char *subrname)
{
	if (!SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, sav))
		scm_wrong_type_arg_msg(subrname, 2, sav, "opencog attention value");

	scm_t_bits misctype = SCM_SMOB_FLAGS(sav);
	if (COG_AV != misctype)
		scm_wrong_type_arg_msg(subrname, 2, sav, "opencog attention value");

	AttentionValue *av = (AttentionValue *) SCM_SMOB_DATA(sav);
	return av;
}

/**
 * Return association list holding contents of a truth value
 */
SCM SchemeSmob::ss_tv_get_value (SCM s)
{
	AttentionValue *tv = verify_tv(s, "cog-tv->alist");
	AttentionValueType tvt = tv->getType();
	switch(tvt)
	{
		case SIMPLE_TRUTH_VALUE:
		{
			SimpleAttentionValue *stv = static_cast<SimpleAttentionValue *>(tv);
			SCM mean = scm_from_double(stv->getMean());
			SCM conf = scm_from_double(stv->getConfidence());
			SCM smean = scm_from_locale_symbol("mean");
			SCM sconf = scm_from_locale_symbol("confidence");

			SCM rc = SCM_EOL;
			rc = scm_acons(sconf, conf, rc);
			rc = scm_acons(smean, mean, rc);
			return rc;
		}
		case COUNT_TRUTH_VALUE:
		{
			CountAttentionValue *ctv = static_cast<CountAttentionValue *>(tv);
			SCM mean = scm_from_double(ctv->getMean());
			SCM conf = scm_from_double(ctv->getConfidence());
			SCM cont = scm_from_double(ctv->getCount());
			SCM smean = scm_from_locale_symbol("mean");
			SCM sconf = scm_from_locale_symbol("confidence");
			SCM scont = scm_from_locale_symbol("count");

			SCM rc = SCM_EOL;
			rc = scm_acons(scont, cont, rc),
			rc = scm_acons(sconf, conf, rc);
			rc = scm_acons(smean, mean, rc);
			return rc;
		}
		case INDEFINITE_TRUTH_VALUE:
		{
			IndefiniteAttentionValue *itv = static_cast<IndefiniteAttentionValue *>(tv);
			SCM lower = scm_from_double(itv->getL());
			SCM upper = scm_from_double(itv->getU());
			SCM conf = scm_from_double(itv->getConfidence());
			SCM slower = scm_from_locale_symbol("lower");
			SCM supper = scm_from_locale_symbol("upper");
			SCM sconf = scm_from_locale_symbol("confidence");

			SCM rc = SCM_EOL;
			rc = scm_acons(sconf, conf, rc);
			rc = scm_acons(supper, upper, rc),
			rc = scm_acons(slower, lower, rc);
			return rc;
		}
		case COMPOSITE_TRUTH_VALUE:
		{
			CompositeAttentionValue *mtv = static_cast<CompositeAttentionValue *>(tv);
			const AttentionValue &ptv = mtv->getVersionedAV(NULL_VERSION_HANDLE);
			AttentionValue *nptv = ptv.clone();
			SCM sptv = take_tv(nptv);

			SCM sprimary = scm_from_locale_symbol("primary");
			SCM sversion = scm_from_locale_symbol("versions");

			// Loop over all the version handles.
			SCM vers = SCM_EOL;
			int nvh = mtv->getNumberOfVersionedAVs();
			for (int i=0; i<nvh; i++)
			{
				VersionHandle vh = mtv->getVersionHandle(i);
				VersionHandle *nvh = new VersionHandle(vh);
				SCM svh = take_vh(nvh);

				const AttentionValue& vtv = mtv->getVersionedAV(vh);
				AttentionValue *nvtv = vtv.clone();
				SCM svtv = take_tv(nvtv);

				vers = scm_acons(svh, svtv, vers);
			}

			SCM rc = SCM_EOL;
			rc = scm_acons(sversion, vers, rc);
			rc = scm_acons(sprimary, sptv, rc);
			return rc;
		}
		default:
			return SCM_EOL;
	}
	return SCM_EOL;
}

#endif /* HAVE_GUILE */
/* ===================== END OF FILE ============================ */
<commit_msg>finish with rought-in of attention value support<commit_after>/*
 * SchemeSmobAV.c
 *
 * Scheme small objects (SMOBS) for attention values.
 *
 * Copyright (c) 2008,2009 Linas Vepstas <linas@linas.org>
 */

#ifdef HAVE_GUILE

#include <libguile.h>

#include <opencog/atomspace/AttentionValue.h>
#include <opencog/guile/SchemeSmob.h>

using namespace opencog;

/* ============================================================== */
/**
 * Search for an attention value in a list of values.
 * Return the attention value if found, else return null.
 * Throw errors if the list is not stictly just key-value pairs
 */
AttentionValue * SchemeSmob::get_av_from_list(SCM slist)
{
	while (scm_is_pair(slist))
	{
		SCM sval = SCM_CAR(slist);
		if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, sval))
		{
			scm_t_bits misctype = SCM_SMOB_FLAGS(sval);
			switch (misctype)
			{
				case COG_AV:
					return (AttentionValue *) SCM_SMOB_DATA(sval);
				default:
					break;
			}
		}

		slist = SCM_CDR(slist);
	}

	return NULL;
}

/* ============================================================== */

std::string SchemeSmob::av_to_string(const AttentionValue *av)
{
#define BUFLEN 120
	char buff[BUFLEN];

	snprintf(buff, BUFLEN, "(av %d %d %d)",
		av->getSTI(), av->getLTI(), av->getVLTI());
	std::string ret = buff;
	return ret;
}

/* ============================================================== */
/**
 * Take over memory management of an attention value
 */
SCM SchemeSmob::take_av (AttentionValue *av)
{
	scm_gc_register_collectable_memory (av,
	                 sizeof(*av), "opencog av");

	SCM smob;
	SCM_NEWSMOB (smob, cog_misc_tag, av);
	SCM_SET_SMOB_FLAGS(smob, COG_AV);
	return smob;
}

/* ============================================================== */
/**
 * Create a new attention value, with indicated sti/lti/vlti
 */
SCM SchemeSmob::ss_new_av (SCM ssti, SCM slti, SCM svlti)
{
	sti_t sti = scm_to_short(ssti);
	lti_t lti = scm_to_short(slti);
	vlti_t vlti = scm_to_short(svlti);

	AttentionValue *av = new AttentionValue(sti, lti, vlti);
	return take_av(av);
}

/* ============================================================== */
/**
 * Return true if the scm is an attention value
 */
SCM SchemeSmob::ss_av_p (SCM s)
{
	if (SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, s))
	{
		scm_t_bits misctype = SCM_SMOB_FLAGS(s);
		switch (misctype)
		{
			case COG_AV:
				return SCM_BOOL_T;

			default:
				return SCM_BOOL_F;
		}
	}
	return SCM_BOOL_F;
}

/* ============================================================== */

AttentionValue * SchemeSmob::verify_av(SCM sav, const char *subrname)
{
	if (!SCM_SMOB_PREDICATE(SchemeSmob::cog_misc_tag, sav))
		scm_wrong_type_arg_msg(subrname, 2, sav, "opencog attention value");

	scm_t_bits misctype = SCM_SMOB_FLAGS(sav);
	if (COG_AV != misctype)
		scm_wrong_type_arg_msg(subrname, 2, sav, "opencog attention value");

	AttentionValue *av = (AttentionValue *) SCM_SMOB_DATA(sav);
	return av;
}

/**
 * Return association list holding contents of an attention value
 */
SCM SchemeSmob::ss_av_get_value (SCM s)
{
	AttentionValue *av = verify_av(s, "cog-av->alist");

	SCM sti = scm_from_short(av->getSTI());
	SCM lti = scm_from_short(av->getLTI());
	SCM vlti = scm_from_short(av->getVLTI());

	SCM ssti = scm_from_locale_symbol("sti");
	SCM slti = scm_from_locale_symbol("lti");
	SCM svlti = scm_from_locale_symbol("vlti");

	SCM rc = SCM_EOL;
	rc = scm_acons(ssti, sti, rc);
	rc = scm_acons(slti, lti, rc);
	rc = scm_acons(svlti, vlti, rc);
	return rc;
}

#endif /* HAVE_GUILE */
/* ===================== END OF FILE ============================ */
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>* root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	BinaryTree(const std::initializer_list<T>&);
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	Node<T>*root_();
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	void output(std::ostream& ost, const Node<T>* temp);
	friend ostream& operator<< <>(std::ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::output(std::ostream& ost, const Node<T>* temp)
{
	if (temp == nullptr)
	{
		throw "error";
		return;
	}
	else
	{
		ost << temp->data << "	";
		output(ost, temp->left);
		output(ost, temp->right);
	}
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& show(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	show(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	show(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& bst)
{
	if (!bst.root)
		throw "error";
	show(ost, bst.root, 0);
	return ost;
}
<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>* root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	BinaryTree(const std::initializer_list<T>&);
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	Node<T>*root_();
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	void output(ostream& ost, const Node<T>* temp);
	friend ostream& operator<< <>(ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::output(std::ostream& ost, const Node<T>* temp)
{
	if (temp == nullptr)
	{
		throw "error";
		return;
	}
	else
	{
		ost << temp->data << "	";
		output(ost, temp->left);
		output(ost, temp->right);
	}
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& show(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	show(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	show(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& bst)
{
	if (!bst.root)
		throw "error";
	show(ost, bst.root, 0);
	return ost;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>* root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	Node<T>*root_();
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	void output(ostream& ost, const Node<T>* temp);
	friend std::ostream& operator<< <>(ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::output(std::ostream& ost, const Node<T>* temp)
{
	if (temp == nullptr)
	{
		throw "error";
		return;
	}
	else
	{
		ost << temp->data << "	";
		output(ost, temp->left);
		output(ost, temp->right);
	}
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& show(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	show(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	show(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& bst)
{
	if (!bst.root)
		throw "error";
	show(ost, bst.root, 0);
	return ost;
}
<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>* root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	BinaryTree(const std::initializer_list<T>&);
	void _deleteElements(Node<T>*);
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	Node<T>*root_();
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	void output(std::ostream& ost, const Node<T>* temp);
	friend std::ostream& operator<< <> (std::ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template <typename T>
void BinaryTree<T>::_deleteElements(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	_deleteElements(temp->left);
	_deleteElements(temp->right);
	delete node;
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	if (!temp)
	{
		throw "error";
	}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::output(std::ostream& ost, const Node<T>* temp)
{
	if (temp == nullptr)
	{
		throw "error";
		return;
	}
	else
	{
		ost << temp->data << "	";
		output(ost, temp->left);
		output(ost, temp->right);
	}
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& show(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	show(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	show(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& temp)
{
	if (!temp.root)
		throw "error";
	show(ost, temp.root, 0);
	return ost;
}
<|endoftext|>


<commit_before>#include "server.h"

namespace REST {

Router* Server::router() {
  return Router::instance();
}

Server::Server(std::string path, Dispatcher* d) : dispatcher(d) {
  srand(time(0));
  Router::instance();

  unlink(path.c_str());
  struct sockaddr_un local;
  handle = socket(AF_UNIX, SOCK_STREAM, 0);
  local.sun_family = AF_UNIX;
  strcpy(local.sun_path, path.c_str());

  int yes = 1;
  if (bind(handle, (struct sockaddr *)&local, strlen(local.sun_path) + sizeof(local.sun_family) + 1) == -1)
    throw PortInUseError();

}

Server::Server(std::string address, int port, Dispatcher* d) : dispatcher(d) {
  srand(time(0));
  Router::instance();
  int status;

  memset(&host_info, 0, sizeof(host_info));

  host_info.ai_family = AF_UNSPEC;
  host_info.ai_socktype = SOCK_STREAM;

  status = getaddrinfo(address.c_str(), std::to_string(port).c_str(), &host_info, &host_info_list);
  if (status != 0)
    throw AddressResolvingError();

  handle = socket(host_info_list->ai_family, host_info_list->ai_socktype, host_info_list->ai_protocol);
  if (handle == -1)
    throw SocketCreationError();

  int yes = 1;
  status = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  status = bind(handle, host_info_list->ai_addr, host_info_list->ai_addrlen);
  if (status == -1)
    throw PortInUseError();
}

Server::~Server() {
  is_running = false;

  delete dispatcher;

  freeaddrinfo(host_info_list);
  close(handle);

#ifdef SERVER_PATH
  unlink(STR(SERVER_PATH));
#endif
}

void Server::run() {
  int status;

  router()->print();

  status = listen(handle, SOMAXCONN);
  if (status == -1)
    throw ServerError();

  while (is_running) {
    struct sockaddr_storage client_addr;
    socklen_t addr_size = sizeof(client_addr);
    int client = accept(handle, (struct sockaddr *)&client_addr, &addr_size);

    try {
      if (client == -1)
        throw ServerError();

      dispatcher->next(client, client_addr);
    } catch (Exception &e) {
      if (is_running)
        std::cerr << "!!! " << e.what() << std::endl;
      close(client);
    }
  }
}

}
<commit_msg>removed unused var<commit_after>#include "server.h"

namespace REST {

Router* Server::router() {
  return Router::instance();
}

Server::Server(std::string path, Dispatcher* d) : dispatcher(d) {
  srand(time(0));
  Router::instance();

  unlink(path.c_str());
  struct sockaddr_un local;
  handle = socket(AF_UNIX, SOCK_STREAM, 0);
  local.sun_family = AF_UNIX;
  strcpy(local.sun_path, path.c_str());

  if (bind(handle, (struct sockaddr *)&local, strlen(local.sun_path) + sizeof(local.sun_family) + 1) == -1)
    throw PortInUseError();

}

Server::Server(std::string address, int port, Dispatcher* d) : dispatcher(d) {
  srand(time(0));
  Router::instance();
  int status;

  memset(&host_info, 0, sizeof(host_info));

  host_info.ai_family = AF_UNSPEC;
  host_info.ai_socktype = SOCK_STREAM;

  status = getaddrinfo(address.c_str(), std::to_string(port).c_str(), &host_info, &host_info_list);
  if (status != 0)
    throw AddressResolvingError();

  handle = socket(host_info_list->ai_family, host_info_list->ai_socktype, host_info_list->ai_protocol);
  if (handle == -1)
    throw SocketCreationError();

  int yes = 1;
  status = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  status = bind(handle, host_info_list->ai_addr, host_info_list->ai_addrlen);
  if (status == -1)
    throw PortInUseError();
}

Server::~Server() {
  is_running = false;

  delete dispatcher;

  freeaddrinfo(host_info_list);
  close(handle);

#ifdef SERVER_PATH
  unlink(STR(SERVER_PATH));
#endif
}

void Server::run() {
  int status;

  router()->print();

  status = listen(handle, SOMAXCONN);
  if (status == -1)
    throw ServerError();

  while (is_running) {
    struct sockaddr_storage client_addr;
    socklen_t addr_size = sizeof(client_addr);
    int client = accept(handle, (struct sockaddr *)&client_addr, &addr_size);

    try {
      if (client == -1)
        throw ServerError();

      dispatcher->next(client, client_addr);
    } catch (Exception &e) {
      if (is_running)
        std::cerr << "!!! " << e.what() << std::endl;
      close(client);
    }
  }
}

}
<|endoftext|>


<commit_before>/*Copyright 2017 Bang & Olufsen A/S

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/

#include "SigmaTcpServer.h"
#include "SpiCommunication.h"
#include "EepromHandler.h"
#include <iostream>
#include <exception>

int main(int argc, char* argv[])
{
 	SigmaTcpServer tcpServer;
	SpiCommunication spiCommIf;

	tcpServer.SetDebugPrint(strcmp(argv[1], "-d") == 0);

	try
	{
		spiCommIf.Initialize("/dev/spidev0.0");
	}
	catch (std::exception& e)
	{
		std::cout << "Error initializing SPI device: " << e.what() << '\n';
	}

	try
	{
		tcpServer.Initialize(8086, &spiCommIf);
	}
	catch (std::exception& e)
	{
		std::cout << "Error initializing TCP server: " << e.what() << '\n';
	}

	try
	{
		tcpServer.Start();
	}
	catch (std::exception& e)
	{
		std::cout << "Error starting TCP server: " << e.what() << '\n';
	}

	return 0;
}<commit_msg>Prevent crashing when no argument given<commit_after>/*Copyright 2017 Bang & Olufsen A/S

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.*/

#include "SigmaTcpServer.h"
#include "SpiCommunication.h"
#include "EepromHandler.h"
#include <iostream>
#include <exception>

int main(int argc, char* argv[])
{
 	SigmaTcpServer tcpServer;
	SpiCommunication spiCommIf;

	if (argc >= 2)
	{
		tcpServer.SetDebugPrint(strcmp(argv[1], "-d") == 0);
	}

	try
	{
		spiCommIf.Initialize("/dev/spidev0.0");
	}
	catch (std::exception& e)
	{
		std::cout << "Error initializing SPI device: " << e.what() << '\n';
	}

	try
	{
		tcpServer.Initialize(8086, &spiCommIf);
	}
	catch (std::exception& e)
	{
		std::cout << "Error initializing TCP server: " << e.what() << '\n';
	}

	try
	{
		tcpServer.Start();
	}
	catch (std::exception& e)
	{
		std::cout << "Error starting TCP server: " << e.what() << '\n';
	}

	return 0;
}<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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/cpp2/transport/core/ThriftProcessor.h>

#include <string>

#include <glog/logging.h>

#include <thrift/lib/cpp/transport/THeader.h>
#include <thrift/lib/cpp2/async/ResponseChannel.h>
#include <thrift/lib/cpp2/server/Cpp2ConnContext.h>
#include <thrift/lib/cpp2/transport/core/ThriftRequest.h>
#include <thrift/lib/cpp2/util/Checksum.h>

namespace apache {
namespace thrift {

using apache::thrift::concurrency::ThreadManager;
using folly::IOBuf;

ThriftProcessor::ThriftProcessor(server::ServerConfigs& serverConfigs)
    : serverConfigs_(serverConfigs) {}

void ThriftProcessor::onThriftRequest(
    RequestRpcMetadata&& metadata,
    std::unique_ptr<IOBuf> payload,
    std::shared_ptr<ThriftChannelIf> channel,
    std::unique_ptr<Cpp2ConnContext> connContext) noexcept {
  DCHECK(payload);
  DCHECK(channel);
  DCHECK(tm_);
  DCHECK(cpp2Processor_);

  bool invalidMetadata =
      !(metadata.protocol_ref() && metadata.name_ref() && metadata.kind_ref() &&
        metadata.seqId_ref());

  bool invalidChecksum = metadata.crc32c_ref() &&
      *metadata.crc32c_ref() != apache::thrift::checksum::crc32c(*payload);

  auto request = std::make_unique<ThriftRequest>(
      serverConfigs_, channel, std::move(metadata), std::move(connContext));

  auto* evb = channel->getEventBase();
  if (UNLIKELY(invalidMetadata)) {
    LOG(ERROR) << "Invalid metadata object";
    evb->runInEventBaseThread([request = std::move(request)]() {
      request->sendErrorWrapped(
          folly::make_exception_wrapper<TApplicationException>(
              TApplicationException::UNSUPPORTED_CLIENT_TYPE,
              "invalid metadata object"),
          "corrupted metadata");
    });
    return;
  }
  if (UNLIKELY(invalidChecksum)) {
    LOG(ERROR) << "Invalid checksum";
    evb->runInEventBaseThread([request = std::move(request)]() {
      request->sendErrorWrapped(
          folly::make_exception_wrapper<TApplicationException>(
              TApplicationException::CHECKSUM_MISMATCH, "checksum mismatch"),
          "corrupted request");
    });
    return;
  }

  auto protoId = request->getProtoId();
  auto reqContext = request->getRequestContext();
  cpp2Processor_->processSerializedRequest(
      std::move(request),
      SerializedRequest(std::move(payload)),
      protoId,
      reqContext,
      evb,
      tm_);
}
} // namespace thrift
} // namespace apache
<commit_msg>Make sure HTTP2 thrift server sets RequestContext for each request<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * 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/cpp2/transport/core/ThriftProcessor.h>

#include <string>

#include <glog/logging.h>

#include <thrift/lib/cpp/transport/THeader.h>
#include <thrift/lib/cpp2/async/ResponseChannel.h>
#include <thrift/lib/cpp2/server/Cpp2ConnContext.h>
#include <thrift/lib/cpp2/transport/core/ThriftRequest.h>
#include <thrift/lib/cpp2/util/Checksum.h>

namespace apache {
namespace thrift {

using apache::thrift::concurrency::ThreadManager;
using folly::IOBuf;

ThriftProcessor::ThriftProcessor(server::ServerConfigs& serverConfigs)
    : serverConfigs_(serverConfigs) {}

void ThriftProcessor::onThriftRequest(
    RequestRpcMetadata&& metadata,
    std::unique_ptr<IOBuf> payload,
    std::shared_ptr<ThriftChannelIf> channel,
    std::unique_ptr<Cpp2ConnContext> connContext) noexcept {
  DCHECK(payload);
  DCHECK(channel);
  DCHECK(tm_);
  DCHECK(cpp2Processor_);

  bool invalidMetadata =
      !(metadata.protocol_ref() && metadata.name_ref() && metadata.kind_ref() &&
        metadata.seqId_ref());

  bool invalidChecksum = metadata.crc32c_ref() &&
      *metadata.crc32c_ref() != apache::thrift::checksum::crc32c(*payload);

  auto request = std::make_unique<ThriftRequest>(
      serverConfigs_, channel, std::move(metadata), std::move(connContext));

  auto* evb = channel->getEventBase();
  if (UNLIKELY(invalidMetadata)) {
    LOG(ERROR) << "Invalid metadata object";
    evb->runInEventBaseThread([request = std::move(request)]() {
      request->sendErrorWrapped(
          folly::make_exception_wrapper<TApplicationException>(
              TApplicationException::UNSUPPORTED_CLIENT_TYPE,
              "invalid metadata object"),
          "corrupted metadata");
    });
    return;
  }
  if (UNLIKELY(invalidChecksum)) {
    LOG(ERROR) << "Invalid checksum";
    evb->runInEventBaseThread([request = std::move(request)]() {
      request->sendErrorWrapped(
          folly::make_exception_wrapper<TApplicationException>(
              TApplicationException::CHECKSUM_MISMATCH, "checksum mismatch"),
          "corrupted request");
    });
    return;
  }

  auto baseReqCtx = cpp2Processor_->getBaseContextForRequest();
  auto reqCtx = baseReqCtx ? folly::RequestContext::copyAsChild(*baseReqCtx)
                           : std::make_shared<folly::RequestContext>();
  folly::RequestContextScopeGuard rctx(reqCtx);

  auto protoId = request->getProtoId();
  auto reqContext = request->getRequestContext();
  cpp2Processor_->processSerializedRequest(
      std::move(request),
      SerializedRequest(std::move(payload)),
      protoId,
      reqContext,
      evb,
      tm_);
}
} // namespace thrift
} // namespace apache
<|endoftext|>