aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac7
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.test.include5
-rw-r--r--src/bitcoin-cli.cpp32
-rw-r--r--src/qt/paymentrequestplus.cpp4
-rw-r--r--src/support/events.h56
-rw-r--r--src/test/raii_event_tests.cpp88
-rw-r--r--src/util.h17
-rw-r--r--src/wallet/rpcwallet.cpp2
9 files changed, 179 insertions, 33 deletions
diff --git a/configure.ac b/configure.ac
index 73414c633d..4723c69d5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -835,6 +835,13 @@ else
fi
fi
+save_CXXFLAGS="${CXXFLAGS}"
+CXXFLAGS="${CXXFLAGS} ${CRYPTO_CFLAGS} ${SSL_CFLAGS}"
+AC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT
+#include <openssl/x509_vfy.h>
+])
+CXXFLAGS="${save_CXXFLAGS}"
+
dnl univalue check
need_bundled_univalue=yes
diff --git a/src/Makefile.am b/src/Makefile.am
index 3428d4613d..a2072865a3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -135,6 +135,7 @@ BITCOIN_CORE_H = \
support/allocators/secure.h \
support/allocators/zeroafterfree.h \
support/cleanse.h \
+ support/events.h \
support/lockedpool.h \
sync.h \
threadsafety.h \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index c1971213a4..27b456240e 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -88,6 +88,7 @@ BITCOIN_TESTS =\
test/policyestimator_tests.cpp \
test/pow_tests.cpp \
test/prevector_tests.cpp \
+ test/raii_event_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
@@ -123,9 +124,9 @@ BITCOIN_TESTS += \
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
-test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS)
+test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
+ $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 776fe65925..e9b530114c 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -17,10 +17,9 @@
#include <boost/filesystem/operations.hpp>
#include <stdio.h>
-#include <event2/event.h>
-#include <event2/http.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
+#include "support/events.h"
#include <univalue.h>
@@ -190,23 +189,19 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
int port = GetArg("-rpcport", BaseParams().RPCPort());
- // Create event base
- struct event_base *base = event_base_new(); // TODO RAII
- if (!base)
- throw std::runtime_error("cannot create event_base");
+ // Obtain event base
+ raii_event_base base = obtain_event_base();
// Synchronously look up hostname
- struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
- if (evcon == NULL)
- throw std::runtime_error("create connection failed");
- evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
+ raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
+ evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
HTTPReply response;
- struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
+ raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
if (req == NULL)
throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
- evhttp_request_set_error_cb(req, http_error_cb);
+ evhttp_request_set_error_cb(req.get(), http_error_cb);
#endif
// Get credentials
@@ -223,7 +218,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
}
- struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req);
+ struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
assert(output_headers);
evhttp_add_header(output_headers, "Host", host.c_str());
evhttp_add_header(output_headers, "Connection", "close");
@@ -231,20 +226,17 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
// Attach request data
std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
- struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req);
+ struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
- int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/");
+ int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
+ req.release(); // ownership moved to evcon in above call
if (r != 0) {
- evhttp_connection_free(evcon);
- event_base_free(base);
throw CConnectionFailed("send http request failed");
}
- event_base_dispatch(base);
- evhttp_connection_free(evcon);
- event_base_free(base);
+ event_base_dispatch(base.get());
if (response.status == 0)
throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 5101e4e0ee..01ec416613 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -159,7 +159,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
std::string data_to_verify; // Everything but the signature
rcopy.SerializeToString(&data_to_verify);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if HAVE_DECL_EVP_MD_CTX_NEW
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context.");
#else
@@ -174,7 +174,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
!EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) {
throw SSLVerifyError("Bad signature, invalid payment request.");
}
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if HAVE_DECL_EVP_MD_CTX_NEW
EVP_MD_CTX_free(ctx);
#endif
diff --git a/src/support/events.h b/src/support/events.h
new file mode 100644
index 0000000000..4f2f3cf9ef
--- /dev/null
+++ b/src/support/events.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SUPPORT_EVENTS_H
+#define BITCOIN_SUPPORT_EVENTS_H
+
+#include <ios>
+#include <memory>
+
+#include <event2/event.h>
+#include <event2/http.h>
+
+#define MAKE_RAII(type) \
+/* deleter */\
+struct type##_deleter {\
+ void operator()(struct type* ob) {\
+ type##_free(ob);\
+ }\
+};\
+/* unique ptr typedef */\
+typedef std::unique_ptr<struct type, type##_deleter> raii_##type
+
+MAKE_RAII(event_base);
+MAKE_RAII(event);
+MAKE_RAII(evhttp);
+MAKE_RAII(evhttp_request);
+MAKE_RAII(evhttp_connection);
+
+raii_event_base obtain_event_base() {
+ auto result = raii_event_base(event_base_new());
+ if (!result.get())
+ throw std::runtime_error("cannot create event_base");
+ return result;
+}
+
+raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {
+ return raii_event(event_new(base, s, events, cb, arg));
+}
+
+raii_evhttp obtain_evhttp(struct event_base* base) {
+ return raii_evhttp(evhttp_new(base));
+}
+
+raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {
+ return raii_evhttp_request(evhttp_request_new(cb, arg));
+}
+
+raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {
+ auto result = raii_evhttp_connection(evhttp_connection_base_new(base, NULL, host.c_str(), port));
+ if (!result.get())
+ throw std::runtime_error("create connection failed");
+ return result;
+}
+
+#endif // BITCOIN_SUPPORT_EVENTS_H
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
new file mode 100644
index 0000000000..87d25c0e2c
--- /dev/null
+++ b/src/test/raii_event_tests.cpp
@@ -0,0 +1,88 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <event2/event.h>
+#include <map>
+#include <stdlib.h>
+
+#include "support/events.h"
+
+#include "test/test_bitcoin.h"
+
+#include <vector>
+
+#include <boost/test/unit_test.hpp>
+
+static std::map<void*, short> tags;
+static std::map<void*, uint16_t> orders;
+static uint16_t tagSequence = 0;
+
+static void* tag_malloc(size_t sz) {
+ void* mem = malloc(sz);
+ if (!mem) return mem;
+ tags[mem]++;
+ orders[mem] = tagSequence++;
+ return mem;
+}
+
+static void tag_free(void* mem) {
+ tags[mem]--;
+ orders[mem] = tagSequence++;
+ free(mem);
+}
+
+BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(raii_event_creation)
+{
+ event_set_mem_functions(tag_malloc, realloc, tag_free);
+
+ void* base_ptr = NULL;
+ {
+ auto base = obtain_event_base();
+ base_ptr = (void*)base.get();
+ BOOST_CHECK(tags[base_ptr] == 1);
+ }
+ BOOST_CHECK(tags[base_ptr] == 0);
+
+ void* event_ptr = NULL;
+ {
+ auto base = obtain_event_base();
+ auto event = obtain_event(base.get(), -1, 0, NULL, NULL);
+
+ base_ptr = (void*)base.get();
+ event_ptr = (void*)event.get();
+
+ BOOST_CHECK(tags[base_ptr] == 1);
+ BOOST_CHECK(tags[event_ptr] == 1);
+ }
+ BOOST_CHECK(tags[base_ptr] == 0);
+ BOOST_CHECK(tags[event_ptr] == 0);
+
+ event_set_mem_functions(malloc, realloc, free);
+}
+
+BOOST_AUTO_TEST_CASE(raii_event_order)
+{
+ event_set_mem_functions(tag_malloc, realloc, tag_free);
+
+ void* base_ptr = NULL;
+ void* event_ptr = NULL;
+ {
+ auto base = obtain_event_base();
+ auto event = obtain_event(base.get(), -1, 0, NULL, NULL);
+
+ base_ptr = (void*)base.get();
+ event_ptr = (void*)event.get();
+
+ // base should have allocated before event
+ BOOST_CHECK(orders[base_ptr] < orders[event_ptr]);
+ }
+ // base should be freed after event
+ BOOST_CHECK(orders[base_ptr] > orders[event_ptr]);
+
+ event_set_mem_functions(malloc, realloc, free);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util.h b/src/util.h
index 97d2723bc4..e27ce121c8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -73,14 +73,15 @@ bool LogAcceptCategory(const char* category);
/** Send a string to the log output */
int LogPrintStr(const std::string &str);
-#define LogPrintf(...) LogPrint(NULL, __VA_ARGS__)
-
-template<typename... Args>
-static inline int LogPrint(const char* category, const char* fmt, const Args&... args)
-{
- if(!LogAcceptCategory(category)) return 0; \
- return LogPrintStr(tfm::format(fmt, args...));
-}
+#define LogPrint(category, ...) do { \
+ if (LogAcceptCategory((category))) { \
+ LogPrintStr(tfm::format(__VA_ARGS__)); \
+ } \
+} while(0)
+
+#define LogPrintf(...) do { \
+ LogPrintStr(tfm::format(__VA_ARGS__)); \
+} while(0)
template<typename... Args>
bool error(const char* fmt, const Args&... args)
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 11d69ac194..936140cf44 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -757,7 +757,7 @@ UniValue movecmd(const JSONRPCRequest& request)
"1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
"2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
"3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
- "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
+ "4. (dummy) (numeric, optional) Ignored. Remains for backward compatibility.\n"
"5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
"\nResult:\n"
"true|false (boolean) true if successful.\n"