Category Archives: Develop

software development

CentOS 6.5安装Freeswitch 1.5小记

Windows下的Freeswitch没有VP8编码,源码里头也没有相应的工程,于是最后决定还是搞台单独的linux服务器。

系统CentOS 6.5 64位,运维的同事装的,应该是个标准版,没有装那些开发包。

Freeswitch的安装过程参考官网wiki,下载的就是git里头最新的版本。

安装过程中遇到一个sqlite的错误。

checking for sqlite3 >= 3.6.20… Package sqlite3 was not found in the pkg-config search path. Perhaps you should add the directory containing `sqlite3.pc’ to the PKG_CONFIG_PATH environment variable No package ‘sqlite3’ found
configure: error: Library requirements (sqlite3 >= 3.6.20) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.

试了一下:[root@localhost freeswitch]# sqlite3
SQLite version 3.6.20
Enter “.help” for instructions

想想应该是少开发包了:[root@localhost freeswitch]# yum install sqlite-devel

后边碰到缺libcurl也照样解决

[root@localhost freeswitch]# yum install libcurl-devel

后面又缺了libpcre:

[root@localhost freeswitch]# yum install pcre
[root@localhost freeswitch]# yum install pcre-devel

speex :

[root@localhost freeswitch]# yum install speex
[root@localhost freeswitch]# yum install speex-devel

最后报了一个mod_xml_rpc.c的错,说参数个数不符,这个就有点麻烦了,也不知道是哪里不匹配,看看这模块似乎也暂时用不上,直接注释掉就可以了。

服务器有公网IP,而且只有一块网卡,所以直接启动就可以了。记得在防火墙里头打开端口,或者直接关掉防火墙(不建议)。

Chinese Word Count插件导致WordPress白屏无法访问

每天早上开机之后看到WordPress提示有插件更新,一般也不仔细看,直接就点批量更新了。昨天早上好像也有两个插件可更新,点了之后就没再细看。后来下午在客户端上发布完中午拍的照片,结果网站无法访问了,直接。看了一下后台的PHP日志,有报错:

[21-Apr-2014 05:18:35 UTC] PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in /home3/shelunet/public_html/wp-includes/pluggable.php on line 1317

看样子是内存不够了,加了内存,结果问题还在;以为是刚才上传的那篇文章有什么问题,于是客户端删除,结果还是不行,看来XMLPRC接口没问题,UI访问有问题。

于是找HostMonster的客服,说wordpress无法访问了,他说可能是Theme或者Plugin的问题,帮我弄了一下,结果就可以了。俺当然要问什么情况,后来他就给了个链接:

WordPress White Screen of Death

看了一下,再想想日志里头那个pluggable.php,应该就是插件的问题,早上升级过的,后来没注意,以为是上传的文章有问题。链接里头是通过cPanel操作的,我是直接在Terminal上,过程也有点不一致,他是要把plugins目录移走,但是似乎光移走不行,还得再放回去,总之就是把那个目录挪动一下就行。然后wordpress就可以登录了,到Plugins页面一看,所有的插件都Disabled了,一个一个Active,很快就发现是这个Chinese Word Count引起的问题,一看版本,14.4.19,应该就是早上更新过,所以出问题了。这个插件如果在浏览器上写文章还有点用处,现在我都用客户端,也没什么意义了,索性不用了。

servlet-mapping里头的url-pattern

最近在看Servlet 2.4的规范,SRV11 Mapping Requests to Servlets里头讲怎么把HTTP 请求映射给Servlet,主要依据的是web.xml里头的url-pattern。原文其实也很短,就两页,就不摘录了,有兴趣的可以去看原文。网上也有中文版的,但是翻译得很一般,还是直接看英文的好。

看得时候可以略微倒过来,先看语法:

  • / 开头 /* 结尾的是路径匹配。
  • *.开头的是扩展名匹配。
  • /代表默认的servlet。
  • 其他的都被用于完全匹配。

匹配的规则按优先级:

  • 先完全匹配
  • 再进行路径匹配,选择路径最长的servlet
  • 再进行扩展名匹配
  • 如果前面都没有匹配上,而且有默认的servlet的话,则交给默认的servlet处理

这里头我觉得有两个地方需要注意:

1、默认的servlet的url-pattern是 /,而不是/*。除非是为了拦截请求等特殊需要,不要把某一个servlet的url-pattern写成 /*。/*属于路径匹配,而且优先级较高,他会匹配走所有的请求。

2、HttpServletRequest接口里有一个getPathInfo方法,API描述有点拗口,其实返回的就是URI里头去掉url-pattern匹配上的那部分之后的内容。比如你有一个处理用户信息的servlet,url-pattern是/user/*,那么当用户访问/user/list时,getPathInfo返回的就是/list。这个在编程是其实也挺管用的。比如对于用户信息,可能会有增删改查等多种操作,你又不想每一种操作都做成一个servlet,这时候你其实只需要user一个servlet,处理的时候只要根据PathInfo就能知道该进行什么样的操作。

用SAX处理xml文件里的multiRef标签

开发某运营商的WebService订购关系通知接口,原先由VAC直接推送,现在中间加了一个网关,VAC推送网关,网关推送给我们,结果解析网关给过来的XML是出现了问题,一抓包发现是请求里头多了一些MultiRef的标签,不符合原先的WSDL定义。比如说userIdType,按正常来说应该是:

<userIdType type="soapenc:int">1</userIdType>

但是实际拿到的却是:

<userIdType href="#id1"/>

指向的是一个id1的标签,需要从下文里头去找出具体的值:

<multiRef id="id1" soapenc:root="0" soapenv:encodingStyle=" "http://schemas.xmlsoap.org/soap/encoding/">http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="soapenc:int">1</multiRef>

大概搜了一下,说其实是AXIS的一个特有的东西,甚至可以说是一个bug,AXIS2里头都已经取消了multiRef,要在AXIS1里头去掉这个也容易,只要改一下配置就可以了,于是联系网关的人,但是人家说这种int型就是用multiRef来传的,至于让他们改配置,自然不现实,人家说你用AXIS来解析好了。。。没办法,只能自己来弄了。

AXIS肯定不想用,这样的话就得大改。找了一下,网上有方法可以直接把格式转换一下,但是似乎略显复杂,而且接口相对于原来的程序而言也不太合适,于是还是决定自己解析。原先只是根据WSDL生成了请求对象,内容是使用SAX来解析的,大概的代码就是这么几行:

SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
VACReqHander handler = new VACReqHander();
parser.parse(in, handler);

主要就是这个VACReqHander,它继承了org.xml.sax.helpers.DefaultHandle,并且重载了其中的一下方法,这些方法会在适当的时候被parser调用。主要的方法有:

public void startDocument() //开始时被调用
public void startElement(String uri, String localName, String qName, Attributes attributes) //元素开始时被调用
public void characters(char[] ch, int start, int length) //取到值的时候被调用
public void endElement(String uri, String localName, String qName) //元素结束时被调用
public void endDocument() //结束时被调用

原先的实现比较简单,在startElement()里头把key放到一个全局的变量里头,即:key = qName,然后再characters()里头根据key来判断具体是哪个元素并且赋值,比如:

if ("userIdType".equals(key))
req.setUserIdType(Integer.valueOf(data));

但是这种只能处理标准格式的数据,如<key>value</key>,但是类似<userIdType href="#id1"/>这种数据的话characters()根本就没有被调用。大概debug了一下,发现这些都被放在startElement()attributes对象里头。这样就好办了,首先定义几个变量来保存数据:

String userIDtypeHref = null; //userIdType元素里的href对应的值,去掉#号,这里即id1
String multiRefID = null; //multiRef元素里的id对应的值,这里即id1
Hashtable<String,int> multiRefs = new Hashtable<String,Internet>(); //存储multiRef里头id和值的对应关系,这里即id1=1

然后在startElement()里头设置变量:

if(qName.equals("userIdType")){
userIDtypeHref = attributes.getValue("href").substring(1);
}
if(qName.equals("multiRef")){
multiRefID = attributes.getValue("id");
}

然后在 characters() 里取得multiRef里的value,并存储到Hashtable:

if ("multiRef".equals(nodeName)) {
if (refid!=null && isDigit(data))
{
multiRefs.put(multiRefID, Integer.valueOf(data));
}
}

最后在endDocument()设置一下userIdType的值:

if (req.getUserIdType()==0 && userIDtypeHref!=null)
req.setUserIdType(multiRefs.get(userIDtypeHref));

其他int类型的值,比如updateType可以同样处理

Freeswitch重新编译时报错:/usr/lib/libnss3.so: undefined reference to `PR_FindSymbol’

