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

#include 
#include 
#include 
#include 
#include 
//#include 

int main(int argc,char *argv[])
{

    struct eXosip_t *context_eXosip;

    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;

    char *identity="sip:[email protected]";   //UAC1,端口是15060
    char *registar="sip:[email protected]:15061"; //UAS,端口是15061
    char *source_call="sip:[email protected]";
    char *dest_call="sip:[email protected]:15061";
    //identify和register这一组地址是和source和destination地址相同的
    //在这个例子中,uac和uas通信,则source就是自己的地址,而目的地址就是uac1的地址
    char command;
    char tmp[4096];

    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");
    }

    //绑定uac自己的端口15060,并进行端口监听
    i=eXosip_listen_addr(IPPROTO_UDP,NULL,15060,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 command:\n");
        scanf("%c",&command);
        getchar();

        switch(command)
        {
        case 'r':
            printf("This modal is not completed!\n");
            break;
        case 'i'://INVITE,发起呼叫请求
            i=eXosip_call_build_initial_invite(&invite,dest_call,source_call,NULL,"This is a call for conversation");
            if(i!=0)
            {
                printf("Initial INVITE failed!\n");
                break;
            }
            //符合SDP格式,其中属性a是自定义格式,也就是说可以存放自己的信息,
            //但是只能有两列,比如帐户信息
            //但是经过测试,格式vot必不可少,原因未知,估计是协议栈在传输时需要检查的
            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); //invite SIP INVITE message to send
            eXosip_unlock();

            //发送了INVITE消息,等待应答
            flag1=1;
            while(flag1)
            {
                je=eXosip_event_wait(0,200); //Wait for an eXosip event
                //(超时时间秒,超时时间毫秒)
                if(je==NULL)
                {
                    printf("No response or the time is over!\n");
                    break;
                }
                switch(je->type)   //可能会到来的事件类型
                {
                case EXOSIP_CALL_INVITE:   //收到一个INVITE请求
                    printf("a new invite received!\n");
                    break;
                case EXOSIP_CALL_PROCEEDING: //收到100 trying消息,表示请求正在处理中
                    printf("proceeding!\n");
                    break;
                case EXOSIP_CALL_RINGING:   //收到180 Ringing应答,表示接收到INVITE请求的UAS正在向被叫用户振铃
                    printf("ringing!\n");
                    printf("call_id is %d,dialog_id is %d \n",je->cid,je->did);
                    break;
                case EXOSIP_CALL_ANSWERED: //收到200 OK,表示请求已经被成功接受,用户应答
                    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);

                    //回送ack应答消息
                    eXosip_call_build_ack(je->did,&ack);
                    eXosip_call_send_ack(je->did,ack);
                    flag1=0; //推出While循环
                    break;
                case EXOSIP_CALL_CLOSED: //a BYE was received for this call
                    printf("the other sid closed!\n");
                    break;
                case EXOSIP_CALL_ACK: //ACK received for 200ok to INVITE
                    printf("ACK received!\n");
                    break;
                default: //收到其他应答
                    printf("other response!\n");
                    break;
                }
                eXosip_event_free(je); //Free ressource in an eXosip event
            }
            break;

        case 'h':   //挂断
            printf("Holded!\n");

            eXosip_lock();
            eXosip_call_terminate(call_id,dialog_id);
            eXosip_unlock();
            break;

        case 'c':
            printf("This modal is not commpleted!\n");
            break;

        case 's': //传输INFO方法
            eXosip_call_build_info(dialog_id,&info);
            snprintf(tmp,4096,"\nThis is a sip message(Method:INFO)");
            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 method : MESSAGE\n");
            eXosip_message_build_request(&message,"MESSAGE",dest_call,source_call,NULL);
            //内容,方法,      to       ,from      ,route
            snprintf(tmp,4096,"This is a sip message(Method:MESSAGE)");
            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);
}

 

代码uas.c

# include 
# include 
# include 
# include 
# include 

//# include 


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:[email protected]";
    char *dest_call = "sip:[email protected]:15060";//client ip
    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, 15061, 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);
                }
                //按照规则,需要回复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");
        }
    }
}

运行截图:

usc.c结果:

linux下编译eXosip、osip,以及UAC和UAS的例子_第1张图片

uas.c结果:
linux下编译eXosip、osip,以及UAC和UAS的例子_第2张图片

你可能感兴趣的:(SIP)