Merge #11726: Cleanups + nit fixes for walletdir PR
[bitcoinplatinum.git] / src / zmq / zmqpublishnotifier.cpp
blobacccb896c0d33bab830e6d65dc39ee342099e9a4
1 // Copyright (c) 2015-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include <chain.h>
6 #include <chainparams.h>
7 #include <streams.h>
8 #include <zmq/zmqpublishnotifier.h>
9 #include <validation.h>
10 #include <util.h>
11 #include <rpc/server.h>
13 static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
15 static const char *MSG_HASHBLOCK = "hashblock";
16 static const char *MSG_HASHTX = "hashtx";
17 static const char *MSG_RAWBLOCK = "rawblock";
18 static const char *MSG_RAWTX = "rawtx";
20 // Internal function to send multipart message
21 static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
23 va_list args;
24 va_start(args, size);
26 while (1)
28 zmq_msg_t msg;
30 int rc = zmq_msg_init_size(&msg, size);
31 if (rc != 0)
33 zmqError("Unable to initialize ZMQ msg");
34 va_end(args);
35 return -1;
38 void *buf = zmq_msg_data(&msg);
39 memcpy(buf, data, size);
41 data = va_arg(args, const void*);
43 rc = zmq_msg_send(&msg, sock, data ? ZMQ_SNDMORE : 0);
44 if (rc == -1)
46 zmqError("Unable to send ZMQ msg");
47 zmq_msg_close(&msg);
48 va_end(args);
49 return -1;
52 zmq_msg_close(&msg);
54 if (!data)
55 break;
57 size = va_arg(args, size_t);
59 va_end(args);
60 return 0;
63 bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
65 assert(!psocket);
67 // check if address is being used by other publish notifier
68 std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator i = mapPublishNotifiers.find(address);
70 if (i==mapPublishNotifiers.end())
72 psocket = zmq_socket(pcontext, ZMQ_PUB);
73 if (!psocket)
75 zmqError("Failed to create socket");
76 return false;
79 int rc = zmq_bind(psocket, address.c_str());
80 if (rc!=0)
82 zmqError("Failed to bind address");
83 zmq_close(psocket);
84 return false;
87 // register this notifier for the address, so it can be reused for other publish notifier
88 mapPublishNotifiers.insert(std::make_pair(address, this));
89 return true;
91 else
93 LogPrint(BCLog::ZMQ, "zmq: Reusing socket for address %s\n", address);
95 psocket = i->second->psocket;
96 mapPublishNotifiers.insert(std::make_pair(address, this));
98 return true;
102 void CZMQAbstractPublishNotifier::Shutdown()
104 assert(psocket);
106 int count = mapPublishNotifiers.count(address);
108 // remove this notifier from the list of publishers using this address
109 typedef std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator iterator;
110 std::pair<iterator, iterator> iterpair = mapPublishNotifiers.equal_range(address);
112 for (iterator it = iterpair.first; it != iterpair.second; ++it)
114 if (it->second==this)
116 mapPublishNotifiers.erase(it);
117 break;
121 if (count == 1)
123 LogPrint(BCLog::ZMQ, "Close socket at address %s\n", address);
124 int linger = 0;
125 zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger));
126 zmq_close(psocket);
129 psocket = nullptr;
132 bool CZMQAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size)
134 assert(psocket);
136 /* send three parts, command & data & a LE 4byte sequence number */
137 unsigned char msgseq[sizeof(uint32_t)];
138 WriteLE32(&msgseq[0], nSequence);
139 int rc = zmq_send_multipart(psocket, command, strlen(command), data, size, msgseq, (size_t)sizeof(uint32_t), nullptr);
140 if (rc == -1)
141 return false;
143 /* increment memory only sequence number after sending */
144 nSequence++;
146 return true;
149 bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
151 uint256 hash = pindex->GetBlockHash();
152 LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s\n", hash.GetHex());
153 char data[32];
154 for (unsigned int i = 0; i < 32; i++)
155 data[31 - i] = hash.begin()[i];
156 return SendMessage(MSG_HASHBLOCK, data, 32);
159 bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
161 uint256 hash = transaction.GetHash();
162 LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s\n", hash.GetHex());
163 char data[32];
164 for (unsigned int i = 0; i < 32; i++)
165 data[31 - i] = hash.begin()[i];
166 return SendMessage(MSG_HASHTX, data, 32);
169 bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex)
171 LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex());
173 const Consensus::Params& consensusParams = Params().GetConsensus();
174 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
176 LOCK(cs_main);
177 CBlock block;
178 if(!ReadBlockFromDisk(block, pindex, consensusParams))
180 zmqError("Can't read block from disk");
181 return false;
184 ss << block;
187 return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size());
190 bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
192 uint256 hash = transaction.GetHash();
193 LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s\n", hash.GetHex());
194 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
195 ss << transaction;
196 return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size());