从网站上看到了这样的一篇博文 :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 event
105                 //(超时时间秒,超时时间毫秒)
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 call
135                     printf("the other sid closed!\n");
136                     break;
137                 case EXOSIP_CALL_ACK: //ACK received for 200ok to INVITE
138                     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 event
145             }
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      ,route
175             snprintf(tmp,4096,"This is a sip message(Method:MESSAGE)");
176             osip_message_set_body(message,tmp,strlen(tmp));
177             //假设格式是xml
178             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             else
136             {
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 calls
146                      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运行结果:

posted on 2014-09-16 11:25  xianbing  阅读(9555)  评论(1编辑  收藏  举报