P2P TELNET

一  缘起

几年前做一个嵌入式的Linux平台上的一个控制和监测的项目。因为施工后,还有很大的可能需要对现场设备进行管理维护、以及应用软件的升级修改操作,而实际设备在安装后的网络环境非常复杂,有可能是多重NAT,也有可能采用的2G,3G或者4G网络。并且设备的安装在地域上的跨度非常大,维护工程师在远程无法访问设备,也就造成无法完成上述任务。

当时意识到如果有一个能够像telnet,ssh一样的P2P的软件,这个问题就可以迎刃迎刃而解了。但是由于工作的问题,想到这个东西了却一直没有动手去考虑实现。最近抽出时间简单的实现一个telnet

 

二  原理

远程无法访问设备的最根本的在于通讯无法进行。如果能够解决通讯问题则可以实现对应的功能,这个就类似QQ的远程桌面。

在网上找到有两个协议非常适合这样的一个任务,这两个协议分别是XMPP和SIP。因此软件的实现就基于这两个协议来实现。

将软件分成服务端和客户端,服务端是被控制的一端,客户端是控制的一端。现在XMPP和SIP的客户端软件非常多,都可以拿来作为客户端使用。因此软件的开发是开发服务端软件

 

 

2.1 XMPP协议。

XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。

XMPP协议严格来讲并不是一个P2P的协议,XMPP的数据通讯需要有一个中间服务器进行转发,所以这是一个中继通讯的协议。考虑到即使有人使用这样的一个方式进行处理,远程设备的管理,因为管理的操作本身并发性不集中。所以XMPP协议完全可以使用,不用考虑它的中继特性了。

XMPP有很多开源的项目,其中gloox是一个用C++实现的XMPP协议客户端库,接口良好,文档也全面,并且整个库编译后也很小,大概1MB吧。完全可以用于嵌入场合。并且这个库是一个跨平台的库,也就意味着可以用于windows,Linux等,笔者也成功的将其移植到arm a8上。

2.2 SIP协议。

SIP(Session Initiation Protocol,会话初始协议)是由IETF(Internet Engineering Task Force,因特网工程任务组)制定的多媒体通信协议。它是一个基于文本的应用层控制协议,用于创建、修改和释放一个或多个参与者的会话。广泛应用于CS(Circuit Switched,电路交换)、NGN(Next Generation Network,下一代网络)以及IMS(IP Multimedia Subsystem,IP多媒体子系统)的网络中,可以支持并应用于语音、视频、数据等多媒体业务,同时也可以应用于Presence(呈现)、Instant Message(即时消息)等特色业务。可以说,有IP网络的地方就有SIP协议的存在。

SIP协议在会话发起之后可以选择采用UDP 的点到点通讯。因此SIP协议在使用的时候可以是一个真正意义上的点到点通讯。

pjsip是一个非常优秀的SIP协议开源库,这是一个用C/C++实现的库。整个库非常小完全可以用于嵌入式系统。并且这个库可以用于windows,Linux多个平台。

 

三  设计

程序的主要流程是:
 图片
 四 然后就是干货,主要代码。如果有需要的整体代码包的可以联系我
  4.1  执行器
#include "exec_linux.h"
#include <stdio.h>
#if defined( __LINUX__ )
CExecLinux::CExecLinux( const std::string& usr , const std::string& str , CP2Pbackend& msger) :
CP2PExec( usr, str, msger )
{
    p_cmd_stdin = proc.GetOutputStream();
    p_cmd_stdout = proc.GetInputStream();
    p_cmd_stderr = proc.GetErrorStream();
}

CExecLinux::~CExecLinux()
{
    {
        boost::mutex::scoped_lock l( m_mutex );
        m_is_run = false;
    }
    my_sleep( 500 );
}

size_t CExecLinux::exec_read( void* buff , size_t len , int& err )
{
    if( buff == NULL ) return -4;
    if( len > CP2PExec::READ_BUFF_SIZE ) len = CP2PExec::READ_BUFF_SIZE;
    size_t ret = 0;
    //读标准错误输出通道
    ret = read( p_cmd_stderr , buff , len );
    if( ret != (size_t)-1 ) err = 0;
    else err = -2;
    //读标准输出通道
    if( err != -2 ){
        if( len + ret > CP2PExec::READ_BUFF_SIZE ) len = CP2PExec::READ_BUFF_SIZE - ret;
        ret = read( p_cmd_stdout , (char*)(buff + ret ), len );
        if( ret != (size_t)-1 ) err = 0;
        else err = 0;
    }
    else{
        ret = read( p_cmd_stdout , buff , len );
        if( ret != (size_t)-1 ) err = 0;
        else err = 0;
    }
    return ret;
}

size_t CExecLinux::exec_write( const void* buff , size_t len , int &err )
{
    size_t ret = write( p_cmd_stdin , buff , len );
    if( ret == (size_t)-1) err = -1;
    else err = 0;

    return ret;
}

void CExecLinux::Start()
{
    m_is_run = true;
    my_sleep( 1000 );
    boost::thread thd( boost::bind( &CExecLinux::do_run , this ));
}

size_t CExecLinux::exec_write( const std::string& data )
{
    int err = 0;
    size_t ret = 0;
    std::string  cmd = data;

#if defined __DEBUG__
    std::cout << "last cmd = " << m_last_cmd << std::endl;
#endif
    if( data == "stop"){
        if(m_last_cmd.empty() == false ){
            cmd = "killall -9 " + m_last_cmd;
            system( cmd.c_str() );
            m_last_cmd.clear();
        }
        ret = 0;
    }
    else{
        cmd = cmd + "\n";
        size_t pos = data.find_first_of(' ');
        if( pos != std::string::npos )
            m_last_cmd = data.substr( 0, pos );
        else
            m_last_cmd = data;

        ret = exec_write( cmd.c_str() , strlen( cmd.c_str() ) , err);
    }

    return ret;
}

