一个基于 osip 库的 UAC 和 UAS 的代码整理

 

一个基于 osip 库的 UAC UAS 的代码整理

从网上搞了一个基于osip 库的 SIP 协议的简单的 UAC 代理客户端和 UAS 代理服务器端,并进行了编译连接,代码整理后如下: 

    ----------- UAC 代理客户端的代码整理 ---------------

/**
 * 一个使用了 osip eXosip 库的 UAC 代理客户端的演示程序
 *
 * - 只是简单的演示了使用了 osip eXosip2 库的 UAC 代理客户端的如下几个功能:
 * * i 发起呼叫 INVITE 请求
 * * h 挂断会话
 * * s 执行方法 INFO
 * * m 执行方法 MESSAGE
 *
 * 编 译:g++ -I/usr/local/include -L/usr/local/lib ua_client.cpp -o ua_client -leXosip2 -losip2 -losipparser2 -lpthread
 *
 */

# include < osip2 / osip_mt . h >
# include < eXosip2 / eXosip . h >

# include < netinet / in . h >
# include < sys / socket . h >
# include < sys / types . h >

# include < iostream >
# include < string >

using namespace std ;

int main ( int argc , char * argv [])
{
    eXosip_event_t * je ;
    osip_message_t * reg = NULL ;
    osip_message_t * invite = NULL ;
    osip_message_t * ack = NULL ;
    osip_message_t * info = NULL ;
    osip_message_t * message = NULL ;
     int call_id , dialog_id ;
     int i , flag ;
     int flag1 = 1 ;
     int id ;
    
     string strIdentity = "sip:136@133.37.55.136" ;
     string strRegisterer = "sip:133.37.55.136:5060" ; // server ip

     string strSrcCall = "sip:136@133.37.55.136" ;
     string strDestCall = "sip:136@133.37.55.136:5060" ; // server ip

    
     char command ;
     char tmp [ 4096 ];
     char localip [ 128 ];

     string strHelp = string ( "/n/t--> 命令字符 功能描述 <--/n/n" )
                         + "/t/tr 向服务器注册/n"
                         + "/t/tc 取消注册/n"
                         + "/t/ti 发起呼叫请求/n"
                         + "/t/th 挂断/n"
                         + "/t/tq 退出程序/n"
                         + "/t/ts 执行方法 INFO/n"
                         + "/t/tm 执行方法 MESSAGE/n"
                         + "/t/te 帮助/n/n" ;
     cout << strHelp ;

     string strMsg ;

    i = eXosip_init ();
     if ( i != 0 )
     {
         cout << "/t--> Couldn't initialize eXosip! <--/n" ;
         return - 1 ;
     }
     else
     {
         cout << "/t--> eXosip_init successfully! <-- /n/n" ;
     }

    i = eXosip_listen_addr ( IPPROTO_UDP , NULL , 5061 , AF_INET , 0 );
     if ( i != 0 )
     {
        eXosip_quit ();
         cerr << "/n/t--> Couldn't initialize transport layer! <-- /n/n" ;
         return - 1 ;
     }
    flag = 1 ;
     while ( flag )
     {
         cout << " 请输入一个命令字符:/t" ;
         cin >> command ;
      
         switch ( command )
         {
         case 'r' :
             cout << "/n/t--> This modal isn't commpleted! /n" << endl ;
             break ;

         case 'i' : // 初始化的 INVITE 请求
            i = eXosip_call_build_initial_invite (& invite ,
                                                  strDestCall . c_str (),
                                                  strSrcCall . c_str (),
                                                   NULL ,
                                                   "This is a call for a conversation" );
             if ( i != 0 )
             {
                 cout << "/n --> Intial INVITE failed! <-- /n" ;
                 break ;
             }

             // 符合 SDP 格式, 其中属性 a 是自定义格式, 也就是说可以存放自己的信息
             // 但是只能是两列, 比如帐户信息
             // 但是经测试, 格式: v o t 必不可少, 原因未知, 估计是协议栈在传输时需要检查的

            strMsg = string ( "v=0/r/n" )
                    + "o=anonymous 0 0 IN IP4 0.0.0.0/r/n"
                    + "t=1 10/r/n"
                    + "a=username:bluesea/r/n"
                    + "a=password:123456/r/n" ;

            osip_message_set_body ( invite , strMsg . c_str (), strMsg . length ());
            osip_message_set_content_type ( invite , "application/sdp" );
      
             // 这里使用了锁机制以保证同步
            eXosip_lock ();
            i = eXosip_call_send_initial_invite ( invite );
            eXosip_unlock ();
            flag1 = 1 ;
             while ( flag1 )
             {
                je = eXosip_event_wait ( 0 , 200 );
                 if ( je == NULL )
                 {
                     cout << "/n/t--> No response or the time is over! <--/n" << endl ;
                     break ;
                 }
          
                 switch ( je -> type )
                 {
                 case EXOSIP_CALL_INVITE :
                     cout << "/n/t--> a new invite reveived! <--/n" << endl ;
                     break ;

                 // announce processing by a remote app
                 case EXOSIP_CALL_PROCEEDING :
                     cout << "/n/t--> proceeding! <--/n" << endl ;
                     break ;

                 // announce ringback
                 case EXOSIP_CALL_RINGING :
                     cout << "/n/t--> ringing! <--/n"
                          << "/n/tcall_id is " << je -> cid
                          << ", dialog_id is " << je -> did << endl ;
                     break ;

                 // 收到请求,表示连接成功,下面发送回复确认
                 case EXOSIP_CALL_ANSWERED :
                     cout << "/n/t--> ok! connected! <--/n" << endl ;
                    call_id = je -> cid ;
                    dialog_id = je -> did ;
                     cout << "/n/tcall_id is " << je -> cid
                          << ", dialog_id is " << je -> did << endl ;
                    eXosip_call_build_ack ( je -> did , & ack );
                    eXosip_call_send_ack ( je -> did , ack );
                    flag1 = 0 ;
                     break ;

                 case EXOSIP_CALL_CLOSED :
                     cout << "/n/t--> the other sid closed! <--/n" << endl ;
                     break ;

                 case EXOSIP_CALL_ACK :
                     cout << "/n/t--> ACK received! <--/n" << endl ;
                     break ;

                 default :
                     cout << "/n/t--> other response!/n" << endl ;
                     break ;
                 }
          
                eXosip_event_free ( je );
             }

             break ;

         case 'h' :
             cout << "/n/t--> Holded ! /n" << endl ;
      
            eXosip_lock ();
            eXosip_call_terminate ( call_id , dialog_id );
            eXosip_unlock ();
             break ;

         case 'c' :
             cout << "/n/t--> This modal isn't commpleted! /n" << endl ;
             break ;

         case 's' :
             // 传输 INFO 方法
            eXosip_call_build_info ( dialog_id , & info );
            
            snprintf ( tmp , 4096 , "hello,bluesea" );
            osip_message_set_body ( info , tmp , strlen ( tmp ));

             // 格式可以任意设定, text/plain 代表文本信息
            osip_message_set_content_type ( info , "text/plain" );
            eXosip_call_send_request ( dialog_id , info );
             break ;

         case 'm' :
             // 传输 MESSAGE 方法, 也就是即时消息,
             // INFO 方法相比,主要区别,是 MESSAGE 不用建立连接,直接传输信息,
             // INFO 必须在建立 INVITE 的基础上传输。
             cout << "/n/t--> the mothed :MESSAGE /n" << endl ;
            eXosip_message_build_request (& message ,
                                           "MESSAGE" ,
                                          strDestCall . c_str (),
                                          strSrcCall . c_str (),
                                           NULL );
            strMsg = "message: hello bluesea!" ;
            osip_message_set_body ( message , strMsg . c_str (), strMsg . length ());
      
             // 假设格式是xml
            osip_message_set_content_type ( message , "text/xml" );
            eXosip_message_send_request ( message );
             break ;

         case 'q' :
            eXosip_quit ();
             cout << "/n/t--> Exit the setup! /n" << endl ;;
            flag = 0 ;
             break ;

         case 'e' :
             cout << strHelp << endl ;
             break ;

         default :
             cout << "/n/t--> 不支持的命令 <--/n" << endl ;
             break ;
         }
     }

     return 0 ;
}

    ----------- UAS 代理服务器端的代码整理 ---------------