原来按照官方指南在CentOS 6.4上安装的Freeswitch,一切顺利。后来需要增加一个xml curl模块,修改了modules.conf之后编译出错:

/usr/lib/libnss3.so: undefined reference to `PR_FindSymbol'
/usr/lib/libnss3.so: undefined reference to `PR_RWLock_Rlock'
/usr/lib/libssl3.so: undefined reference to `PR_OpenAnonFileMap'
/usr/lib/libnss3.so: undefined reference to `PR_UnloadLibrary'
/usr/lib/libnss3.so: undefined reference to `PL_InitArenaPool'
/usr/lib/libnss3.so: undefined reference to `PR_NewRWLock'
/usr/lib/libnss3.so: undefined reference to `PR_RWLock_Wlock'
/usr/lib/libnss3.so: undefined reference to `PR_LoadLibrary'
/lib/libldap_r-2.4.so.2: undefined reference to `PR_GetEnv'
/usr/lib/libnssutil3.so: undefined reference to `PR_LoadLibraryWithFlags'
/usr/lib/libnssutil3.so: undefined reference to `PL_ClearArenaPool'
/usr/lib/libnss3.so: undefined reference to `PR_DestroyRWLock'
/usr/lib/libnss3.so: undefined reference to `PR_NewTCPSocket'
/lib/libldap_r-2.4.so.2: undefined reference to `PR_SetEnv'
/lib/libldap_r-2.4.so.2: undefined reference to `PR_GetLibraryName'
/usr/lib/libssl3.so: undefined reference to `PR_ErrorInstallTable'
/usr/lib/libssl3.so: undefined reference to `PR_ExportFileMapAsString'
/usr/lib/libnssutil3.so: undefined reference to `PR_GetLibraryFilePathname'
/usr/lib/libnss3.so: undefined reference to `PR_FindFunctionSymbol'
/usr/lib/libsmime3.so: undefined reference to `PL_NewHashTable'
/lib/libldap_r-2.4.so.2: undefined reference to `PR_ErrorToString'
/usr/lib/libnss3.so: undefined reference to `PR_RWLock_Unlock'
/usr/lib/libssl3.so: undefined reference to `PR_ImportFileMapFromString'
/lib/libldap_r-2.4.so.2: undefined reference to `PR_GetDirectorySeparator'
collect2: ld returned 1 exit status
make[1]: *** [freeswitch] 错误 1
make: *** [all] 错误 2