#endif
4.2  通讯控制器
#include "inc.h"
#if USE_GLOOX_LIB  == 1

#if defined(__WXMSW__)
    #include <wx/wx.h>
    #include <wx/process.h>
#endif // defined
#include <gloox/disco.h>
#include "CBackendGloox.h"
#if defined( _WIN32 ) || defined(__GNUWIN32__ ) || defined( __WXMSW__ )
    #include "exec_win32.h"
#elif defined( __LINUX__ )
    #include "exec_linux.h"
#endif // defined
#include <stdio.h>

CBackendGloox  *globe_p2p_telnetd = NULL;

CBackendGloox::CBackendGloox(const std::string& svr , const std::string& usr , const std::string& passwd)
:CP2Pbackend( svr , usr , passwd )
{
    do_connect(svr , usr , passwd );
//    array_exec.clear();
}

CBackendGloox::~CBackendGloox()
{

}

void CBackendGloox::Re( const std::string& msg )
{
    m_session->send( "\n" + msg );
}

void CBackendGloox::do_start_shell( const std::string& user  )
{
#if defined(__WXMSW__ ) || defined(_WIN32) || defined( __GNUWIN32__ )
    CExecWin32 *p_exec = NULL;
    p_exec = new CExecWin32( user , "cmd.exe" , *this );
    *p_exec << "telnet 127.0.0.1\r\n";
#elif defined( __LINUX__ )
    CExecLinux *p_exec = NULL;
    p_exec = new CExecLinux( user , "/bin/bash" , *this );
#endif

    if( p_exec == NULL ) return;
    p_exec->SetNotify( boost::bind( &CBackendGloox :: Re , this , _1 ));
    p_exec->Start();
    make_new_connection( p_exec );
}

void CBackendGloox::do_connect( const std::string& svr , const std::string& usr , const std::string& passwd )
{
#if defined __LINUX__
    std::string    sys = "lINUX";
#elif defined _WIN32
    std::string    sys = "Windows";
#endif // defined
    std::stringstream ss;
    ss << usr << "@" << svr ;
    std::string  str_jid = ss.str();
    JID  jid( ss.str() );
    j = new gloox::Client( jid , passwd );
    if( j == NULL ) throw j;
    j->registerConnectionListener( this );
    j->registerMessageSessionHandler( this , 0 );
    j->disco()->setVersion( "p2ptelnetd", GLOOX_VERSION, "test" );
    j->disco()->setIdentity( "client", "bot" );
    j->disco()->addFeature( XMLNS_CHAT_STATES );
    StringList ca;
    ca.push_back( "/data/cacert.crt" );
    j->setCACerts( ca );

    j->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );

    if( j->connect( ) ){//使用阻塞方式启动客户端
        ConnectionError ce = ConnNoError;
        while( ce == ConnNoError ) {
          ce = j->recv();
        }
        printf( "ce: %d\n", ce );
    }

   delete( j );
}
//
void CBackendGloox::handleMessage( const Message& msg, MessageSession * /*session*/ )
{
    std::string user = msg.from().full();
    //将远程发过来的数据发送给执行器,让执行器执行
    //完成后执行器会自动调用反馈处理
    //if( msg.body().empty() == true ) return;
    process_msg( user , msg.body() );
}

void CBackendGloox::handleMessageEvent( const JID& from, MessageEventType event )
{
   // printf( "received event: %d from: %s\n", event, from.full().c_str() );
}

void CBackendGloox::onDisconnect( ConnectionError e )
{
    printf( "message_test: disconnected: %d\n", e );
    if( e == ConnAuthenticationFailed )
    printf( "auth failed. reason: %d\n", j->authError() );
}

void CBackendGloox::onConnect()
{
#if defined( __WXDEBUG__ ) || defined( __DEBUG__ )
    std::cout << "connected server " << std::endl;
#endif // defined
}

bool CBackendGloox::onTLSConnect( const CertInfo& info )
{
      time_t from( info.date_from );
      time_t to( info.date_to );

      printf( "status: %d\nissuer: %s\npeer: %s\nprotocol: %s\nmac: %s\ncipher: %s\ncompression: %s\n"
              "from: %s\nto: %s\n",
              info.status, info.issuer.c_str(), info.server.c_str(),
              info.protocol.c_str(), info.mac.c_str(), info.cipher.c_str(),
              info.compression.c_str(), ctime( &from ), ctime( &to ) );
      return true;
}

void CBackendGloox::handleChatState( const JID& from, ChatStateType state )
{
    printf( "received state: %d from: %s\n", state, from.full().c_str() );
}

void CBackendGloox::handleLog( LogLevel level, LogArea area, const std::string& message )
{
    //printf("log: level: %d, area: %d, %s\n", level, area, message.c_str() );
}

void CBackendGloox::handleMessageSession( MessageSession *session )
{
    j->disposeMessageSession( m_session );
    m_session = session;

    m_session->registerMessageHandler( this );
    m_messageEventFilter = new MessageEventFilter( m_session );
    m_messageEventFilter->registerMessageEventHandler( this );
    m_chatStateFilter = new ChatStateFilter( m_session );
    m_chatStateFilter->registerChatStateHandler( this );
}

void CBackendGloox :: disconnect()
{
    j->disconnect();
}
#endif

转载于:https://my.oschina.net/u/3071588/blog/1542017

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值