经过一段时间的学习,对sip总算有了一点认识,在学习过程中,遇到了太多的问题,郁闷过,惆怅过,但是一咬牙,还是过来了。令我感动的是,在网上遇到一些很热心的朋友,不厌其烦地给我以解惑,感谢他们,尤其是友善的大狗,呵呵,希望将来有一天他能看到这篇文章。
我是利用eXosip协议栈进行开发的,网上有一篇<一个简单的sip呼叫例子>,写的不错,但是好像有一些问题,而对于初学者来说,能拿到 一个好的例子,对sip的理解可以到达事半功倍的效果。于是便把自己的写的例子拿出来,让大家参考一下,若有问题,欢迎指正。
只需把里面的IP地址改正、编译即可使用。
/******************************************
编译方法:gcc xxx.c -o xxx -leXosip2
****************************************/
/*******************UAS***********************
本文可以任意转载,但必须保留出处
作者:rainfish
网址:http://blog.csdn.net/bat603/
测试环境:eXosip3.0.1/redhat AS 4
************************************************/
- #include <eXosip2/eXosip.h>
- #include <osip2/osip_mt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- int
- main (int argc, char *argv[])
- {
- 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:133@192.168.0.133";
- char *dest_call = "sip:140@192.168.0.140:5060";
- char command;
- char tmp[4096];
- char localip[128];
- int pos = 0;
- //初始化sip
- i = eXosip_init ();
- if (i != 0)
- {
- printf ("Can't initialize eXosip!/n");
- return -1;
- }
- else
- {
- printf ("eXosip_init successfully!/n");
- }
- i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5060, AF_INET, 0);
- if (i != 0)
- {
- eXosip_quit ();
- fprintf (stderr, "eXosip_listen_addr error!/nCouldn'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;
- // printf ("the cid is %s, did is %s/n", je->did, je->cid);
- switch (je->type)
- {
- case EXOSIP_MESSAGE_NEW://新的消息到来
- printf (" EXOSIP_MESSAGE_NEW!/n");
- if (MSG_IS_MESSAGE (je->request))//如果接受到的消息类型是MESSAGE
- {
- {
- osip_body_t *body;
- osip_message_get_body (je->request, 0, &body);
- printf ("I get the msg is: %s/n", body->body);
- //printf ("the cid is %s, did is %s/n", je->did, je->cid);
- }
- //按照规则,需要回复200 OK信息
- eXosip_message_build_answer (je->tid, 200,&answer);
- eXosip_message_send_answer (je->tid, 200,answer);
- }
- break;
- case EXOSIP_CALL_INVITE:
- //得到接收到消息的具体信息
- printf ("Received a INVITE msg from %s:%s, UserName is %s, password is %s/n"
- ,je->request->req_uri->host, je->request->req_uri->port, je->request->req_uri->username
- , je->request->req_uri->password);
- //得到消息体,认为该消息就是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)
- {
- printf ("This request msg is invalid!Cann't response!/n");
- 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);
- printf ("send 200 over!/n");
- }
- eXosip_unlock ();
- //显示出在sdp消息体中的 attribute 的内容,里面计划存放我们的信息
- printf ("the INFO is :/n");
- while (!osip_list_eol (remote_sdp->a_attributes, pos))
- {
- sdp_attribute_t *at;
- at = (sdp_attribute_t *) osip_list_get (remote_sdp->a_attributes, pos);
- printf ("%s : %s/n", at->a_att_field, at->a_att_value);
- //这里解释了为什么在SDP消息体中属性a里面存放必须是两列
- pos ++;
- }
- break;
- case EXOSIP_CALL_ACK:
- printf ("ACK recieved!/n");
- // printf ("the cid is %s, did is %s/n", je->did, je->cid);
- break;
- case EXOSIP_CALL_CLOSED:
- printf ("the remote hold the session!/n");
- // 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);
- printf ("bye send 200 over!/n");
- }
- break;
- case EXOSIP_CALL_MESSAGE_NEW:
- //至于该类型和EXOSIP_MESSAGE_NEW的区别,源代码这么解释的
- /*
- request related events within calls (except INVITE)
- EXOSIP_CALL_MESSAGE_NEW, //< announce new incoming request.
- response received for request outside calls
- EXOSIP_MESSAGE_NEW, //< announce new incoming request.
- 我也不是很明白,理解是: EXOSIP_CALL_MESSAGE_NEW是一个呼叫中的新的消息到来,
- 比如ring trying都算,所以在接受到后必须判断
- 该消息类型,EXOSIP_MESSAGE_NEW而是表示不是呼叫内的消息到来。
- 该解释有不妥地方,仅供参考。
- */
- printf(" EXOSIP_CALL_MESSAGE_NEW/n");
- 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);
- printf ("the body is %s/n", body->body);
- }
- }
- break;
- default:
- printf ("Could not parse the msg!/n");
- }
- }
- }
/*******************UAC*********************
本文可以任意转载,但必须保留出处
作者:rainfish
网址:http://blog.csdn.net/bat603/
测试环境:eXosip3.0.1/redhat AS 4
***************************************************************************/
- #include <eXosip2/eXosip.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/types.h>
- 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;
- char *identity = "sip:140@192.168.0.140";
- char *registerer = "sip:192.168.0.133:5060";
- char *source_call = "sip:140@192.168.0.140";
- char *dest_call = "sip:133@192.168.0.133:5060";
- char command;
- char tmp[4096];
- char localip[128];
- printf("r 向服务器注册/n/n");
- printf("c 取消注册/n/n");
- printf("i 发起呼叫请求/n/n");
- printf("h 挂断/n/n");
- printf("q 退出程序/n/n");
- printf("s 执行方法INFO/n/n");
- printf("m 执行方法MESSAGE/n/n");
- //初始化
- i = eXosip_init ();
- if (i != 0)
- {
- printf ("Couldn't initialize eXosip!/n");
- return -1;
- }
- else
- {
- printf ("eXosip_init successfully!/n");
- }
- i = eXosip_listen_addr (IPPROTO_UDP, NULL, 5060, AF_INET, 0);
- if (i != 0)
- {
- eXosip_quit ();
- fprintf (stderr, "Couldn't initialize transport layer!/n");
- return -1;
- }
- flag = 1;
- while (flag)
- {
- printf ("please input the comand:/n");
- scanf ("%c", &command);
- getchar ();
- switch (command)
- {
- case 'r':
- printf ("This modal isn't commpleted!/n");
- break;
- case 'i':/* INVITE */
- i = eXosip_call_build_initial_invite (&invite, dest_call
- , source_call, NULL, "This si a call for a conversation");
- if (i != 0)
- {
- printf ("Intial INVITE failed!/n");
- break;
- }
- //符合SDP格式,其中属性a是自定义格式,也就是说可以存放自己的信息,但是只能是两列,比如帐户信息
- //但是经测试,格式:v o t必不可少,原因未知,估计是协议栈在传输时需要检查的
- 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");
- osip_message_set_body (invite, tmp, strlen(tmp));
- 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)
- {
- printf ("No response or the time is over!/n");
- break;
- }
- switch (je->type)
- {
- case EXOSIP_CALL_INVITE:
- printf ("a new invite reveived!/n");
- break;
- case EXOSIP_CALL_PROCEEDING:
- printf ("proceeding!/n");
- break;
- case EXOSIP_CALL_RINGING:
- printf ("ringing!/n");
- // call_id = je->cid;
- // dialog_id = je->did;
- printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did);
- break;
- case EXOSIP_CALL_ANSWERED:
- printf ("ok! connected!/n");
- call_id = je->cid;
- dialog_id = je->did;
- printf ("call_id is %d, dialog_id is %d /n", je->cid, je->did);
- eXosip_call_build_ack (je->did, &ack);
- eXosip_call_send_ack (je->did, ack);
- flag1 = 0;
- break;
- case EXOSIP_CALL_CLOSED:
- printf ("the other sid closed!/n");
- break;
- case EXOSIP_CALL_ACK:
- printf ("ACK received!/n");
- break;
- default:
- printf ("other response!/n");
- break;
- }
- eXosip_event_free (je);
- }
- break;
- case 'h':
- printf ("Holded !/n");
- eXosip_lock ();
- eXosip_call_terminate (call_id, dialog_id);
- eXosip_unlock ();
- break;
- case 'c':
- printf ("This modal isn't commpleted!/n");
- break;
- case 's':
- //传输INFO方法
- eXosip_call_build_info (dialog_id, &info);
- snprintf (tmp , 4096,
- "hello,rainfish");
- 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的基础上传输。
- printf ("the mothed :MESSAGE/n");
- eXosip_message_build_request (&message, "MESSAGE", dest_call, source_call, NULL);
- snprintf (tmp, 4096,
- "hellor rainfish");
- osip_message_set_body (message, tmp, strlen(tmp));
- //假设格式是xml
- osip_message_set_content_type (message, "text/xml");
- eXosip_message_send_request (message);
- break;
- case 'q':
- eXosip_quit ();
- printf ("Exit the setup!/n");
- flag = 0;
- break;
- }
- }
- return (0);
- }
文章转载自: 罗索工作室 [ http://www.rosoo.net]
本文标题:一个用eXosip实现的UAC和UAS的例子
本文作者:bat603 本文来源:blog.csdn.net
本文地址: http://www.rosoo.net/a/201004/9182.html