void Peer::handle_read(const system::error_code& e, std::size_t bytes_transferred) { log_trace("args error: %s, bytes: %d", e.message(), bytes_transferred); if (!e) { _activity = true; string rx; for(int i = 0; i < bytes_transferred; i++) rx.push_back(_buffer[i]); vRecv += rx; // Now call the parser: bool fRet = false; loop { boost::tuple<boost::tribool, CDataStream::iterator> parser_result = _msgParser.parse(_chain, _message, vRecv.begin(), vRecv.end()); tribool result = get<0>(parser_result); vRecv.erase(vRecv.begin(), get<1>(parser_result)); if (result) { if (_messageHandler.handleMessage(this, _message) ) fRet = true; } else if (!result) { log_warn("Peer %s sending bogus - disconnecting", addr.toString()); _peerManager.post_stop(shared_from_this()); }// continue; // basically, if we get a false result, we should consider to disconnect from the Peer! else break; } // now if fRet is true, something were processed by the filters - we want to send to the peers / we check for which vSends cointains stuff and the we run if (fRet && nVersion > 0) { // first reply reply(); // then trickle Peers peers = _peerManager.getAllPeers(); size_t rand = GetRand(peers.size()); for (Peers::iterator peer = peers.begin(); peer != peers.end(); ++peer) if(rand-- == 0) { (*peer)->trickle(); break; } // then broadcast for (Peers::iterator peer = peers.begin(); peer != peers.end(); ++peer) (*peer)->broadcast(); // now write to the peers with non-empty vSend buffers for (Peers::iterator peer = peers.begin(); peer != peers.end(); ++peer) { (*peer)->flush(); } } // then wait for more data _socket.async_read_some(buffer(_buffer), boost::bind(&Peer::handle_read, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); // async_read(_socket, _recv, boost::bind(&Peer::handle_read, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); }
/** accepts and keeps track of connections. reads data from connected peers and notifies through virtual methods if packets can be deserialized \param tls use GnuTLS for encryption \param port listen for incoming connections at this port \param maxPeers maximum number of connected peers */ void serve(bool tls, int port, int maxPeers) { if (tls) sock.reset(new TLSSocket()); else sock.reset(new Socket()); sock->setNonBlocking(); sock->bind(port); sock->listen(maxPeers); Select select; /* Wait for a peer, send data and term */ while (!closed) { select.reset(); if (peers.size() < maxPeers) select.input(sock->getFd()); for (typename Peers::iterator i = peers.begin(); i != peers.end(); i++) { select.input((*i)->getFd()); } if (select.select(100) == -1) continue; if (select.canRead(sock->getFd()) && peers.size() < maxPeers) { try { Socket* csock = sock->accept(); if (tls) { boost::threadpool::schedule(pool, boost::bind(&Server::handshake, this, csock)); } else { peers.push_back(boost::shared_ptr<PeerT>(new PeerT())); csock->setNonBlocking(); peers.back()->setup(csock); onJoin(*peers.back()); } } catch (SocketExcept& e) { std::cerr << e.what() << std::endl; } } if (tls) { Socket* sock = NULL; socketsReady.try_pop_front(sock); if (sock) { sock->setNonBlocking(); peers.push_back(boost::shared_ptr<PeerT>(new PeerT())); peers.back()->setup(sock); onJoin(*peers.back()); } } for (size_t i = 0; i < peers.size(); i++) { boost::shared_ptr<PeerT>& p = peers[i]; if (select.canRead(p->getFd())) p->onInput(); while (p->hasPacket()) { onPacket(*p); } } // collect dead peers size_t count = peers.size(); for (size_t i = 0; i < count; ) { if (!peers[i]->isActive()) { onLeave(*peers[i]); peers[i] = peers[peers.size() - 1]; count--; } else i++; } if (count < peers.size()) { peers.resize(count); } } }