/**
 * 一个使用了 osip eXosip 库的 UAS 代理服务端的演示程序
 *
 * - 只是简单的演示了使用了 osip eXosip2 库的 UAS 代理服务端的如下几个功能:
 *
 * 编 译:g++ -I/usr/local/include -L/usr/local/lib ua_server.cpp -o ua_server -leXosip2 -losip2 -losipparser2 -lpthread
 *
 */

# include < eXosip2 / eXosip . h >

# include < netinet / in . h >
# include < sys / socket . h >
# include < sys / types . h >

# include < iostream >
# include < fstream >
# include < string >

using namespace std ;

int main ()
{
    eXosip_event_t * je = NULL ;
    osip_message_t * ack = NULL ;
    osip_message_t * invite = NULL ;
    osip_message_t * answer = NULL ;
    sdp_message_t * remote_sdp = NULL ;
     int call_id , dialog_id ;
     int i , j ;
     int id ;

     char * sour_call = "sip:136@133.37.55.136" ;
     char * dest_call = "sip:136@133.37.55.136:5061" ; //client ip/port

     char command ;
     char tmp [ 4096 ];
     char localip [ 128 ];
     int pos = 0 ;

     // 初始化 sip
    i = eXosip_init ();
     if ( i != 0 )
     {
         cerr << "/n/t--> Can't initialize eXosip!/n" ;
         return - 1 ;
     }
     else
     {
         cout << "/n/t--> eXosip_init successfully!/n" ;
     }
    
    i = eXosip_listen_addr ( IPPROTO_UDP , NULL , 5060 , AF_INET , 0 );
     if ( i != 0 )
     {
        eXosip_quit ();
         cerr << "/n/t--> eXosip_listen_addr error! Couldn't initialize transport layer!/n" ;
     }

     for (;;)
     {
         // 侦听是否有消息到来
        je = eXosip_event_wait ( 0 , 50 );

         // 协议栈带有此语句, 具体作用未知
        eXosip_lock ();
        eXosip_default_action ( je );
        eXosip_automatic_refresh ();
        eXosip_unlock ();

         if ( je == NULL ) // 没有接收到消息,继续
         {
             continue ;
         }

         switch ( je -> type )
         {
         case EXOSIP_MESSAGE_NEW : // 新的消息到来
             cout << "/n/t*** EXOSIP_MESSAGE_NEW!/n" << endl ;

             if ( MSG_IS_MESSAGE ( je -> request )) // 如果接收到的消息类型是 MESSAGE
             {
                 {
                    osip_body_t * body ;
                    osip_message_get_body ( je -> request , 0 , & body );
                     cout << "I get the msg is: " << body -> body << endl ;
                 }

                 // 按照规则,需要回复 OK 信息
                eXosip_message_build_answer ( je -> tid , 200 , & answer );
                eXosip_message_send_answer ( je -> tid , 200 , answer );
             }
             break ;

         case EXOSIP_CALL_INVITE : // INVITE 请求消息
             // 得到接收到消息的具体信息
             cout << "/n/tReceived a INVITE msg from " << je -> request -> req_uri -> host
                  << " : " << je -> request -> req_uri -> port
                  << ", username is " << je -> request -> req_uri -> username << endl ;

             // 得到消息体, 认为该消息就是 SDP 格式.
            remote_sdp = eXosip_get_remote_sdp ( je -> did );
            call_id = je -> cid ;
            dialog_id = je -> did ;
        
            eXosip_lock ();

            eXosip_call_send_answer ( je -> tid , 180 , NULL );
            i = eXosip_call_build_answer ( je -> tid , 200 , & answer );
             if ( i != 0 )
             {
                 cout << "/n/t--> This request msg is invalid! Cann't response!/n" << endl ;
                eXosip_call_send_answer ( je -> tid , 400 , NULL );
             }
             else
             {
                snprintf ( tmp , 4096 ,
                     "v=0/r/n"
                     "o=anonymous 0 0 IN IP4 0.0.0.0/r/n"
                     "t=1 10/r/n"
                     "a=username:rainfish/r/n"
                     "a=password:123/r/n" );
            
                 // 设置回复的SDP 消息体, 下一步计划分析消息体
                 // 没有分析消息体,直接回复原来的消息,这一块做的不好。
                osip_message_set_body ( answer , tmp , strlen ( tmp ));
                osip_message_set_content_type ( answer , "application/sdp" );
            
                eXosip_call_send_answer ( je -> tid , 200 , answer );
                 cout << "/n/t--> send 200 over!" << endl ;
             }

            eXosip_unlock ();
        
             // 显示出在 sdp 消息体中的 attribute 的内容, 里面计划存放我们的信息
             cout << "/n/t--> The INFO is :/n" ;
             while (! osip_list_eol ( &( remote_sdp -> a_attributes ), pos ))
             {
                sdp_attribute_t * at ;
            
                 // 这里解释了为什么在SDP 消息体中属性a 里面存放必须是两列
                at = ( sdp_attribute_t *) osip_list_get ( &( remote_sdp -> a_attributes) , pos );
                 cout << "/n/t" << at -> a_att_field
                      << " : " << at -> a_att_value << endl ;
            
                pos ++;
             }
             break ;

         case EXOSIP_CALL_ACK :
             cout << "/n/t--> ACK recieved!/n" << endl ;
             // printf ("the cid is %s, did is %s/n", je->did, je->cid); 
             break ;

         case EXOSIP_CALL_CLOSED :
             cout << "/n/t--> the remote hold the session!/n" << endl ;
             // eXosip_call_build_ack(dialog_id, &ack);
             // eXosip_call_send_ack(dialog_id, ack); 
            i = eXosip_call_build_answer ( je -> tid , 200 , & answer );
             if ( i != 0 )
             {
                 printf ( "This request msg is invalid!Cann't response!/n" );
                eXosip_call_send_answer ( je -> tid , 400 , NULL );
             }
             else
             {
                eXosip_call_send_answer ( je -> tid , 200 , answer );
                 cout << "/n/t--> bye send 200 over!/n" ;
             }
             break ;

         case EXOSIP_CALL_MESSAGE_NEW :

             cout << "/n/t*** EXOSIP_CALL_MESSAGE_NEW/n" << endl ;
             if ( MSG_IS_INFO ( je -> request ) ) // 如果传输的是 INFO 方法
             {
                eXosip_lock ();
                i = eXosip_call_build_answer ( je -> tid , 200 , & answer );
                 if ( i == 0 )
                 {
                    eXosip_call_send_answer ( je -> tid , 200 , answer );
                 }

                eXosip_unlock ();

                 {
                    osip_body_t * body ;
                    osip_message_get_body ( je -> request , 0 , & body );
                     cout << "the body is " << body -> body << endl ;
                 }
             }
             break ;

         default :
             cout << "/n/t--> Could not parse the msg!/n" << endl ;
         }
     }

     return 0 ;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值