diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ec5cef..feb68e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,13 @@ option(WEBCC_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON) option(WEBCC_BUILD_UNITTEST "Build unit test?" ON) option(WEBCC_BUILD_EXAMPLE "Build examples?" ON) +if(WIN32) + option(WEBCC_ENABLE_VLD "Enable VLD (Visual Leak Detector)?" OFF) + if(WEBCC_ENABLE_VLD) + add_definitions(-DWEBCC_ENABLE_VLD) + endif() +endif() + set(WEBCC_LOG_LEVEL "VERB" CACHE STRING "Log level (VERB, INFO, WARN, ERRO or FATA)") if(WEBCC_ENABLE_LOG) @@ -96,13 +103,17 @@ endif() # For including its own headers as "webcc/http_client.h". include_directories(${PROJECT_SOURCE_DIR}/src) +if(WIN32) + include_directories(${PROJECT_SOURCE_DIR}/third_party/win32/include) + link_directories(${PROJECT_SOURCE_DIR}/third_party/win32/lib) +endif() + # SOAP support needs pugixml to parse and create XML. if(WEBCC_ENABLE_SOAP) - add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/pugixml) + add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/src/pugixml) # For including pugixml as "pugixml/pugixml.hpp". - # TODO: Remove "pugixml" prefix? - include_directories(${PROJECT_SOURCE_DIR}/third_party) + include_directories(${PROJECT_SOURCE_DIR}/third_party/src) endif() add_subdirectory(src/webcc) @@ -112,8 +123,8 @@ if(WEBCC_BUILD_EXAMPLE) add_subdirectory(${PROJECT_SOURCE_DIR}/example/http/async_client) # REST example needs jsoncpp to parse and create JSON. - add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/jsoncpp) - include_directories(${PROJECT_SOURCE_DIR}/third_party/jsoncpp) + add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/src/jsoncpp) + include_directories(${PROJECT_SOURCE_DIR}/third_party/src/jsoncpp) add_subdirectory(${PROJECT_SOURCE_DIR}/example/rest/book_server) add_subdirectory(${PROJECT_SOURCE_DIR}/example/rest/book_client) @@ -126,6 +137,6 @@ if(WEBCC_BUILD_EXAMPLE) endif() if(WEBCC_BUILD_UNITTEST) - add_subdirectory(third_party/gtest) + add_subdirectory(third_party/src/gtest) add_subdirectory(unittest) endif() diff --git a/example/http/async_client/main.cc b/example/http/async_client/main.cc index 51e215c..8718939 100644 --- a/example/http/async_client/main.cc +++ b/example/http/async_client/main.cc @@ -40,7 +40,7 @@ void Test(boost::asio::io_context& ioc) { } int main() { - LOG_INIT("", webcc::LOG_CONSOLE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); boost::asio::io_context ioc; diff --git a/example/http/client/main.cc b/example/http/client/main.cc index 33e87ca..81d8267 100644 --- a/example/http/client/main.cc +++ b/example/http/client/main.cc @@ -28,7 +28,7 @@ void Test() { } int main() { - LOG_INIT("", webcc::LOG_CONSOLE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); Test(); Test(); diff --git a/example/rest/book_async_client/main.cc b/example/rest/book_async_client/main.cc index 2671a8f..7ee1018 100644 --- a/example/rest/book_async_client/main.cc +++ b/example/rest/book_async_client/main.cc @@ -101,7 +101,7 @@ int main(int argc, char* argv[]) { return 1; } - LOG_INIT("", webcc::LOG_CONSOLE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); std::string host = argv[1]; std::string port = argv[2]; diff --git a/example/rest/book_client/main.cc b/example/rest/book_client/main.cc index 331b553..d49b063 100644 --- a/example/rest/book_client/main.cc +++ b/example/rest/book_client/main.cc @@ -5,6 +5,19 @@ #include "webcc/logger.h" #include "webcc/rest_client.h" +// In order to run with VLD, please copy the following files to the example +// output folder from "third_party\win32\bin": +// - dbghelp.dll +// - Microsoft.DTfW.DHL.manifest +// - vld_x86.dll +#if (defined(WIN32) || defined(_WIN64)) +#if defined(_DEBUG) && defined(WEBCC_ENABLE_VLD) +#pragma message ("< include vld.h >") +#include "vld/vld.h" +#pragma comment(lib, "vld") +#endif +#endif + // ----------------------------------------------------------------------------- // Write a JSON object to string. @@ -160,7 +173,7 @@ int main(int argc, char* argv[]) { return 1; } - LOG_INIT("", webcc::LOG_CONSOLE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); std::string host = argv[1]; std::string port = argv[2]; diff --git a/example/rest/book_server/main.cc b/example/rest/book_server/main.cc index f523e7b..6f1f5b0 100644 --- a/example/rest/book_server/main.cc +++ b/example/rest/book_server/main.cc @@ -5,6 +5,19 @@ #include "book_services.h" +// In order to run with VLD, please copy the following files to the example +// output folder from "third_party\win32\bin": +// - dbghelp.dll +// - Microsoft.DTfW.DHL.manifest +// - vld_x86.dll +#if (defined(WIN32) || defined(_WIN64)) +#if defined(_DEBUG) && defined(WEBCC_ENABLE_VLD) +#pragma message ("< include vld.h >") +#include "vld/vld.h" +#pragma comment(lib, "vld") +#endif +#endif + void Help(const char* argv0) { std::cout << "Usage: " << argv0 << " [seconds]" << std::endl; std::cout << "If |seconds| is provided, the server will sleep these seconds " @@ -21,7 +34,7 @@ int main(int argc, char* argv[]) { return 1; } - LOG_INIT("", webcc::LOG_FILE | webcc::LOG_CONSOLE | webcc::LOG_OVERWRITE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); unsigned short port = std::atoi(argv[1]); diff --git a/example/soap/calc_client/main.cc b/example/soap/calc_client/main.cc index 85c493e..61d8f2e 100644 --- a/example/soap/calc_client/main.cc +++ b/example/soap/calc_client/main.cc @@ -5,7 +5,7 @@ #include "calc_client.h" int main() { - LOG_INIT("", webcc::LOG_CONSOLE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); CalcClient calc; diff --git a/example/soap/calc_server/main.cc b/example/soap/calc_server/main.cc index 2c8fb2f..3834ba4 100644 --- a/example/soap/calc_server/main.cc +++ b/example/soap/calc_server/main.cc @@ -17,7 +17,7 @@ int main(int argc, char* argv[]) { return 1; } - LOG_INIT("", webcc::LOG_CONSOLE); + WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); unsigned short port = std::atoi(argv[1]); diff --git a/src/webcc/async_http_client.cc b/src/webcc/async_http_client.cc index ee35b75..508dfee 100644 --- a/src/webcc/async_http_client.cc +++ b/src/webcc/async_http_client.cc @@ -13,8 +13,12 @@ namespace webcc { +extern void AdjustBufferSize(std::size_t content_length, + std::vector* buffer); + AsyncHttpClient::AsyncHttpClient(boost::asio::io_context& io_context) : socket_(io_context), + buffer_(kBufferSize), timeout_seconds_(kMaxReceiveSeconds), deadline_(io_context) { resolver_.reset(new tcp::resolver(io_context)); @@ -165,21 +169,36 @@ void AsyncHttpClient::ReadHandler(boost::system::error_code ec, return; } + LOG_VERB("Socket async read handler."); + if (ec || length == 0) { Stop(); + LOG_ERRO("Socket read error."); response_handler_(response_, kSocketReadError, timed_out_); return; } + LOG_INFO("Read data, length: %d.", length); + + bool content_length_parsed = response_parser_->content_length_parsed(); + // Parse the response piece just read. // If the content has been fully received, |finished()| will be true. if (!response_parser_->Parse(buffer_.data(), length)) { Stop(); + LOG_ERRO("Failed to parse HTTP response."); response_handler_(response_, kHttpError, timed_out_); return; } + if (!content_length_parsed && + response_parser_->content_length_parsed()) { + // Content length just has been parsed. + AdjustBufferSize(response_parser_->content_length(), &buffer_); + } + if (response_parser_->finished()) { + LOG_INFO("Finished to read and parse HTTP response."); LOG_VERB("HTTP response:\n%s", response_->Dump(4, "> ").c_str()); Stop(); response_handler_(response_, kNoError, timed_out_); @@ -199,11 +218,8 @@ void AsyncHttpClient::CheckDeadline() { // The deadline has passed. // The socket is closed so that any outstanding asynchronous operations // are canceled. - boost::system::error_code ignored_ec; - socket_.close(ignored_ec); - - deadline_.expires_at(boost::posix_time::pos_infin); - + LOG_WARN("HTTP client timed out."); + Stop(); timed_out_ = true; } diff --git a/src/webcc/async_http_client.h b/src/webcc/async_http_client.h index 817db9d..c3c1d95 100644 --- a/src/webcc/async_http_client.h +++ b/src/webcc/async_http_client.h @@ -1,9 +1,9 @@ #ifndef WEBCC_ASYNC_HTTP_CLIENT_H_ #define WEBCC_ASYNC_HTTP_CLIENT_H_ -#include #include #include +#include #include "boost/asio/deadline_timer.hpp" #include "boost/asio/io_context.hpp" @@ -67,7 +67,7 @@ class AsyncHttpClient : public std::enable_shared_from_this { std::unique_ptr resolver_; tcp::resolver::results_type endpoints_; - std::array buffer_; + std::vector buffer_; std::unique_ptr response_parser_; diff --git a/src/webcc/globals.h b/src/webcc/globals.h index 9066ba6..4208c12 100644 --- a/src/webcc/globals.h +++ b/src/webcc/globals.h @@ -17,8 +17,7 @@ namespace webcc { // ----------------------------------------------------------------------------- // Constants -// Buffer size for sending HTTP request and receiving HTTP response. -// TODO: Configurable +// Default buffer size for socket reading. const std::size_t kBufferSize = 1024; const std::size_t kInvalidLength = static_cast(-1); diff --git a/src/webcc/http_client.cc b/src/webcc/http_client.cc index 91c2a15..40694b6 100644 --- a/src/webcc/http_client.cc +++ b/src/webcc/http_client.cc @@ -19,20 +19,43 @@ namespace webcc { +// Adjust buffer size according to content length. +// This is to avoid reading too many times. +// Also used by AsyncHttpClient. +void AdjustBufferSize(std::size_t content_length, std::vector* buffer) { + const std::size_t kMaxTimes = 10; + + // According to test, a client never read more than 200000 bytes a time. + // So it doesn't make sense to set any larger size, e.g., 1MB. + const std::size_t kMaxBufferSize = 200000; + + LOG_INFO("Adjust buffer size according to content length."); + + std::size_t min_buffer_size = content_length / kMaxTimes; + if (min_buffer_size > buffer->size()) { + buffer->resize(std::min(min_buffer_size, kMaxBufferSize)); + LOG_INFO("Resize read buffer to %d.", buffer->size()); + } else { + LOG_INFO("Keep the current buffer size (%d).", buffer->size()); + } +} + HttpClient::HttpClient() : socket_(io_context_), + buffer_(kBufferSize), timeout_seconds_(kMaxReceiveSeconds), deadline_(io_context_) { - deadline_.expires_at(boost::posix_time::pos_infin); } bool HttpClient::Request(const HttpRequest& request) { response_.reset(new HttpResponse()); response_parser_.reset(new HttpResponseParser(response_.get())); + stopped_ = false; timed_out_ = false; // Start the persistent actor that checks for deadline expiry. + deadline_.expires_at(boost::posix_time::pos_infin); CheckDeadline(); if ((error_ = Connect(request)) != kNoError) { @@ -50,6 +73,15 @@ bool HttpClient::Request(const HttpRequest& request) { return true; } +void HttpClient::Stop() { + stopped_ = true; + + boost::system::error_code ignored_ec; + socket_.close(ignored_ec); + + deadline_.cancel(); +} + Error HttpClient::Connect(const HttpRequest& request) { using boost::asio::ip::tcp; @@ -88,6 +120,7 @@ Error HttpClient::Connect(const HttpRequest& request) { // check whether the socket is still open before deciding if we succeeded // or failed. if (ec || !socket_.is_open()) { + Stop(); if (!ec) { timed_out_ = true; } @@ -114,6 +147,7 @@ Error HttpClient::SendReqeust(const HttpRequest& request) { } while (ec == boost::asio::error::would_block); if (ec) { + Stop(); return kSocketWriteError; } @@ -121,6 +155,8 @@ Error HttpClient::SendReqeust(const HttpRequest& request) { } Error HttpClient::ReadResponse() { + deadline_.expires_from_now(boost::posix_time::seconds(timeout_seconds_)); + Error error = kNoError; DoReadResponse(&error); @@ -132,8 +168,6 @@ Error HttpClient::ReadResponse() { } void HttpClient::DoReadResponse(Error* error) { - deadline_.expires_from_now(boost::posix_time::seconds(timeout_seconds_)); - boost::system::error_code ec = boost::asio::error::would_block; socket_.async_read_some( @@ -142,24 +176,42 @@ void HttpClient::DoReadResponse(Error* error) { std::size_t length) { ec = inner_ec; + LOG_VERB("Socket async read handler."); + + if (stopped_) { + return; + } + if (inner_ec || length == 0) { + Stop(); *error = kSocketReadError; LOG_ERRO("Socket read error."); return; } + LOG_INFO("Read data, length: %d.", length); + + bool content_length_parsed = response_parser_->content_length_parsed(); + // Parse the response piece just read. - // If the content has been fully received, next time flag "finished_" - // will be set. if (!response_parser_->Parse(buffer_.data(), length)) { + Stop(); *error = kHttpError; LOG_ERRO("Failed to parse HTTP response."); return; } + if (!content_length_parsed && + response_parser_->content_length_parsed()) { + // Content length just has been parsed. + AdjustBufferSize(response_parser_->content_length(), &buffer_); + } + if (response_parser_->finished()) { // Stop trying to read once all content has been received, // because some servers will block extra call to read_some(). + Stop(); + LOG_INFO("Finished to read and parse HTTP response."); return; } @@ -173,16 +225,17 @@ void HttpClient::DoReadResponse(Error* error) { } void HttpClient::CheckDeadline() { + if (stopped_) { + return; + } + if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now()) { // The deadline has passed. // The socket is closed so that any outstanding asynchronous operations // are canceled. - boost::system::error_code ignored_ec; - socket_.close(ignored_ec); - - deadline_.expires_at(boost::posix_time::pos_infin); - + LOG_WARN("HTTP client timed out."); + Stop(); timed_out_ = true; } diff --git a/src/webcc/http_client.h b/src/webcc/http_client.h index ae926b1..cd940db 100644 --- a/src/webcc/http_client.h +++ b/src/webcc/http_client.h @@ -1,8 +1,9 @@ #ifndef WEBCC_HTTP_CLIENT_H_ #define WEBCC_HTTP_CLIENT_H_ -#include +#include #include +#include #include "boost/asio/deadline_timer.hpp" #include "boost/asio/io_context.hpp" @@ -24,6 +25,7 @@ class HttpClient { DELETE_COPY_AND_ASSIGN(HttpClient); void set_timeout_seconds(int timeout_seconds) { + assert(timeout_seconds > 0); timeout_seconds_ = timeout_seconds; } @@ -37,6 +39,9 @@ class HttpClient { bool Request(const HttpRequest& request); private: + // Terminate all the actors to shut down the connection. + void Stop(); + Error Connect(const HttpRequest& request); Error SendReqeust(const HttpRequest& request); @@ -51,13 +56,15 @@ class HttpClient { boost::asio::ip::tcp::socket socket_; - std::array buffer_; + std::vector buffer_; HttpResponsePtr response_; std::unique_ptr response_parser_; Error error_ = kNoError; + bool stopped_ = false; + // If the error was caused by timeout or not. bool timed_out_ = false; diff --git a/src/webcc/http_connection.cc b/src/webcc/http_connection.cc index 497d621..95f0a23 100644 --- a/src/webcc/http_connection.cc +++ b/src/webcc/http_connection.cc @@ -12,8 +12,9 @@ namespace webcc { HttpConnection::HttpConnection(boost::asio::ip::tcp::socket socket, - HttpRequestHandler* handler) + HttpRequestHandler* handler) : socket_(std::move(socket)), + buffer_(kBufferSize), request_handler_(handler), request_parser_(&request_) { } @@ -28,7 +29,7 @@ void HttpConnection::Close() { } void HttpConnection::SetResponseContent(std::string&& content, - const std::string& content_type) { + const std::string& content_type) { response_.SetContent(std::move(content)); response_.SetContentType(content_type); } @@ -47,7 +48,7 @@ void HttpConnection::AsyncRead() { } void HttpConnection::ReadHandler(boost::system::error_code ec, - std::size_t length) { + std::size_t length) { if (ec) { if (ec != boost::asio::error::operation_aborted) { Close(); @@ -88,7 +89,7 @@ void HttpConnection::AsyncWrite() { // io_context.run), even though DoWrite() is invoked by worker threads. This is // ensured by Asio. void HttpConnection::WriteHandler(boost::system::error_code ec, - std::size_t length) { + std::size_t length) { if (!ec) { LOG_INFO("Response has been sent back."); diff --git a/src/webcc/http_connection.h b/src/webcc/http_connection.h index 1c1aac5..56981d1 100644 --- a/src/webcc/http_connection.h +++ b/src/webcc/http_connection.h @@ -1,9 +1,9 @@ #ifndef WEBCC_HTTP_CONNECTION_H_ #define WEBCC_HTTP_CONNECTION_H_ -#include #include #include +#include #include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket @@ -51,12 +51,12 @@ class HttpConnection : public std::enable_shared_from_this { // Socket for the connection. boost::asio::ip::tcp::socket socket_; + // Buffer for incoming data. + std::vector buffer_; + // The handler used to process the incoming request. HttpRequestHandler* request_handler_; - // Buffer for incoming data. - std::array buffer_; - // The incoming request. HttpRequest request_; diff --git a/src/webcc/http_parser.cc b/src/webcc/http_parser.cc index d5043c9..65c91e1 100644 --- a/src/webcc/http_parser.cc +++ b/src/webcc/http_parser.cc @@ -4,6 +4,7 @@ #include "boost/lexical_cast.hpp" #include "webcc/http_message.h" +#include "webcc/logger.h" namespace webcc { @@ -16,10 +17,10 @@ HttpParser::HttpParser(HttpMessage* message) finished_(false) { } -bool HttpParser::Parse(const char* data, std::size_t len) { +bool HttpParser::Parse(const char* data, std::size_t length) { if (header_parsed_) { // Add the data to the content. - AppendContent(data, len); + AppendContent(data, length); if (IsContentFull()) { // All content has been read. @@ -29,7 +30,7 @@ bool HttpParser::Parse(const char* data, std::size_t len) { return true; } - pending_data_.append(data, len); + pending_data_.append(data, length); std::size_t off = 0; while (true) { @@ -64,9 +65,10 @@ bool HttpParser::Parse(const char* data, std::size_t len) { if (header_parsed_) { // Headers just ended. + LOG_INFO("HTTP headers parsed."); if (!content_length_parsed_) { - // No Content-Length, no content. (TODO: Support chucked data) + // No Content-Length, no content. Finish(); return true; } else { @@ -110,7 +112,16 @@ void HttpParser::ParseContentLength(const std::string& line) { try { content_length_ = boost::lexical_cast(value); + LOG_INFO("Content length: %d", content_length_); + + // Reserve memory to avoid frequent reallocation when append. + try { + content_.reserve(content_length_); + } catch (std::exception& e) { + LOG_ERRO("Failed to reserve content memory: %s.", e.what()); + } } catch (boost::bad_lexical_cast&) { + LOG_ERRO("Invalid content length: %s.", value.c_str()); } } } diff --git a/src/webcc/http_parser.h b/src/webcc/http_parser.h index fa5b3bb..7fe8830 100644 --- a/src/webcc/http_parser.h +++ b/src/webcc/http_parser.h @@ -18,11 +18,12 @@ class HttpParser { DELETE_COPY_AND_ASSIGN(HttpParser); - bool finished() const { - return finished_; - } + bool finished() const { return finished_; } - bool Parse(const char* data, std::size_t len); + bool content_length_parsed() const { return content_length_parsed_; } + std::size_t content_length() const { return content_length_; } + + bool Parse(const char* data, std::size_t length); protected: virtual bool ParseStartLine(const std::string& line) = 0; diff --git a/src/webcc/logger.h b/src/webcc/logger.h index e1dee14..0b5a1ea 100644 --- a/src/webcc/logger.h +++ b/src/webcc/logger.h @@ -30,6 +30,10 @@ enum LogMode { LOG_OVERWRITE = 8, // Overwrite any existing log file. }; +// Commonly used modes. +const int LOG_CONSOLE_FILE_APPEND = LOG_CONSOLE | LOG_FILE; +const int LOG_CONSOLE_FILE_OVERWRITE = LOG_CONSOLE | LOG_FILE | LOG_OVERWRITE; + // Initialize logger. // If |dir| is empty, log file will be generated in current directory. void LogInit(const std::string& dir, int modes); @@ -39,8 +43,7 @@ void LogWrite(int level, const char* file, int line, const char* format, ...); } // namespace webcc // Initialize the logger with a level. -// E.g., LOG_INIT(FLUSH) -#define LOG_INIT(dir, modes) webcc::LogInit(dir, modes); +#define WEBCC_LOG_INIT(dir, modes) webcc::LogInit(dir, modes); #if (defined(WIN32) || defined(_WIN64)) @@ -126,7 +129,7 @@ void LogWrite(int level, const char* file, int line, const char* format, ...); #else // WEBCC_ENABLE_LOG == 0 -#define LOG_INIT(modes) +#define WEBCC_LOG_INIT(modes) #if (defined(WIN32) || defined(_WIN64)) #define LOG_VERB(format, ...) diff --git a/src/webcc/rest_client.cc b/src/webcc/rest_client.cc index 71cc101..0d4f878 100644 --- a/src/webcc/rest_client.cc +++ b/src/webcc/rest_client.cc @@ -25,7 +25,10 @@ bool RestClient::Request(const std::string& method, request.Build(); HttpClient http_client; - http_client.set_timeout_seconds(timeout_seconds_); + + if (timeout_seconds_ > 0) { + http_client.set_timeout_seconds(timeout_seconds_); + } if (!http_client.Request(request)) { error_ = http_client.error(); diff --git a/src/webcc/rest_client.h b/src/webcc/rest_client.h index 2512324..9615281 100644 --- a/src/webcc/rest_client.h +++ b/src/webcc/rest_client.h @@ -63,8 +63,8 @@ class RestClient { std::string host_; std::string port_; - // -1 means default timeout (normally 30s) will be used. - int timeout_seconds_ = -1; + // Timeout in seconds; only effective when > 0. + int timeout_seconds_ = 0; HttpResponsePtr response_; diff --git a/src/webcc/soap_client.cc b/src/webcc/soap_client.cc index 7892c2c..db32bd3 100644 --- a/src/webcc/soap_client.cc +++ b/src/webcc/soap_client.cc @@ -50,7 +50,7 @@ Error SoapClient::Call(const std::string& operation, HttpClient http_client; - if (timeout_seconds_ != -1) { + if (timeout_seconds_ > 0) { http_client.set_timeout_seconds(timeout_seconds_); } diff --git a/src/webcc/soap_client.h b/src/webcc/soap_client.h index 3880f94..522db54 100644 --- a/src/webcc/soap_client.h +++ b/src/webcc/soap_client.h @@ -26,8 +26,8 @@ class SoapClient { std::vector&& parameters, std::string* result); - // -1 means default timeout (normally 30s) will be used. - int timeout_seconds_ = -1; + // Timeout in seconds; only effective when > 0. + int timeout_seconds_ = 0; // If the error was caused by timeout or not. bool timed_out_ = false; diff --git a/third_party/README.txt b/third_party/README.txt deleted file mode 100644 index 73e5c60..0000000 --- a/third_party/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -Pugixml is not a Git submodule because its Git repo is not well structured. It does have a CMakeLists.txt but it's difficult to integrate. - -TODO: Use Git submodule for gtest? \ No newline at end of file diff --git a/third_party/gtest/CMakeLists.txt b/third_party/src/gtest/CMakeLists.txt similarity index 100% rename from third_party/gtest/CMakeLists.txt rename to third_party/src/gtest/CMakeLists.txt diff --git a/third_party/gtest/gtest-all.cc b/third_party/src/gtest/gtest-all.cc similarity index 100% rename from third_party/gtest/gtest-all.cc rename to third_party/src/gtest/gtest-all.cc diff --git a/third_party/gtest/gtest-death-test.cc b/third_party/src/gtest/gtest-death-test.cc similarity index 100% rename from third_party/gtest/gtest-death-test.cc rename to third_party/src/gtest/gtest-death-test.cc diff --git a/third_party/gtest/gtest-death-test.h b/third_party/src/gtest/gtest-death-test.h similarity index 100% rename from third_party/gtest/gtest-death-test.h rename to third_party/src/gtest/gtest-death-test.h diff --git a/third_party/gtest/gtest-filepath.cc b/third_party/src/gtest/gtest-filepath.cc similarity index 100% rename from third_party/gtest/gtest-filepath.cc rename to third_party/src/gtest/gtest-filepath.cc diff --git a/third_party/gtest/gtest-internal-inl.h b/third_party/src/gtest/gtest-internal-inl.h similarity index 100% rename from third_party/gtest/gtest-internal-inl.h rename to third_party/src/gtest/gtest-internal-inl.h diff --git a/third_party/gtest/gtest-message.h b/third_party/src/gtest/gtest-message.h similarity index 100% rename from third_party/gtest/gtest-message.h rename to third_party/src/gtest/gtest-message.h diff --git a/third_party/gtest/gtest-param-test.h b/third_party/src/gtest/gtest-param-test.h similarity index 100% rename from third_party/gtest/gtest-param-test.h rename to third_party/src/gtest/gtest-param-test.h diff --git a/third_party/gtest/gtest-param-test.h.pump b/third_party/src/gtest/gtest-param-test.h.pump similarity index 100% rename from third_party/gtest/gtest-param-test.h.pump rename to third_party/src/gtest/gtest-param-test.h.pump diff --git a/third_party/gtest/gtest-port.cc b/third_party/src/gtest/gtest-port.cc similarity index 100% rename from third_party/gtest/gtest-port.cc rename to third_party/src/gtest/gtest-port.cc diff --git a/third_party/gtest/gtest-printers.cc b/third_party/src/gtest/gtest-printers.cc similarity index 100% rename from third_party/gtest/gtest-printers.cc rename to third_party/src/gtest/gtest-printers.cc diff --git a/third_party/gtest/gtest-printers.h b/third_party/src/gtest/gtest-printers.h similarity index 100% rename from third_party/gtest/gtest-printers.h rename to third_party/src/gtest/gtest-printers.h diff --git a/third_party/gtest/gtest-spi.h b/third_party/src/gtest/gtest-spi.h similarity index 100% rename from third_party/gtest/gtest-spi.h rename to third_party/src/gtest/gtest-spi.h diff --git a/third_party/gtest/gtest-test-part.cc b/third_party/src/gtest/gtest-test-part.cc similarity index 100% rename from third_party/gtest/gtest-test-part.cc rename to third_party/src/gtest/gtest-test-part.cc diff --git a/third_party/gtest/gtest-test-part.h b/third_party/src/gtest/gtest-test-part.h similarity index 100% rename from third_party/gtest/gtest-test-part.h rename to third_party/src/gtest/gtest-test-part.h diff --git a/third_party/gtest/gtest-typed-test.cc b/third_party/src/gtest/gtest-typed-test.cc similarity index 100% rename from third_party/gtest/gtest-typed-test.cc rename to third_party/src/gtest/gtest-typed-test.cc diff --git a/third_party/gtest/gtest-typed-test.h b/third_party/src/gtest/gtest-typed-test.h similarity index 100% rename from third_party/gtest/gtest-typed-test.h rename to third_party/src/gtest/gtest-typed-test.h diff --git a/third_party/gtest/gtest.cc b/third_party/src/gtest/gtest.cc similarity index 100% rename from third_party/gtest/gtest.cc rename to third_party/src/gtest/gtest.cc diff --git a/third_party/gtest/gtest.h b/third_party/src/gtest/gtest.h similarity index 100% rename from third_party/gtest/gtest.h rename to third_party/src/gtest/gtest.h diff --git a/third_party/gtest/gtest_main.cc b/third_party/src/gtest/gtest_main.cc similarity index 100% rename from third_party/gtest/gtest_main.cc rename to third_party/src/gtest/gtest_main.cc diff --git a/third_party/gtest/gtest_pred_impl.h b/third_party/src/gtest/gtest_pred_impl.h similarity index 100% rename from third_party/gtest/gtest_pred_impl.h rename to third_party/src/gtest/gtest_pred_impl.h diff --git a/third_party/gtest/gtest_prod.h b/third_party/src/gtest/gtest_prod.h similarity index 100% rename from third_party/gtest/gtest_prod.h rename to third_party/src/gtest/gtest_prod.h diff --git a/third_party/gtest/internal/gtest-death-test-internal.h b/third_party/src/gtest/internal/gtest-death-test-internal.h similarity index 100% rename from third_party/gtest/internal/gtest-death-test-internal.h rename to third_party/src/gtest/internal/gtest-death-test-internal.h diff --git a/third_party/gtest/internal/gtest-filepath.h b/third_party/src/gtest/internal/gtest-filepath.h similarity index 100% rename from third_party/gtest/internal/gtest-filepath.h rename to third_party/src/gtest/internal/gtest-filepath.h diff --git a/third_party/gtest/internal/gtest-internal.h b/third_party/src/gtest/internal/gtest-internal.h similarity index 100% rename from third_party/gtest/internal/gtest-internal.h rename to third_party/src/gtest/internal/gtest-internal.h diff --git a/third_party/gtest/internal/gtest-linked_ptr.h b/third_party/src/gtest/internal/gtest-linked_ptr.h similarity index 100% rename from third_party/gtest/internal/gtest-linked_ptr.h rename to third_party/src/gtest/internal/gtest-linked_ptr.h diff --git a/third_party/gtest/internal/gtest-param-util-generated.h b/third_party/src/gtest/internal/gtest-param-util-generated.h similarity index 100% rename from third_party/gtest/internal/gtest-param-util-generated.h rename to third_party/src/gtest/internal/gtest-param-util-generated.h diff --git a/third_party/gtest/internal/gtest-param-util-generated.h.pump b/third_party/src/gtest/internal/gtest-param-util-generated.h.pump similarity index 100% rename from third_party/gtest/internal/gtest-param-util-generated.h.pump rename to third_party/src/gtest/internal/gtest-param-util-generated.h.pump diff --git a/third_party/gtest/internal/gtest-param-util.h b/third_party/src/gtest/internal/gtest-param-util.h similarity index 100% rename from third_party/gtest/internal/gtest-param-util.h rename to third_party/src/gtest/internal/gtest-param-util.h diff --git a/third_party/gtest/internal/gtest-port.h b/third_party/src/gtest/internal/gtest-port.h similarity index 100% rename from third_party/gtest/internal/gtest-port.h rename to third_party/src/gtest/internal/gtest-port.h diff --git a/third_party/gtest/internal/gtest-string.h b/third_party/src/gtest/internal/gtest-string.h similarity index 100% rename from third_party/gtest/internal/gtest-string.h rename to third_party/src/gtest/internal/gtest-string.h diff --git a/third_party/gtest/internal/gtest-tuple.h b/third_party/src/gtest/internal/gtest-tuple.h similarity index 100% rename from third_party/gtest/internal/gtest-tuple.h rename to third_party/src/gtest/internal/gtest-tuple.h diff --git a/third_party/gtest/internal/gtest-tuple.h.pump b/third_party/src/gtest/internal/gtest-tuple.h.pump similarity index 100% rename from third_party/gtest/internal/gtest-tuple.h.pump rename to third_party/src/gtest/internal/gtest-tuple.h.pump diff --git a/third_party/gtest/internal/gtest-type-util.h b/third_party/src/gtest/internal/gtest-type-util.h similarity index 100% rename from third_party/gtest/internal/gtest-type-util.h rename to third_party/src/gtest/internal/gtest-type-util.h diff --git a/third_party/gtest/internal/gtest-type-util.h.pump b/third_party/src/gtest/internal/gtest-type-util.h.pump similarity index 100% rename from third_party/gtest/internal/gtest-type-util.h.pump rename to third_party/src/gtest/internal/gtest-type-util.h.pump diff --git a/third_party/jsoncpp/CMakeLists.txt b/third_party/src/jsoncpp/CMakeLists.txt similarity index 100% rename from third_party/jsoncpp/CMakeLists.txt rename to third_party/src/jsoncpp/CMakeLists.txt diff --git a/third_party/jsoncpp/json/json-forwards.h b/third_party/src/jsoncpp/json/json-forwards.h similarity index 100% rename from third_party/jsoncpp/json/json-forwards.h rename to third_party/src/jsoncpp/json/json-forwards.h diff --git a/third_party/jsoncpp/json/json.h b/third_party/src/jsoncpp/json/json.h similarity index 100% rename from third_party/jsoncpp/json/json.h rename to third_party/src/jsoncpp/json/json.h diff --git a/third_party/jsoncpp/jsoncpp.cpp b/third_party/src/jsoncpp/jsoncpp.cpp similarity index 100% rename from third_party/jsoncpp/jsoncpp.cpp rename to third_party/src/jsoncpp/jsoncpp.cpp diff --git a/third_party/pugixml/CMakeLists.txt b/third_party/src/pugixml/CMakeLists.txt similarity index 100% rename from third_party/pugixml/CMakeLists.txt rename to third_party/src/pugixml/CMakeLists.txt diff --git a/third_party/pugixml/pugiconfig.hpp b/third_party/src/pugixml/pugiconfig.hpp similarity index 100% rename from third_party/pugixml/pugiconfig.hpp rename to third_party/src/pugixml/pugiconfig.hpp diff --git a/third_party/pugixml/pugixml.cpp b/third_party/src/pugixml/pugixml.cpp similarity index 100% rename from third_party/pugixml/pugixml.cpp rename to third_party/src/pugixml/pugixml.cpp diff --git a/third_party/pugixml/pugixml.hpp b/third_party/src/pugixml/pugixml.hpp similarity index 100% rename from third_party/pugixml/pugixml.hpp rename to third_party/src/pugixml/pugixml.hpp diff --git a/third_party/win32/bin/Microsoft.DTfW.DHL.manifest b/third_party/win32/bin/Microsoft.DTfW.DHL.manifest new file mode 100644 index 0000000..e61222f --- /dev/null +++ b/third_party/win32/bin/Microsoft.DTfW.DHL.manifest @@ -0,0 +1,7 @@ + + + + + + + diff --git a/third_party/win32/bin/dbghelp.dll b/third_party/win32/bin/dbghelp.dll new file mode 100644 index 0000000..62d8508 Binary files /dev/null and b/third_party/win32/bin/dbghelp.dll differ diff --git a/third_party/win32/bin/vld_x86.dll b/third_party/win32/bin/vld_x86.dll new file mode 100644 index 0000000..2b08acd Binary files /dev/null and b/third_party/win32/bin/vld_x86.dll differ diff --git a/third_party/win32/include/vld/vld.h b/third_party/win32/include/vld/vld.h new file mode 100644 index 0000000..a24a09f --- /dev/null +++ b/third_party/win32/include/vld/vld.h @@ -0,0 +1,307 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Visual Leak Detector - Import Library Header +// Copyright (c) 2005-2013 VLD Team +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See COPYING.txt for the full terms of the GNU Lesser General Public License. +// +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "vld_def.h" + +#if defined _DEBUG || defined VLD_FORCE_ENABLE + +#include + +#pragma comment(lib, "vld.lib") + +// Force a symbolic reference to the global VisualLeakDetector class object from +// the DLL. This ensures that the DLL is loaded and linked with the program, +// even if no code otherwise imports any of the DLL's exports. +#pragma comment(linker, "/include:__imp_?g_vld@@3VVisualLeakDetector@@A") + +//////////////////////////////////////////////////////////////////////////////// +// +// Visual Leak Detector APIs +// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// VLDDisable - Disables Visual Leak Detector's memory leak detection at +// runtime. If memory leak detection is already disabled, then calling this +// function has no effect. +// +// Note: In multithreaded programs, this function operates on a per-thread +// basis. In other words, if you call this function from one thread, then +// memory leak detection is only disabled for that thread. If memory leak +// detection is enabled for other threads, then it will remain enabled for +// those other threads. It was designed to work this way to insulate you, +// the programmer, from having to ensure thread synchronization when calling +// VLDEnable() and VLDDisable(). Without this, calling these two functions +// unsynchronized could result in unpredictable and unintended behavior. +// But this also means that if you want to disable memory leak detection +// process-wide, then you need to call this function from every thread in +// the process. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDDisable (); + +// VLDEnable - Enables Visual Leak Detector's memory leak detection at runtime. +// If memory leak detection is already enabled, which it is by default, then +// calling this function has no effect. +// +// Note: In multithreaded programs, this function operates on a per-thread +// basis. In other words, if you call this function from one thread, then +// memory leak detection is only enabled for that thread. If memory leak +// detection is disabled for other threads, then it will remain disabled for +// those other threads. It was designed to work this way to insulate you, +// the programmer, from having to ensure thread synchronization when calling +// VLDEnable() and VLDDisable(). Without this, calling these two functions +// unsynchronized could result in unpredictable and unintended behavior. +// But this also means that if you want to enable memory leak detection +// process-wide, then you need to call this function from every thread in +// the process. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDEnable (); + +// VLDRestore - Restore Visual Leak Detector's previous state. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDRestore (); + +// VLDGlobalDisable - Disables Visual Leak Detector's memory leak detection at +// runtime in all threads. If memory leak detection is already disabled, +// then calling this function has no effect. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDGlobalDisable (); + +// VLDGlobalEnable - Enables Visual Leak Detector's memory leak detection +// at runtime in all threads. If memory leak detection is already enabled, +// which it is by default, then calling this function has no effect. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDGlobalEnable (); + +// VLDReportLeaks - Report leaks up to the execution point. +// +// Return Value: +// +// None. +// +__declspec(dllimport) UINT VLDReportLeaks (); + +// VLDGetLeaksCount - Return memory leaks count to the execution point. +// +// Return Value: +// +// None. +// +__declspec(dllimport) UINT VLDGetLeaksCount (); + +// VLDMarkAllLeaksAsReported - Mark all leaks as reported. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDMarkAllLeaksAsReported (); + + +// VLDRefreshModules - Look for recently loaded DLLs and patch them if necessary. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDRefreshModules(); + + +// VLDEnableModule - Enable Memory leak checking on the specified module. +// +// module: module handle. +// +// Return Value: +// +// None. +// + +__declspec(dllimport) void VLDEnableModule(HMODULE module); + + +// VLDDisableModule - Disable Memory leak checking on the specified module. +// +// module: module handle. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDDisableModule(HMODULE module); + +// VLDGetOptions - Return all current options. +// +// Return Value: +// +// Mask of current options. +// +__declspec(dllimport) UINT VLDGetOptions(); + +// VLDGetReportFilename - Return current report filename. +// +// filename: current report filename (max characters - MAX_PATH). +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDGetReportFilename(WCHAR *filename); + +// VLDSetOptions - Update the report options via function call rather than INI file. +// +// option_mask: Only the following flags are checked +// VLD_OPT_AGGREGATE_DUPLICATES +// VLD_OPT_MODULE_LIST_INCLUDE +// VLD_OPT_SAFE_STACK_WALK +// VLD_OPT_SLOW_DEBUGGER_DUMP +// VLD_OPT_TRACE_INTERNAL_FRAMES +// VLD_OPT_START_DISABLED +// VLD_OPT_SKIP_HEAPFREE_LEAKS +// VLD_OPT_VALIDATE_HEAPFREE +// +// maxDataDump: maximum number of user-data bytes to dump for each leaked block. +// +// maxTraceFrames: maximum number of frames per stack trace for each leaked block. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDSetOptions(UINT option_mask, SIZE_T maxDataDump, UINT maxTraceFrames); + +// VLDSetModulesList - Set list of modules included/excluded in leak detection +// depending on parameter "includeModules". +// +// modules: list of modules to be forcefully included/excluded in leak detection. +// +// includeModules: include or exclude that modules. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDSetModulesList(CONST WCHAR *modules, BOOL includeModules); + +// VLDGetModulesList - Return current list of included/excluded modules +// depending on flag VLD_OPT_TRACE_INTERNAL_FRAMES. +// +// modules: destination string for list of included/excluded modules (maximum length 512 characters). +// +// size: maximum string size. +// +// Return Value: +// +// BOOL: TRUE if include modules, otherwise FALSE. +// +__declspec(dllimport) BOOL VLDGetModulesList(WCHAR *modules, UINT size); + +// VLDSetReportOptions - Update the report options via function call rather than INI file. +// +// Only the following flags are checked +// VLD_OPT_REPORT_TO_DEBUGGER +// VLD_OPT_REPORT_TO_FILE +// VLD_OPT_REPORT_TO_STDOUT +// VLD_OPT_UNICODE_REPORT +// +// filename is optional and can be NULL. +// +// Return Value: +// +// None. +// +__declspec(dllimport) void VLDSetReportOptions(UINT option_mask, CONST WCHAR *filename); + +// VLDSetReportHook - Installs or uninstalls a client-defined reporting function by hooking it +// into the C run-time debug reporting process (debug version only). +// +// mode: The action to take: VLD_RPTHOOK_INSTALL or VLD_RPTHOOK_REMOVE. +// +// pfnNewHook: Report hook to install or remove. +// +// Return Value: +// +// int: 0 if success. +// +__declspec(dllimport) int VLDSetReportHook(int mode, VLD_REPORT_HOOK pfnNewHook); + +// VLDResolveCallstacks - Performs symbol resolution for all saved extent CallStack's that have +// been tracked by Visual Leak Detector. This function is necessary for applications that +// dynamically load and unload modules, and through which memory leaks might be included. +// If this is NOT called, stack traces may have stack frames with no symbol information. This +// happens because the symbol API's cannot look up symbols for a binary / module that has been unloaded +// from the process. +// +// Return Value: +// +// None. +// +__declspec(dllexport) void VLDResolveCallstacks(); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#else // !_DEBUG + +#define VLDEnable() +#define VLDDisable() +#define VLDRestore() +#define VLDReportLeaks() 0 +#define VLDGetLeaksCount() 0 +#define VLDMarkAllLeaksAsReported() +#define VLDRefreshModules() +#define VLDEnableModule(a) +#define VLDDisableModule(b) +#define VLDGetOptions() 0 +#define VLDGetReportFilename(a) +#define VLDSetOptions(a, b, c) +#define VLDSetReportHook(a, b) +#define VLDSetModulesList(a) +#define VLDGetModulesList(a, b) FALSE +#define VLDSetReportOptions(a, b) + +#endif // _DEBUG diff --git a/third_party/win32/include/vld/vld_def.h b/third_party/win32/include/vld/vld_def.h new file mode 100644 index 0000000..93bbfaf --- /dev/null +++ b/third_party/win32/include/vld/vld_def.h @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Visual Leak Detector - Import Library Header +// Copyright (c) 2005-2013 VLD Team +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// +// See COPYING.txt for the full terms of the GNU Lesser General Public License. +// +//////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define VLD_OPT_AGGREGATE_DUPLICATES 0x0001 // If set, aggregate duplicate leaks in the leak report. +#define VLD_OPT_MODULE_LIST_INCLUDE 0x0002 // If set, modules in the module list are included, all others are excluded. +#define VLD_OPT_REPORT_TO_DEBUGGER 0x0004 // If set, the memory leak report is sent to the debugger. +#define VLD_OPT_REPORT_TO_FILE 0x0008 // If set, the memory leak report is sent to a file. +#define VLD_OPT_SAFE_STACK_WALK 0x0010 // If set, the stack is walked using the "safe" method (StackWalk64). +#define VLD_OPT_SELF_TEST 0x0020 // If set, perform a self-test to verify memory leak self-checking. +#define VLD_OPT_SLOW_DEBUGGER_DUMP 0x0040 // If set, inserts a slight delay between sending output to the debugger. +#define VLD_OPT_START_DISABLED 0x0080 // If set, memory leak detection will initially disabled. +#define VLD_OPT_TRACE_INTERNAL_FRAMES 0x0100 // If set, include useless frames (e.g. internal to VLD) in call stacks. +#define VLD_OPT_UNICODE_REPORT 0x0200 // If set, the leak report will be encoded UTF-16 instead of ASCII. +#define VLD_OPT_VLDOFF 0x0400 // If set, VLD will be completely deactivated. It will not attach to any modules. +#define VLD_OPT_REPORT_TO_STDOUT 0x0800 // If set, the memory leak report is sent to stdout. +#define VLD_OPT_SKIP_HEAPFREE_LEAKS 0x1000 // If set, VLD skip HeapFree memory leaks. +#define VLD_OPT_VALIDATE_HEAPFREE 0x2000 // If set, VLD verifies and reports heap consistency for HeapFree calls. +#define VLD_OPT_RELEASE_CRT_RUNTIME 0x4000 // If set, VLD treat CRT runtime as release version (use only with define VLD_FORCE_ENABLE). + +#define VLD_RPTHOOK_INSTALL 0 +#define VLD_RPTHOOK_REMOVE 1 + +typedef int (__cdecl * VLD_REPORT_HOOK)(int reportType, wchar_t *message, int *returnValue); diff --git a/third_party/win32/lib/debug/vld.lib b/third_party/win32/lib/debug/vld.lib new file mode 100644 index 0000000..0cf8962 Binary files /dev/null and b/third_party/win32/lib/debug/vld.lib differ