分享

【GBT28181开发:SIP协议实践】之Windows下编译eXosip、osip

 xinyz4104 2016-05-10

【GBT28181开发:SIP协议实践】之Windows下编译eXosip、osip


 
今天开始了SIP开源库的学习,我选择了osip和eXosip,但是这两个库的编译使用有些麻烦,源码下来之后编译会出现很多问题,网上也没有找到完整的编译介绍,只能一步一步的找办法解决,最后终于编译成功!先大概记录下编译过程,后面还要再整理下。

期间还向CSDN论坛求助了下,但是还没有反应:http://bbs.csdn.net/topics/390499635?page=1#post-394866714

描述error LNK2019: 无法解析的外部符号 _osip_transaction_set_naptr_record,该符号在函数 __eXosip_transaction_init 中被引用

原因:开源代码的库有些函数没有导出,需要手动在def文件中添加

解决方法:第二步的2,3两小步就是为了解决这个问题。


第一步,下载osip和eXosip

osip:    http://ftp./Unix/NonGNU//osip/libosip2-3.6.0.tar.gz
eXosip: http://download.savannah./releases/exosip/libeXosip2-3.6.0.tar.gz

第二步,解压,编译osip:

1.进入libosip2-3.6.0\platform\vsnet目录,用VS2010直接打开osip.sln文件,项目自动转换

2.更改libosip2-3.6.0\platform\vsnet\osip2.def 文件,在文件末尾追加
  
   osip_transaction_set_naptr_record @138

3.更改libosip2-3.6.0\platform\vsnet\osipparser2.def 文件,在文件末尾追加


   osip_realloc @416
   osip_strcasestr @417  
   __osip_uri_escape_userinfo @418



4.先编译osipparser2,再编译osip2,最后在libosip2-3.6.0\platform\vsnet\Debug DLL下生成库文件:


osip2.lib

osip2.dll
osipparser2.lib
osipparser2.dll

第三步,解压,编译eXosip

进入libeXosip2-3.6.0\platform\vsnet目录,用VS2010直接打开eXosip.sln文件,项目自动转换:

1.将osip2.lib,osip2.dll,osipparser2.lib,osipparser2.dll拷贝到Debug目录下
2.C/C++ --> 预处理器 --> 预处理器定义: 删除HAVE_OPENSSL_SSL_H
3.C/C++ --> 常规 --> 附加包含目录:     将osip的头文件libosip2-3.6.0\include包含进来

4.编译,生成eXosip.lib


第四步,新建UAC例子项目

1.链接器 --> 输入 --> 附加依赖项:增加静态库引用:Dnsapi.lib;Iphlpapi.lib;Ws2_32.lib;osip2.lib;osipparser2.lib;exosip.lib;

2.C/C++ -->常规 -->附加包含目录: 将osip和eXosip的头文件libosip2-3.6.0\include、libeXosip2-3.6.0\include包含进来


3.链接器 --> 常规  --> 附加库目录:将osip和eXosip的库包含进来,libeXosip2-3.6.0\platform\vsnet\Debug

4.编译UAC代码:

  1. <span style="font-family:SimSun;">#include <eXosip2/eXosip.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <winsock2.h>  
  5.   
  6. int main(int argc,char *argv[])  
  7. {  
  8.   
  9.     struct eXosip_t *context_eXosip;  
  10.   
  11.     eXosip_event_t *je;  
  12.     osip_message_t *reg=NULL;  
  13.     osip_message_t *invite=NULL;  
  14.     osip_message_t *ack=NULL;  
  15.     osip_message_t *info=NULL;  
  16.     osip_message_t *message=NULL;  
  17.   
  18.     int call_id,dialog_id;  
  19.     int i,flag;  
  20.     int flag1=1;  
  21.   
  22.     char *identity="sip:140@127.0.0.1";   //UAC1,端口是15060  
  23.     char *registar="sip:133@127.0.0.1:15061"//UAS,端口是15061  
  24.     char *source_call="sip:140@127.0.0.1";  
  25.     char *dest_call="sip:133@127.0.0.1:15061";  
  26.     //identify和register这一组地址是和source和destination地址相同的  
  27.     //在这个例子中,uac和uas通信,则source就是自己的地址,而目的地址就是uac1的地址  
  28.     char command;  
  29.     char tmp[4096];  
  30.   
  31.     printf("r   向服务器注册\n\n");  
  32.     printf("c   取消注册\n\n");  
  33.     printf("i   发起呼叫请求\n\n");  
  34.     printf("h   挂断\n\n");  
  35.     printf("q   推出程序\n\n");  
  36.     printf("s   执行方法INFO\n\n");  
  37.     printf("m   执行方法MESSAGE\n\n");  
  38.   
  39.     //初始化  
  40.     i=eXosip_init();  
  41.   
  42.     if(i!=0)  
  43.     {  
  44.         printf("Couldn't initialize eXosip!\n");  
  45.         return -1;  
  46.     }  
  47.     else  
  48.     {  
  49.         printf("eXosip_init successfully!\n");  
  50.     }  
  51.   
  52.     //绑定uac自己的端口15060,并进行端口监听  
  53.     i=eXosip_listen_addr(IPPROTO_UDP,NULL,15060,AF_INET,0);  
  54.     if(i!=0)  
  55.     {  
  56.         eXosip_quit();  
  57.         fprintf(stderr,"Couldn't initialize transport layer!\n");  
  58.         return -1;  
  59.     }  
  60.     flag=1;  
  61.   
  62.     while(flag)  
  63.     {  
  64.         //输入命令  
  65.         printf("Please input the command:\n");  
  66.         scanf("%c",&command);  
  67.         getchar();  
  68.   
  69.         switch(command)  
  70.         {  
  71.         case 'r':  
  72.             printf("This modal is not completed!\n");  
  73.             break;  
  74.         case 'i'://INVITE,发起呼叫请求  
  75.             i=eXosip_call_build_initial_invite(&invite,dest_call,source_call,NULL,"This is a call for conversation");                                             
  76.             if(i!=0)  
  77.             {  
  78.                 printf("Initial INVITE failed!\n");  
  79.                 break;  
  80.             }  
  81.             //符合SDP格式,其中属性a是自定义格式,也就是说可以存放自己的信息,  
  82.             //但是只能有两列,比如帐户信息  
  83.             //但是经过测试,格式vot必不可少,原因未知,估计是协议栈在传输时需要检查的  
  84.             _snprintf(tmp,4096,  
  85.                 "v=0\r\n"  
  86.                 "o=anonymous 0 0 IN IP4 0.0.0.0\r\n"  
  87.                 "t=1 10\r\n"  
  88.                 "a=username:rainfish\r\n"  
  89.                 "a=password:123\r\n");  
  90.   
  91.             osip_message_set_body(invite,tmp,strlen(tmp));  
  92.             osip_message_set_content_type(invite,"application/sdp");  
  93.   
  94.             eXosip_lock();  
  95.             i=eXosip_call_send_initial_invite(invite); //invite SIP INVITE message to send  
  96.             eXosip_unlock();  
  97.   
  98.             //发送了INVITE消息,等待应答  
  99.             flag1=1;  
  100.             while(flag1)  
  101.             {  
  102.                 je=eXosip_event_wait(0,200); //Wait for an eXosip event  
  103.                 //(超时时间秒,超时时间毫秒)   
  104.                 if(je==NULL)  
  105.                 {  
  106.                     printf("No response or the time is over!\n");  
  107.                     break;  
  108.                 }  
  109.                 switch(je->type)   //可能会到来的事件类型  
  110.                 {  
  111.                 case EXOSIP_CALL_INVITE:   //收到一个INVITE请求  
  112.                     printf("a new invite received!\n");  
  113.                     break;  
  114.                 case EXOSIP_CALL_PROCEEDING: //收到100 trying消息,表示请求正在处理中  
  115.                     printf("proceeding!\n");  
  116.                     break;  
  117.                 case EXOSIP_CALL_RINGING:   //收到180 Ringing应答,表示接收到INVITE请求的UAS正在向被叫用户振铃  
  118.                     printf("ringing!\n");  
  119.                     printf("call_id is %d,dialog_id is %d \n",je->cid,je->did);  
  120.                     break;  
  121.                 case EXOSIP_CALL_ANSWERED: //收到200 OK,表示请求已经被成功接受,用户应答  
  122.                     printf("ok!connected!\n");  
  123.                     call_id=je->cid;  
  124.                     dialog_id=je->did;  
  125.                     printf("call_id is %d,dialog_id is %d \n",je->cid,je->did);  
  126.   
  127.                     //回送ack应答消息  
  128.                     eXosip_call_build_ack(je->did,&ack);  
  129.                     eXosip_call_send_ack(je->did,ack);  
  130.                     flag1=0; //推出While循环  
  131.                     break;  
  132.                 case EXOSIP_CALL_CLOSED: //a BYE was received for this call  
  133.                     printf("the other sid closed!\n");  
  134.                     break;  
  135.                 case EXOSIP_CALL_ACK: //ACK received for 200ok to INVITE   
  136.                     printf("ACK received!\n");  
  137.                     break;  
  138.                 default//收到其他应答  
  139.                     printf("other response!\n");  
  140.                     break;  
  141.                 }  
  142.                 eXosip_event_free(je); //Free ressource in an eXosip event  
  143.             }  
  144.             break;  
  145.   
  146.         case 'h':   //挂断  
  147.             printf("Holded!\n");  
  148.   
  149.             eXosip_lock();  
  150.             eXosip_call_terminate(call_id,dialog_id);  
  151.             eXosip_unlock();  
  152.             break;  
  153.   
  154.         case 'c':  
  155.             printf("This modal is not commpleted!\n");  
  156.             break;  
  157.   
  158.         case 's'//传输INFO方法  
  159.             eXosip_call_build_info(dialog_id,&info);  
  160.             _snprintf(tmp,4096,"\nThis is a sip message(Method:INFO)");  
  161.             osip_message_set_body(info,tmp,strlen(tmp));  
  162.             //格式可以任意设定,text/plain代表文本信息;  
  163.             osip_message_set_content_type(info,"text/plain");  
  164.             eXosip_call_send_request(dialog_id,info);  
  165.             break;  
  166.   
  167.         case 'm':  
  168.             //传输MESSAGE方法,也就是即时消息,和INFO方法相比,我认为主要区别是:  
  169.             //MESSAGE不用建立连接,直接传输信息,而INFO消息必须在建立INVITE的基础上传输  
  170.             printf("the method : MESSAGE\n");  
  171.             eXosip_message_build_request(&message,"MESSAGE",dest_call,source_call,NULL);  
  172.             //内容,方法,      to       ,from      ,route  
  173.             _snprintf(tmp,4096,"This is a sip message(Method:MESSAGE)");  
  174.             osip_message_set_body(message,tmp,strlen(tmp));  
  175.             //假设格式是xml  
  176.             osip_message_set_content_type(message,"text/xml");  
  177.             eXosip_message_send_request(message);  
  178.             break;  
  179.   
  180.         case 'q':  
  181.             eXosip_quit();  
  182.             printf("Exit the setup!\n");  
  183.             flag=0;  
  184.             break;  
  185.         }  
  186.     }  
  187.   
  188.     return(0);  
  189. }</span>  



第五步,编译UAS项目:


与UAC同样的设置后,编译


  1. <span style="font-family:SimSun;"># include <eXosip2/eXosip.h>  
  2. # include <stdio.h>  
  3. # include <stdlib.h>  
  4. # include <Winsock2.h>  
  5.   
  6.   
  7. int main (int argc, char *argv[])  
  8. {  
  9.    eXosip_event_t *je = NULL;  
  10.    osip_message_t *ack = NULL;  
  11.    osip_message_t *invite = NULL;  
  12.    osip_message_t *answer = NULL;  
  13.    sdp_message_t *remote_sdp = NULL;  
  14.    int call_id, dialog_id;  
  15.    int i,j;  
  16.    int id;  
  17.    char *sour_call = "sip:140@127.0.0.1";  
  18.    char *dest_call = "sip:133@127.0.0.1:15060";//client ip  
  19.    char command;  
  20.    char tmp[4096];  
  21.    char localip[128];  
  22.    int pos = 0;  
  23.    //初始化sip  
  24.    i = eXosip_init ();  
  25.    if (i != 0)  
  26. {  
  27.    printf ("Can't initialize eXosip!\n");  
  28.    return -1;  
  29. }  
  30.    else  
  31. {  
  32.    printf ("eXosip_init successfully!\n");  
  33. }  
  34.    i = eXosip_listen_addr (IPPROTO_UDP, NULL, 15061, AF_INET, 0);  
  35.    if (i != 0)  
  36. {  
  37.    eXosip_quit ();  
  38.    fprintf (stderr, "eXosip_listen_addr error!\nCouldn't initialize transport layer!\n");  
  39. }  
  40.    for(;;)  
  41. {  
  42.    //侦听是否有消息到来  
  43.    je = eXosip_event_wait (0,50);   
  44.    //协议栈带有此语句,具体作用未知  
  45.    eXosip_lock ();  
  46.    eXosip_default_action (je);  
  47.    eXosip_automatic_refresh ();  
  48.    eXosip_unlock ();  
  49.    if (je == NULL)//没有接收到消息  
  50. continue;  
  51.    // printf ("the cid is %s, did is %s/n", je->did, je->cid);  
  52.    switch (je->type)  
  53. {  
  54. case EXOSIP_MESSAGE_NEW://新的消息到来  
  55.    printf (" EXOSIP_MESSAGE_NEW!\n");  
  56.    if (MSG_IS_MESSAGE (je->request))//如果接受到的消息类型是MESSAGE  
  57.        {  
  58.    {  
  59.        osip_body_t *body;  
  60.        osip_message_get_body (je->request, 0, &body);   
  61.        printf ("I get the msg is: %s\n", body->body);  
  62.        //printf ("the cid is %s, did is %s/n", je->did, je->cid);  
  63.    }  
  64.    //按照规则,需要回复OK信息  
  65.    eXosip_message_build_answer (je->tid, 200,&answer);  
  66.    eXosip_message_send_answer (je->tid, 200,answer);  
  67.        }  
  68.    break;  
  69. case EXOSIP_CALL_INVITE:  
  70.    //得到接收到消息的具体信息  
  71.          printf ("Received a INVITE msg from %s:%s, UserName is %s, password is %s\n",je->request->req_uri->host,  
  72.       je->request->req_uri->port, je->request->req_uri->username, je->request->req_uri->password);  
  73.    //得到消息体,认为该消息就是SDP格式.  
  74.    remote_sdp = eXosip_get_remote_sdp (je->did);  
  75.    call_id = je->cid;  
  76.    dialog_id = je->did;  
  77.      
  78.    eXosip_lock ();  
  79.    eXosip_call_send_answer (je->tid, 180, NULL);  
  80.    i = eXosip_call_build_answer (je->tid, 200, &answer);  
  81.    if (i != 0)  
  82.        {  
  83.       printf ("This request msg is invalid!Cann't response!\n");  
  84.       eXosip_call_send_answer (je->tid, 400, NULL);  
  85.        }  
  86.    else  
  87.        {  
  88.       snprintf (tmp, 4096,  
  89.             "v=0\r\n"  
  90.             "o=anonymous 0 0 IN IP4 0.0.0.0\r\n"  
  91.             "t=1 10\r\n"  
  92.             "a=username:rainfish\r\n"  
  93.             "a=password:123\r\n");  
  94.         
  95.       //设置回复的SDP消息体,下一步计划分析消息体  
  96.       //没有分析消息体,直接回复原来的消息,这一块做的不好。  
  97.       osip_message_set_body (answer, tmp, strlen(tmp));  
  98.       osip_message_set_content_type (answer, "application/sdp");  
  99.         
  100.       eXosip_call_send_answer (je->tid, 200, answer);  
  101.       printf ("send 200 over!\n");  
  102.        }  
  103.    eXosip_unlock ();  
  104.      
  105.    //显示出在sdp消息体中的attribute 的内容,里面计划存放我们的信息  
  106.    printf ("the INFO is :\n");  
  107.    while (!osip_list_eol ( &(remote_sdp->a_attributes), pos))  
  108.        {  
  109.       sdp_attribute_t *at;  
  110.         
  111.       at = (sdp_attribute_t *) osip_list_get ( &remote_sdp->a_attributes, pos);  
  112.       printf ("%s : %s\n", at->a_att_field, at->a_att_value);//这里解释了为什么在SDP消息体中属性a里面存放必须是两列  
  113.         
  114.       pos ++;  
  115.        }  
  116.    break;  
  117. case EXOSIP_CALL_ACK:  
  118.    printf ("ACK recieved!\n");  
  119.    // printf ("the cid is %s, did is %s/n", je->did, je->cid);   
  120.    break;  
  121. case EXOSIP_CALL_CLOSED:  
  122.    printf ("the remote hold the session!\n");  
  123.    // eXosip_call_build_ack(dialog_id, &ack);  
  124.    //eXosip_call_send_ack(dialog_id, ack);   
  125.    i = eXosip_call_build_answer (je->tid, 200, &answer);  
  126.    if (i != 0)  
  127.        {  
  128.       printf ("This request msg is invalid!Cann't response!\n");  
  129.       eXosip_call_send_answer (je->tid, 400, NULL);  
  130.         
  131.       }  
  132.    else  
  133.        {  
  134.       eXosip_call_send_answer (je->tid, 200, answer);  
  135.       printf ("bye send 200 over!\n");  
  136.        }         
  137.    break;  
  138. case EXOSIP_CALL_MESSAGE_NEW://至于该类型和EXOSIP_MESSAGE_NEW的区别,源代码这么解释的  
  139. /* 
  140. // request related events within calls (except INVITE)  
  141.       EXOSIP_CALL_MESSAGE_NEW,          < announce new incoming request.  
  142. // response received for request outside calls  
  143.          EXOSIP_MESSAGE_NEW,          < announce new incoming request.  
  144.          我也不是很明白,理解是:EXOSIP_CALL_MESSAGE_NEW是一个呼叫中的新的消息到来,比如ring trying都算,所以在接受到后必须判断 
  145.          该消息类型,EXOSIP_MESSAGE_NEW而是表示不是呼叫内的消息到来。 
  146.          该解释有不妥地方,仅供参考。 
  147. */  
  148.    printf(" EXOSIP_CALL_MESSAGE_NEW\n");  
  149.    if (MSG_IS_INFO(je->request) ) //如果传输的是INFO方法  
  150.    {  
  151.                eXosip_lock ();  
  152.              i = eXosip_call_build_answer (je->tid, 200, &answer);  
  153.              if (i == 0)  
  154.             {  
  155.                eXosip_call_send_answer (je->tid, 200, answer);  
  156.             }  
  157.              eXosip_unlock ();  
  158.       {  
  159.        osip_body_t *body;  
  160.        osip_message_get_body (je->request, 0, &body);  
  161.        printf ("the body is %s\n", body->body);  
  162.       }  
  163.    }  
  164.    break;   
  165. default:  
  166.    printf ("Could not parse the msg!\n");  
  167. }  
  168. }  
  169. }  
  170. </span>  


例子已经上传:http://download.csdn.net/detail/longlong530/5647749

运行示意图:






    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约