void protobuf_codec::handle_message(connection_ptr& conn) const { loki::buffer* buffer = conn->get_buffer(); while (buffer->data_size() >= MSG_NAME_LENGTH_SIZE + MIN_MSG_NAME_SIZE + MSG_HEADER_LENGTH) { const uint32_t flag = buffer->get<uint32_t>(); const uint32_t msg_len = flag & 0x0000ffff; if (msg_len + MSG_HEADER_LENGTH > buffer->data_size()) { //message not enough, wait break; } if (msg_len > MAX_MSG_LENGTH || msg_len < MSG_NAME_LENGTH_SIZE + MIN_MSG_NAME_SIZE) { LOG(ERROR)<<"message length error "<<msg_len<<",readable="<<buffer->data_size(); conn->close(); break; } char buff[MAX_MSG_LENGTH]; size_t len = sizeof(buff); LOG(INFO)<<__func__<<", flag="<<flag; bool ret = conn->restore_msg((const char*)buffer->data_ptr() + MSG_HEADER_LENGTH, flag, buff, len); if (!ret) { LOG(ERROR)<<"restore msg error"; conn->close(); break; } uint32_t errorcode = 0; MessagePtr message = parse(buff, len, errorcode); if (errorcode == 0 && message) { callback_(conn, message); buffer->consume(MSG_HEADER_LENGTH + msg_len); } else { LOG(ERROR)<<"Parse message error ,errorcode="<<errorcode; conn->close(); break; } } }
// close: - close this connection // close:all; close all connections void close_connection(connection_ptr connection) { if (connection){ connection->close(close::status::NORMAL); } else { typename std::set<connection_ptr>::iterator it; for (it = m_connections.begin(); it != m_connections.end(); it++) { (*it)->close(close::status::NORMAL); } } }
/** * Sends a close signal to every connection with the specified code and * reason. The default code is 1001/Going Away and the default reason is * blank. * * @param code The WebSocket close code to send to remote clients as the * reason that the connection is being closed. * @param reason The WebSocket close reason to send to remote clients as the * text reason that the connection is being closed. Must be valid UTF-8. */ void close_all(close::status::value code = close::status::GOING_AWAY, const std::string& reason = "") { boost::lock_guard<boost::recursive_mutex> lock(m_lock); m_alog->at(log::alevel::ENDPOINT) << "Endpoint received signal to close all connections cleanly with code " << code << " and reason " << reason << log::endl; // TODO: is there a more elegant way to do this? In some code paths // close can call terminate immediately which removes the connection // from m_connections, invalidating the iterator. typename std::set<connection_ptr>::iterator it; for (it = m_connections.begin(); it != m_connections.end();) { const connection_ptr con = *it++; con->close(code,reason); } }
/** * Received in response to get_headers message, we should certify that we requested this. */ void handle_headers( const connection_ptr& con, chan_data& cdat, const headers_message& msg ) { try { FC_ASSERT( !!cdat.requested_headers ); cdat.requested_headers.reset(); // TODO: validate that all ids reported have the min proof of work for a name. ilog( "received ${x} block headers", ("msg",msg.headers.size() ) ); _fork_db.cache_header( msg.first ); _new_block_info = true; name_id_type prev_id = msg.first.id(); for( auto itr = msg.headers.begin(); itr != msg.headers.end(); ++itr ) { name_header next_head( *itr, prev_id ); ilog( "${id} = ${next_head}", ("id",next_head.id())("next_head",next_head) ); _fork_db.cache_header( next_head ); prev_id = next_head.id(); if( prev_id > max_name_hash() ) { // then we should disconnect.... wlog( "node produced name header with insufficient minimum work" ); con->close(); return; } cdat.available_blocks.insert(prev_id); } if( prev_id != msg.head_block_id ) { cdat.requested_headers = fc::time_point::now(); get_headers_message request; request.locator_hashes.push_back( prev_id ); con->send( network::message( request, _chan_id ) ); } } FC_RETHROW_EXCEPTIONS( warn, "", ("msg",msg) ) }
/* Ends a test by canceling the timeout timer, marking the end time, generating * statistics and closing the websocket connection. */ void case_handler::end(connection_ptr con) { std::vector<double> avgs; avgs.resize(m_quantile_count, 0); std::vector<double> quantiles; quantiles.resize(m_quantile_count, 0); double avg = 0; double stddev = 0; double total = 0; double seconds = 0; if (m_timeout > 0) { m_timer->cancel(); } // TODO: handle weird sizes and error conditions better if (m_end.size() > m_quantile_count) { boost::chrono::steady_clock::time_point last = m_start; // convert RTTs to microsecs // std::vector<boost::chrono::steady_clock::time_point>::iterator it; for (it = m_end.begin(); it != m_end.end(); ++it) { boost::chrono::nanoseconds dur = *it - last; m_times.push_back(static_cast<double> (dur.count()) / 1000.); last = *it; } std::sort(m_times.begin(), m_times.end()); size_t samples_per_quantile = m_times.size() / m_quantile_count; // quantiles for (size_t i = 0; i < m_quantile_count; ++i) { quantiles[i] = m_times[((i + 1) * samples_per_quantile) - 1]; } // total average and quantile averages for (size_t i = 0; i < m_times.size(); ++i) { avg += m_times[i]; avgs[i / samples_per_quantile] += m_times[i] / static_cast<double>(samples_per_quantile); } avg /= static_cast<double> (m_times.size()); // standard dev corrected for estimation from sample for (size_t i = 0; i < m_times.size(); ++i) { stddev += (m_times[i] - avg) * (m_times[i] - avg); } // Bessel's correction stddev /= static_cast<double> (m_times.size() - 1); stddev = std::sqrt(stddev); } else { m_times.push_back(0); } boost::chrono::nanoseconds total_dur = m_end[m_end.size()-1] - m_start; total = static_cast<double> (total_dur.count()) / 1000.; // microsec seconds = total / 10000000.; std::stringstream s; std::string outcome; switch (m_pass) { case FAIL: outcome = "fail"; break; case PASS: outcome = "pass"; break; case TIME_OUT: outcome = "time_out"; break; case RUNNING: throw case_exception("end() called from RUNNING state"); break; } s << "{\"result\":\"" << outcome << "\",\"min\":" << m_times[0] << ",\"max\":" << m_times[m_times.size()-1] << ",\"median\":" << m_times[(m_times.size()-1)/2] << ",\"avg\":" << avg << ",\"stddev\":" << stddev << ",\"total\":" << total << ",\"bytes\":" << m_bytes << ",\"quantiles\":["; for (size_t i = 0; i < m_quantile_count; i++) { s << (i > 0 ? "," : ""); s << "["; s << avgs[i] << "," << quantiles[i]; s << "]"; } s << "]"; if (m_rtts) { s << ",\"rtts\":["; for (size_t i = 0; i < m_times.size(); i++) { s << (i > 0 ? "," : "") << m_times[i]; } s << "]"; }; s << "}"; m_data = s.str(); con->close(websocketpp::close::status::NORMAL,""); }