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[];
char localip[];
int pos = ; //初始化sip
i = eXosip_init ();
if (i != )
{
printf ("Can't initialize eXosip!/n");
return -;
}
else
{
printf ("eXosip_init successfully!/n");
} i = eXosip_listen_addr (IPPROTO_UDP, NULL, , AF_INET, );
if (i != )
{
eXosip_quit ();
fprintf (stderr, "eXosip_listen_addr error!/nCouldn't initialize transport layer!/n");
} for(;;)
{
//侦听是否有消息到来
je = eXosip_event_wait (,); //协议栈带有此语句,具体作用未知 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, , &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, ,&answer);
eXosip_message_send_answer (je->tid, ,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, , NULL); i = eXosip_call_build_answer (je->tid, , &answer);
if (i != )
{
printf ("This request msg is invalid!Cann't response!/n");
eXosip_call_send_answer (je->tid, , NULL);
}
else
{
snprintf (tmp, ,
"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, , 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, , &answer);
if (i != )
{
printf ("This request msg is invalid!Cann't response!/n");
eXosip_call_send_answer (je->tid, , NULL);
}
else
{
eXosip_call_send_answer (je->tid, , 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, , &answer);
if (i == )
{
eXosip_call_send_answer (je->tid, , answer);
}
eXosip_unlock ();
{
osip_body_t *body;
osip_message_get_body (je->request, , &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 = ;
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[];
char localip[]; 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 != )
{
printf ("Couldn't initialize eXosip!/n");
return -;
}
else
{
printf ("eXosip_init successfully!/n");
} i = eXosip_listen_addr (IPPROTO_UDP, NULL, , AF_INET, );
if (i != )
{
eXosip_quit ();
fprintf (stderr, "Couldn't initialize transport layer!/n");
return -;
} flag = ; 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 != )
{
printf ("Intial INVITE failed!/n");
break;
}
/*符合SDP格式,其中属性a是自定义格式,
也就是说可以存放自己的信息,
但是只能是两列,比如帐户信息
但是经测试,格式:v o t必不可少,原因未知,
估计是协议栈在传输时需要检查的
*/
snprintf (tmp, ,
"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 = ;
while (flag1)
{
je = eXosip_event_wait (, );
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 = ;
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, , "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, , "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 = ;
break;
}
}
return ();
}
osip及eXosip的编译方法的更多相关文章
- Genome2D编译方法
Genome2D是一个高效的2D引擎,现在支持Flash(stage3d)和HTML5,因为只有作者一个人在维护,就没开源代码. 最近和作者沟通了下,已经开源啦. 作者划分了几个模块,编译起来不是特别 ...
- Spark-1.0.1 的make-distribution.sh编译、SBT编译、Maven编译 三种编译方法
fesh个人实践,欢迎经验交流!本文Blog地址:http://www.cnblogs.com/fesh/p/3775343.html 本文编译方法所支持的hadoop环境是Hadoop-2.2.0, ...
- 详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法
详细地jsoncpp编译方法 和 vs2010中导入第三方库的方法 一 编译链接 1 在相应官网下载jsoncpp 2 解压得到jsoncpp-src-0.5.0文件 3 打开jsoncpp-src- ...
- (DT系列一)DTS结构及其编译方法
DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 3,dts是如何被编译的,以及编译后会生成一个什么文件. 二:参考文字 1,DTS(device tre ...
- 【转】(DT系列一)DTS结构及其编译方法----不错
原文网址:http://www.cnblogs.com/biglucky/p/4057476.html DTS结构及其编译方法 一:主要问题 1,需要了解dtsi与dts的关系 2,dts的结构模型 ...
- 简单的Android之apk包反编译方法
网上相关的文章一大堆了,我只是总结下自己的反编译方法和工具 工具下载地址: http://download.csdn.net/detail/zsjangel/7104663 下载上面的三个工具的压缩包 ...
- sass学习笔记 -- sass的四种编译方法
sass的四种编译方法:(.scss) (一)ruby下的命令行编译 首先需要安装ruby,注意需勾选Add Ruby executables to your PATH选项,以添加环境变量. ruby ...
- (转)wxWidgets 2.9.2svn(3.x)最小体积编译方法
官方论坛.网上记录的wxWidgets编译方法,会导致编译后的程序库非常大,原因在于对编译的方法选择不当.下面简单总结一下如何编译最新的SVN代码.下载最新源码(每日构建):http://biolpc ...
- Hadoop编译方法
伪分布式: hadoop-env.sh core-site.xml hdfs-site.xml mapred-site.xml 1.在hadoop官网下载hadoop的源码(同步跟踪最新源代码) mv ...
随机推荐
- UUID详解
什么是UUID? UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法 ...
- Linux+eclipse+gdb调试postgresql源码
pg内核源码解析课上用的vs调试pg源码, VS用起来确实方便,但是配置调试环境着实有点麻烦.首先得装个windows系统,最好是xp,win7稍微麻烦点:最好使用vs05,08和10也可以,但是比0 ...
- 【Ruby on Rails学习二】在线学习资料的整理
由于工作任务重,时间紧,没有太多学习的时间,大致找了些在线学习资料,这里做个整理,希望对同样准备学习的朋友有帮助 在线文档类: Ruby on Rails 实战圣经 使用 Rails 4.2 及 R ...
- JS-事件处理
1.一个简单的单击事件: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...
- 加上固件密码,Mac更安全
在Mac OS X中,管理员密码非常重要,在修改系统参数或安装软件时都要求输入密码,这避免了绝大部分的破坏性误操作和恶意程序(尽管Mac上恶意程序本来就少的可怜). 但是对Mac OS X比较熟悉的人 ...
- H面试程序(10): 字符串包含问题
题目描述:判断第二个字符串中的元素是否都能在第一个字符串中找到: 注意:和字符串的字串的问题有所区别,如第一个字符串为 abcdefg,第二个字符串为 aaabc,第二个字串还是包含于第一个字符串 ...
- Android经常使用的五种弹出对话框
一个Android开发中经常使用对话框的小样例,共同拥有五种对话框:普通弹出对话框,单选对话框,多选对话框,输入对话框及进度条样式对话框: <LinearLayout xmlns:android ...
- Linux下配置免安装版Tomcat
一.下载免安装版Tomcat 打开Tomcat主页http://tomcat.apache.org/,下载Tomcat免安装版,我这里下载的是apache-tomcat-7.0.2.tar.gz. 二 ...
- [React] React Router: Redirect
The Redirect component in react-router does exactly what it sounds like. It allows us to redirect fr ...
- passwd-shadow文件
[root@rusky /]# vi /etc/passwd root:x:::Redhat5:/root:/bin/bash rusky:x::::/home/rusky:/bin/bash 1.r ...