PageRenderTime 28ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/legacy/libdissent/network.cc

https://github.com/brainburn/Dissent
C++ | 662 lines | 511 code | 94 blank | 57 comment | 93 complexity | 5d621598c12dc698ea783a2e3abd642d MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0
  1. /* libdissent/network.cc
  2. Network layer (w/ signing and logging) for dissent protocol.
  3. Author: Shu-Chun Weng <scweng _AT_ cs .DOT. yale *DOT* edu>
  4. */
  5. /* ====================================================================
  6. * Dissent: Accountable Group Anonymity
  7. * Copyright (c) 2010 Yale University.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to
  21. *
  22. * Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor,
  24. * Boston, MA 02110-1301 USA
  25. */
  26. #include "network.hpp"
  27. #include <QtGlobal>
  28. #include <QAbstractSocket>
  29. #include <QCoreApplication>
  30. #include <QHostAddress>
  31. #include <QHostInfo>
  32. #include <QSet>
  33. #include <QSignalMapper>
  34. #include <QTcpServer>
  35. #include <QTcpSocket>
  36. #include <QTimer>
  37. #include <QVariant>
  38. #include <cstdio>
  39. #include "QByteArrayUtil.hpp"
  40. #include "config.hpp"
  41. #include "crypto.hpp"
  42. #include "random_util.hpp"
  43. namespace Dissent{
  44. const int Network::MulticastNodeId;
  45. Network::Network(Configuration* config)
  46. : _config(config),
  47. _multicast(0),
  48. _isReady(false),
  49. _inReceivingPhase(false),
  50. _nonce(-1){
  51. _prepare = new NetworkPrepare(config, &_server, &_clients);
  52. connect(_prepare, SIGNAL(networkReady()),
  53. this, SLOT(NetworkReady()));
  54. _prepare->DoPrepare(
  55. QHostAddress::Any,
  56. config->nodes[config->my_node_id].port);
  57. }
  58. void Network::ResetSession(qint32 nonce){
  59. _nonce = nonce;
  60. ClearLog();
  61. // clear accumulative hash
  62. }
  63. int Network::Send(int node_id, const QByteArray& data){
  64. QTcpSocket* socket = _clients[node_id];
  65. Q_ASSERT(socket);
  66. Q_ASSERT(socket->state() == QAbstractSocket::ConnectedState);
  67. QByteArray plaintext, sig;
  68. PrepareMessage(LogEntry::SEND, data, &plaintext, &sig);
  69. int w_count = socket->write(plaintext);
  70. w_count += socket->write(sig);
  71. Q_ASSERT(w_count == plaintext.size() + sig.size());
  72. //printf("To %d: %s\n", node_id, (char*) plaintext.toHex().data());
  73. //printf("Sig: %s\n", (char*) sig.toHex().data());
  74. //printf("-> %s:%d\n",
  75. // (char*) socket->peerAddress().toString().toUtf8().data(),
  76. // socket->peerPort());
  77. LogEntry log = { LogEntry::SEND, node_id, _nonce, data, sig, true };
  78. _log.push_back(log);
  79. return w_count;
  80. }
  81. int Network::Broadcast(const QByteArray& data){
  82. QByteArray plaintext, sig;
  83. PrepareMessage(LogEntry::BROADCAST_SEND, data, &plaintext, &sig);
  84. foreach(const NodeInfo& node, _config->nodes)
  85. if(node.node_id != _config->my_node_id && !node.excluded){
  86. QTcpSocket* socket = _clients[node.node_id];
  87. Q_ASSERT_X(socket, "Network::Broadcast",
  88. (const char*) QString("socket[%1] = null")
  89. .arg(node.node_id).toUtf8().data());
  90. Q_ASSERT_X(socket->state() == QAbstractSocket::ConnectedState,
  91. "Network::Broadcast",
  92. (const char*) QString("socket[%1] wrong state")
  93. .arg(node.node_id).toUtf8().data());
  94. int w_count = socket->write(plaintext);
  95. w_count += socket->write(sig);
  96. Q_ASSERT(w_count == plaintext.size() + sig.size());
  97. }
  98. LogEntry log = { LogEntry::BROADCAST_SEND, -1, _nonce, data, sig, true };
  99. _log.push_back(log);
  100. return plaintext.size() + sig.size();
  101. }
  102. int Network::MulticastXor(const QByteArray& data){
  103. Q_ASSERT(_multicast == 0);
  104. const int collector_node_id = _config->topology.front().node_id;
  105. if(collector_node_id == _config->my_node_id){
  106. _multicast = new MulticastXorProcessor(this, _config->num_nodes, data);
  107. connect(_multicast, SIGNAL(multicastReady(QByteArray)),
  108. this, SLOT(MulticastReady(QByteArray)), Qt::QueuedConnection);
  109. connect(_multicast, SIGNAL(multicastError(int, QString)),
  110. this, SLOT(MulticastError(int, QString)));
  111. while(_multicastBuffer.size()){
  112. Q_ASSERT(_multicastBuffer.front().status == Buffer::DONE);
  113. const LogEntry& entry = _multicastBuffer.front().entry;
  114. _multicast->EnterMessage(entry.node_id, entry.data);
  115. _multicastBuffer.pop_front();
  116. }
  117. return data.size();
  118. }
  119. QTcpSocket* socket = _clients[collector_node_id];
  120. Q_ASSERT(socket);
  121. Q_ASSERT(socket->state() == QAbstractSocket::ConnectedState);
  122. QByteArray plaintext, sig;
  123. PrepareMessage(LogEntry::MULTICAST, data, &plaintext, &sig);
  124. int w_count = socket->write(plaintext);
  125. w_count += socket->write(sig);
  126. Q_ASSERT(w_count == plaintext.size() + sig.size());
  127. LogEntry log = { LogEntry::MULTICAST, collector_node_id,
  128. _nonce, data, sig, true };
  129. _log.push_back(log);
  130. return w_count;
  131. }
  132. int Network::Read(int node_id, QByteArray* data){
  133. QList<Buffer>& buffer = _buffers[node_id];
  134. while(buffer.size() > 0 && buffer.front().status == Buffer::DONE){
  135. const Buffer& buf = buffer.front();
  136. const bool valid = buf.entry.valid;
  137. int nonce = buf.entry.nonce;
  138. *data = buf.entry.data;
  139. _log.push_back(buf.entry);
  140. buffer.pop_front(); // now we can drop it from buffer
  141. if(nonce != _nonce) fprintf(stderr, "Invalid nonce\n");
  142. if(valid && nonce == _nonce)
  143. return 1;
  144. }
  145. return 0;
  146. }
  147. void Network::PrepareMessage(int type, const QByteArray& data,
  148. QByteArray* message, QByteArray* sig){
  149. // Updates of this function should pair up with updates of
  150. // ValidateLogEntry() and ClientHasReadyRead()
  151. message->clear();
  152. QByteArrayUtil::AppendInt(type, message);
  153. QByteArrayUtil::AppendInt(_nonce, message);
  154. // TODO(scw): how to accumulate hash?
  155. message->append(data);
  156. bool r = Crypto::GetInstance()->Sign(&_config->identity_sk,
  157. *message, sig);
  158. Q_ASSERT_X(r, "Network::PrepareMessage", "message signing failed");
  159. int message_length = message->size();
  160. QByteArrayUtil::PrependInt(sig->size(), message);
  161. QByteArrayUtil::PrependInt(message_length, message);
  162. }
  163. bool Network::ValidateLogEntry(LogEntry* entry){
  164. // Updates of this function should pair up with updates of
  165. // PrepareMessage() and ClientHasReadyRead()
  166. bool valid_sig = Crypto::GetInstance()->Verify(
  167. &_config->nodes[entry->node_id].identity_pk,
  168. entry->data,
  169. entry->signature);
  170. entry->dir = static_cast<LogEntry::Dir>(
  171. QByteArrayUtil::ExtractInt(true, &entry->data));
  172. entry->nonce =
  173. QByteArrayUtil::ExtractInt(true, &entry->data);
  174. bool valid_dir = (entry->dir == LogEntry::SEND ||
  175. entry->dir == LogEntry::BROADCAST_SEND ||
  176. entry->dir == LogEntry::MULTICAST ||
  177. entry->dir == LogEntry::MULTICAST_FINAL);
  178. if(entry->dir == LogEntry::SEND)
  179. entry->dir = LogEntry::RECV;
  180. else if(entry->dir == LogEntry::BROADCAST_SEND)
  181. entry->dir = LogEntry::BROADCAST_RECV;
  182. if(!valid_sig) fprintf(stderr, "Invalid signature\n");
  183. if(!valid_dir) fprintf(stderr, "Invalid direction\n");
  184. return entry->valid = (valid_sig && valid_dir);
  185. }
  186. void Network::ClientHasReadyRead(int node_id){
  187. // Updates of this function should pair up with updates of
  188. // PrepareMessage() and ValidateLogEntry()
  189. if(_config->nodes[node_id].excluded)
  190. return;
  191. QMap<int, QTcpSocket*>::const_iterator it = _clients.constFind(node_id);
  192. if(it == _clients.constEnd())
  193. qFatal("Unknown client notifying ready");
  194. QTcpSocket* socket = it.value();
  195. QList<Buffer>& buffer = _buffers[node_id];
  196. if(buffer.size() == 0 || buffer.back().status == Buffer::DONE)
  197. buffer.push_back(Buffer());
  198. Buffer& buf = buffer.back();
  199. QByteArray byte_array;
  200. switch(buf.status){
  201. case Buffer::NEW:
  202. if(socket->bytesAvailable() < QByteArrayUtil::IntegerSize * 2)
  203. return;
  204. byte_array = socket->read(QByteArrayUtil::IntegerSize * 2);
  205. buf.data_len = QByteArrayUtil::ExtractInt(true, &byte_array);
  206. buf.sig_len = QByteArrayUtil::ExtractInt(true, &byte_array);
  207. buf.status = Buffer::HAS_SIZE;
  208. // fall through
  209. case Buffer::HAS_SIZE:
  210. if(socket->bytesAvailable() < buf.data_len)
  211. return;
  212. buf.entry.data = socket->read(buf.data_len);
  213. buf.status = Buffer::DATA_DONE;
  214. // fprintf(stderr, "<%d> %s\n", node_id, (char*) buf.entry.data.toHex().data());
  215. // fall through
  216. case Buffer::DATA_DONE:
  217. if(socket->bytesAvailable() < buf.sig_len)
  218. return;
  219. buf.entry.signature = socket->read(buf.sig_len);
  220. buf.entry.node_id = node_id;
  221. buf.status = Buffer::DONE;
  222. // fprintf(stderr, "s%d> %s\n", node_id, (char*) buf.entry.signature.toHex().data());
  223. if(!ValidateLogEntry(&buf.entry)){
  224. fprintf(stderr,
  225. "Package from node %d cannot be validated\n"
  226. ">> %s\n", node_id, buf.entry.data.toHex().data());
  227. break;
  228. }else if(buf.entry.dir == LogEntry::MULTICAST){
  229. if(_config->topology.front().node_id !=
  230. _config->my_node_id){
  231. fprintf(stderr,
  232. "multicast message from node %d to non-leader\n",
  233. node_id);
  234. break;
  235. }
  236. if(!_multicast){
  237. _multicastBuffer.push_back(buf);
  238. buffer.pop_back();
  239. // No consumer, log it ourselves and pop off
  240. _log.push_back(buf.entry);
  241. }else{
  242. Q_ASSERT_X(_multicastBuffer.size() == 0,
  243. "Network::ClientHasReadyRead",
  244. "multicast and multicast buffer shouldn't"
  245. " coexist");
  246. LogEntry entry = buf.entry;
  247. buffer.pop_back();
  248. _multicast->EnterMessage(node_id, entry.data);
  249. // No consumer, log it ourselves and pop off
  250. _log.push_back(entry);
  251. }
  252. break;
  253. }else if(buf.entry.dir == LogEntry::MULTICAST_FINAL){
  254. node_id = MulticastNodeId;
  255. _buffers[MulticastNodeId].push_back(buf);
  256. buffer.pop_back();
  257. }
  258. if(_inReceivingPhase){
  259. emit readyRead(node_id);
  260. }
  261. break;
  262. default:
  263. qFatal("Invalid buf.status: %d\n", buf.status);
  264. break;
  265. }
  266. // XXX(scw): change tail recursion to loop
  267. if(socket->bytesAvailable() > 0)
  268. ClientHasReadyRead(node_id);
  269. }
  270. void Network::WaitForBytesWritten(){
  271. foreach(const NodeInfo& node, _config->nodes)
  272. if(node.node_id != _config->my_node_id && !node.excluded){
  273. QTcpSocket* socket = _clients[node.node_id];
  274. Q_ASSERT_X(socket, "Network::WaitForBytesWritten",
  275. (const char*) QString("socket[%1] = null")
  276. .arg(node.node_id).toUtf8().data());
  277. while(socket->state() == QAbstractSocket::ConnectedState &&
  278. socket->bytesToWrite() > 0){
  279. qApp->processEvents();
  280. socket->flush();
  281. socket->waitForBytesWritten(-1);
  282. }
  283. }
  284. }
  285. void Network::NetworkReady(){
  286. // Or keep it so that hosts can reconnect if connection dropped?
  287. delete _prepare; _prepare = 0;
  288. _signalMapper = new QSignalMapper(this);
  289. connect(_signalMapper, SIGNAL(mapped(int)),
  290. this, SLOT(ClientHasReadyRead(int)));
  291. _clientNodeId.clear();
  292. for(QMap<int, QTcpSocket*>::const_iterator it = _clients.constBegin();
  293. it != _clients.constEnd(); ++it){
  294. _buffers.insert(it.key(), QList<Buffer>());
  295. _clientNodeId.insert(it.value(), it.key());
  296. _signalMapper->setMapping(it.value(), it.key());
  297. connect(it.value(), SIGNAL(readyRead()),
  298. _signalMapper, SLOT(map()));
  299. ClientHasReadyRead(it.key());
  300. }
  301. _buffers.insert(MulticastNodeId, QList<Buffer>());
  302. _isReady = true;
  303. emit networkReady();
  304. connect(qApp, SIGNAL(aboutToQuit()),
  305. this, SLOT(TearDown()));
  306. }
  307. void Network::MulticastReady(QByteArray data){
  308. delete _multicast;
  309. _multicast = 0;
  310. QByteArray plaintext, sig;
  311. PrepareMessage(LogEntry::MULTICAST_FINAL, data, &plaintext, &sig);
  312. foreach(const NodeInfo& node, _config->nodes)
  313. if(node.node_id != _config->my_node_id && !node.excluded){
  314. QTcpSocket* socket = _clients[node.node_id];
  315. Q_ASSERT_X(socket, "Network::MulticastReady",
  316. (const char*) QString("socket[%1] = null")
  317. .arg(node.node_id).toUtf8().data());
  318. Q_ASSERT_X(socket->state() == QAbstractSocket::ConnectedState,
  319. "Network::MulticastReady",
  320. (const char*) QString("socket[%1] wrong state")
  321. .arg(node.node_id).toUtf8().data());
  322. int w_count = socket->write(plaintext);
  323. w_count += socket->write(sig);
  324. Q_ASSERT(w_count == plaintext.size() + sig.size());
  325. }
  326. LogEntry entry = { LogEntry::MULTICAST_FINAL, -1, _nonce, data, sig, true };
  327. Buffer buffer;
  328. buffer.status = Buffer::DONE;
  329. buffer.entry = entry;
  330. _buffers[MulticastNodeId].push_back(buffer);
  331. if(_isReady)
  332. emit readyRead(MulticastNodeId);
  333. }
  334. void Network::MulticastError(int node_id, const QString& reason){
  335. emit inputError(node_id, reason);
  336. }
  337. void Network::TearDown(){
  338. WaitForBytesWritten();
  339. for(QMap<int, QTcpSocket*>::const_iterator it = _clients.constBegin();
  340. it != _clients.constEnd(); ++it)
  341. it.value()->close();
  342. }
  343. void Network::StartIncomingNetwork(){
  344. if(_inReceivingPhase)
  345. return;
  346. // fprintf(stderr, "starting incoming network\n");
  347. _inReceivingPhase = true;
  348. for(QMap<int, QList<Buffer> >::const_iterator it = _buffers.constBegin();
  349. it != _buffers.constEnd(); ++it){
  350. // fprintf(stderr, "node %d: size = %d\n", it.key(), it.value().size());
  351. if(it.value().size() > 0 && it.value().front().status == Buffer::DONE){
  352. // fprintf(stderr, "node %d readyRead\n", it.key());
  353. emit readyRead(it.key());
  354. }
  355. }
  356. }
  357. void Network::StopIncomingNetwork(){
  358. _inReceivingPhase = false;
  359. }
  360. const char* const NetworkPrepare::ChallengePropertyName =
  361. "NetworkPrepareChallenge";
  362. const char* const NetworkPrepare::NodeIdPropertyName =
  363. "NetworkPrepareNodeId";
  364. const char* const NetworkPrepare::AnswerLengthPropertyName =
  365. "NetworkPrepareAnswerLength";
  366. const int NetworkPrepare::ChallengeLength = 64; // SHA-1 uses 512-bit blocks
  367. NetworkPrepare::NetworkPrepare(Configuration* config,
  368. QTcpServer* server,
  369. QMap<int, QTcpSocket*>* sockets)
  370. : _config(config), _server(server), _sockets(sockets) {}
  371. void NetworkPrepare::DoPrepare(const QHostAddress& address, quint16 port){
  372. connect(_server, SIGNAL(newConnection()),
  373. this, SLOT(NewConnection()));
  374. bool r = _server->listen(address, port);
  375. // fprintf(stderr, "%s:%d: %s\n",
  376. // address.toString().toUtf8().data(), port,
  377. // r ? "true" : "false");
  378. Q_ASSERT_X(r, "Network::Network(Configuration*)",
  379. _server->errorString().toUtf8().data());
  380. _incomeSignalMapper = new QSignalMapper(this);
  381. connect(_incomeSignalMapper, SIGNAL(mapped(QObject*)),
  382. this, SLOT(ReadNodeId(QObject*)));
  383. _answerSignalMapper = new QSignalMapper(this);
  384. connect(_answerSignalMapper, SIGNAL(mapped(QObject*)),
  385. this, SLOT(ReadChallengeAnswer(QObject*)));
  386. _connectSignalMapper = new QSignalMapper(this);
  387. _errorSignalMapper = new QSignalMapper(this);
  388. _challengeSignalMapper = new QSignalMapper(this);
  389. connect(_challengeSignalMapper, SIGNAL(mapped(QObject*)),
  390. this, SLOT(ReadChallenge(QObject*)));
  391. QTimer::singleShot(1000, this, SLOT(TryConnect()));
  392. }
  393. void NetworkPrepare::AddSocket(int node_id, QTcpSocket* socket){
  394. _sockets->insert(node_id, socket);
  395. if(_sockets->size() < _config->num_nodes - 1)
  396. return;
  397. for(QMap<int, NodeInfo>::const_iterator it = _config->nodes.constBegin();
  398. it != _config->nodes.constEnd(); ++it){
  399. if(it.key() == _config->my_node_id)
  400. continue;
  401. QMap<int, QTcpSocket*>::const_iterator jt =
  402. _sockets->constFind(it.key());
  403. if(jt == _sockets->constEnd())
  404. return;
  405. QTcpSocket* s = *jt;
  406. if(!s->isValid() || s->state() != QAbstractSocket::ConnectedState)
  407. return;
  408. }
  409. disconnect(_server, SIGNAL(newConnection()),
  410. this, SLOT(NewConnection()));
  411. emit networkReady();
  412. }
  413. void NetworkPrepare::NewConnection(){
  414. QTcpSocket* socket = _server->nextPendingConnection();
  415. char challenge[ChallengeLength];
  416. Random::GetInstance()->GetBlock(sizeof(challenge), challenge);
  417. QByteArray ba(challenge, sizeof(challenge));
  418. socket->setProperty(ChallengePropertyName, ba);
  419. _incomeSignalMapper->setMapping(socket, socket);
  420. connect(socket, SIGNAL(readyRead()), _incomeSignalMapper, SLOT(map()));
  421. socket->write(ba);
  422. }
  423. void NetworkPrepare::ReadNodeId(QObject* o){
  424. QTcpSocket* socket = qobject_cast<QTcpSocket*>(o);
  425. Q_ASSERT(socket);
  426. if(socket->bytesAvailable() < QByteArrayUtil::IntegerSize * 2)
  427. return;
  428. QByteArray data = socket->read(8);
  429. int node_id = QByteArrayUtil::ExtractInt(true, &data);
  430. int answer_length = QByteArrayUtil::ExtractInt(true, &data);
  431. QHostInfo remote = QHostInfo::fromName(_config->nodes[node_id].addr);
  432. if(!remote.addresses().contains(socket->peerAddress())){
  433. // XXX(scw): wrong host message
  434. fprintf(stderr, "peer %d expect from %s but from %s\n",
  435. node_id,
  436. (char*) _config->nodes[node_id].addr.toUtf8().data(),
  437. (char*) socket->peerAddress().toString().toUtf8().data());
  438. socket->disconnectFromHost();
  439. delete socket;
  440. return;
  441. }
  442. socket->setProperty(NodeIdPropertyName, node_id);
  443. socket->setProperty(AnswerLengthPropertyName, answer_length);
  444. _answerSignalMapper->setMapping(socket, socket);
  445. disconnect(socket, SIGNAL(readyRead()), _incomeSignalMapper, SLOT(map()));
  446. connect(socket, SIGNAL(readyRead()), _answerSignalMapper, SLOT(map()));
  447. ReadChallengeAnswer(o);
  448. }
  449. void NetworkPrepare::ReadChallengeAnswer(QObject* o){
  450. QTcpSocket* socket = qobject_cast<QTcpSocket*>(o);
  451. Q_ASSERT(socket);
  452. bool ok = false;
  453. int answer_length =
  454. socket->property(AnswerLengthPropertyName).toInt(&ok);
  455. Q_ASSERT_X(ok, "NetworkPrepare::ReadChallengeAnswer",
  456. "anser length property not an integer");
  457. if(socket->bytesAvailable() < answer_length)
  458. return;
  459. int node_id = socket->property(NodeIdPropertyName).toInt(&ok);
  460. Q_ASSERT_X(ok, "NetworkPrepare::ReadChallengeAnswer",
  461. "node id property not an integer");
  462. QByteArray challenge =
  463. socket->property(ChallengePropertyName).toByteArray();
  464. Q_ASSERT(challenge.size() == ChallengeLength);
  465. QByteArray answer = socket->read(answer_length);
  466. if(!Crypto::GetInstance()->Verify(
  467. &_config->nodes[node_id].identity_pk,
  468. challenge,
  469. answer)){
  470. // XXX(scw): challenge failed message
  471. fprintf(stderr, "node %d challenge failed\n", node_id);
  472. socket->disconnectFromHost();
  473. delete socket;
  474. return;
  475. }
  476. socket->setProperty(NodeIdPropertyName, QVariant());
  477. socket->setProperty(AnswerLengthPropertyName, QVariant());
  478. socket->setProperty(ChallengePropertyName, QVariant());
  479. disconnect(socket, SIGNAL(readyRead()),
  480. _answerSignalMapper, SLOT(map()));
  481. AddSocket(node_id, socket);
  482. }
  483. void NetworkPrepare::TryConnect(){
  484. connect(_connectSignalMapper, SIGNAL(mapped(QObject*)),
  485. this, SLOT(Connected(QObject*)));
  486. connect(_errorSignalMapper, SIGNAL(mapped(QObject*)),
  487. this, SLOT(ConnectError(QObject*)));
  488. foreach(const NodeInfo& node, _config->nodes){
  489. if(node.node_id >= _config->my_node_id)
  490. continue;
  491. QTcpSocket* socket = new QTcpSocket(_server);
  492. connect(socket, SIGNAL(connected()),
  493. _connectSignalMapper, SLOT(map()));
  494. connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
  495. _errorSignalMapper, SLOT(map()));
  496. _connectSignalMapper->setMapping(socket, socket);
  497. _errorSignalMapper->setMapping(socket, socket);
  498. socket->setProperty(NodeIdPropertyName, node.node_id);
  499. socket->connectToHost(node.addr, node.port);
  500. }
  501. }
  502. void NetworkPrepare::Connected(QObject* o){
  503. QTcpSocket* socket = qobject_cast<QTcpSocket*>(o);
  504. Q_ASSERT(socket);
  505. disconnect(socket, SIGNAL(connected()),
  506. _connectSignalMapper, SLOT(map()));
  507. disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
  508. _errorSignalMapper, SLOT(map()));
  509. _challengeSignalMapper->setMapping(socket, socket);
  510. connect(socket, SIGNAL(readyRead()),
  511. _challengeSignalMapper, SLOT(map()));
  512. ReadChallenge(o);
  513. }
  514. void NetworkPrepare::ConnectError(QObject* o){
  515. // XXX(scw): error message? retry count? wait before retry?
  516. QTcpSocket* socket = qobject_cast<QTcpSocket*>(o);
  517. Q_ASSERT(socket);
  518. bool ok = false;
  519. int node_id = socket->property(NodeIdPropertyName).toInt(&ok);
  520. Q_ASSERT_X(ok, "NetworkPrepare::ConnectError",
  521. "node id property not an integer");
  522. const NodeInfo& node = _config->nodes[node_id];
  523. socket->connectToHost(node.addr, node.port);
  524. }
  525. void NetworkPrepare::ReadChallenge(QObject* o){
  526. QTcpSocket* socket = qobject_cast<QTcpSocket*>(o);
  527. Q_ASSERT(socket);
  528. if(socket->bytesAvailable() < ChallengeLength)
  529. return;
  530. QByteArray challenge = socket->read(ChallengeLength);
  531. QByteArray answer;
  532. bool r = Crypto::GetInstance()->Sign(
  533. &_config->identity_sk, challenge, &answer);
  534. Q_ASSERT_X(r, "NetworkPrepare::ReadChallenge",
  535. "challeng signing failed");
  536. QByteArrayUtil::PrependInt(answer.size(), &answer);
  537. QByteArrayUtil::PrependInt(_config->my_node_id, &answer);
  538. socket->write(answer);
  539. bool ok = false;
  540. int node_id = socket->property(NodeIdPropertyName).toInt(&ok);
  541. Q_ASSERT_X(ok, "NetworkPrepare::ConnectError",
  542. "node id property not an integer");
  543. socket->setProperty(NodeIdPropertyName, QVariant());
  544. disconnect(socket, SIGNAL(readyRead()),
  545. _challengeSignalMapper, SLOT(map()));
  546. AddSocket(node_id, socket);
  547. }
  548. MulticastXorProcessor::MulticastXorProcessor(
  549. Network* network, int num_nodes, const QByteArray& self_data)
  550. : QObject(network), _numNodes(num_nodes), _data(self_data){}
  551. void MulticastXorProcessor::EnterMessage(
  552. int node_id, const QByteArray& data){
  553. if(_received.contains(node_id)){
  554. emit multicastError(node_id, "Multiple message from the same node");
  555. return;
  556. }
  557. char* p_d = _data.data();
  558. const char* p_s = data.constData();
  559. char* p_end = p_d + _data.size();
  560. for(; p_d < p_end; ++p_d, ++p_s)
  561. *p_d ^= *p_s;
  562. _received.insert(node_id);
  563. if(_received.size() == _numNodes - 1)
  564. emit multicastReady(_data);
  565. }
  566. }
  567. // -*- vim:sw=4:expandtab:cindent: