首页 > 代码库 > linux下编译eXosip、osip,以及UAC和UAS的例子

linux下编译eXosip、osip,以及UAC和UAS的例子

从网站上看到了这样的一篇博文 :Windows下编译eXosip、osip,以及UAC和UAS的例子  (链接:http://www.cnblogs.com/dyllove98/archive/2013/06/25/3155427.html)

觉得对学习sip的初学者,包括我,都是很有帮助的。但是那是在window下的编译,我在这里稍微改了一下,让它支持在linux下编译测试运行通过。

我们这里使用库的版本:libosip2-3.6.0.tar,libeXosip2-3.6.0.tar,大家可以自己进入正面的链接去下载。

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

  1、解压libosip2-3.6.0.tar ,比如解压目录为 /usr/local/src/,
        #tar zxvf libosip2-3.6.0.tar -C /usr/local/src

        编译该lib库:
        #./configure
        #make
        #make install

  2、同理编译libeXosip2
      注意最后要更新库,否则在程序执行时,可能会提示找不到库,编译后的库文件及头文件会默认放在/usr/local目录下:
      #ldconfig

  3、编译代码uac.c 和 uas.c
       #gcc uac.c -o uac -losip2 -leXosip2 -lpthread
       #gcc uas.c -o uas -losip2 -leXosip2 -lpthread

  4、测试运行uas 和 uac,最好打开两个shell来运行
       #./uas
       #./uac
       注意:如果在运行过程中提示找不到libosip2.so.6等类似的提示,说明osip动态库的路径可能还没有包含进去,可以使用下面的命令手动包含动态库的路径
       #export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

代码uac.c

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

代码uas.c

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

运行截图:

uac运行结果:

uas运行结果:

linux下编译eXosip、osip,以及UAC和UAS的例子