diff --git a/CMakeLists.txt b/CMakeLists.txt index f4422ee..d417550 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,15 +86,6 @@ ENDIF() find_package(OpenSSL) -IF(APPLE) - # As of 10.10 yosemite, the OpenSSL static libraries shipped with os x have a dependency - # on zlib, so any time you link in openssl you also need to link zlib. . We really want to detect whether openssl was configured with the --no-zlib - # option or not when it was built, but that's difficult to do in practice, so we - # just always try to link it in on mac. - find_package( ZLIB REQUIRED ) -ENDIF(APPLE) - - set( CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_LIB_SUFFIXES} ) option( UNITY_BUILD OFF ) @@ -137,6 +128,7 @@ set( fc_sources src/log/appender.cpp src/log/console_appender.cpp src/log/file_appender.cpp + src/log/gelf_appender.cpp src/log/logger_config.cpp src/crypto/openssl.cpp src/crypto/aes.cpp @@ -353,6 +345,14 @@ if(WIN32) endif(WIN32) +IF(APPLE) + # As of 10.10 yosemite, the OpenSSL static libraries shipped with os x have a dependency + # on zlib, so any time you link in openssl you also need to link zlib. . We really want to detect whether openssl was configured with the --no-zlib + # option or not when it was built, but that's difficult to do in practice, so we + # just always try to link it in on mac. + find_package( ZLIB REQUIRED ) +ENDIF(APPLE) + SET(OPENSSL_CONF_TARGET ) IF(DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) SET (OPENSSL_CONF_TARGET ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/include/fc/exception/exception.hpp b/include/fc/exception/exception.hpp index a3b26a0..1457214 100644 --- a/include/fc/exception/exception.hpp +++ b/include/fc/exception/exception.hpp @@ -298,21 +298,26 @@ namespace fc * @brief Checks a condition and throws an assert_exception if the test is FALSE */ #define FC_ASSERT( TEST, ... ) \ - FC_EXPAND_MACRO( \ - do { if( !(TEST) ) { FC_THROW_EXCEPTION( fc::assert_exception, #TEST ": " __VA_ARGS__ ); } } while(0) \ - ) + FC_EXPAND_MACRO( \ + FC_MULTILINE_MACRO_BEGIN \ + if( !(TEST) ) \ + FC_THROW_EXCEPTION( fc::assert_exception, #TEST ": " __VA_ARGS__ ); \ + FC_MULTILINE_MACRO_END \ + ) #define FC_CAPTURE_AND_THROW( EXCEPTION_TYPE, ... ) \ - do { throw EXCEPTION_TYPE( FC_LOG_MESSAGE( error, "", FC_FORMAT_ARG_PARAMS(__VA_ARGS__) ) ); } while(0) + FC_MULTILINE_MACRO_BEGIN \ + throw EXCEPTION_TYPE( FC_LOG_MESSAGE( error, "", FC_FORMAT_ARG_PARAMS(__VA_ARGS__) ) ); \ + FC_MULTILINE_MACRO_END //#define FC_THROW( FORMAT, ... ) // FC_INDIRECT_EXPAND workas around a bug in Visual C++ variadic macro processing that prevents it // from separating __VA_ARGS__ into separate tokens #define FC_INDIRECT_EXPAND(MACRO, ARGS) MACRO ARGS #define FC_THROW( ... ) \ - do { \ - throw fc::exception( FC_INDIRECT_EXPAND(FC_LOG_MESSAGE, ( error, __VA_ARGS__ )) ); \ - } while(0) + FC_MULTILINE_MACRO_BEGIN \ + throw fc::exception( FC_INDIRECT_EXPAND(FC_LOG_MESSAGE, ( error, __VA_ARGS__ )) ); \ + FC_MULTILINE_MACRO_END #define FC_EXCEPTION( EXCEPTION_TYPE, FORMAT, ... ) \ EXCEPTION_TYPE( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ) @@ -322,9 +327,9 @@ namespace fc * @param format - a const char* string with "${keys}" */ #define FC_THROW_EXCEPTION( EXCEPTION, FORMAT, ... ) \ - do { \ - throw EXCEPTION( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \ - } while(0) + FC_MULTILINE_MACRO_BEGIN \ + throw EXCEPTION( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \ + FC_MULTILINE_MACRO_END /** @@ -332,10 +337,10 @@ namespace fc * @brief Appends a log_message to the exception ER and rethrows it. */ #define FC_RETHROW_EXCEPTION( ER, LOG_LEVEL, FORMAT, ... ) \ - do { \ - ER.append_log( FC_LOG_MESSAGE( LOG_LEVEL, FORMAT, __VA_ARGS__ ) ); \ - throw;\ - } while(0) + FC_MULTILINE_MACRO_BEGIN \ + ER.append_log( FC_LOG_MESSAGE( LOG_LEVEL, FORMAT, __VA_ARGS__ ) ); \ + throw; \ + FC_MULTILINE_MACRO_END #define FC_LOG_AND_RETHROW( ) \ catch( fc::exception& er ) { \ diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 4a05cd4..1a16926 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -1,5 +1,7 @@ #pragma once #include +#include + #include #include #include @@ -226,5 +228,37 @@ namespace fc { temp_directory(const fc::path& tempFolder = fc::temp_directory_path()); }; + +#if !defined(__APPLE__) + // this code is known to work on linux and windows. It may work correctly on mac, + // or it may need slight tweaks or extra includes. It's disabled now to avoid giving + // a false sense of security. +# define FC_HAS_SIMPLE_FILE_LOCK +#endif +#ifdef FC_HAS_SIMPLE_FILE_LOCK + /** simple class which only allows one process to open any given file. + * approximate usage: + * int main() { + * fc::simple_file_lock instance_lock("~/.my_app/.lock"); + * if (!instance_lock.try_lock()) { + * elog("my_app is already running"); + * return 1; + * } + * // do stuff here, file will be unlocked when instance_lock goes out of scope + * } + */ + class simple_lock_file + { + public: + simple_lock_file(const path& lock_file_path); + ~simple_lock_file(); + bool try_lock(); + void unlock(); + private: + class impl; + std::unique_ptr my; + }; +#endif // FC_HAS_SIMPLE_FILE_LOCK + } diff --git a/include/fc/log/gelf_appender.hpp b/include/fc/log/gelf_appender.hpp new file mode 100644 index 0000000..2228313 --- /dev/null +++ b/include/fc/log/gelf_appender.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +namespace fc +{ + // Log appender that sends log messages in JSON format over UDP + // https://www.graylog2.org/resources/gelf/specification + class gelf_appender : public appender + { + public: + struct config + { + string endpoint = "127.0.0.1:12201"; + string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server) + }; + + gelf_appender(const variant& args); + ~gelf_appender(); + virtual void log(const log_message& m) override; + + private: + class impl; + fc::shared_ptr my; + }; +} // namespace fc + +#include +FC_REFLECT(fc::gelf_appender::config, + (endpoint)(host)) diff --git a/include/fc/log/logger.hpp b/include/fc/log/logger.hpp index 7121d5f..9005d75 100644 --- a/include/fc/log/logger.hpp +++ b/include/fc/log/logger.hpp @@ -61,74 +61,77 @@ namespace fc #define DEFAULT_LOGGER #endif - +// suppress warning "conditional expression is constant" in the while(0) for visual c++ +// http://cnicholson.net/2009/03/stupid-c-tricks-dowhile0-and-c4127/ +#define FC_MULTILINE_MACRO_BEGIN do { +#ifdef _MSC_VER +# define FC_MULTILINE_MACRO_END \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + } while (0) \ + __pragma(warning(pop)) +#else +# define FC_MULTILINE_MACRO_END } while (0) +#endif + #define fc_dlog( LOGGER, FORMAT, ... ) \ - do { \ - if( (LOGGER).is_enabled( fc::log_level::debug ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (LOGGER).is_enabled( fc::log_level::debug ) ) \ (LOGGER).log( FC_LOG_MESSAGE( debug, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define fc_ilog( LOGGER, FORMAT, ... ) \ - do { \ - if( (LOGGER).is_enabled( fc::log_level::info ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (LOGGER).is_enabled( fc::log_level::info ) ) \ (LOGGER).log( FC_LOG_MESSAGE( info, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define fc_wlog( LOGGER, FORMAT, ... ) \ - do { \ - if( (LOGGER).is_enabled( fc::log_level::warn ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (LOGGER).is_enabled( fc::log_level::warn ) ) \ (LOGGER).log( FC_LOG_MESSAGE( warn, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define fc_elog( LOGGER, FORMAT, ... ) \ - do { \ - if( (LOGGER).is_enabled( fc::log_level::error ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (LOGGER).is_enabled( fc::log_level::error ) ) \ (LOGGER).log( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define dlog( FORMAT, ... ) \ - do { \ - if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::debug ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::debug ) ) \ (fc::logger::get(DEFAULT_LOGGER)).log( FC_LOG_MESSAGE( debug, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END /** * Sends the log message to a special 'user' log stream designed for messages that * the end user may like to see. */ #define ulog( FORMAT, ... ) \ - do { \ - if( (fc::logger::get("user")).is_enabled( fc::log_level::debug ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (fc::logger::get("user")).is_enabled( fc::log_level::debug ) ) \ (fc::logger::get("user")).log( FC_LOG_MESSAGE( debug, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define ilog( FORMAT, ... ) \ - do { \ - if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::info ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::info ) ) \ (fc::logger::get(DEFAULT_LOGGER)).log( FC_LOG_MESSAGE( info, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define wlog( FORMAT, ... ) \ - do { \ - if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::warn ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::warn ) ) \ (fc::logger::get(DEFAULT_LOGGER)).log( FC_LOG_MESSAGE( warn, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #define elog( FORMAT, ... ) \ - do { \ - if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::error ) ) { \ + FC_MULTILINE_MACRO_BEGIN \ + if( (fc::logger::get(DEFAULT_LOGGER)).is_enabled( fc::log_level::error ) ) \ (fc::logger::get(DEFAULT_LOGGER)).log( FC_LOG_MESSAGE( error, FORMAT, __VA_ARGS__ ) ); \ - } \ - } while (0) + FC_MULTILINE_MACRO_END #include #include @@ -164,13 +167,13 @@ namespace fc // a slowdown. #ifdef FC_DISABLE_LOGGING # undef ulog -# define ulog(...) do {} while(0) +# define ulog(...) FC_MULTILINE_MACRO_BEGIN FC_MULTILINE_MACRO_END # undef elog -# define elog(...) do {} while(0) +# define elog(...) FC_MULTILINE_MACRO_BEGIN FC_MULTILINE_MACRO_END # undef wlog -# define wlog(...) do {} while(0) +# define wlog(...) FC_MULTILINE_MACRO_BEGIN FC_MULTILINE_MACRO_END # undef ilog -# define ilog(...) do {} while(0) +# define ilog(...) FC_MULTILINE_MACRO_BEGIN FC_MULTILINE_MACRO_END # undef dlog -# define dlog(...) do {} while(0) +# define dlog(...) FC_MULTILINE_MACRO_BEGIN FC_MULTILINE_MACRO_END #endif \ No newline at end of file diff --git a/src/crypto/base58.cpp b/src/crypto/base58.cpp index 48fe27d..f7fc37e 100644 --- a/src/crypto/base58.cpp +++ b/src/crypto/base58.cpp @@ -618,7 +618,7 @@ std::string to_base58( const std::vector& d ) std::vector from_base58( const std::string& base58_str ) { std::vector out; if( !DecodeBase58( base58_str.c_str(), out ) ) { - FC_THROW_EXCEPTION( exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); + FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); } return std::vector((const char*)out.data(), ((const char*)out.data())+out.size() ); } @@ -629,7 +629,7 @@ size_t from_base58( const std::string& base58_str, char* out_data, size_t out_da //slog( "%s", base58_str.c_str() ); std::vector out; if( !DecodeBase58( base58_str.c_str(), out ) ) { - FC_THROW_EXCEPTION( exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); + FC_THROW_EXCEPTION( parse_error_exception, "Unable to decode base58 string ${base58_str}", ("base58_str",base58_str) ); } memcpy( out_data, out.data(), out.size() ); diff --git a/src/filesystem.cpp b/src/filesystem.cpp index db33f1c..85dd1f5 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -19,6 +19,10 @@ #include #include #include +# ifdef FC_HAS_SIMPLE_FILE_LOCK + #include + #include +# endif #endif namespace fc { @@ -495,4 +499,101 @@ namespace fc { return appCurrentPath; } + +#ifdef FC_HAS_SIMPLE_FILE_LOCK + class simple_lock_file::impl + { + public: +#ifdef _WIN32 + HANDLE file_handle; +#else + int file_handle; +#endif + bool is_locked; + path lock_file_path; + + impl(const path& lock_file_path); + ~impl(); + + bool try_lock(); + void unlock(); + }; + + simple_lock_file::impl::impl(const path& lock_file_path) : + is_locked(false), + lock_file_path(lock_file_path), +#ifdef _WIN32 + file_handle(INVALID_HANDLE_VALUE) +#else + file_handle(-1) +#endif + {} + + simple_lock_file::impl::~impl() + { + unlock(); + } + + bool simple_lock_file::impl::try_lock() + { +#ifdef _WIN32 + HANDLE fh = CreateFileA(lock_file_path.to_native_ansi_path().c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, 0, + OPEN_ALWAYS, 0, NULL); + if (fh == INVALID_HANDLE_VALUE) + return false; + is_locked = true; + file_handle = fh; + return true; +#else + int fd = open(lock_file_path.string().c_str(), O_RDWR|O_CREAT, 0644); + if (fd < 0) + return false; + if (flock(fd, LOCK_EX|LOCK_NB) == -1) + { + close(fd); + return false; + } + is_locked = true; + file_handle = fd; + return true; +#endif + } + + void simple_lock_file::impl::unlock() + { +#ifdef WIN32 + CloseHandle(file_handle); + file_handle = INVALID_HANDLE_VALUE; + is_locked = false; +#else + flock(file_handle, LOCK_UN); + close(file_handle); + file_handle = -1; + is_locked = false; +#endif + } + + + simple_lock_file::simple_lock_file(const path& lock_file_path) : + my(new impl(lock_file_path)) + { + } + + simple_lock_file::~simple_lock_file() + { + } + + bool simple_lock_file::try_lock() + { + return my->try_lock(); + } + + void simple_lock_file::unlock() + { + my->unlock(); + } +#endif // FC_HAS_SIMPLE_FILE_LOCK + } diff --git a/src/log/appender.cpp b/src/log/appender.cpp index 737625c..c4d9c9e 100644 --- a/src/log/appender.cpp +++ b/src/log/appender.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "console_defines.h" @@ -45,4 +46,6 @@ namespace fc { static bool reg_console_appender = appender::register_appender( "console" ); static bool reg_file_appender = appender::register_appender( "file" ); + static bool reg_gelf_appender = appender::register_appender( "gelf" ); + } // namespace fc diff --git a/src/log/gelf_appender.cpp b/src/log/gelf_appender.cpp new file mode 100644 index 0000000..e8b7a7b --- /dev/null +++ b/src/log/gelf_appender.cpp @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace fc +{ + + class gelf_appender::impl : public retainable + { + public: + config cfg; + optional gelf_endpoint; + udp_socket gelf_socket; + boost::mutex socket_mutex; + + impl(const config& c) : + cfg(c) + { + } + + ~impl() + { + } + }; + + gelf_appender::gelf_appender(const variant& args) : + my(new impl(args.as())) + { + try + { + try + { + // if it's a numeric address:port, this will parse it + my->gelf_endpoint = ip::endpoint::from_string(my->cfg.endpoint); + } + catch (...) + { + } + if (!my->gelf_endpoint) + { + // couldn't parse as a numeric ip address, try resolving as a DNS name. + // This can yield, so don't do it in the catch block above + string::size_type colon_pos = my->cfg.endpoint.find(':'); + try + { + uint16_t port = boost::lexical_cast(my->cfg.endpoint.substr(colon_pos + 1, my->cfg.endpoint.size())); + + string hostname = my->cfg.endpoint.substr( 0, colon_pos ); + std::vector endpoints = resolve(hostname, port); + if (endpoints.empty()) + FC_THROW_EXCEPTION(unknown_host_exception, "The host name can not be resolved: ${hostname}", + ("hostname", hostname)); + my->gelf_endpoint = endpoints.back(); + } + catch (const boost::bad_lexical_cast&) + { + FC_THROW("Bad port: ${port}", ("port", my->cfg.endpoint.substr(colon_pos + 1, my->cfg.endpoint.size()))); + } + } + + if (my->gelf_endpoint) + my->gelf_socket.open(); + } + catch (...) + { + std::cerr << "error opening GELF socket to endpoint ${endpoint}" << my->cfg.endpoint << "\n"; + } + } + + gelf_appender::~gelf_appender() + {} + + void gelf_appender::log(const log_message& message) + { + if (!my->gelf_endpoint) + return; + + log_context context = message.get_context(); + + mutable_variant_object gelf_message; + gelf_message["version"] = "1.1"; + gelf_message["host"] = my->cfg.host; + gelf_message["short_message"] = format_string(message.get_format(), message.get_data()); + + gelf_message["timestamp"] = context.get_timestamp().time_since_epoch().count() / 1000000.; + + switch (context.get_log_level()) + { + case log_level::debug: + gelf_message["level"] = 7; // debug + break; + case log_level::info: + gelf_message["level"] = 6; // info + break; + case log_level::warn: + gelf_message["level"] = 4; // warning + break; + case log_level::error: + gelf_message["level"] = 3; // error + break; + case log_level::all: + case log_level::off: + // these shouldn't be used in log messages, but do something deterministic just in case + gelf_message["level"] = 6; // info + break; + } + + if (!context.get_context().empty()) + gelf_message["context"] = context.get_context(); + gelf_message["_line"] = context.get_line_number(); + gelf_message["_file"] = context.get_file(); + gelf_message["_method_name"] = context.get_method(); + gelf_message["_thread_name"] = context.get_thread_name(); + if (!context.get_task_name().empty()) + gelf_message["_task_name"] = context.get_task_name(); + + string gelf_message_as_string = json::to_string(gelf_message); + std::shared_ptr send_buffer(new char[gelf_message_as_string.size()], [](char* p){ delete[] p; }); + memcpy(send_buffer.get(), gelf_message_as_string.c_str(), gelf_message_as_string.size()); + + { + scoped_lock lock(my->socket_mutex); + my->gelf_socket.send_to(send_buffer, gelf_message_as_string.size(), *my->gelf_endpoint); + } + } +} // fc diff --git a/src/log/log_message.cpp b/src/log/log_message.cpp index 7e26cf4..09b6815 100644 --- a/src/log/log_message.cpp +++ b/src/log/log_message.cpp @@ -83,7 +83,9 @@ namespace fc void log_context::append_context( const fc::string& s ) { - my->context += "->" + s; + if (!my->context.empty()) + my->context += " -> "; + my->context += s; } log_context::~log_context(){} @@ -158,6 +160,7 @@ namespace fc string log_context::get_host_name()const { return my->hostname; } time_point log_context::get_timestamp()const { return my->timestamp; } log_level log_context::get_log_level()const{ return my->level; } + string log_context::get_context()const { return my->context; } variant log_context::to_variant()const diff --git a/src/network/http/http_server.cpp b/src/network/http/http_server.cpp index e0dd9b6..648fc54 100644 --- a/src/network/http/http_server.cpp +++ b/src/network/http/http_server.cpp @@ -25,7 +25,7 @@ namespace fc { namespace http { case fc::http::reply::RecordCreated: ss << "Record Created\r\n"; break; case fc::http::reply::NotFound: ss << "Not Found\r\n"; break; case fc::http::reply::Found: ss << "Found\r\n"; break; - case fc::http::reply::InternalServerError: ss << "Internal Server Error\r\n"; break; + default: ss << "Internal Server Error\r\n"; break; } for( uint32_t i = 0; i < rep.headers.size(); ++i ) { ss << rep.headers[i].key <<": "<flush(); } - _out->flush(); } void send_error( variant id, fc::exception& e ) { @@ -59,9 +59,9 @@ namespace fc { namespace rpc { *_out <<",\"code\":0,\"data\":"; json::to_stream( *_out, variant(e)); *_out << "}}\n"; + _out->flush(); } //wlog( "exception: ${except}", ("except", variant(e)) ); - _out->flush(); } void handle_message( const variant_object& obj ) @@ -306,8 +306,8 @@ namespace fc { namespace rpc { *my->_out << ",\"params\":"; fc::json::to_stream( *my->_out, named_args ); *my->_out << "}\n"; + my->_out->flush(); } - my->_out->flush(); } void json_connection::notice( const fc::string& method ) { @@ -316,8 +316,8 @@ namespace fc { namespace rpc { *my->_out << "{\"method\":"; json::to_stream( *my->_out, method ); *my->_out << "}\n"; + my->_out->flush(); } - my->_out->flush(); } @@ -342,8 +342,8 @@ namespace fc { namespace rpc { { *my->_out << ",\"params\":[]}\n"; } + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } @@ -361,8 +361,8 @@ namespace fc { namespace rpc { *my->_out << ",\"params\":["; fc::json::to_stream( *my->_out, a1 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2 ) @@ -381,8 +381,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a2 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3 ) @@ -403,8 +403,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a3 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } @@ -428,8 +428,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a4 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } @@ -455,8 +455,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a5 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } @@ -484,8 +484,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a6 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method, const variant& a1, const variant& a2, const variant& a3, const variant& a4, const variant& a5, const variant& a6, const variant& a7 ) @@ -514,8 +514,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a7 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method, @@ -554,8 +554,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a8 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method, @@ -597,8 +597,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a9 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method, @@ -643,8 +643,8 @@ namespace fc { namespace rpc { *my->_out << ","; fc::json::to_stream( *my->_out, a10 ); *my->_out << "]}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } @@ -665,8 +665,8 @@ namespace fc { namespace rpc { *my->_out << ",\"params\":"; fc::json::to_stream( *my->_out, named_args ); *my->_out << "}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; } future json_connection::async_call( const fc::string& method ) @@ -680,8 +680,8 @@ namespace fc { namespace rpc { *my->_out << ",\"method\":"; json::to_stream( *my->_out, method ); *my->_out << "}\n"; + my->_out->flush(); } - my->_out->flush(); return my->_awaiting[id]; }