搜了一下,找到一个Bug报告,大概意思就是在CentOS6上libcurl用到了libnss3.so,而libnss3.so需要libnspr4.so。第一次make的时候用了系统提供的/lib/libnspr4.so,这个没问题。然后再编译的时候就去用了/usr/local/freeswitch/lib/libnspr4.so,这个就有问题了。解决方法有两个,一是 ./configure –without-libcurl,而是删掉/usr/local/freeswitch/lib。

不过第一个方法对我来说不管用,因为xml curl本来就需要用到libcurl,不能去掉。

VMware9虚拟机安装MAC OS X Mountain Lion 10.8.2

准备有空看看iOS开发,首先便是装个虚拟机。基本上按照这篇VMware9虚拟机安装MAC OS X Mountain Lion 10.8.2详细图文教程来,过程倒是也很顺利,也没遇到什么问题。

装完系统之后装XCode,安装文件在Windows下面,按说已经装了VMware Tools,应该可以通过VMware Shared Folders来共享文件的,结果在桌面却没有找到传说中的VMware Shared Folders,看教程里的贴图似乎也没有。于是用Samba解决,安装过程也很顺利,考虑到桌面系统可能比较耗资源,新建虚拟机的时候我分配了最大的2个内核和4G内存,有文章提到这样会导致XCode安装失败,我这里倒是挺正常的。

再回到这个VMware Shared Folders,看了下鼠标能够直接自由移动了,VMware Tools应该是正常的,就是桌面没有那个文件夹。搜了一下,讲到的大部分都是怎么删掉这个的,记得有一次启动的时候似乎看到了桌面的VMware Shared Folders一闪而过,一搜还真找到些线索:在这篇:Mac OS X Lion 10.7.3 VMware Image – Release Notes + Links的一个回复里头提到了解决方法:

Maybe a very late reply but here is a solution for having vmware shared folders always visible. Ofcourse first you must edit the settings for the virtual machine and under options enable shared folders:

Step 1: (Make sure you are quick on this)

Soon as your mac desktop appears double click on vmware shared folders before it disappears so that the shared folder window will open.

Step 2:

On the shared folder window right click the label on the top centre of the window that says vmware shared folder and you will have options for some other directories like “my mac” or whatever you named your account. Click on that directory and there you will see your vmware shared folder.

Step 3:

Drag that vmware shared folder to the dock so that a shortcut is placed in the dock and voila the shared folders will always be available to you from now on

