thttpd源代码阅读笔记

thttpd源代码阅读笔记

thttpd是一个非常小巧的轻量级web server,适合做嵌入式web服务器,它的官方网站是http://www.acme.com/software/thttpd/
thttpd的代码量很小,大约1万行代码,代码风格好像是GNU,阅读不太习惯,用indent格式化:indent -kr -i4 -l200 -bad -bap -ip8 *.c
由于我的vim将tab设置为4个空格,代码中空格与tab共用,需要把tab还原为8个空格,才不出现排版混乱。

在fedora 12下编译,有错误:
htpasswd.c:52: error: conflicting types for 'getline'
/usr/include/stdio.h:655: error: previous declaration of 'getline' was here
htpasswd.c:52: error: conflicting types for 'getline'
/usr/include/stdio.h:655: error: previous declaration of 'getline' was here
make[1]: *** [htpasswd.o] Error 1
make[1]: Leaving directory `/home/deli/work/thttpd-2.25b/extras'
make: *** [subdirs] Error 2

原因是getline 已加入 POSIX 2008,可以把extras/htpasswd.c 里面的getline重命名为get_line或别的。

代码根目录下,就这几个文件:
fdwatch.c match.c strerror.c thttpd.c
libhttpd.c mmc.c tdate_parse.c timers.c

extras子目录两个
htpasswd.c makeweb.c

main函数在 thttpd.c
先梳理一些基本知识,看代码就容易多了。

编写守护进程(daemon)遵循的一般步骤:
1. 在父进程中执行fork并执行exit退出。
2. 在子进程调用setsid。
3. 让根目录“/” 成为子进程的工作目录。
4. 把子进程的umask变为0。
5. 关闭不必要的文件描述符。

除了上面所提的步骤,thttpd.c 跟其他服务器软件一样,解析参数,信号的处理,读取配置文件等。

Apache采用多进程模型响应用户请求,thttpd对并发请求不使用 fork()来派生子进程处理,采用IO多路复用解决方案。代码在fdwatch.c/h,对select()/poll()/kqueue()进行了封装,也加上了超时处理机制,跟Android RIL串口多路服用的代码非常相似。

至于socket网络编程,对HTTP/1.1协议的支持,都在libhttpd.c里面处理。

注意到了两个文本文件 mime_encodings.txt mime_types.txt,在Makefile.in里做处理,用sed格式化,生成mime_types.h,mime_encodings.h,在libhttpd.c中 再#include 进来,这是很常见的程序设计方法,好处就是修改方便,不容易出错。

升级 bugzilla 3.02 至 3.62

07年末到现在,bugzilla还没升级过。按照官方的文档操作,很不幸,cookie设置有问题,登录后,点别的页面,又要求输入用户名与密码,搞了一天,很烦躁。仔细检查 data/params 千百遍

'cookiedomain' => '',
'cookiepath' => '/',

应该没错。浏览器cookie也有保存了。想不出问题出现在哪。随便点点,好像就在 管理员界面 – 核心参数, 把 ssl_redirect 选项设为关,就ok了。

3.02的图形报表一直无法生成,服务器是bluehost,后台log看不到,调试困难,升级到了3.62,就显示出来了 :-)

关于汉化包

http://www.bugzilla.org/download/

蒋艳 (jiangyanfeng)同学只翻译到3.4.3版本,台湾的repeat 已经搞到了 3.7.2 ,只好先拿繁体中文来用,一些同事反馈说不习惯繁体字,呃,用sed 替换字符串呗,以前用phpbb mods的时候,我也干过这事。写个sh脚本,替换常用的计算机文字,以后再出新版本,跑那个脚本刷一下,80%的文字替换应该没问题吧。

报表中文乱码的解决

不知道bluehost是否安装有中文字体,我把我机器上安装的文泉驿微米黑字体拷贝到bluehost上,

要修改 template/cn/default/reports 目录下三个文件:
report-bar.png.tmpl report-line.png.tmpl report-pie.png.tmpl

在 graph.set(x_label => col_field_disp, 这一行的前面加上

graph.set_title_font("/home/xxx/www/fonts/wqy-microhei/wqy-microhei.ttc",16);  
graph.set_x_label_font("/home/xxxx/www/fonts/wqy-microhei/wqy-microhei.ttc",10);  
graph.set_y_label_font("/home/xxxx/www/fonts/wqy-microhei/wqy-microhei.ttc",10);  
graph.set_x_axis_font("/home/xxxx/www/fonts/wqy-microhei/wqy-microhei.ttc",10);  
graph.set_y_axis_font("/home/xxxx/www/fonts/wqy-microhei/wqy-microhei.ttc",10);  
graph.set_legend_font("/home/xxxx/www/fonts/wqy-microhei/wqy-microhei.ttc",10);  

提交bug页面table出现断行问题

修改 template/cn/default/bug/create/create.html.tmpl
添加相应的th标签 nowrap=”nowrap” 属性

修改皮肤
升级后,原来主界面爬动的bug不见了,测试mm终于可以不用尖叫了,呵呵:)
默认的皮肤真的很丑,导航栏的颜色看起来很土。参考这里 http://www.firefox.net.cn/forum/viewtopic.php?t=9551提供的css,参考了 Basecamp 导航栏的颜色,
修改 skins/standard/global.css 里的#titles 标签,把背景颜色改为青草色
background-color: #195D00;

看起来舒服多了,还可以为测试人员保护视力 :-)

解决donut Gtalk、Market登录不了的问题

拿到一个开发板,研究一下为什么gtak,market都登录不了的问题。折腾了许久,很纠结,试过几个ROM的包都不行。今天再搞不定,明天还计划准备对market进行反编译。

Gtalk界面提示:无法连接到服务器。请稍后重试。
logcat是:
1050 GTalkService W [GTalkConnection.12] doConnect: caught java.lang.IllegalStateException: empty JID resource

market界面出现这样的提示:出现服务器错误,请重试,或者取消并返回上一屏幕。
后台logcat是:

1190 vending D com.android.vending.BaseActivity$BaseAction.run(): ApiException:
1190 vending D com.android.vending.api.FatalCommunicationException: Sent a bad request.
1190 vending D at com.android.vending.api.RequestDispatcher.throwException(RequestDispatcher.java:371)
1190 vending D at com.android.vending.api.RequestDispatcher.performRequestsOverNetwork(RequestDispatcher.java
212)
1190 vending D at com.android.vending.api.RequestDispatcher.performRequests(RequestDispatcher.java:174)
1190 vending D at com.android.vending.api.RequestManager.doRequestsOverNetwork(RequestManager.java:244)
1190 vending D at com.android.vending.api.RequestManager.doRequests(RequestManager.java:230)
1190 vending D at com.android.vending.BaseActivity$BaseAction.run(BaseActivity.java:1476)
1190 vending D at com.android.vending.BaseActivity$BaseAction$BackgroundThread$1.run(BaseActivity.java:1556)
1190 vending D at java.lang.Thread.run(Thread.java:1060)
1190 vending I om.android.vending.BaseActivity$BaseAction.displayErrorUi(): General error in com.android.vend
ng.AssetBrowserActivity$NetworkDataLoadAction
1190 vending I om.android.vending.api.FatalCommunicationException: Sent a bad request.
1190 vending I at com.android.vending.api.RequestDispatcher.throwException(RequestDispatcher.java:371)
1190 vending I at com.android.vending.api.RequestDispatcher.performRequestsOverNetwork(RequestDispatcher.java
212)
1190 vending I at com.android.vending.api.RequestDispatcher.performRequests(RequestDispatcher.java:174)
1190 vending I at com.android.vending.api.RequestManager.doRequestsOverNetwork(RequestManager.java:244)
1190 vending I at com.android.vending.api.RequestManager.doRequests(RequestManager.java:230)
1190 vending I at com.android.vending.BaseActivity$BaseAction.run(BaseActivity.java:1476)
1190 vending I at com.android.vending.BaseActivity$BaseAction$BackgroundThread$1.run(BaseActivity.java:1556)
1190 vending I at java.lang.Thread.run(Thread.java:1060)
1024 GTalkSerice E createAccountFromSettings caughtjava.lang.NumberFormatException: unable to parse 'null' as integer, use default port 5228

首先tcpdump获取数据包,然后用wireshark分析,发现

POST /market/api/ApiRequest HTTP/1.1\r\n
version=2&request=ClIxxxxxxxxxxxxxxxxxxxxxxxxAggBFA (中间有个人信息,用xxx替代)

总是返回 404错误,肯定是参数问题。request的参数,是经过base64加密过的,一直琢磨不出到底是哪个参数错了。

到了下午,痛定思痛,整理一下思路:

1. market与gtalk都登录不了,而gmail可以正常使用,从wireshark分析的数据包来看,DNS解析正常,没有被盾。
2. market与gtalk都登录不了,两者共有的东西是什么?是gtalkservice。
3. 同样的包,在模拟上,gtalk 可以登录使用,market却不行。

好,再仔细分析log:

[GTalkConnection.9] doConnect: caught java.lang.IllegalStateException: empty JID resource

开始也注意到这条log,但上面说的第三点因素,加上 Google这条错误信息,没有搜索记录,别人没遇到这问题,所以就没在意。

GTalkConnection是不是在gtalkservice里面? 用apktoo 反编译 gtalkservice.apk,搜索”empty JID resource” 字符串,还真在这个文件GTalkConnection.smali,代码大概是:

String resource = Settings.getJidResource();

if (TextUtils.isEmpty(resource )) {
    throw new IllegalStateException("empty JID resource");
}

搜索一下getJidResource, 文档写:

public static String getJidResource()

Returns the GTalk JID resource associated with this device.

Returns:
String the JID resource of the device. It uses the device IMEI in the computation of the JID resource. If IMEI is not ready (i.e. telephony module not ready), we’ll return an empty string.

哈哈哈,太明显了,IMEI!!! 在设置里,查看手机的IMEI,显示是未知,90%应该是这个问题了,先做个假的测试一下。

frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java

 897     public String getDeviceId() {
 898         return mImei;
 899     }
 

用模拟器上的值,改为:

 897     public String getDeviceId() {
 898         /*return mImei;*/
 899         return "000000000000000";
 900     }
 

到 frameworks/base目录下,mm -B , 重新生成frameworks.jar, push 到手机,重启,ok,market, gtalk可正常使用 :)

总结一下,给我一杯凉水,我需要冷静,log很重要,搞php我每次都先看apache error log, 搞C/C++, gdb无敌,一到android,没能潜移默化,可能是最初对Java的抵触,反感。现在发现用Java写程式也是蛮是享受的事。

Android 2.2系统在线升级的移植

之前我们自己做过一个在线T卡升级的应用程序,设计思路是非常简单的,获取本地手机版本号,获取并解析服务器上json格式的最新信息,如果服务器上的版本号大于本地手机的版本号,则可以下载并md5验证升级包,然后调用系统函数升级即可。

从Android 2.2开始,Google服务框架 GoogleServicesFramework.apk 包自带的系统更新处理了android.settings.SYSTEM_UPDATE_SETTINGS这个intent。我们自己做的手机,当然不可能用Google自带的在线升级。为了不修改 GoogleServicesFramework.apk,在Settings的AndroidManifest.xml文件,把 SYSTEM_UPDATE_SETTINGS,修改为别的名字,比如 SYSTEM_UPGRADE_SETTINGS。 还需要同步修改这个文件:

Settings/res/xml/device_info_settings.xml
今天发神经病,花了一大早上的时候反编译GoogleServicesFramework里的update,看看别人如何设计的,就几个文件:
[deli@athena update]$ tree .
.
├── Download.java
├── StateWatcher.java
├── SystemUpdateActivity.java
├── SystemUpdateInstallDialog.java
├── SystemUpdateService.java
└── SystemUpdateVerifierTask.java

搞出600多行代码,才发现跟GoogleServicesFramework这个包里的其他代码非常缠绵,只好作罢。 大概思路也弄明白了,跟我们一样,也是用Downloads.ByUri 这个组件下载文件,
调用系统函数 RecoverySystem.installPackage(context, new File(filename)); 唯一的差别是没有网络连接的情况下,引导用户到设置的界面,比较人性化,很注重用户体验,我们直接跳出个对话框,没有网络连接,以后是要修改的。

默认的,installPackage 这个函数只支持文件放在 /data或/cahce 目录,但是,一般一个系统升级包有70M,一般机器不能保证有那么大的空间,我们只好把文件放在 SD card里,修改installPackage 函数,让它支持 sdcard 目录:

// from froyo, /sdcard ==> /mnt/sdcard
} else if (filename.startsWith("/mnt/sdcard/")) {
    filename = "SDCARD:" + filename.substring(12);

更新: 2011/7/23

一些网友遇到这样的 error:

FileNotFoundException: /cache/recovery/command (Permission denied)

记得在AndroidManifest.xml加上权限

<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
<uses-permission android:name="android.permission.REBOOT" />

进阶:C2DM

使用 c2dm,给用户发push 通知消息,在状态栏提示有新版本可以更新啦。这部分的代码,可以参考大名鼎鼎的 CyanogenMod 的做法 CMUpdateNotify

试用在线协作工具egroupware

年初,用mediawiki搭建了公司内部文档系统,用到现在,wiki还是不利于协作,找几个groupware研究研究。G一下,有小杜学习笔记的一篇开源Groupware软件试用手记 里面推荐使用 egroupware。

安装参考 Ubuntu wiki 提供的EGroupware安装设置

打开下载页面 http://www.egroupware.org/download,怎么有个 trial for 30 days,傻眼了几分钟,网上不是说免费的么?原来免费版本在下边有 sourceforge.net字样的连接,发现长时间呆在电脑旁,人都变傻了。

按照安装提示,填好一些选项,生成header.inc.php 文件,并修改文件权限

chmod 700 header.inc.php

设置检查页面发现session无法读写,修改为 apache user即可。

sudo chown deli:deli /var/lib/php/session

装完后,发现需要个中文语言包,原来不需要特别下载,访问 setup 目录,进入设置界面,修改语言。

遇到一些问题:

1. 点 通讯录标签,页面空白,看了log:
[Mon Aug 30 16:21:05 2010] [notice] child pid 3045 exit signal Segmentation fault (11)
有时间再debug它。还在玩玩中,觉得ok才在公司推广使用。
2. css样式表文中字体,一般字体设定到12px以上才能够看清楚。11px的话,ie会自动调整,但ff不会。

下午试用了一下 大名鼎鼎的basecamp,发现商业的比较好用 :-) 恨不能自己亲自动手写一个,呵呵。一个买3k,卖出10k套,噢~~ 不好意思,哪有这么好的事,刚才做了个白日梦。

Pages: Prev 1 2 3 ... 11 12 13 14 15 16 17 18 19 20 21 Next