zoukankan      html  css  js  c++  java
  • osip及eXosip的编译方法

    osip及eXosip的编译方法

    在最新版本的osip2、exosip2中不支持在VC6.0下编译osip、exosip协议栈的方法

    说明:
    1.以下文章中的osip版本为3.1.0
    2.eXosip版本为3.1.0
    3.编译环境为:Windows XP 专业版本+VS 2005
    4.实例程序下载:http://download.csdn.net/source/617797
    5.osip、exosip、openssl的开发包下载,开发包包括:osip2.dll、osipparser2.dll、exosip2.dll、libeay32.dll、ssleay32.dll和相对应的lib文件,下载地址同上

    第一步,下载:
    http://download.savannah.gnu.org/releases/osip/libosip2-3.1.0.tar.gz
    下载最新的osip库并解压
    http://download.savannah.gnu.org/releases/exosip/libeXosip2-3.1.0.tar.gz
    下载最新的eXsoip库并解压
    第二步,编译osip3.1.0:
    1.用VS2005打开libosip2-3.1.0/platform/vsnet/osip.sln
    2.对osip2和osipparser2项目生成Release DLL
    3.其生成的LIB/DLL 位于:libosip2-3.1.0/platform/vsnet/Release DLL/下
    4.如果有出现外部变量找不到的情况,很有可能是生成的dll没有实现该函数,在def文件中删除找不到的外部变量就好了
    第三步,编译eXosip3.1.0:
    1.用VS2005打开libeXosip2-3.1/platform/vsnet/eXosip.sln
    2.将libosip2-3.1/include/osip2目录COPY到libeXosip2-3.1/include/下
    3.将libosip2-3.1/include/osipparser2目录COPY到libeXosip2-3.1/include/下
    4.在libeXosip2-3.1目录下新建lib目录
    5.将“第二步”中生成的libosip2-3.1/platform/vsnet/Release DLL/osip2.lib文件COPY到libeXosip2-3.1/lib目录下
    6.将“第二步”中生成的libosip2-3.1/platform/vsnet/Release DLL/osipparser2.lib文件COPY到libeXosip2-3.1/lib目录下
    7.修改项目属性,新增Dnsapi.lib Iphlpapi.lib Ws2_32.lib osip2.lib osipparser2.lib库输入
    8.修改项目属性,新增库目录../../lib
    9.修改项目的输出为.DLL,默认为.lib
    10.编译Relase DLL
    11.其生成的LIB/DLL 位于:libeXosip2-3.1/platform/vsnet/Release/下

    注意:

    在eXoSip.def 中添加下面函数的导出,不知道是为什么 这些函数没有导出!
         eXosip_call_set_reference
        eXosip_call_build_initial_invite
        eXosip_call_send_initial_invite
        eXosip_call_build_request
        eXosip_call_build_ack
        eXosip_call_send_ack
        eXosip_call_build_refer
        eXosip_call_build_info
        eXosip_call_build_options
        eXosip_call_build_update
        eXosip_call_build_notify
        eXosip_call_send_request
        eXosip_call_build_answer
        eXosip_call_send_answer
        eXosip_call_terminate
        eXosip_call_build_prack
        eXosip_call_send_prack
        eXosip_call_get_referto
        eXosip_call_find_by_replaces

    编译osip可能会出现如下错误:

    1:在osipparser.dll的def文件会出现几个拼写错误,如缺少MD5_****的函数前面缺少osip_,使得连接器出现link2019错误,解决方法是在前面加上osip_

    2:但是如果在编译的时候出现错误:

    libnet_prand.obj : error LNK2001: unresolved external symbol __imp__CryptReleaseContext@8
    libnet_prand.obj : error LNK2001: unresolved external symbol __imp__CryptGenRandom@12
    libnet_prand.obj : error LNK2001: unresolved external symbol __imp__CryptAcquireContextA@20
    Debug/Libnet.dll : fatal error LNK1120: 3 unresolved externals

    仔细看了下,CryptReleaseContext等这三个函数不是从advapi32.lib里导入的么?难道要加上advapi32.lib库?在项目设置的连接里把advapi32.lib加上,然后rebuil all,果然成功。

    如果出现是__RTC_CheckEsp这个外部变量无法解析,很大可能是两个项目的配置不一样,比如说一个能从父项目继承什么。另外一个没有设置,就会出现这个问题。

    编译eXosip可能会出现的问题:

    要包含头文件:ssleay32.lib libeay32.lib Dnsapi.lib Iphlpapi.lib Ws2_32.lib osip2.lib osipparser2.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ,其中ssleay32.lib libeay32.lib是openssl的静态库。

    可能还会找不到一些无法解析的外部变量,可能是在osip的输出dll的def文件中没有加上

         osip_transaction_set_srv_record     @122

    然后重新编译osip

    外部变量问题,一般都是库文件的问题,记住要把库文件放在工程目录lib目录下(没有lib目录自己新建一个) 然后在工具->项目->c/c++->C++目录下把设置../../lib设置成包含的目录

    其中ssleay32.lib libeay32.lib是openssl编译形成的静态链接库,可以从网上下载,或者自己编译

    之外,尤其大家下载的源代码由于认为的或者是编译环境的不同,容易造成多种错误,我还碰到了个无法解析的Osip_^^^!!#@!@#!函数无法解析的情况,在osip中的def文件一查,果然缺少个122的函数文件输出声明,加进去重新编译osip,成功,在编译eXosip成功!

    最后运行实例,进行项目配置:

    osip及eXosip的开发方法:
    将以下程序作为UAS.CPP保存

    // UAS.cpp : 定义控制台应用程序的入口点。
    //
    # include <eXosip2/eXosip.h>
    # include <stdio.h>
    # include <stdlib.h>
    # include <Winsock2.h>
    
    /*
    # include <netinet/in.h>
    # include <sys/socket.h>
    # include <sys/types.h>
    */
    
    #pragma comment(lib, "osip2.lib")
    #pragma comment(lib, "osipparser2.lib")
    #pragma comment(lib, "eXosip.lib")
    #pragma comment(lib, "Iphlpapi.lib")
    #pragma comment(lib, "Dnsapi.lib")
    #pragma comment(lib, "ws2_32.lib")
    
    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:24@10.16.79.24";
        char *dest_call = "sip:24@10.16.79.24:5061";//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, 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);
    
                    //按照规则,需要回复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");
                break;
            }
        }
    }

    将以下程序作为UAC.CPP保存

    // UAC.cpp : 定义控制台应用程序的入口点。
    //
    # include <eXosip2/eXosip.h>
    # include <stdio.h>
    # include <stdlib.h>
    # include <Winsock2.h>
    
    /*
    #i nclude <netinet/in.h>
    #i nclude <sys/socket.h>
    #i nclude <sys/types.h>
    */
    
    #pragma comment(lib, "osip2.lib")
    #pragma comment(lib, "osipparser2.lib")
    #pragma comment(lib, "eXosip.lib")
    #pragma comment(lib, "Iphlpapi.lib")
    #pragma comment(lib, "Dnsapi.lib")
    #pragma comment(lib, "ws2_32.lib")
    
    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:24@10.16.79.24";
        char *registerer = "sip:10.16.79.24:5060";//server ip
        char *source_call = "sip:24@10.16.79.24";
        char *dest_call = "sip:24@10.16.79.24:5060";//server ip
    
        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, 5061, 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);
    }
  • 相关阅读:
    【算法工程师/专家(用户行为分析方向),阿里云计算有限公司】前程无忧官方招聘网站
    linux文件设备与I/O: dup和dup2函数
    【高级网页分析工程师,360安全卫士】前程无忧官方招聘网站
    分享:gzip头部格式
    C调试时常用的宏
    分享:Waterfox 18.0.1 发布,64 位的 Firefox
    开发人员应该对IIS理论层的知识了解的多一些~第三讲 网页从IIS端到客户端浏览器经历的阶段
    开发人员应该对IIS理论层的知识了解的多一些~第一讲 什么是Http?
    开发人员应该对IIS理论层的知识了解的多一些~第二讲 静态网页与动态网页如何被解释执行的
    Javascript基础与面向对象基础~目录
  • 原文地址:https://www.cnblogs.com/elisha-blogs/p/3956395.html
Copyright © 2011-2022 走看看