fc::variants parse_recognized_interactive_command( fc::buffered_istream& argument_stream, const rpc_server::method_data& method_data) { fc::variants arguments; for (unsigned i = 0; i < method_data.parameters.size(); ++i) { try { arguments.push_back(_self->parse_argument_of_known_type(argument_stream, method_data, i)); } catch( const fc::eof_exception& e ) { if (method_data.parameters[i].classification != rpc_server::required_positional) return arguments; else FC_THROW("Missing argument ${argument_number} of command \"${command}\"", ("argument_number", i + 1)("command", method_data.name)("cause",e.to_detail_string()) ); } catch( fc::parse_error_exception& e ) { FC_RETHROW_EXCEPTION(e, error, "Error parsing argument ${argument_number} of command \"${command}\": ${detail}", ("argument_number", i + 1)("command", method_data.name)("detail", e.get_log())); } if (method_data.parameters[i].classification == rpc_server::optional_named) break; } return arguments; }
void detail::process_impl::exec(const fc::path& exe, vector<string> args, const fc::path& work_dir /* = fc::path() */, fc::iprocess::exec_opts opts /* = open_all */) { chan = sshc->my->open_channel(""); sshc->my->call_ssh2_function(boost::bind(libssh2_channel_handle_extended_data2, chan, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL)); try { fc::scoped_lock<fc::mutex> process_startup_lock(sshc->my->process_startup_mutex); fc::string command_line = sshc->my->remote_system_is_windows ? windows_shell_escape_command(exe, args) : unix_shell_escape_command(exe, args); sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_process_startup, chan, "exec", sizeof("exec") - 1, command_line.c_str(), command_line.size()), "exec failed: ${message}"); // equiv to libssh2_channel_exec(chan, cmd) macro } catch (fc::exception& er) { elog( "error starting process" ); FC_RETHROW_EXCEPTION(er, error, "error starting process"); } }
// Parse the given line into a command and arguments, returning them in the form our // json-rpc server functions require them. void parse_json_command(const std::string& line_to_parse, std::string& command, fc::variants& arguments) { // the first whitespace-separated token on the line should be an un-quoted // JSON-RPC command name command.clear(); arguments.clear(); std::string::const_iterator iter = std::find_if(line_to_parse.begin(), line_to_parse.end(), ::isspace); if (iter != line_to_parse.end()) { // then there are arguments to this function size_t first_space_pos = iter - line_to_parse.begin(); command = line_to_parse.substr(0, first_space_pos); fc::istream_ptr argument_stream = std::make_shared<fc::stringstream>((line_to_parse.substr(first_space_pos + 1))); fc::buffered_istream buffered_argument_stream(argument_stream); while (1) { try { arguments.emplace_back(fc::json::from_stream(buffered_argument_stream)); } catch (fc::eof_exception&) { break; } catch (fc::parse_error_exception& e) { FC_RETHROW_EXCEPTION(e, error, "Error parsing argument ${argument_number} of command \"${command}\": ${detail}", ("argument_number", arguments.size() + 1)("command", command)("detail", e.get_log())); } } } else { // no arguments command = line_to_parse; } }
void message_oriented_connection_impl::read_loop() { const int BUFFER_SIZE = 16; const int LEFTOVER = BUFFER_SIZE - sizeof(message_header); assert(BUFFER_SIZE >= sizeof(message_header)); _connected_time = fc::time_point::now(); try { message m; while( true ) { char buffer[BUFFER_SIZE]; _sock.read(buffer, BUFFER_SIZE); _bytes_received += BUFFER_SIZE; memcpy((char*)&m, buffer, sizeof(message_header)); assert( m.size <= MAX_MESSAGE_SIZE ); size_t remaining_bytes_with_padding = 16 * ((m.size - LEFTOVER + 15) / 16); m.data.resize(LEFTOVER + remaining_bytes_with_padding); //give extra 16 bytes to allow for padding added in send call std::copy(buffer + sizeof(message_header), buffer + sizeof(buffer), m.data.begin()); if (remaining_bytes_with_padding) { _sock.read(&m.data[LEFTOVER], remaining_bytes_with_padding); _bytes_received += remaining_bytes_with_padding; } m.data.resize(m.size); // truncate off the padding bytes _last_message_received_time = fc::time_point::now(); try { // message handling errors are warnings... _delegate->on_message(_self, m); } /// Dedicated catches needed to distinguish from general fc::exception catch ( fc::canceled_exception& e ) { throw e; } catch ( fc::eof_exception& e ) { throw e; } catch ( fc::exception& e ) { /// Here loop should be continued so exception should be just caught locally. wlog( "message transmission failed ${er}", ("er", e.to_detail_string() ) ); } } } catch ( const fc::canceled_exception& e ) { wlog( "disconnected ${e}", ("e", e.to_detail_string() ) ); _delegate->on_connection_closed(_self); } catch ( const fc::eof_exception& e ) { wlog( "disconnected ${e}", ("e", e.to_detail_string() ) ); _delegate->on_connection_closed(_self); } catch ( fc::exception& e ) { elog( "disconnected ${er}", ("er", e.to_detail_string() ) ); _delegate->on_connection_closed(_self); FC_RETHROW_EXCEPTION( e, warn, "disconnected ${e}", ("e", e.to_detail_string() ) ); } catch ( ... ) { _delegate->on_connection_closed(_self); FC_THROW_EXCEPTION( fc::unhandled_exception, "disconnected: {e}", ("e", fc::except_str() ) ); } }
void read_loop() { const int BUFFER_SIZE = 16; const int LEFTOVER = BUFFER_SIZE - sizeof(message_header); try { message m; while( !_read_loop_complete.canceled() ) { char tmp[BUFFER_SIZE]; sock->read( tmp, BUFFER_SIZE ); memcpy( (char*)&m, tmp, sizeof(message_header) ); m.data.resize( m.size + 16 ); //give extra 16 bytes to allow for padding added in send call memcpy( (char*)m.data.data(), tmp + sizeof(message_header), LEFTOVER ); sock->read( m.data.data() + LEFTOVER, 16*((m.size -LEFTOVER + 15)/16) ); m.data.resize(m.size); try { // message handling errors are warnings... con_del->on_connection_message( self, m ); } catch ( fc::canceled_exception& e ) { wlog(".");throw; } catch ( fc::eof_exception& e ) { wlog(".");throw; } catch ( fc::exception& e ) { wlog( "disconnected ${er}", ("er", e.to_detail_string() ) ); return; // TODO: log and potentiall disconnect... for now just warn. } catch( ... ) { wlog("...????" ); return; } } } catch ( const fc::canceled_exception& e ) { if( con_del ) { con_del->on_connection_disconnected( self ); } else { wlog( "disconnected ${e}", ("e", e.to_detail_string() ) ); } wlog( "exit read loop" ); return; } catch ( const fc::eof_exception& e ) { if( con_del ) { ilog( "."); fc::async( [=](){con_del->on_connection_disconnected( self );} ); ilog( "."); } else { wlog( "disconnected ${e}", ("e", e.to_detail_string() ) ); } } catch ( fc::exception& er ) { wlog( ".." ); if( con_del ) { elog( "disconnected ${er}", ("er", er.to_detail_string() ) ); //con_del->on_connection_disconnected( self ); fc::async( [=](){con_del->on_connection_disconnected( self );} ); } else { elog( "disconnected ${e}", ("e", er.to_detail_string() ) ); } FC_RETHROW_EXCEPTION( er, warn, "disconnected ${e}", ("e", er.to_detail_string() ) ); } catch ( ... ) { wlog( "unhandled??" ); // TODO: call con_del->???? FC_THROW_EXCEPTION( unhandled_exception, "disconnected: {e}", ("e", fc::except_str() ) ); } }
void gntp_notifier_impl::send_gntp_message(const std::string& message) { std::shared_ptr<boost::asio::ip::tcp::socket> sock(new boost::asio::ip::tcp::socket(asio::default_io_service())); bool connected = false; if (endpoint) { // we've successfully connected before, connect to the same endpoint that worked last time try { asio::tcp::connect(*sock, *endpoint); connected = true; } catch (exception& er) { ilog("Failed to connect to GNTP service using an endpoint that previously worked: ${error_report}", ("error_report", er.to_detail_string())); sock->close(); // clear the cached endpoint and fall through to the full connection procedure endpoint = optional<boost::asio::ip::tcp::endpoint>(); } catch (...) { ilog("Failed to connect to GNTP service using an endpoint that previously worked"); sock->close(); // clear the cached endpoint and fall through to the full connection procedure endpoint = optional<boost::asio::ip::tcp::endpoint>(); } } if (!connected) { // do the full connection procedure auto eps = asio::tcp::resolve(hostname, boost::lexical_cast<std::string>(port)); if (eps.size() == 0) FC_THROW("Unable to resolve host '${host}'", ("host", hostname)); for (uint32_t i = 0; i < eps.size(); ++i) { try { boost::system::error_code ec; ilog("Attempting to connect to GNTP srvice"); asio::tcp::connect(*sock, eps[i]); endpoint = eps[i]; connected = true; break; } catch (const exception& er) { ilog("Failed to connect to GNTP service: ${error_reprot}", ("error_report", er.to_detail_string()) ); sock->close(); } catch (...) { ilog("Failed to connect to GNTP service"); sock->close(); } } } if (!connected) FC_THROW("Unable to connect to any resolved endpoint for ${host}:${port}", ("host", hostname)("port", port)); try { asio::ostream<boost::asio::ip::tcp::socket> write_stream(sock); write_stream.write(message.c_str(), message.size()); write_stream.flush(); write_stream.close(); } catch (exception& er) { FC_RETHROW_EXCEPTION(er, warn, "Caught an exception while sending data to GNTP service"); } catch (...) { FC_THROW("Caught an exception while sending data to GNTP service"); } }
void mutex::lock() { fc::context* current_context = fc::thread::current().my->current; if( !current_context ) current_context = fc::thread::current().my->current = new fc::context( &fc::thread::current() ); { fc::unique_lock<fc::spin_yield_lock> lock(m_blist_lock); if( !m_blist ) { // nobody else owns the mutex, so we get it; add our context as the last and only element on the mutex's list m_blist = current_context; assert(!current_context->next_blocked_mutex); return; } // allow recusive locks fc::context* dummy_context_to_unblock = 0; if ( get_tail( m_blist, dummy_context_to_unblock ) == current_context ) { // if we already have the lock (meaning we're on the tail of the list) then // we shouldn't be trying to grab the lock again assert(false); // EMF: I think recursive locks are currently broken -- we need to // keep track of how many times this mutex has been locked by the // current context. Unlocking should decrement this count and unblock // the next context only if the count drops to zero return; } // add ourselves to the head of the list current_context->next_blocked_mutex = m_blist; m_blist = current_context; #if 0 int cnt = 0; auto i = m_blist; while( i ) { i = i->next_blocked_mutex; ++cnt; } //wlog( "wait queue len %1%", cnt ); #endif } try { fc::thread::current().yield(false); // if yield() returned normally, we should now own the lock (we should be at the tail of the list) BOOST_ASSERT( current_context->next_blocked_mutex == 0 ); } catch ( exception& e ) { wlog( "lock threw: ${e}", ("e", e)); cleanup( *this, m_blist_lock, m_blist, current_context); FC_RETHROW_EXCEPTION(e, warn, "lock threw: ${e}", ("e", e)); } catch ( ... ) { wlog( "lock threw unexpected exception" ); cleanup( *this, m_blist_lock, m_blist, current_context); throw; } }
fc::variant parse_argument_of_known_type( fc::buffered_istream& argument_stream, const rpc_server::method_data& method_data, unsigned parameter_index) { const rpc_server::parameter_data& this_parameter = method_data.parameters[parameter_index]; if (this_parameter.type == "asset") { // for now, accept plain int, assume it's always in the base asset uint64_t amount_as_int; try { fc::variant amount_as_variant = fc::json::from_stream(argument_stream); amount_as_int = amount_as_variant.as_uint64(); } catch( fc::bad_cast_exception& e ) { FC_RETHROW_EXCEPTION(e, error, "Error parsing argument ${argument_number} of command \"${command}\": ${detail}", ("argument_number", parameter_index + 1)("command", method_data.name)("detail", e.get_log())); } catch( fc::parse_error_exception& e ) { FC_RETHROW_EXCEPTION(e, error, "Error parsing argument ${argument_number} of command \"${command}\": ${detail}", ("argument_number", parameter_index + 1)("command", method_data.name)("detail", e.get_log())); } return fc::variant(bts::blockchain::asset(amount_as_int)); } else if (this_parameter.type == "address") { // allow addresses to be un-quoted while( isspace(argument_stream.peek()) ) argument_stream.get(); fc::stringstream address_stream; try { while( !isspace(argument_stream.peek()) ) address_stream.put(argument_stream.get()); } catch( const fc::eof_exception& ) { // expected and ignored } std::string address_string = address_stream.str(); try { bts::blockchain::address::is_valid(address_string); } catch( fc::exception& e ) { FC_RETHROW_EXCEPTION(e, error, "Error parsing argument ${argument_number} of command \"${command}\": ${detail}", ("argument_number", parameter_index + 1)("command", method_data.name)("detail", e.get_log())); } return fc::variant( bts::blockchain::address(address_string) ); } else { // assume it's raw JSON try { return fc::json::from_stream( argument_stream ); } catch( fc::parse_error_exception& e ) { FC_RETHROW_EXCEPTION(e, error, "Error parsing argument ${argument_number} of command \"${command}\": ${detail}", ("argument_number", parameter_index + 1)("command", method_data.name)("detail", e.get_log())); } } }