diff --git a/CMakeLists.txt b/CMakeLists.txt index 36b2b3f..e269e91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ add_subdirectory(vendor) setup_library( fc SOURCES ${sources} ) #setup_executable( json_rpc_test SOURCES tests/json_rpc_test.cpp LIBRARIES fc ${ZLIB_LIBRARY} ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ${Boost_DATE_TIME_LIBRARY}) -#setup_executable( ssh_test SOURCES tests/ssh.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY}) +setup_executable( ssh_test SOURCES tests/ssh.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY}) setup_executable( logger_test SOURCES tests/logger.cpp LIBRARIES fc ${pthread_library} ${rt_library} ${Boost_THREAD_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${rt_library} ssh2 ${OPENSSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY} ${ZLIB_LIBRARY} ${ALL_OPENSSL_LIBRARIES} ${Boost_DATE_TIME_LIBRARY}) diff --git a/include/fc/lexical_cast.hpp b/include/fc/lexical_cast.hpp index 2df3522..3c0aa3a 100644 --- a/include/fc/lexical_cast.hpp +++ b/include/fc/lexical_cast.hpp @@ -41,6 +41,10 @@ namespace fc { struct lexical_cast { static fc::string cast( const R& v ) { return to_string( v ); } }; + template + struct lexical_cast { + static std::string cast( const R& v ) { return to_string( v ); } + }; template struct lexical_cast { diff --git a/include/fc/logger.hpp b/include/fc/logger.hpp index d89a086..4b2fafc 100644 --- a/include/fc/logger.hpp +++ b/include/fc/logger.hpp @@ -31,6 +31,11 @@ namespace fc { ovalue meta; // key based args + template + log_message& operator()( const string& arg, const T& v ) { + return (*this)(arg,value(v)); + } + log_message& operator()( const string& arg, value&& v ); log_message& operator()( const string& arg, const value& v ); // position based args... diff --git a/include/fc/ptr.hpp b/include/fc/ptr.hpp index d8089b0..b52da28 100644 --- a/include/fc/ptr.hpp +++ b/include/fc/ptr.hpp @@ -1,5 +1,4 @@ #pragma once -//#include #include #include #include diff --git a/include/fc/reflect.hpp b/include/fc/reflect.hpp index 54c97fb..44d86c2 100644 --- a/include/fc/reflect.hpp +++ b/include/fc/reflect.hpp @@ -75,9 +75,11 @@ void throw_bad_enum_cast( const char* k, const char* e ); fc::reflector::visit( visitor ); -#ifndef WIN32 +#ifndef _MSC_VER #define TEMPLATE template #else + // Disable warning C4482: nonstandard extention used: enum 'enum_type::enum_value' used in qualified name + #pragma warning( disable: 4482 ) #define TEMPLATE #endif @@ -178,6 +180,11 @@ template<> struct reflector {\ #define FC_REFLECT( TYPE, MEMBERS ) \ FC_REFLECT_DERIVED( TYPE, BOOST_PP_SEQ_NIL, MEMBERS ) +#define FC_REFLECT_TYPENAME( TYPE ) \ +namespace fc { \ + template<> struct get_typename { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \ +} + #define FC_REFLECT_FWD( TYPE ) \ namespace fc { \ template<> struct get_typename { static const char* name() { return BOOST_PP_STRINGIZE(TYPE); } }; \ diff --git a/include/fc/ssh/client.hpp b/include/fc/ssh/client.hpp index b9c6a79..b88451d 100644 --- a/include/fc/ssh/client.hpp +++ b/include/fc/ssh/client.hpp @@ -5,6 +5,7 @@ namespace fc { class path; + class logger; namespace ssh { namespace detail { class client_impl; @@ -56,9 +57,37 @@ namespace fc { * Because the client creates other resources that depend upon * it, it can only be created as a std::shared_ptr (aka client::ptr) * via client::create(); + * */ class client { public: + enum trace_level { + TRACE_NONE = 0, + TRACE_TRANS = (1<<1), + TRACE_KEX = (1<<2), + TRACE_AUTH = (1<<3), + TRACE_CONN = (1<<4), + TRACE_SCP = (1<<5), + TRACE_SFTP = (1<<6), + TRACE_ERROR = (1<<7), + TRACE_PUBLICKEY = (1<<8), + TRACE_SOCKET = (1<<9) + }; + /** + * Everything but TRACE_ERROR will be logged at fc::log_level::debug, while + * TRACE_ERROR will be logged at fc::log_level::error + * + * @param bitmask comprised of values from trace_level + **/ + void set_trace_level( int bitmask ); + int get_trace_level()const; + + /** + * Override the default logger used by fc::ssh::client + */ + void set_logger( const logger& lgr ); + const logger& get_logger()const; + void connect( const fc::string& user, const fc::string& host, uint16_t port = 22); /** diff --git a/include/fc/string.hpp b/include/fc/string.hpp index 5f8f4cb..50215b0 100644 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -22,6 +22,8 @@ namespace std { typedef basic_string, allocator > string; } +#include + namespace fc { // typedef std::string string; /** diff --git a/include/fc/tuple.hpp b/include/fc/tuple.hpp index 019340e..9fe9638 100644 --- a/include/fc/tuple.hpp +++ b/include/fc/tuple.hpp @@ -118,7 +118,7 @@ namespace fc { typedef fc::tuple type; \ }; - BOOST_PP_REPEAT_FROM_TO( 1, 4, TUPLE, unused ) + BOOST_PP_REPEAT_FROM_TO( 1, 5, TUPLE, unused ) #undef FORWARD_PARAMS diff --git a/include/fc/utility.hpp b/include/fc/utility.hpp index a65c9a0..96742ae 100644 --- a/include/fc/utility.hpp +++ b/include/fc/utility.hpp @@ -1,9 +1,8 @@ -#ifndef _FC_UTILITY_HPP_ -#define _FC_UTILITY_HPP_ +#pragma once #include #include -#define nullptr 0 +//#define nullptr 0 typedef decltype(sizeof(int)) size_t; namespace std { @@ -49,4 +48,3 @@ namespace fc { a = fc::move(b); b = fc::move(tmp); } -#endif // _FC_UTILITY_HPP_ diff --git a/include/fc/value.hpp b/include/fc/value.hpp index 705c95b..0f095e8 100644 --- a/include/fc/value.hpp +++ b/include/fc/value.hpp @@ -7,6 +7,11 @@ #include #include +#ifdef _MSC_VER + // Disable warning C4482: nonstandard extention used: enum 'enum_type::enum_value' used in qualified name + #pragma warning( disable: 4482 ) +#endif + namespace fc { template struct tuple; diff --git a/include/fc/value_io.hpp b/include/fc/value_io.hpp index a817a38..a9efa4a 100644 --- a/include/fc/value_io.hpp +++ b/include/fc/value_io.hpp @@ -277,6 +277,9 @@ namespace fc { } template inline void unpack( const fc::value& val, tuple& t ) { + if( val.size() < tuple::size ) + FC_THROW_REPORT( "Attempt to unpack tuple of size ${size} from array of size ${array_size}", + fc::value( "size", tuple::size)("array_size",val.size() ) ); t.visit( tuple_from_value_visitor(val) ); } diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 0b6978e..40993b9 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -76,7 +76,7 @@ namespace fc { } fc::string path::string()const { - return _p->string().c_str(); + return _p->string(); } fc::path path::filename()const { return _p->filename(); diff --git a/src/json_rpc_connection.cpp b/src/json_rpc_connection.cpp index 21e4b83..4f96cba 100644 --- a/src/json_rpc_connection.cpp +++ b/src/json_rpc_connection.cpp @@ -120,9 +120,9 @@ namespace fc { namespace json { } cur = cur->next; } - FC_THROW_MSG( "Unexpected reply with id %s", id ); + FC_THROW_REPORT( "Unexpected reply with id ${id}", id_itr->val ); } - FC_THROW_MSG( "Method with no 'id' or 'method' field" ); + FC_THROW_REPORT( "Method with no 'id' or 'method' field" ); } diff --git a/src/json_rpc_stream_connection.cpp b/src/json_rpc_stream_connection.cpp index a67dff6..e00d11a 100644 --- a/src/json_rpc_stream_connection.cpp +++ b/src/json_rpc_stream_connection.cpp @@ -38,19 +38,18 @@ namespace fc { namespace json { fc::string line; fc::getline( in, line ); while( !in.eof() ) { - // std::cerr<<"\n**line size: "<_name; + if( !m.context ) m.context = my->_name; + else m.context = *m.context + "->" + my->_name; for( auto itr = my->_appenders.begin(); itr != my->_appenders.end(); ++itr ) (*itr)->log( m ); diff --git a/src/logger_config.cpp b/src/logger_config.cpp index 2ec5214..95619ba 100644 --- a/src/logger_config.cpp +++ b/src/logger_config.cpp @@ -23,7 +23,7 @@ namespace fc { get_logger_map().clear(); get_appender_map().clear(); - slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() ); + //slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() ); for( size_t i = 0; i < cfg.appenders.size(); ++i ) { appender::create( cfg.appenders[i].name, cfg.appenders[i].type, cfg.appenders[i].args ); // TODO... process enabled @@ -48,7 +48,7 @@ namespace fc { } logging_config logging_config::default_config() { - slog( "default cfg" ); + //slog( "default cfg" ); logging_config cfg; cfg.appenders.push_back( appender_config( "stderr", "console", diff --git a/src/ssh.cpp b/src/ssh.cpp index 15e44c6..04375cf 100644 --- a/src/ssh.cpp +++ b/src/ssh.cpp @@ -12,7 +12,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -76,10 +79,13 @@ namespace fc { namespace ssh { class client_impl : public fc::retainable { public: client_impl() { - sftp = nullptr; - session = nullptr; - knownhosts = nullptr; - } + sftp = nullptr; + session = nullptr; + knownhosts = nullptr; + _trace_level = LIBSSH2_TRACE_ERROR; + logr = fc::logger::get( "fc::ssh::client" ); + logr.set_parent( fc::logger::get( "default" ) ); + } LIBSSH2_SESSION* session; LIBSSH2_KNOWNHOSTS* knownhosts; LIBSSH2_SFTP* sftp; @@ -98,6 +104,7 @@ namespace fc { namespace ssh { bool session_connected; fc::promise::ptr read_prom; fc::promise::ptr write_prom; + fc::spin_lock _spin_lock; LIBSSH2_CHANNEL* open_channel( const fc::string& pty_type ); static void kbd_callback(const char *name, int name_len, @@ -166,26 +173,30 @@ namespace fc { namespace ssh { } sock.reset( new boost::asio::ip::tcp::socket( fc::asio::default_io_service() ) ); - bool resolved = false; + bool resolved = false; for( uint32_t i = 0; i < eps.size(); ++i ) { + std::stringstream ss; ss << eps[i]; try { - boost::system::error_code ec; - std::stringstream ss; ss << eps[i]; - slog( "Attempting to connect to %s", ss.str().c_str() ); - fc::asio::tcp::connect( *sock, eps[i] ); - endpt = eps[i]; - resolved = true; - break; - } catch ( ... ) { - wlog( "%s", fc::except_str().c_str() ); - sock->close(); - } + boost::system::error_code ec; + fc_ilog( logr, "Attempting to connect to ${endpoint}", ("endpoint",ss.str().c_str()) ); + fc::asio::tcp::connect( *sock, eps[i] ); + endpt = eps[i]; + resolved = true; + break; + } catch ( fc::error_report& er ) { + fc_ilog( logr, "Failed to connect to ${endpoint}\n${error_reprot}", + ("endpoint",ss.str().c_str())("error_report", er.to_detail_string()) ); + sock->close(); + } + } + if( !resolved ) { + FC_THROW_REPORT( "Unable to connect to any resolved endpoint for ${host}:${port}", + fc::value().set("host", hostname).set("port",port) ); } - if( !resolved ) { - FC_THROW_REPORT( "Unable to connect to any resolved endpoint for ${host}:${port}", - fc::value().set("host", hostname).set("port",port) ); - } session = libssh2_session_init(); + libssh2_trace( session, _trace_level ); + libssh2_trace_sethandler( session, this, client_impl::handle_trace ); + *libssh2_session_abstract(session) = this; libssh2_session_set_blocking( session, 0 ); @@ -207,14 +218,21 @@ namespace fc { namespace ssh { authenticate(); //slog("."); } catch ( error_report& er ) { - elog( "%s", er.to_detail_string().c_str() ); + elog( "%s", er.to_detail_string().c_str() ); close(); throw FC_REPORT_PUSH( er, "Unable to connect to ssh server" );; } catch ( ... ) { close(); FC_THROW_REPORT( "Unable to connect to ssh server", fc::value().set("exception", fc::except_str() ) ); - } + } } + + static void handle_trace( LIBSSH2_SESSION* session, void* context, const char* data, size_t length ) { + client_impl* my = (client_impl*)context; + fc::string str(data,length); + fc_wlog( my->logr, "${message}", ("message",str) ); + } + void close() { if( session ) { @@ -226,7 +244,7 @@ namespace fc { namespace ssh { ec = libssh2_sftp_shutdown(sftp); } }catch(...){ - elog( "... caught error closing sftp session???" ); + fc_wlog( logr, "caught closing sftp session" ); } sftp = 0; } @@ -243,33 +261,31 @@ namespace fc { namespace ssh { } session = 0; } catch ( ... ){ - elog( "... caught error freeing session???" ); + fc_wlog( logr, "caught freeing session" ); session = 0; } try { if( sock ) { - slog( "closing socket" ); sock->close(); } } catch ( ... ){ - elog( "... caught error closing socket???" ); + fc_wlog( logr, "caught error closing socket" ); } sock.reset(0); try { if( read_prom ) read_prom->wait(); } catch ( ... ){ - wlog( "caught error waiting on read prom" ); + fc_wlog( logr, "caught error waiting on read" ); } try { if( write_prom ) write_prom->wait(); } catch ( ... ){ - wlog( "caught error waiting on write prom" ); + fc_wlog( logr, "caught error waiting on write" ); } } } void authenticate() { - //slog( "auth" ); try { char * alist = libssh2_userauth_list(session, uname.c_str(),uname.size()); char * msg = 0; @@ -308,7 +324,7 @@ namespace fc { namespace ssh { keybd = true; } else { - slog( "Unknown/unsupported authentication type '%s'", s.c_str() ); + fc_wlog( logr, "Unknown/unsupported authentication type '${auth_type}'", ("auth_type",s.c_str())); } }); @@ -331,7 +347,6 @@ namespace fc { namespace ssh { } // authenticate() bool try_pass() { - //slog( "try pass" ); int ec = libssh2_userauth_password(session, uname.c_str(), upass.c_str() ); while( ec == LIBSSH2_ERROR_EAGAIN ) { wait_on_socket(); @@ -341,7 +356,6 @@ namespace fc { namespace ssh { return !ec; } bool try_keyboard() { - //slog( "try keyboard" ); int ec = libssh2_userauth_keyboard_interactive(session, uname.c_str(), &client_impl::kbd_callback); while( ec == LIBSSH2_ERROR_EAGAIN ) { @@ -353,7 +367,6 @@ namespace fc { namespace ssh { } bool try_pub_key() { - //slog( "try pub key" ); int ec = libssh2_userauth_publickey_fromfile(session, uname.c_str(), pubkey.c_str(), @@ -375,7 +388,7 @@ namespace fc { namespace ssh { * @todo figure out why this method results in deadlocks... */ void wait_on_socket() { - fc::usleep( fc::microseconds(10000) ); + fc::usleep(fc::microseconds(5000)); return; auto dir = libssh2_session_block_directions(session); @@ -383,53 +396,52 @@ namespace fc { namespace ssh { fc::promise::ptr rprom, wprom; if( dir & LIBSSH2_SESSION_BLOCK_INBOUND ) { - rprom = read_prom; - if(!rprom.get()) { - // elog( " this %2% NEW READ PROM %1% ", read_prom.get(), this ); - read_prom.reset( new fc::promise("read_prom") ); - // wlog( " new read prom %1% this %2%", read_prom.get(), this ); - rprom = read_prom; - sock->async_read_some( boost::asio::null_buffers(), - [=]( const boost::system::error_code& e, size_t ) { - this->read_prom->set_value(e); - this->read_prom.reset(0); - } ); - } else { - // elog( "already waiting on read %1%", read_prom.get() ); + fc::scoped_lock lock(this->_spin_lock); + if( !read_prom ) { + read_prom.reset( new fc::promise("read_prom") ); + sock->async_read_some( boost::asio::null_buffers(), + [=]( const boost::system::error_code& e, size_t ) { + fc::scoped_lock lock(this->_spin_lock); + this->read_prom->set_value(e); + this->read_prom.reset(nullptr); + } ); } + rprom = read_prom; } if( dir & LIBSSH2_SESSION_BLOCK_OUTBOUND ) { - wprom = write_prom; + fc::scoped_lock lock(this->_spin_lock); if( !write_prom ) { write_prom.reset( new fc::promise("write_prom") ); - wprom = write_prom; sock->async_write_some( boost::asio::null_buffers(), [=]( const boost::system::error_code& e, size_t ) { this->write_prom->set_value(e); this->write_prom.reset(0); } ); - } else { - // elog( "already waiting on write" ); } + wprom = write_prom; } boost::system::error_code ec; if( rprom.get() && wprom.get() ) { - // elog( "************* Attempt to wait in either direction currently waits for both directions ****** " ); - //wlog( "rprom %1% wprom %2%", rprom.get(), write_prom.get() ); - // wlog( "wait on read %1% or write %2% ", rprom.get(), wprom.get() ); wlog( "wait both dir" ); - typedef fc::future fprom; fprom fw(wprom); fprom fr(rprom); - int r = fc::wait_any( fw, fr, fc::seconds(5) ); + int r = fc::wait_any( fw, fr, fc::seconds(1) ); switch( r ) { case 0: + if( wprom->wait() ) { + FC_THROW_REPORT( "Socket Error ${message}", + fc::value().set( "message", boost::system::system_error(rprom->wait() ).what() ) ); + } break; case 1: + if( rprom->wait() ) { + FC_THROW_REPORT( "Socket Error ${message}", + fc::value().set( "message", boost::system::system_error(rprom->wait() ).what() ) ); + } break; } } else if( rprom ) { @@ -444,6 +456,7 @@ namespace fc { namespace ssh { } } } + void init_sftp() { if( !sftp ) { sftp = libssh2_sftp_init(session); @@ -460,13 +473,20 @@ namespace fc { namespace ssh { } } - + int _trace_level; + logger logr; }; + } client::client():my( new detail::client_impl() ){} client::~client(){} + void client::set_trace_level( int bitmask ) { my->_trace_level = bitmask; } + int client::get_trace_level()const { return my->_trace_level; } + const logger& client::get_logger()const { return my->logr; } + void client::set_logger( const logger& l ) { my->logr = l; } + void client::connect( const fc::string& user, const fc::string& host, uint16_t port ) { my->hostname = host; my->uname = user; @@ -498,7 +518,7 @@ namespace fc { namespace ssh { if( remote_dir.filename() == fc::path(".") ) remote_dir /= local_dir.filename(); - slog( "scp -r %s %s", local_dir.generic_string().c_str(), remote_dir.generic_string().c_str() ); + fc_dlog( my->logr, "scp -r ${local} ${remote}", ("local",local_dir)("remote",remote_dir) ); create_directories( remote_dir ); directory_iterator ditr(local_dir); @@ -514,7 +534,7 @@ namespace fc { namespace ssh { } else if( fc::is_regular_file(*ditr) ) { scp_send( *ditr, remote_dir / (*ditr).filename() ); } else { - wlog( "Skipping %s", fc::canonical(*ditr).generic_string().c_str() ); + fc_wlog( my->logr, "Skipping '${path}", ("path",fc::canonical(*ditr)) ); } ++ditr; } @@ -522,7 +542,7 @@ namespace fc { namespace ssh { void client::scp_send( const fc::path& local_path, const fc::path& remote_path, std::function progress ) { - slog( "scp %s %s", local_path.generic_string().c_str(), remote_path.generic_string().c_str() ); + fc_ilog( my->logr, "scp ${local} ${remote}", ("local",local_path)("remote",remote_path ) ); /** * Tests have shown that if one scp is 'blocked' by a need to read (presumably to * ack recv for the trx window), and then a second transfer begins that the first @@ -606,7 +626,6 @@ namespace fc { namespace ssh { ec = libssh2_channel_close( chan ); } } catch ( error_report& er ) { - wlog( "%s", er.to_detail_string().c_str() ); // clean up chan int ec = libssh2_channel_free(chan ); while( ec == LIBSSH2_ERROR_EAGAIN ) { @@ -715,7 +734,7 @@ namespace fc { namespace ssh { ec = libssh2_sftp_shutdown(my->sftp); } }catch(...){ - elog( "... caught error closing sftp session???" ); + fc_wlog( my->logr, "caught closing sftp sessionn" ); } my->sftp = 0; } @@ -732,27 +751,26 @@ namespace fc { namespace ssh { } my->session = 0; } catch ( ... ){ - elog( "... caught error freeing session???" ); + fc_wlog( my->logr, "caught error freeing session" ); my->session = 0; } try { if( my->sock ) { - slog( "closing socket" ); my->sock->close(); } } catch ( ... ){ - elog( "... caught error closing socket???" ); + fc_wlog( my->logr, "caught error closing socket" ); } my->sock.reset(0); try { if( my->read_prom ) my->read_prom->wait(); } catch ( ... ){ - wlog( "caught error waiting on read prom" ); + fc_wlog( my->logr,"caught error waiting on read prom" ); } try { if( my->write_prom ) my->write_prom->wait(); } catch ( ... ){ - wlog( "caught error waiting on write prom" ); + fc_wlog( my->logr, "caught error waiting on write prom" ); } } } @@ -837,19 +855,22 @@ namespace fc { namespace ssh { void detail::process_impl::flush() { if( !chan ) return; + /* channel_flush deleates input buffer, and does not ensure writes go out + * int ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA); while( ec == LIBSSH2_ERROR_EAGAIN ) { sshc.my->wait_on_socket(); ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA ); } - ec = libssh2_channel_flush_ex( chan, 0 ); + ec = libssh2_channel_flush( chan ); while( ec == LIBSSH2_ERROR_EAGAIN ) { sshc.my->wait_on_socket(); - ec = libssh2_channel_flush_ex( chan, 0 ); + ec = libssh2_channel_flush( chan ); } if( ec < 0 ) { FC_THROW_REPORT( "ssh flush failed", fc::value().set( "channel_error", ec) ); } + */ } int detail::process_impl::read_some( char* data, size_t len, int stream_id ){ if( !sshc.my->session ) { FC_THROW_REPORT( "Session closed" ); } @@ -958,11 +979,11 @@ namespace fc { namespace ssh { } ostream& detail::process_ostream::write( const char* buf, size_t len ) { - size_t wrote = 0; - do { - wrote += proc.write_some( buf+wrote, len-wrote, 0 ); - } while( wrote < len ); - return *this; + size_t wrote = 0; + do { + wrote += proc.write_some( buf+wrote, len-wrote, 0 ); + } while( wrote < len ); + return *this; } void detail::process_ostream::close(){ proc.send_eof(); @@ -988,7 +1009,6 @@ namespace fc { namespace ssh { ec = libssh2_channel_shell(chan); } } else { - //slog( "%s", cmd.c_str() ); ec = libssh2_channel_exec( chan, cmd.c_str() ); while( ec == LIBSSH2_ERROR_EAGAIN ) { sshc.my->wait_on_socket(); diff --git a/tests/ssh.cpp b/tests/ssh.cpp index 0254bb6..d3c0e31 100644 --- a/tests/ssh.cpp +++ b/tests/ssh.cpp @@ -6,23 +6,38 @@ int main( int argc, char** argv ) { try { - // if( argc < 3 ) { - // fc::cout<>pw; + slog( "create ssh client" ); fc::ssh::client c; - c.connect( "dlarimer", "", "localhost" ); - fc::ssh::process proc = c.exec( "/bin/ls" ); + c.connect( "dlarimer", "rapture", "10.10.10.112" ); + slog( "connected" ); + fc::ssh::process proc = c.exec( "/bin/cat -u" ); + slog( "proc!"); + fc::string hello( "hello.............." ); + hello += hello; + hello += hello; + hello += hello; + hello += hello; + hello += hello; + hello += "\n"; + /* + hello += hello2; + */ + fc::string line; + proc.in_stream().write(hello.c_str(), hello.size() ); + fc::getline( proc.out_stream(), line ); + fc::cout<