大概意思就是启动时在桌面上的VMware Shared Folders快捷方式消失前双击,最后把它拖到Dock上。倒确实能用,不过比较狗血,你不一定能有那么快,而且明显治标不治本。于是再找了一下,在一个讲怎么删除这个VMware Shared Folders的帖子:Getting rid of “VMware Shared Folders” under OS X 找到些线索,他说要删除:

/Library/LaunchDaemons/com.vmware.launchd.tools.plist
          

这个看起来是个自动启动的东西,里头其实最后就是这么一个命令:

/Library/Application Support/VMware Tools/services.sh --start
          

手动执行(空格前要加\)时会报一些错,但是桌面的快捷方式也已经创建了。看了一下这个service.sh,大概就是load两个kext,然后mount,最后创建快捷方式。其实启动之后其实前两步都没问题,mount之后/Volumes/VMware Shared Folders也是存在的,就是不知道为什么快捷方式创建之后又会消失。

这样如果重启的话还会有问题,所以比较靠谱的还是自己创建一个快捷方式:

ln -s /Volumes/VMware\ Shared\ Folders/ ~/Desktop/VMware\ Shared\ Folders
          

这样就可以了。至于为什么自动创建的快捷方式会消失,这个待查。

最后,有什么iOS开发的书推荐么?最好是快速入门的那种。谢谢

Ubuntu 12.10 Server编译Linphone 2.0 for Android

下的最新的Ubuntu 12.10 Server,Win7上装的虚拟机,全部默认安装,然后就开始编译Linphone。除了README上要求的以外,也还有有一些需要的东西,比如git、ant、jdk(JDK需要通过网站下载)等。但是基本上来说还算是很顺畅的。下面的history,我去掉了一些没用或是重复的。

sudo apt-get update
sudo apt-get upgrade
unzip adt-bundle-linux-x86_64-20130219.zip
bunzip2 android-ndk-r8e-linux-x86_64.tar.bz2
tar xvf android-ndk-r8e-linux-x86_64.tar
tar zxvf linphone-android-20130410.tar.gz
cp SILK_SDK_SRC_v1.0.8.zip linphone-android/submodules/mssilk/sdk/
export PATH=$PATH:/home/sding/adt-bundle-linux-x86_64-20130219/sdk/platform-tools:/home/sding/adt-bundle-linux-x86_64-20130219/sdk/tools:/home/sding/android-ndk-r8e
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
sudo apt-get install pkg-config
sudo apt-get install ia32-libs
sudo apt-get install make
sudo apt-get install git
sudo apt-get install ant
tar zxvf jdk-7u17-linux-x64.tar.gz
mv -f jdk1.7.0_17/ /usr/local/
export JAVA_HOME=/usr/local/jdk1.7.0_17/
cd linphone-android/
make

Linphone 2.0 for Android 编译

新版的Linphone支持SUBSCRIBE/NOTIFY了,当然要把最新代码拿出来集成到我们的客户端里头。

这次编译除了ndk之外还需要Android sdk,其他的前提条件倒是差不多。

上次我是在centos 5.5 64位上编译成功的,结果这次在同一个环境地下居然不行了,编译第一个模块libilbc-rfc3951就碰到了问题:

configure: error: cannot find install-sh, install.sh, or shtool in build-aux “.”/build-aux
make: *** [/root/linphone-android/submodules/libilbc-rfc3951/Makefile] Error 1

搜了一下没搞明白怎么回事儿,装了shtool也没有用,单独把这个模块的源代码clone出来编译也遇到同样的问题。于是转向机器上的另外一个centos 6.3的虚拟机。

准备环境倒也不麻烦,无非就是autoconf, automake, aclocal, libtoolize, pkgconfig这几个,不过aclocal,libtoolize通过yum是找不到的,安装autoconf的时候不要yum,直接用源代码编译安装,这样也就包含了aclocal和libtoolize了。

然后就遇到下载文件按失败:

/usr/bin/wget –no-check-certificate http://www.webrtc.org/ilbc-freeware/ilbc-source-code-and-utili/ilbc-utilities/extract-cfile.awk -O extract-cfile.awk
–2013-04-10 23:17:41– http://www.webrtc.org/ilbc-freeware/ilbc-source-code-and-utili/ilbc-utilities/extract-cfile.awk
正在解析主机 www.webrtc.org… 74.125.31.121, 2404:6800:4008:c01::79
正在连接 www.webrtc.org|74.125.31.121|:80… 失败:拒绝连接。
正在连接 www.webrtc.org|2404:6800:4008:c01::79|:80… 失败:网络不可达。

看了一下,这个www.webrtd.org被盾了,需要用代理访问,windows下载之后上传即可。(PS: 后来又能下载了)

