Skip to content

Commit

Permalink
Add barebones IPC framework to bitcoin-qt and bitcoind
Browse files Browse the repository at this point in the history
This adds some IPC functions and classes in src/ipc/ that let bitcoin-qt fork a
bitcoind process and communicate with it over a socketpair.

Only a handful of IPC calls are implemented, but this demonstrates a working
framework supporting bidirectional IPC calls (requests from bitcoin-qt to
bitcoind and notifications from bitcoind to bitcoin-qt).

The IPC protocol used in this implementation is Cap'n Proto
(https://capnproto.org/), but this could be swapped out for another protocol.
Can'n Proto types and libraries are only accessed in ipc/server.cpp and
ipc/client.cpp, and not in any headers or other parts of bitcoin code.
  • Loading branch information
ryanofsky committed Apr 3, 2017
1 parent 29efc39 commit 0ca73bc
Show file tree
Hide file tree
Showing 37 changed files with 1,939 additions and 128 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,7 @@ AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes])
AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes])
AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes])

AC_DEFINE_UNQUOTED(BITCOIN_DAEMON_NAME, "$BITCOIN_DAEMON_NAME", [Base name of bitcoind executable])
AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])
AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version])
AC_DEFINE(CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION, [Build revision])
Expand Down
17 changes: 15 additions & 2 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ BITCOIN_CORE_H = \
httpserver.h \
indirectmap.h \
init.h \
ipc/client.h \
ipc/interfaces.h \
ipc/messages.capnp.h \
ipc/serialize.h \
ipc/server.h \
ipc/util.h \
key.h \
keystore.h \
dbwrapper.h \
Expand Down Expand Up @@ -173,7 +179,7 @@ obj/build.h: FORCE
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h

# server: shared between bitcoind and bitcoin-qt
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) $(CAPNP_RPC_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
Expand Down Expand Up @@ -326,6 +332,13 @@ libbitcoin_util_a_SOURCES = \
compat/glibc_sanity.cpp \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
ipc/client.cpp \
ipc/interfaces.cpp \
ipc/messages.capnp \
ipc/messages.capnp.c++ \
ipc/serialize.cpp \
ipc/server.cpp \
ipc/util.cpp \
random.cpp \
rpc/protocol.cpp \
support/cleanse.cpp \
Expand Down Expand Up @@ -374,7 +387,7 @@ bitcoind_LDADD = \
$(LIBMEMENV) \
$(LIBSECP256K1)

bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS)
bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(CAPNP_RPC_LIBS)

# bitcoin-cli binary #
bitcoin_cli_SOURCES = bitcoin-cli.cpp
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
$(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(CAPNP_RPC_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX

Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.qttest.include
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
$(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(CAPNP_RPC_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)

Expand Down
8 changes: 8 additions & 0 deletions src/bitcoind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "compat.h"
#include "rpc/server.h"
#include "init.h"
#include "ipc/server.h"
#include "noui.h"
#include "scheduler.h"
#include "util.h"
Expand Down Expand Up @@ -188,6 +189,13 @@ bool AppInit(int argc, char* argv[])

int main(int argc, char* argv[])
{
// Check if bitcoind is being invoked as an IPC server. If so, then bypass
// normal execution and just respond to requests from the IPC channel.
int exitStatus;
if (ipc::StartServer(argc, argv, exitStatus)) {
return exitStatus;
}

SetupEnvironment();

// Connect bitcoind signal handlers
Expand Down
52 changes: 52 additions & 0 deletions src/ipc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
Bitcoin Interprocess Communication
==================================

The IPC functions and classes in `src/ipc/` allow the `bitcoin-qt` process to
fork a `bitcoind` process and communicate with it over a socketpair. This gives
`bitcoin-qt` a code a bit of modularity, avoiding a monolithic architecture
where UI, P2P, wallet, consensus, and database code all runs in a single
process.

In the future, the IPC mechanism could be extended to allow other subdivisions
of functionality. For example, wallet code could run in a separate process from
P2P code. Also in the future, IPC sockets could also be exposed more publicly.
For example, exposed IPC server sockets could allow a `bitcoin-qt` process to
control a `bitcoind` process other than the one it spawns internally. These
changes would be straightforward to implement, but would create security,
backwards-compatibility, complexity, and maintainablity concerns, so would
require further discussion.

The IPC protocol used is [Cap'n Proto](https://capnproto.org/), but the protocol
could be swapped out for another protocol (such as JSON-RPC with long polling)
without changing any code outside of the `src/ipc/` directory. No Cap'n Proto
types are used or headers included in any public interface.

Here are the important files in the `src/ipc/` directory:

Public Interfaces
-----------------

* `interfaces.h``Node`, `Wallet`, `Handler` interface definitions

* `client.h``StartClient` function to spawn a `bitcoind` process and
return a `Node` object controlling it through a socketpair.

* `server.h``StartServer` function to allow a `bitcoind` process to
open a socket file descriptor and respond to remote commands.

Other Files
-----------

* `interfaces.cpp – In-process implementations of `Node`, `Wallet`, `Handler`
interfaces.

* `client.cpp – IPC implementations of `Node`, `Wallet`, `Handler`
interfaces that forward calls to a socket.

* `server.cpp – IPC implementation responding to client requests.

* `messages.capnp – IPC interface definition.

* `serialize.{h,cpp}` – Helper functions for translating IPC messages.

* `util.{h,cpp}` – Helper functions for making and receiving IPC calls.
Loading

0 comments on commit 0ca73bc

Please sign in to comment.