从网站上看到了这样的一篇博文 :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运行结果:
来源:https://www.cnblogs.com/elisha-blogs/p/3974534.html