后面就遇到:

ant partial-clean
make: execvp: ant: 权限不够
make: *** [generate-apk] 错误 127

yum install ant错误消失了,但是马上就遇到:
BUILD FAILED
/root/linphone-android/build.xml:91: The following error occurred while executing this line:
/root/adt-bundle-linux-x86_64-20130219/sdk/tools/ant/build.xml:206: No supported regular expression matcher found: java.lang.ClassNotFoundException: org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp

手工安装最新的ant 1.9.0。

然后就遇到:

[aapt] /root/adt-bundle-linux-x86_64-20130219/sdk/platform-tools/aapt: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

BUILD FAILED
/root/adt-bundle-linux-x86_64-20130219/sdk/tools/ant/build.xml:647: The following error occurred while executing this line:
/root/adt-bundle-linux-x86_64-20130219/sdk/tools/ant/build.xml:688: null returned: 127

装了几个版本的libz之后都有问题,后来忽然想到README里头有一句:on some 64 bits systems you’ll need the ia32-libs package。

看了一下果然是需要32位的包,因为安卓源代码本来就是32位的。可是找了半天也没有找到这个ia32-libs,ubuntu上倒是有现成的。那就只能见招拆招了,直接http://rpmfind.net/搜 libz.so.1,找32位的下载安装,幸好缺的包也不多,再装了一个libncurses.so.5之后总算成功了。

要是32位系统的可能会更容易些,估计ubuntu会更容易些,yum现在很落后了,好多包也没有,或者就是很老。下次试试。

Linphone 2.0 for IPhone编译

新的Linphone已经支持SUBSCRIBE/NOTIFY,当然还有MESSAGE,这样的话就差不多把SIMPLE协议几个主要的功能都支持了,还是很有意义的。

于是重新下载代码编译,编译条件也没怎么变,而且出奇的顺利,开始遇到了一些问题,后来升级了XCode就可以了。

也没有遇到上次的那个armv7s的问题,强烈推荐大家重新编译。

FreeSWITCH ESL Client内存溢出

Linphone 1.x版本还不支持SUBSCRIBE/NOTIFY,所以也无法知道好友的状态,不得以做了一个代理,客户端每隔一段时间通过代理去freeswitch查询状态,代理用freeswitch ESL Client类连接freeswitch,但是代理运行一段时间之后就会内存溢出,然后崩溃。

2013-04-07 11:16:09,378 WARN [org.apache.mina.filter.logging.LoggingFilter] (LoggingFilter.java:123) – EXCEPTION :
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:633)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:95)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
at org.jboss.netty.channel.socket.nio.SocketSendBufferPool$Preallocation.<init>(SocketSendBufferPool.java:156)
at org.jboss.netty.channel.socket.nio.SocketSendBufferPool.<init>(SocketSendBufferPool.java:42)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.<init>(AbstractNioWorker.java:44)
at org.jboss.netty.channel.socket.nio.NioWorker.<init>(NioWorker.java:45)
at org.jboss.netty.channel.socket.nio.NioWorkerPool.createWorker(NioWorkerPool.java:45)
at org.jboss.netty.channel.socket.nio.NioWorkerPool.createWorker(NioWorkerPool.java:28)
at org.jboss.netty.channel.socket.nio.AbstractNioWorkerPool.newWorker(AbstractNioWorkerPool.java:99)
at org.jboss.netty.channel.socket.nio.AbstractNioWorkerPool.init(AbstractNioWorkerPool.java:69)
at org.jboss.netty.channel.socket.nio.NioWorkerPool.<init>(NioWorkerPool.java:39)
at org.jboss.netty.channel.socket.nio.NioWorkerPool.<init>(NioWorkerPool.java:33)
at org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory.<init>(NioClientSocketChannelFactory.java:152)
at org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory.<init>(NioClientSocketChannelFactory.java:117)
at org.freeswitch.esl.client.inbound.Client.connect(Client.java:113)

本来以为是程序里头什么地方资源没释放,后来查了一下,倒还真不是那么回事儿。

具体可以看看:Netty内存泄露XSocket内存泄漏问题深度分析,第一个讲的是现象,第二个更深入一些,说问题在于DirectByteBuffer。

不过第二个实施起来有点难度,而且也不能完全解决问题;而org.freeswitch.esl.client.inbound.Client里头用的NioClientSocketChannelFactory类作为一个工厂类确实没有必要每次都new,做成静态的即可。

于是改代码,然后重新编译。基本就是git和maven,具体可以参考:http://wiki.freeswitch.org/wiki/Java_ESL_Client