星期五, 十月 20, 2006
正则表达式的一些文章与工具
http://aspxboy.com/private/508/default.aspx
http://www.codeproject.com/dotnet/regextutorial.asp
http://www.codeproject.com/dotnet/expresso.asp
http://www.radsoftware.com.au/regexdesigner/
星期二, 十月 17, 2006
P2P 赢利模式分析
可以肯定的是P2P技术存在大量的TCP/UDP连接,和大量打开的端口,与传统网络安全中尽量少开端口的得理念相背离。基于P2P的产品试图突破防火墙的控制,大量使用了80,443,22,21,25等知名端口,重这一点来说,一方宣布智能穿透防火墙,令一方宣布专业封杀P2P。大有水火不容的态势。
这一切在我看来,P2P产品没有一个标准的缘故,P2P行业的自律性也差了点,P2P服务目前所看到的利益来自于人气,这一点类是于传统网站,在P2P赢利模式不清楚的情况下,只有用户多了,才有赚钱的可能,使用P2P技术强制使用个人/单位/服务商的带宽,带宽就是钱啊,这么看来,P2P有点“抢钱”的意思,话在说回来,想要使用P2P提供的优质服务,总的付出点代价。这样,电信/网通就急了。那些被P2P占用带宽的公司也急了!
问题的解决,需要多方利益的统一,说起来容易做起来难。内容提供商,服务运营商,基础设施(主要是网络),用户以及这个链条中的其它环节,现在的利益还没有统一,彼此之间也不负责,大部分是服务运营商在唱独角戏。脚指头想都知道,有限的风投花完了该怎么办,出路在哪里?那个惨啊,可想而知。
P2P行业就这么完了吗?当初一点点小的技术创新,惹得互联网波涛汹涌的气势都哪里去了?泡沫过后,大家冷静下来的时候,也就是该有人站出来的时候了!会是谁呢,谁来整合这个残局?如果行业平静了,其实还是有很多人可以出来充当这一角色,他所要解决的问题就是拣贝壳,从贝壳中拿出那颗受过苦难的贝壳中孕育出的那颗珍珠。价值体现出来了,那些小贝壳们又出现了希望。传统媒体(主要是电视台),网络运营商(电信/网通),门户网站都可以充当这个拣贝壳的角色,充当P2P运营模式中的主流。非主流的情况应该是作为增值模块来提供某一服务,不过这个应该是个小头。
Google Video在目前我所在的区域拒绝提供服务,也无从评判现有P2P新媒体服务的好坏,当各种因素平衡的时候,P2P的春天会来临,仍在P2P行业里面奋斗的人们,请坚持你们的理想,保持这种创新的活力!
写道这里已经严重跑题,本来是想讨论P2P与网络安全的问题,却成了发表感慨。
不说了,兄弟我拭目以待!
星期一, 十月 16, 2006
Apache 2.0性能优化—MPM的选择与配置
Apache 2.0在性能上的改善最吸引人。在支持POSIX线程的Unix系统上,Apache可以通过不同的MPM运行在一种多进程与多线程相混合的模式下,增强部分配置的可扩充性能。相比于Apache 1.3,2.0版本做了大量的优化来提升处理能力和可伸缩性,并且大多数改进在默认状态下即可生效。但是在编译和运行时刻,2.0也有许多可以显著提高性能的选择。本文不想叙述那些以功能换取速度的指令,如HostnameLookups等,而只是说明在2.0中影响性能的最核心特性:MPM(Multi -Processing Modules,多道处理模块)的基本工作原理和配置指令。
毫不夸张地说,MPM的引入是Apache 2.0最重要的变化。大家知道,Apache是基于模块化的设计,而Apache 2.0更扩展了模块化设计到Web服务器的最基本功能。服务器装载了一种多道处理模块,负责绑定本机网络端口、接受请求,并调度子进程来处理请求。扩展模块化设计有两个重要好处:
◆ Apache可以更简洁、有效地支持多种操作系统;
◆ 服务器可以按站点的特殊需要进行自定制。
在用户级,MPM看起来和其它Apache模块非常类似。主要区别是在任意时刻只能有一种MPM被装载到服务器中。
指定MPM的方法
下面以Red Hat Linux 9为平台,说明在Apache 2.0中如何指定MPM (Apache采用2.0.45)。先解压缩源代码包httpd-2.0.45.tar.gz,生成httpd-2.0.45目录(Apache 1.3源代码包的命名规则是apache_1.3.NN.tar.gz,而2.0版则是httpd-2.0.NN.tar.gz,其中NN是次版本号)。
进入httpd-2.0.45目录,运行以下代码:
$ ./configure --help|grep mpm
显示如下:
--with-mpm=MPM
Choose the process model for Apache to use.
MPM={beos|worker|prefork|mpmt_os2| perchild|leader|threadpool}
上述操作用来选择要使用的进程模型,即哪种MPM模块。Beos、mpmt_os2分别是BeOS和OS/2上缺省的MPM, perchild主要设计目的是以不同的用户和组的身份来运行不同的子进程。这在运行多个需要CGI的虚拟主机时特别有用,会比1.3版中的SuExec 机制做得更好。leader和threadpool都是基于worker的变体,还处于实验性阶段,某些情况下并不会按照预期设想的那样工作,所以 Apache官方也并不推荐使用。因此,我们主要阐述prefork和worker这两种和性能关系最大的产品级MPM ( 有关其它的MPM详细说明,请参见Apache官方文档:http://httpd.apache.org/docs-2.0/mod/)。
prefork的工作原理及配置
如果不用“--with-mpm”显式指定某种MPM,prefork就是Unix平台上缺省的MPM。它所采用的预派生子进程方式也是 Apache 1.3中采用的模式。prefork本身并没有使用到线程,2.0版使用它是为了与1.3版保持兼容性;另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,这也使其成为最稳定的MPM之一。
若使用prefork,在make编译和make install安装后,使用“httpd -l”来确定当前使用的MPM,应该会看到prefork.c(如果看到worker.c说明使用的是worker MPM,依此类推)。再查看缺省生成的httpd.conf配置文件,里面包含如下配置段:
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150
MaxRequestsPerChild 0
prefork的工作原理是,控制进程在最初建立“StartServers”个子进程后,为了满足MinSpareServers设置的需要创建一个进程,等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足 MinSpareServers设置的值为止。这就是预派生(prefork)的由来。这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。
MaxSpareServers设置了最大的空闲进程数,如果空闲进程数大于这个值,Apache会自动kill掉一些多余进程。这个值不要设得过大,但如果设的值比MinSpareServers小,Apache会自动把其调整为MinSpareServers+1。如果站点负载较大,可考虑同时加大MinSpareServers和MaxSpareServers。
MaxRequestsPerChild设置的是每个子进程可处理的请求数。每个子进程在处理了“MaxRequestsPerChild” 个请求后将自动销毁。0意味着无限,即子进程永不销毁。虽然缺省设为0可以使每个子进程处理更多的请求,但如果设成非零值也有两点重要的好处:
◆ 可防止意外的内存泄漏;
◆ 在服务器负载下降的时侯会自动减少子进程数。
因此,可根据服务器的负载来调整这个值。笔者认为10000左右比较合适。
MaxClients是这些指令中最为重要的一个,设定的是Apache可以同时处理的请求,是对Apache性能影响最大的参数。其缺省值 150是远远不够的,如果请求总数已达到这个值(可通过ps -ef|grep http|wc -l来确认),那么后面的请求就要排队,直到某个已处理请求完毕。这就是系统资源还剩下很多而HTTP访问却很慢的主要原因。系统管理员可以根据硬件配置和负载情况来动态调整这个值。虽然理论上这个值越大,可以处理的请求就越多,但Apache默认的限制不能大于256。如果把这个值设为大于256,那么 Apache将无法起动。事实上,256对于负载稍重的站点也是不够的。在Apache 1.3中,这是个硬限制。如果要加大这个值,必须在“configure”前手工修改的源代码树下的src/include/httpd.h中查找 256,就会发现“#define HARD_SERVER_LIMIT 256”这行。把256改为要增大的值(如4000),然后重新编译Apache即可。在Apache 2.0中新加入了ServerLimit指令,使得无须重编译Apache就可以加大MaxClients。下面是笔者的prefork配置段:
StartServers 10
MinSpareServers 10
MaxSpareServers 15
ServerLimit 2000
MaxClients 1000
MaxRequestsPerChild 10000
上述配置中,ServerLimit的最大值是20000,对于大多数站点已经足够。如果一定要再加大这个数值,对位于源代码树下server/mpm/prefork/prefork.c中以下两行做相应修改即可:
#define DEFAULT_SERVER_LIMIT 256
#define MAX_SERVER_LIMIT 20000
worker的工作原理及配置
相对于prefork,worker是2.0 版中全新的支持多线程和多进程混合模型的MPM。由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。但是, worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性。这种MPM的工作方式将是Apache 2.0的发展趋势。
在configure -with-mpm=worker后,进行make编译、make install安装。在缺省生成的httpd.conf中有以下配置段:
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
worker的工作原理是,由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的ThreadsPerChild 线程数,各个线程独立地处理请求。同样,为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;而MaxClients设置了所有子进程中的线程总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。
MinSpareThreads和MaxSpareThreads的最大缺省值分别是75和250。这两个参数对Apache的性能影响并不大,可以按照实际情况相应调节。
ThreadsPerChild是worker MPM中与性能相关最密切的指令。ThreadsPerChild的最大缺省值是64,如果负载较大,64也是不够的。这时要显式使用 ThreadLimit指令,它的最大缺省值是20000。上述两个值位于源码树server/mpm/worker/worker.c中的以下两行:
#define DEFAULT_THREAD_LIMIT 64
#define MAX_THREAD_LIMIT 20000
这两行对应着ThreadsPerChild和ThreadLimit的限制数。最好在configure之前就把64改成所希望的值。注意,不要把这两个值设得太高,超过系统的处理能力,从而因Apache不起动使系统很不稳定。
Worker模式下所能同时处理的请求总数是由子进程总数乘以ThreadsPerChild值决定的,应该大于等于MaxClients。如果负载很大,现有的子进程数不能满足时,控制进程会派生新的子进程。默认最大的子进程总数是16,加大时也需要显式声明ServerLimit(最大值是20000)。这两个值位于源码树server/mpm/worker/worker.c中的以下两行:
#define DEFAULT_SERVER_LIMIT 16
#define MAX_SERVER_LIMIT 20000
需要注意的是,如果显式声明了ServerLimit,那么它乘以ThreadsPerChild的值必须大于等于MaxClients,而且MaxClients必须是ThreadsPerChild的整数倍,否则Apache将会自动调节到一个相应值(可能是个非期望值)。下面是笔者的 worker配置段:
StartServers 3
MaxClients 2000
ServerLimit 25
MinSpareThreads 50
MaxSpareThreads 200
ThreadLimit 200
ThreadsPerChild 100
MaxRequestsPerChild 0
通过上面的叙述,可以了解到Apache 2.0中prefork和worker这两个重要MPM的工作原理,并可根据实际情况来配置Apache相关的核心参数,以获得最大的性能和稳定性。
其它更详细的写以到http://httpd.apache.org/docs-2.0/
C10K 10K并发连接问题!
已经是WEB服务器解决10K并发连接的时候了,你不这么认为吗?毕竟,WEB是现拥有最大的地盘。
现在的的 计算机配置更高了。$1,200美元左右可以买到1G处理器的机器,装有2G的内存与千兆网卡。我们看看,如果有20K客户端,那么每个客户端分得50KHz CPU,100K字节内存,50Kbits/sec的带宽。(这种情况下每个客户端花费6美分。那些每客户端100美元的服务器许可证费用看上去贵了点)。所以,硬件不再是瓶颈。(老外就是细致,这都算的这么 清楚!)
在1999年,最忙的一台FTP站点 cdrom.com, 实际上已经通过G比特以太网并发处理了10K的连接。到了2001年,相同的速度的服务已经在几个ISP中提供,它们希望能够为规模不断扩大的商业用户提供服务。瘦客户端模型的计算形式又回来了,这时网络上工作的服务器,服务者数以千计的客户。
文中讨论了一些如何配置操作系统以及如何写代码支持以千计的客户端的问题,讨论集中在类Unix操作系统,但是Windows也有所涉及!
星期日, 十月 15, 2006
星期六, 十月 14, 2006
感受 血色浪漫 的青春!
说实话,我是70年代出生,80年代长大的,70年代的记忆基本没有,但记得家里面有一幅1980年的墙画,大概是那个沂蒙山的红军芭蕾舞剧,不过好多人家里贴了将军、伟人的墙画。不过血色浪漫里的好多细节应该都是那个时代真实的反映。至少父母老是提起当年下乡的知青。
感受最深的要数里面信天游的歌曲,也只有在那片土地的人才能够引起深层次的共鸣。山西人走西口,闯关东的故事已经成为了历史,成为提到晋商必须提到的事。而与这些故事相关的信天游的传唱,却是见证在那块土地成长的烙印。高中毕业的时候,大家开毕业会,我们的生物学老师 [注: 一个年轻漂亮毕业于山西大学的女孩,也是我们本地人] 唱了一首走西口~~~哥哥你走西口,小妹妹我实在难留~~~,唱得自然是好,心里那个感动!想想,这种通过读书考学走出那块土地的我,与当年走西口谋生的先辈们也没什么区别。我可是那位老师得意的学生,虽然只带了我一年的生物课,可老师对我那个映像绝对深刻。大概是她在教第5章的时候,我基本上已经看完了整本书,在她下来巡视的时候,我被发现看别的课程,生气地问我自然选择与遗传变异的关系(达尔文物种起源,高中生物学第7章的内容吧),我回答的那个顺利啊!由于我这个人看得东西虽多,做的练习题却比别人少的多,结果在10年前的高考成绩却不理想,勉强混入北京。
知青下乡肯定有很多东西是他们在城里所接触不到的。童年的有些事情记忆深刻,有的甜蜜,有的苦楚。城里的孩子可能听都没有听过,一并说出来,我这叫插播 绿色童年。我们不讨论钟跃民看到那个小孩带来的烤田鼠时候的感觉,童年时候确实是烤过知了和麻雀以及玉米土豆地瓜之流,这段以后再说吧。记得小时候家里的大人们到田里干活,就把小孩放到一边自己玩。(托尔所,幼儿园那可不是我小时候就知道的概念) 我和一个小朋友在天边玩,玩到了灌木丛里,碰到了里面的马蜂窝,我们常用捅了马蜂窝来形容惹了多大的麻烦,你们想不到的那个情况,俩个娃哭的那个惨。我那慈爱的爷爷一把火扫了那个马蜂窝,算是为我报仇。还有一次,在田边的路上被自行车撞个正着,两眼之间,一个血洞,待到医院缝了四针,包扎好后绝对就是戏剧里面的小丑角色。我十岁左右的时候,和我一起被蜂蜇的那个朋友因为得了鼠疫(就是那种可怕的传染病)而死去,此后,也不可能在有关于这位小伙伴其它的回忆。(小时候打架/打仗的事情有空再说)。
关于布票/粮票的记忆:布票的记忆来自于母亲的口述,粮票的记忆是初中时候的。爷爷奶奶和我们住在一条胡同相隔的两个院子里,母亲让我拿五尺布票给奶奶,就在两个院子的路上我跑去玩了后来把那个布票弄丢了,回来我和母亲撒谎,说给了奶奶。结果呢自然是被打一顿。初中的时候,由于全国粮票的即将作废,所以有一段时间经常去粮店买馒头、花卷。
星期二, 十月 10, 2006
mod_lua性能提升,是mod_python速度115%
mod_python
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0mod_lua
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.0.59
Server Hostname: localhost
Server Port: 80
Document Path: /tmp/hello.py
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 1.78125 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 102500 bytes
HTML transferred: 6000 bytes
Requests per second: 463.77 [#/sec] (mean)
Time per request: 2.156 [ms] (mean)
Time per request: 2.156 [ms] (mean, across all concurrent requests)
Transfer rate: 92.75 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.3 0 15
Processing: 0 1 4.7 0 15
Waiting: 0 1 4.5 0 15
Total: 0 1 5.1 0 15
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 15
95% 15
98% 15
99% 15
100% 15 (longest request)
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0这次修改可谓全胜
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Server Software: Apache/2.0.59
Server Hostname: localhost
Server Port: 80
Document Path: /tmp/hello.lua
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 0.937500 seconds
Complete requests: 500
Failed requests: 0
Write errors: 0
Total transferred: 102000 bytes
HTML transferred: 6000 bytes
Requests per second: 533.33 [#/sec] (mean)
Time per request: 1.875 [ms] (mean)
Time per request: 1.875 [ms] (mean, across all concurrent requests)
Transfer rate: 105.60 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.2 0 15
Processing: 0 1 4.2 0 15
Waiting: 0 1 4.1 0 15
Total: 0 1 4.7 0 15
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 0
90% 15
95% 15
98% 15
99% 15
100% 15 (longest request)
速度比如下每秒处理的请求 463.77/533.33(mod_python/mod_lua)
每个请求处理花费的时间微妙: 2.156/1.875(mod_python/mod_lua)
性能提升的原因说明:
1 mod_lua从串行处理方式改成并行处理方式
2 lua虚拟机采用了空闲池处理
星期六, 十月 07, 2006
OpenSSL 公开加密算法中如何添加新算法
2002-07-06: Word文档写完
2005-04-07: 发布于个人Blogger
OpenSSL 中公开密钥算法中,我仅仅讨论RSA算法模块!
与RSA相关的数据结构包括。
typedef struct rsa_st RSA;
typedef struct rsa_meth_st
{
const char *name;
int (*rsa_pub_enc)(int flen,unsigned char *from,unsigned char *to,
RSA *rsa,int padding);
int (*rsa_pub_dec)(int flen,unsigned char *from,unsigned char *to,
RSA *rsa,int padding);
int (*rsa_priv_enc)(int flen,unsigned char *from,unsigned char *to,
RSA *rsa,int padding);
int (*rsa_priv_dec)(int flen,unsigned char *from,unsigned char *to,
RSA *rsa,int padding);
int (*rsa_mod_exp)(BIGNUM *r0,BIGNUM *I,RSA *rsa); /* Can be null */
int (*bn_mod_exp)(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx,
BN_MONT_CTX *m_ctx); /* Can be null */
int (*init)(RSA *rsa); /* called at new */
int (*finish)(RSA *rsa); /* called at free */
int flags; /* RSA_METHOD_FLAG_* things */
char *app_data; /* may be needed! */
/* New sign and verify functions: some libraries don't allow arbitrary data
* to be signed/verified: this allows them to be used. Note: for this to work
* the RSA_public_decrypt() and RSA_private_encrypt() should *NOT* be used
* RSA_sign(), RSA_verify() should be used instead. Note: for backwards
* compatibility this functionality is only enabled if the RSA_FLAG_SIGN_VER
* option is set in 'flags'.
*/
int (*rsa_sign)(int type, unsigned char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
int (*rsa_verify)(int dtype, unsigned char *m, unsigned int m_len,
unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
} RSA_METHOD;
/* 对RSA算法的添加一般式提供可供OPENSSL模块使用的加速卡和加密卡接口,将操作接口采用上面的结构进行封装,并不是上面所有的接口都需要实现,但四个加解密函数以及初始化和结束函数应该是必须提供的*/
struct rsa_st
{
/* The first parameter is used to pickup errors where
* this is passed instead of aEVP_PKEY, it is set to 0 */
int pad;
int version;
#if 0
RSA_METHOD *meth;
#else
struct engine_st *engine;
#endif
BIGNUM *n; /* n=pq */
BIGNUM *e; /* e和n,为公开密钥,e与(p-1)(q-1)互为素数 */
BIGNUM *d; /* 私人密钥,ed=1mod(p-1)(q-1) */
BIGNUM *p; /* 大素数 p ,p q 互为素数,且长度一样 */
BIGNUM *q; /* 大素数 q */
BIGNUM *dmp1;
BIGNUM *dmq1;
BIGNUM *iqmp;
/* be careful using this if the RSA structure is shared */
CRYPTO_EX_DATA ex_data;
int references;
int flags;
/* Used to cache montgomery values */
BN_MONT_CTX *_method_mod_n;
BN_MONT_CTX *_method_mod_p;
BN_MONT_CTX *_method_mod_q;
/* all BIGNUM values are actually in the following data, if it is not
* NULL */
char *bignum_data;
BN_BLINDING *blinding;
};
/* 加密过程 c=me mod n 解密过程 m=cd mod n */
/* 根据加解密算法的需要,以及使用的是公钥还是私钥,上面的结构中的字段需要有选择地实现,在任何时候,对n和e,以及flags的初始化都是不可少的*/
/* 如果是为硬件密码引擎提供接口,可以参考crypt/engine/hw_*.c的各个模块*/
/* 关于大数的描述将在另外的文档中说明 */
/* Type needs to be a bit field
* Sub-type needs to be for variations on the method, as in, can it do
* arbitrary encryption.... */
typedef struct evp_pkey_st
{
int type;
int save_type;
int references;
union {
char *ptr;
#ifndef NO_RSA
struct rsa_st *rsa; /* RSA */
#endif
#ifndef NO_DSA
struct dsa_st *dsa; /* DSA */
#endif
#ifndef NO_DH
struct dh_st *dh; /* DH */
#endif
} pkey;
int save_parameters;
STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
} EVP_PKEY;
#define EVP_PKEY_MO_SIGN 0x0001
#define EVP_PKEY_MO_VERIFY 0x0002
#define EVP_PKEY_MO_ENCRYPT 0x0004
#define EVP_PKEY_MO_DECRYPT 0x0008
用于封装公开密钥算法中,各种公开密钥和私人密钥的结构。
OpenSSL 中硬件引擎所要完成的工作本质上就是实现RSA_METHOD结构中的函数指针。
/* 软件算法RSA算法如何生成公私密钥对 */
RSA *RSA_generate_key(int bits, unsigned long e_value,
void (*callback)(int,int,void *), void *cb_arg)
{
/*
输入
bits, 密钥长度
e_value, e值,也就是公开密钥
callback 回调函数
cb_args 回调函数的参数
*/
RSA *rsa=NULL;
BIGNUM *r0=NULL,*r1=NULL,*r2=NULL,*r3=NULL,*tmp;
int bitsp,bitsq,ok= -1,n=0,i;
BN_CTX *ctx=NULL,*ctx2=NULL;
ctx=BN_CTX_new();
if (ctx == NULL) goto err;
ctx2=BN_CTX_new();
if (ctx2 == NULL) goto err;
BN_CTX_start(ctx);
r0 = BN_CTX_get(ctx);
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
r3 = BN_CTX_get(ctx);
if (r3 == NULL) goto err;
/* 大质数p,q的位数 bitsp,bitsq
如果RSA采用了bits位加密强度
则:大质数p的长度为,bitsp = (bits+1)/2
大质数q的长度为,bitsq =bits-bitsp,
*/
bitsp=(bits+1)/2;
bitsq=bits-bitsp;
rsa=RSA_new();
if (rsa == NULL) goto err;
/* set e */
rsa->e=BN_new();
if (rsa->e == NULL) goto err;
#if 1
/* The problem is when building with 8, 16, or 32 BN_ULONG,
* unsigned long can be larger */
for (i=0; i
{
if (e_value & (1UL<
BN_set_bit(rsa->e,i);
}
#else
if (!BN_set_word(rsa->e,e_value)) goto err;
#endif
/* generate p and q */
for (;;)
{
rsa->p=BN_generate_prime(NULL,bitsp,0,NULL,NULL,callback,cb_arg);
if (rsa->p == NULL) goto err;
if (!BN_sub(r2,rsa->p,BN_value_one())) goto err;
if (!BN_gcd(r1,r2,rsa->e,ctx)) goto err;
if (BN_is_one(r1)) break;
if (callback != NULL) callback(2,n++,cb_arg);
BN_free(rsa->p);
}
if (callback != NULL) callback(3,0,cb_arg);
for (;;)
{
rsa->q=BN_generate_prime(NULL,bitsq,0,NULL,NULL,callback,cb_arg);
if (rsa->q == NULL) goto err;
if (!BN_sub(r2,rsa->q,BN_value_one())) goto err;
if (!BN_gcd(r1,r2,rsa->e,ctx)) goto err;
if (BN_is_one(r1) && (BN_cmp(rsa->p,rsa->q) != 0))
break;
if (callback != NULL) callback(2,n++,cb_arg);
BN_free(rsa->q);
}
if (callback != NULL) callback(3,1,cb_arg);
if (BN_cmp(rsa->p,rsa->q) <>
{
tmp=rsa->p;
rsa->p=rsa->q;
rsa->q=tmp;
}
/* calculate n */
rsa->n=BN_new();
if (rsa->n == NULL) goto err;
if (!BN_mul(rsa->n,rsa->p,rsa->q,ctx)) goto err;
/* calculate d */
if (!BN_sub(r1,rsa->p,BN_value_one())) goto err; /* p-1 */
if (!BN_sub(r2,rsa->q,BN_value_one())) goto err; /* q-1 */
if (!BN_mul(r0,r1,r2,ctx)) goto err; /* (p-1)(q-1) */
/* should not be needed, since gcd(p-1,e) == 1 and gcd(q-1,e) == 1 */
/* for (;;)
{
if (!BN_gcd(r3,r0,rsa->e,ctx)) goto err;
if (BN_is_one(r3)) break;
if (1)
{
if (!BN_add_word(rsa->e,2L)) goto err;
continue;
}
RSAerr(RSA_F_RSA_GENERATE_KEY,RSA_R_BAD_E_VALUE);
goto err;
}
*/
/* 生成d,私人密钥 */
rsa->d=BN_mod_inverse(NULL,rsa->e,r0,ctx2); /* d */
if (rsa->d == NULL) goto err;
/* 生成中间计算结果 */
/* calculate d mod (p-1) */
rsa->dmp1=BN_new();
if (rsa->dmp1 == NULL) goto err;
if (!BN_mod(rsa->dmp1,rsa->d,r1,ctx)) goto err;
/* calculate d mod (q-1) */
rsa->dmq1=BN_new();
if (rsa->dmq1 == NULL) goto err;
if (!BN_mod(rsa->dmq1,rsa->d,r2,ctx)) goto err;
/* calculate inverse of q mod p */
rsa->iqmp=BN_mod_inverse(NULL,rsa->q,rsa->p,ctx2);
if (rsa->iqmp == NULL) goto err;
ok=1;
err:
if (ok == -1)
{
RSAerr(RSA_F_RSA_GENERATE_KEY,ERR_LIB_BN);
ok=0;
}
BN_CTX_end(ctx);
BN_CTX_free(ctx);
BN_CTX_free(ctx2);
if (!ok)
{
if (rsa != NULL) RSA_free(rsa);
return(NULL);
}
else
return(rsa);
}
/* This is a structure for storing implementations of various crypto
* algorithms and functions. */
typedef struct engine_st
{
const char *id;
const char *name;
RSA_METHOD *rsa_meth;
DSA_METHOD *dsa_meth;
DH_METHOD *dh_meth;
RAND_METHOD *rand_meth;
BN_MOD_EXP bn_mod_exp;
BN_MOD_EXP_CRT bn_mod_exp_crt;
int (*init)(void);
int (*finish)(void);
int (*ctrl)(int cmd, long i, void *p, void (*f)());
EVP_PKEY *(*load_privkey)(const char *key_id, const char *passphrase);
EVP_PKEY *(*load_pubkey)(const char *key_id, const char *passphrase);
int flags;
/* reference count on the structure itself */
int struct_ref;
/* reference count on usability of the engine type. NB: This
* controls the loading and initialisation of any functionlity
* required by this engine, whereas the previous count is
* simply to cope with (de)allocation of this structure. Hence,
* running_ref <= struct_ref at all times. */
int funct_ref;
/* Used to maintain the linked-list of engines. */
struct engine_st *prev;
struct engine_st *next;
} ENGINE;
/* 描述硬件引擎的数据结构,需要实现的字段包括,id,name,init,finish,如果引擎提供rsa算法,则必须实现rsa_method */
/* 提供返回ENGINE的接口,并在crypt/engine/engine_int.h申明。*/
ENGINE *ENGINE_HardCard();
如果想把HardCard加到OPENSSL的缺省引擎列表中,需要在在crypto/engine/engine_list.c 的engine_internal_check()中添加实现代码。
static int engine_internal_check(void)
{
if(engine_list_flag)
return 1;
/* This is our first time up, we need to populate the list
* with our statically compiled-in engines. */
if(!engine_list_add(ENGINE_openssl()))
return 0;
#ifndef NO_HW
#ifndef NO_HW_CSWIFT
if(!engine_list_add(ENGINE_cswift()))
return 0;
#endif /* !NO_HW_CSWIFT */
#ifndef NO_HW_NCIPHER
if(!engine_list_add(ENGINE_ncipher()))
return 0;
#endif /* !NO_HW_NCIPHER */
#ifndef NO_HW_ATALLA
if(!engine_list_add(ENGINE_atalla()))
return 0;
#endif /* !NO_HW_ATALLA */
#endif /* !NO_HW */
engine_list_flag = 1;
return 1;
}
否则,你在使用引擎之前必须手动完成engine_list_add这个过程。
在init函数中实现引擎的初始化,在ENGINE_set_default(ENGINE *e,long flag)还函数中调用,finish释放Engine所占用的资源。
如果要采用引擎实现的算法,可以通过下面的程序来实现。
ENGINE *e=NULL;
if((e = ENGINE_by_id("pkicard")) == NULL)
{
printf("invalid engine pkicard");
}
printf("engine pkicard set\n");
if(!ENGINE_set_default(e, ENGINE_METHOD_RSA))
{/* 引擎提供的加密算法被制定为缺省的RSA算法 */
printf("PKICARD RSA\n");
goto end;
}
在实现公钥和私钥加解密的时候会涉及到padding的问题,padding的处理方式必须与标准RSA算法相同。
RSA_pub_dec()采用RSA_padding_check_PKCS1_type_1去调明文数据的padding.
RSA_pub_enc()采用RSA_padding_add_PKCS1_type_2去调明文数据的padding.
RSA_priv_dec()采用RSA_padding_check_PKCS1_type_2去调明文数据的padding.
RSA_priv_enc()采用RSA_padding_add_PKCS1_type_1去调明文数据的padding.
以上是PKCS1的padding处理方式,更为详细的资料请来查看源代码
crypt/rsa/rsa_pk1.c
在crypt/rsa/rsa.h还能找到其他的padding方式。具体的应用请查看相关代码。
在接口实现的过程中,各种加密卡的字节序和位序可能各不相同,需要作提要的调整以满足OpenSSL的接口。
另外:engine中提供了不少加密卡的引擎代码,可以参考实现之。
OpenSSL 对称加密算法中如何添加新算法
2002-06-18: Word文档写完
2005-04-07: 发布于个人Blogger
1.关于加密算法的加载
在调用加密算法之前,通过调用OpenSSL_add_all_algorithms来加载加密算法函数和单向散列算法函数
void OpenSSL_add_all_algorithms(void)
{
OpenSSL_add_all_ciphers(); /* 加载加密算法 */
OpenSSL_add_all_digests(); /* 加载单向散列函数 */
}
void OpenSSL_add_all_ciphers(void)函数实现如下:
void OpenSSL_add_all_ciphers(void)
{
EVP_add_cipher(EVP_rc2_cfb());
。。。。。。
PKCS12_PBE_add();
PKCS5_PBE_add();
}
/* 这个过程的主要任务是向全局变量,static LHASH *names_lh,注册加密算法,如果添加了新的加密算法,必需向names_lh注册。 */
由于DES算法接口内容较多,所以我们从IDEA算法的接口开始研究!
#ifndef NO_IDEA
EVP_add_cipher(EVP_idea_ecb()); /*添加EBC加密模式 */
EVP_add_cipher(EVP_idea_cfb()); /*添加CFB加密模式 */
EVP_add_cipher(EVP_idea_ofb()); /*添加OCF加密模式 */
EVP_add_cipher(EVP_idea_cbc()); /*添加CBC加密模式 */
EVP_add_cipher_alias(SN_idea_cbc,"IDEA"); /*添加cbc加密算法的别名 “IDEA” */
EVP_add_cipher_alias(SN_idea_cbc,"idea"); /*添加cbc加密算法的别名 “idea” */
#endif
在包括IDEA加密算法的情况下,OpenSSL将会选择IDAE加密算法模块!
下面来看看EVP_add_cipher函数是怎么实现的,
int EVP_add_cipher(EVP_CIPHER *c)
{
int r;
r=OBJ_NAME_add(OBJ_nid2sn(c->nid),OBJ_NAME_TYPE_CIPHER_METH,(char *)c);
if (r == 0) return(0);
r=OBJ_NAME_add(OBJ_nid2ln(c->nid),OBJ_NAME_TYPE_CIPHER_METH,(char *)c);
return(r);
}
/* 向全决变量names_lh 注册 obj_name_types 变量的过程 */
int OBJ_NAME_add(const char *name, int type, const char *data)
{
OBJ_NAME *onp,*ret;
int alias;
if ((names_lh == NULL) && !OBJ_NAME_init()) return(0);
alias=type&OBJ_NAME_ALIAS;
type&= ~OBJ_NAME_ALIAS;
onp=(OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME));
if (onp == NULL)
{
/* ERROR */
return(0);
}
onp->name=name;
onp->alias=alias;
onp->type=type;
onp->data=data;
ret=(OBJ_NAME *)lh_insert(names_lh,onp);
if (ret != NULL)
{
/* free things */
if ((name_funcs_stack != NULL) && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type))
{
/* XXX: I'm not sure I understand why the free
* function should get three arguments...
* -- Richard Levitte
*/
sk_NAME_FUNCS_value(name_funcs_stack,ret->type)
->free_func(ret->name,ret->type,ret->data);
}
OPENSSL_free(ret);
}
else
{
if (lh_error(names_lh))
{
/* ERROR */
return(0);
}
}
return(1);
}
names_lh 是 LHASH的全局变量,用于维护obj_name_types的类型的变量。(在crypt/objects/o_names.c中定义)
(crypt/objects/obj_dat.h)相关的全局变量
static unsigned char lvalues[2896] 全局变量,已经初始化,存放了OpenSSL所有Object的相关信息。
nid_objs 是ASN1_OBJECT结构的数组全局变量,已经初始化,记录了所有OpenSSL用到的类型的名字
static ASN1_OBJECT *sn_objs[NUM_SN] 全局变量,已经初始化。
static ASN1_OBJECT *ln_objs[NUM_LN] 全局变量,已经初始化。
crypt/object/objects.h 中定义的结构
typedef struct obj_name_st
{
int type;
int alias;
const char *name;
const char *data;
} OBJ_NAME;
注意:crypto/objects 目录下面维护整个OpenSSL模块化的重要的程序,下面逐个做出介绍。
objects.txt 按照一定的语法结构,定义了SN_base, LN_base, NID_base,OBJ_base。经过perl程序objects.pl通过命令perl objects.pl objects.txt obj_mac.num obj_mac.h 处理后,生成了obj_mac.num 和obj_mac.h两个文件。
obj_mac.num 用来查阅 OBJ_base与NID_base之间的对应关系。
obj_mac.h 用来提供c语言类型SN_base, LN_base, NID_base,OBJ_base定义。
objects.h 同样提供了c语言类型SN_base, LN_base, NID_base,OBJ_base定义,在obj_mac.h 更新之后,必须对对应的objects.h 中的内容作出同步,及保持与obj_mac.h的定义一至,同时objects.h中也声明了一些对OBJ_name的操作函数。
objects.h 经过perl程序perl obj_dat.pl objects.h obj_dat.h处理之后,生成obj_dat.h头文件。
obj_dat.h 中定义了如下的全局变量。
#define NUM_NID 393
#define NUM_SN 392
#define NUM_LN 392
#define NUM_OBJ 366
static unsigned char lvalues[2896],
static ASN1_OBJECT nid_objs[NUM_NID],
static ASN1_OBJECT *sn_objs[NUM_SN],
static ASN1_OBJECT *ln_objs[NUM_LN],
static ASN1_OBJECT *obj_objs[NUM_OBJ],
这些变量多有ASN1_OBJECT有关,在objects.txt中定义的所有的对象都会体现出来,具体的作用还不太清楚,需要继续研究!
对OpenSSL中宏的研究
密码算法接口的定义
typedef struct evp_cipher_st EVP_CIPHER;
/* 加密算法后被names_lh来管理,可以通算法的名称或别名来检索 */
struct evp_cipher_st
{
int nid; /*加密算法的nid*/
int block_size; /*数据块的大小 */
int key_len; /* Default value for variable length ciphers */
int iv_len; /* 对于CBC,CFB,OFB的加密算法初始化矢量*/
unsigned long flags; /* Various flags */
int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc); /* init key */
int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, unsigned int inl);/* encrypt/decrypt data */
int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */
int ctx_size; /* how big the ctx needs to be */
int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Populate a ASN1_TYPE with parameters */
int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */
int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Miscellaneous operations */
void *app_data; /* Application data */
};
如果正确定义了EVP_CIPHER变量,这个算法就可以被OpenSSL所接受了。
下面的宏将定义ECB,CBC,CFB,OFB算法EVP_CIPHER定义。
#define BLOCK_CIPHER_defs(cname, kstruct, \
nid, block_size, key_len, iv_len, flags,\
init_key, cleanup, set_asn1, get_asn1, ctrl)\
static EVP_CIPHER cname##_cbc = {\
nid##_cbc, block_size, key_len, iv_len, \
flags | EVP_CIPH_CBC_MODE,\
init_key,\
cname##_cbc_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
set_asn1, get_asn1,\
ctrl, \
NULL \
};\
EVP_CIPHER *EVP_##cname##_cbc(void) { return &cname##_cbc; }\
static EVP_CIPHER cname##_cfb = {\
nid##_cfb64, 1, key_len, iv_len, \
flags | EVP_CIPH_CFB_MODE,\
init_key,\
cname##_cfb_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
set_asn1, get_asn1,\
ctrl,\
NULL \
};\
EVP_CIPHER *EVP_##cname##_cfb(void) { return &cname##_cfb; }\
static EVP_CIPHER cname##_ofb = {\
nid##_ofb64, 1, key_len, iv_len, \
flags | EVP_CIPH_OFB_MODE,\
init_key,\
cname##_ofb_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
set_asn1, get_asn1,\
ctrl,\
NULL \
};\
EVP_CIPHER *EVP_##cname##_ofb(void) { return &cname##_ofb; }\
static EVP_CIPHER cname##_ecb = {\
nid##_ecb, block_size, key_len, iv_len, \
flags | EVP_CIPH_ECB_MODE,\
init_key,\
cname##_ecb_cipher,\
cleanup,\
sizeof(EVP_CIPHER_CTX)-sizeof((((EVP_CIPHER_CTX *)NULL)->c))+\
sizeof((((EVP_CIPHER_CTX *)NULL)->c.kstruct)),\
(ctx_size 其中有联合的结构,如何获取EVP_CIPHER_CTX数据长度)
set_asn1, get_asn1,\
ctrl,\
NULL \
};\
EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
上面的宏在经过处理之后,变成了四中加密模式的EVP_CIPHER定义,这个结构中封装了加密操作汉书,密钥初始化函数,以及密钥的清理函数。除了实现加密算法之外,还比需实现对应的密钥结构!
EVP_CIPHER_CTX就是密钥结构,完成对加密算法密钥的管理。
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
struct evp_cipher_ctx_st
{
const EVP_CIPHER *cipher;
int encrypt; /* encrypt or decrypt */
int buf_len; /* number we have left */
unsigned char oiv[EVP_MAX_IV_LENGTH]; /* original iv */
unsigned char iv[EVP_MAX_IV_LENGTH]; /* working iv */
unsigned char buf[EVP_MAX_IV_LENGTH]; /* saved partial block */
int num; /* used by cfb/ofb mode */
void *app_data; /* application stuff */
int key_len; /* May change for variable length cipher */
/* 通过联合的方式管理密钥,对各种密钥实现灵活的管理 */
union {
#ifndef NO_RC4
struct
{
unsigned char key[EVP_RC4_KEY_SIZE];
RC4_KEY ks; /* working key */
} rc4;
#endif
#ifndef NO_DES
des_key_schedule des_ks;/* key schedule */
struct
{
des_key_schedule ks;/* key schedule */
des_cblock inw;
des_cblock outw;
} desx_cbc;
struct
{
des_key_schedule ks1;/* key schedule */
des_key_schedule ks2;/* key schedule (for ede) */
des_key_schedule ks3;/* key schedule (for ede3) */
} des_ede;
#endif
#ifndef NO_IDEA
IDEA_KEY_SCHEDULE idea_ks;/* key schedule */
#endif
#ifndef NO_RC2
struct {
int key_bits; /* effective key bits */
RC2_KEY ks;/* key schedule */
} rc2;
#endif
#ifndef NO_RC5
struct {
int rounds; /* number of rounds */
RC5_32_KEY ks;/* key schedule */
} rc5;
#endif
#ifndef NO_BF
BF_KEY bf_ks;/* key schedule */
#endif
#ifndef NO_CAST
CAST_KEY cast_ks;/* key schedule */
#endif
} c;
};
下面的函数用来实现设定加密密钥和解密密钥。
void set_encrypt_key(const unsigned char *key, KEY_SCHEDULE *ks)
void set_decrypt_key(const unsigned char *key, KEY_SCHEDULE *ks)
在这两个函数的基础上实现EVP_CIPHER中密钥初始化函数。
static int init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
if(!enc)
{
if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE) enc = 1;
else if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB_MODE) enc = 1;
}
if (enc)
set_encrypt_key(key,&(ctx->c. ks));
else
{
set_decrypt_key(key,&(ctx->c. ks));
}
return 1;
}
/* 清除保留在内存中的密码 */
static int clean_key(EVP_CIPHER_CTX *ctx)
{
if(ctx)
memset(&(ctx-c.ks),0,sizeof(ctx->c.ks));
return 1;
}
如果加密算法结构EVP_CIPHER是通过BLOCK_CIPHER_defs宏定义的,则四种模式的算法接口必须何处理宏之后的接口一样:
int cname_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
int cname_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
int cname_cfb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
int cname_ofb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl);
二:四种加密模式的实现
四种加密模式与基本加解密算法之间的关系!
假设加密算法和解密算法的实现函数接口如下
void encrypt(const unsigned char *in, unsigned char *out, const KEY *key, int *length)
void decrypt(const unsigned char *in, unsigned char *out, const KEY *key, int *length)
void ecb_ encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int enc)
{/* 电子密码本: Electronic Code Book */
register int i;
int len = 8;
register long l = length;
unsigned char buf[8];
if(enc)/*encryption*/
{
for(i=0;i<=l;i+=8)
{
encrypt(&in[i], &out[i], key, &len);/*len == 8 will always be true here*/
}
else
{
for(i=0;i<=l;i+=8)
{
decrypt(&in[i], &out[i], key, &len);/*len == 8 will always be true here*/
}
}
}
void cbc_encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int enc)
{/* 密钥分组连接模式 */
register int i;
int len = 8;
register long l = length;
unsigned char buf[8];
if(enc)/*encryption*/
{
for(l-=8; l>=0; l-=8, in+=8, out+=8)
{
for(i=0; i<8;>
buf[i] = in[i] ^ iv[i];
encrypt(buf, iv, key, &len);/*len == 8 will always be true here*/
for(i=0; i<8;>
out[i] = iv[i];
}
/*final block*/
if(l != -8)
{
for(i=0; i
buf[i] = in[i] ^ iv[i];
for(; i<8;>
buf[i] = iv[i];
encrypt(buf, iv, key, &len);/*len == 8 here*/
for(i=0; i<8;>
out[i] = iv[i];
}
/* 加密输出为做下一次得iv ,iv与in异或运算的结果作为加密输入*/
}
else/*decryption*/
{
for(l-=8; l>=0; l-=8, in+=8, out +=8)
{
decrypt(in, buf, key, &len);
for(i=0; i<8;>
out[i] = buf[i] ^ iv[i];
for(i=0; i<8;>
iv[i] = in[i];
}
/*final block*/
if(l != -8)
{
decrypt(in, buf, key, &len);
for(i=0; i
out[i] = buf[i] ^ iv[i];
for(i=0; i<8;>
iv[i] = in[i];
}
}
l = 0;
i = 0;
}
void cfb64_encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int *num, int enc)
{/* 密码反馈模式 */
register long l = length;
unsigned char buf[8];
register int i, save = 0, n = *num;/*start from previously saved processing position*/
int len = 8;
/*restore from previously saved iv*/
for(i=n; i<8;>
buf[i] = iv[i];
if(enc)
{
while(l--)
{
if(n == 0)
{
encrypt(iv, buf, key, &len);
save = 1;
}
*(out++) = iv[n] = *(in++) ^ buf[n];
n = (n+1)&0x07;
}
}
else
{
while(l--)
{
if(n == 0)
{
encrypt(iv, buf, key, &len);
save = 1;
}
*(out++) = (iv[n]=*(in++)) ^ buf[n];
n = (n+1)&0x07;
}
}
if(save)/*store encrypted data into iv for next encryption*/
for(i=n; i<8;>
iv[i] = buf[i];
/* cfb加密输出得结果作为下次得IV, in与加密IV的结果作异或运算的结果作为cfb加密的输出 */
*num = n;/*store current processing position as entry of next encryption*/
save = i = n = 0;
}
void ofb64_encrypt(const unsigned char *in, unsigned char *out,
long length, const KEY *key, unsigned char *iv, int *num)
{/* 输出反馈模式 */
register long l = length;
register int i, n = *num;/*start from previously saved processing position*/
int len = 8;
unsigned char buf[8];
/*restore from previously saved iv*/
if(n != 0)
for(i=n; i<8;>
buf[i] = iv[i];
while(l--)
{
if(n == 0)
{
encrypt(iv, buf, key, &len);
for(i=0; i<8;>
iv[i] = buf[i];
}
*(out++) = *(in++) ^ buf[n];
n = (n+1)&0x07; /* n=(n+1)%0x08*/
/* iv加密输出结果作魏下一次iv, iv与in异或运算的结果作为ofb加密输出 */
}
*num = n;/*store current processing position as entry of next encryption*/
i = n = 0;
}
三:如何在SSL协议中添加新的加密算法!
首先,我们来看相关的全局变量 ssl3_ciphers[],在ssl/s3_lib.c中定义
变量的类型定义如下:
typedef struct ssl_cipher_st
{
int valid;
const char *name; /* text name */
unsigned long id; /* id, 4 bytes, first is version */
unsigned long algorithms; /* what ciphers are used */
unsigned long algo_strength; /* strength and export flags */
unsigned long algorithm2; /* Extra flags */
int strength_bits; /* Number of bits really used */
int alg_bits; /* Number of bits for algorithm */
unsigned long mask; /* used for matching */
unsigned long mask_strength; /* also used for matching */
} SSL_CIPHER;
举例来说明
/* Cipher 03 */
{
1,
SSL3_TXT_RSA_RC4_40_MD5, //字符串,在ssl3.h中定义!
SSL3_CK_RSA_RC4_40_MD5, //整形,在ssl3.h中定义
SSL_kRSA|SSL_aRSA|SSL_RC4 |SSL_MD5 |SSL_SSLV3,(在ssl_loal.h中定义)
//密钥交换算法|身份认证算法|加密算法|消息摘要算法|ssl协议版本号
SSL_EXPORT|SSL_EXP40,
0,
40,
128,
SSL_ALL_CIPHERS,
SSL_ALL_STRENGTHS,
},
如果增加了新的加密算法,必须注意定义的所数值是否可用,如果涉及到位与运算,还必须更改相应的掩码!
EVP_CIPHER *ssl_cipher_methods在ssl_ciph中定义,在函数void load_ciphers(void) 中完成对ssl_cipher_methods的初始化工作!
请在这里添加新的加密算法!并且在int ssl_cipher_get_evp(SSL_SESSION *s, const EVP_CIPHER **enc, const EVP_MD **md, SSL_COMP **comp)和static unsigned long ssl_cipher_get_disabled(void)中添加相应的实现算法!
编成语言性能评测
http://www.timestretch.com/FractalBenchmark.html
compare python vs lua, ruby, PHP and Haskell
http://william-os4y.livejournal.com/2216.html
星期五, 十月 06, 2006
几种Apache CGI模块性能简单分析比较
工作在Windows 2003, VS 2005下完成,全部采用动态编译
-
mod_python已被捐赈给apache由apache关方维护,轻松搞定(支持python 2.4,不支持python2.5)
mod_php 一直被作为CGI开发的热点,也非常容易搞定
mod_lua 是本人的开源项目,自然不用碰到问题(支持最新lua 5.1.1)
mod_ruby 这个小日本的东西,在他上面花的时间最多, 首先与yarv(ruby 2.0)还不兼容,另外在ruby 1.8.5的编译时候需要在程序内部切换一个宏,另外还有个内存问题! 文档资料也很少.(mod_lua根本还没有文档,我以后会陆续给出)!需要一定的经验,不能自动完成.
( 就我对apache与ruby的了解程度自信可以搞定, 对于小日本开源软件的态度还真不敢恭维,ROR不知是被那位炒起来的, 反正mod_ruby的性能不敢恭维.)
---PHP的测试
页面
echo "Hello World!";命令行
ab -n 100 http://localhost/tmp/hello.php
输出结果
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: Apache/2.0.59
Server Hostname: localhost
Server Port: ; 80
Document Path: ; /tmp/hello.php
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 0.609375 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 28700 bytes
HTML transferred: 1200 bytes
Requests per second: 164.10 [#/sec] (mean)
Time per request: 6.094 [ms] (mean)
Time per request: 6.094 [ms] (mean, across all concurrent requests)
Transfer rate: 45.95 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.1 0 15
Processing: 0 4 7.2 0 15
Waiting: 0 4 7.1 0 15
Total: 0 5 7.2 0 15
Percentage of the requests served within a certain time (ms)
50% 0
66% 15
75% 15
80% 15
90% 15
95% 15
98% 15
99% 15
100% 15 (longest request)
------mod_pythonde的测试
页面
from mod_python import apache命令行
def handler(req):
req.content_type = 'text/plain'
req.write("Hello World!")
return apache.OK
ab -n 100 http://localhost/tmp/hello.py输出结果
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking www.nutstech.com (be patient).....done
Server Software: Apache/2.0.59
Server Hostname: www.nutstech.com
Server Port: 80
Document Path: /tmp/hello.py
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 0.359375 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 20500 bytes
HTML transferred: 1200 bytes
Requests per second: 278.26 [#/sec] (mean)
Time per request: 3.594 [ms] (mean)
Time per request: 3.594 [ms] (mean, across all concurrent requests)
Transfer rate: 55.65 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.6 0 15
Processing: 0 2 5.7 0 15
Waiting: 0 2 5.2 0 15
Total: 0 3 6.0 0 15
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 15
90% 15
95% 15
98% 15
99% 15
100% 15 (longest request)
-----mod_lua的测试
页面程序
http.print("Hello World!")命令行
ab -n 100 http://localhost/tmp/hello.lua测试结果
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: Apache/2.0.59
Server Hostname: localhost
Server Port: 80
Document Path: /tmp/hello.lua
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 0.468750 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 24200 bytes
HTML transferred: 1200 bytes
Requests per second: 213.33 [#/sec] (mean)
Time per request: 4.688 [ms] (mean)
Time per request: 4.688 [ms] (mean, across all concurrent requests)
Transfer rate: 49.07 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.6 0 15
Processing: 0 3 6.6 0 31
Waiting: 0 2 6.0 0 15
Total: 0 3 6.9 0 31
Percentage of the requests served within a certain time (ms)
50% 0
66% 0
75% 0
80% 15
90% 15
95% 15
98% 15
99% 31
100% 31 (longest request)
----mod_ruby的测试
页面
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new
print cgi.header("type"=>"text/plain")
print "Hello World!"
命令
ab -n 100 http://localhost/tmp/hello.rbx测试结果
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: Apache/2.0.59
Server Hostname: localhost
Server Port: 80
Document Path: /tmp/hello.rbx
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 1.187500 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 24300 bytes
HTML transferred: 1200 bytes
Requests per second: 84.21 [#/sec] (mean)
Time per request: 11.875 [ms] (mean)
Time per request: 11.875 [ms] (mean, across all concurrent requests)
Transfer rate: 19.37 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.1 0 15
Processing: 0 10 9.1 15 46
Waiting: 0 9 9.1 15 46
Total: 0 10 9.1 15 46
Percentage of the requests served within a certain time (ms)
50% 15
66% 15
75% 15
80% 15
90% 15
95% 31
98% 31
99% 46
100% 46 (longest request)
This is ApacheBench, Version 2.0.41-dev <$Revision: 1.121.2.12 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 2006 The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient).....done
Server Software: Apache/2.0.59
Server Hostname: localhost
Server Port: 80
Document Path: /tmp/hello.rbx
Document Length: 12 bytes
Concurrency Level: 1
Time taken for tests: 1.187500 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 24300 bytes
HTML transferred: 1200 bytes
Requests per second: 84.21 [#/sec] (mean)
Time per request: 11.875 [ms] (mean)
Time per request: 11.875 [ms] (mean, across all concurrent requests)
Transfer rate: 19.37 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 2.1 0 15
Processing: 0 10 9.1 15 46
Waiting: 0 9 9.1 15 46
Total: 0 10 9.1 15 46
Percentage of the requests served within a certain time (ms)
50% 15
66% 15
75% 15
80% 15
90% 15
95% 31
98% 31
99% 46
100% 46 (longest request)
结果比较:
- 模块名称 结果(次/秒)
- mod_python 278.26
- mod_lua 213.33
- mod_php 164.10
- mod_ruby 84.21
当然php在WEB开发中的地位已经巩固, 但我相信很快就会被python赶上并超越
我开发的mod_lua,是为嵌入式应用准备的,在执行速度与模块大小方面都不错!且可直接用共享内存来通信 具体大家可以到 http://sf.net/projects/modlua 去了解!
mod_ruby是在是不敢恭维,如果采用eruby估计会更慢,将用ruby开发web的人,需要仔细考虑了
安全访问wikipedia的最好方法
中文:https://secure.wikimedia.org/wikipedia/zh/wiki/
星期四, 十月 05, 2006
glibc win32 native build!
http://www.gimp.org/~tml/gimp/win32/downloads.html
星期三, 十月 04, 2006
关于iolanguage
ruby上次研究的结果是不太理想, 本来估计开发者短时很难从根本上有所改进, 但是最近发新yarv 也就是Rite 2.0的核心表现还很优秀!
从微尘《一个Python程序的6次改进》想到的
下面是总结出来的最快的python实现
import datetime
if __name__ == "__main__":
t1=datetime.datetime.today()
f = file("email.txt","r")
f2 = file("email_new.txt","w")
f2.writelines(set(f))
f.close()
f2.close()
t2=datetime.datetime.today()
print str(t2-t1)
在我机器上的测试结果:
python 2.5: 0:00:00.172000
这个程序语言特性用到了极致, 近乎完美地解决了问题,佩服!
一位网友的ruby实现
#!/usr/bin/env ruby
t = Time.new
file = 'email.txt'
f1= File.new('email.txt', 'r')
data = f1.readlines
f1.close
f2 = File.new('email_rb.txt', 'w')
f2.write(data.uniq.join)
f2.close
puts Time.new - t
ruby 2.0.0 (Base: Ruby 1.9.0 2006-04-08) [i386-mswin32]
YARVCore 0.4.1 Rev: 545 (2006-09-01) [opts: [inline method cache] ]
这个程序也很酷,结果 0.391
看了之后,马上产生了用lua写一个同样程序的想法!
lines = {}
f1 = io.open ("email.txt","r")
for line in f1:lines() do lines[line] = true end
f1:close()
f2 = io.open ("e_t.txt","w+")
for line in pairs(lines) do f2:write(line, "\n") end
f2:close()
print(os.clock())
Lua 5.1.1 Copyright (C) 1994-2006 Lua.org, PUC-Rio: 0.406
测试结果: Python:Ruby:Lua = 172:391:406
是不是LUA就差了呢!才不是呢!
这也是可以理解的, LUA io操作肯定是没有优化的,没有一次将所有的数据读入/写出,我尝试一次读入出数据,然后对读入的数据按照string的方式来处理,然后一次写盘,测试的结果是比上面的程序慢了一倍,问题在于lua对于字符串的操作同样也为优化,花的时间很长,CPU/内存开销都很大,看来又比要对字符处处理做一个扩展库.
另外将上面的程序两个循环合并成一个同时操作读入/写出文件后性能也不理想,因为同时在两个文件上进行IO操作,硬盘磁头会频繁移动,性能反而降低。LUA的优势要嵌入C/C++才能表现出来!
不过python的表现让我惊奇, rite的表现也很惹人注意。
由于我的开发工作决定使用lua会更好。所以我会继续使用lua.
iolanguage也进入了我的视线,抽空也的研究一下!
星期二, 十月 03, 2006
COM中讨厌的 RtlSizeHeap, ActiveX host in IE
内存管理的问题
I didn't have time to get to the bottom of this --- though I suspect that it's related to COM BSTRs (or VARIANTS) and the handling/deallocation of them. There are some strict rules as to who has to free BSTR memory -- check out MSDN to get some more info on this. I've also found that heap management under Windows 2000 is quite a bit different than NT 4. There seems to be more heap optimization going on -- which causes some code (probably written incorrectly!) to blow that worked fine in NT4.
In the case of my original post, I didn't have time to go back and trace everything out, so I brought the VC++ ADO COM object into my source as a CLASS module instead of a COM object (which in this one case cleared things up). As noted above, I'm sure the issues were mine -- and related to how BSTRs or variants were being handled. Sure seems strange that ALL the addresses for all three problems were the same! Anybody have any other ideas?
下面是一个低级错误:
>>I get the above error when i return a string parameter
>>of LPCSTR type
Is it a string literal? IOW, are you doint sth. like
LPCSTR foo()
{
LPCSTR _p = "123";
return _p;
}
If so, change it to use a non-const memory area, e.g.
LPCSTR foo()
{
LPCSTR _a [] = "123";
return _a;
}
我想,道理是一样的不过,出现问题的情况会比上面复杂的多!
http://msdn2.microsoft.com/en-us/library/ms235460(d=ide).aspx
异质编译连接的问题
http://discussms.hosting.lsoft.com/SCRIPTS/WA-MSD.EXE?A2=ind0112a&L=atl&amp;amp;amp;D=0&T=0&P=4234
又一个,同一内存释放了两次
而我碰到的问题不在上面的范畴之内,一个ActiveX的事件,用attachEvent多次处理后,会随机产生RtlSizeHeap错误,改用[script for="ID" event="Event" language="javascript"][/script],错误消失,在attachEvent的时候对传给事件处理程序的参数被修改了,所以产生。但为什么前者会产生这种现象呢,还不清楚!
后来在google里面找ActiveX attachEvent的相关资料,大多是关于标准HTML元素的,对ActiveX较少,不过找到一本不错的书! 构建WEB应用程序的人非常值得去读一下!http://book.itzero.com/read/others/McGraw.Hill.Osborne.JavaScript.2.0.The.Complete.Reference.Second.Edition.eBook-LiB_html/8166final/toc.html
下面的链接简单介绍了ActiveX事件处理的方法!
http://discuss.develop.com/archives/wa.exe?A2=ind0212b&L=atl&T=0&H=1&P=4599
LuaCOM for Lua 5.1.1 Fixed!
除了上面引用的 LuaCOM - more questions 中所解决的问题外,LuaCOM 在 Lua 5.1.1中还有一个比较严重的问题,那就是 接口 参数传入有问题,具体原因还不太清楚,可能是lua 5.1与lua 5.0在传入函数参数时,对于堆栈的操作发生改变,类似于下面的代码需要修正!
1 多处定义的 self_param=1,并未在其他地方使用,干脆移除,要不干扰我们对代码的理解!
2 文中多处定义的 const int first_param = 2; 会在COM接口lua 5.1中造成第一个参数丢失,所以改成const int first_param = 1
3 const int num_params = luaCompat_getNumParams(L, 4) - 1; 由于first_param 从2改为1,所以把它改成const int num_params = luaCompat_getNumParams(L, 4);
基本上就这样,还需要更多的验证,另外对luacom的改动,需要内lua的VM机制与COM机制有比较深入的认识,说实话,这两件事情都比较复杂,另外由于luacom的不跨平台性,用ATL与luabind来重新实现应该是比较好的选择,代码量可能会更小!
修改,上面的方法存在问题,如果是用obj.method的方法来调用,需要用上面的方法修改,如果用obj:Method的方法来调用的话,就不需要改拉!
LuaCOM - more questions
LuaCOM - more questionsby Terry Bayne Jan 31, 2006; 09:26pm :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Good Morning. I've started using LuaCOM and I have a few questions. I am not a COM guru so please excuse my ignorance. I am trying to build on the examples from the LuaCOM documentation, and in doing so I have no problem opening up Microsoft Word. The problem comes when I try to create a new document - most of the examples on the web do something like this: word = luacom.CreateObject("Word.Application") assert(word) word.visible = true -- Works good up to this point doc = word.Documents.Add() The last statement fails. I've tried passing parameters, even tried this: word = luacom.CreateObject("Word.Application") mt = luacom.CreateObject("type.missing") assert(word) word.visible = true -- Works good up to this point doc = word.Documents.Add(mt,mt,mt,mt) All this gets me is a type mismatch error. Any ideas? Thanks Terry | |
Re: LuaCOM - more questionsby Fabio Mascarenhas Jan 31, 2006; 10:08pm :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Hi, Terry, This: > doc = word.Documents.Add() should be this: doc = word.Documents:Add() Method calls use ':'. Reading and writing properties use '.'. -- Fabio Mascarenhas On 1/31/06, Terry Bayne <tbayne@...> wrote: > Good Morning. > > I've started using LuaCOM and I have a few questions. I am not a COM guru so please excuse my ignorance. >when I try to create a new document - most of the examples on the web do >something like this: > > word = luacom.CreateObject("Word.Application") > assert(word) > word.visible = true > -- Works good up to this point > doc = word.Documents.Add() > > The last statement fails. I've tried passing parameters, even tried this: > All this gets me is a type mismatch error. | |
LuaCOM - more questionsby Michael Cumming Jan 31, 2006; 11:01pm :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Terry, Its doc = word.Documents:Add() note the ':' not '.' Mike | |
Re: LuaCOM - more questionsby Terry Bayne Feb 01, 2006; 12:10am :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Fabio, Thanks for spotting that, but still getting a type mismatch error: LUA: Calling word.Documents:Add Error executing lua code: [COM error:(E:\Blackdog\kibble\trunk\luacom\src\library\tLuaCOM.cpp,403):Type mismatch.] Here is the lua code I am running: word = luacom.CreateObject("Word.Application") MT = luacom.CreateObject("type.missing") assert(word)word.visible = true print("Calling word.Documents:Add") doc = word.Documents:Add() print("Back from Documents:Add()") Any ideas? Also I have tried passing MT to the Add() call like so: doc = word.Documents:Add(MT,MT,MT,MT) Thanks On Tue, 31 Jan 2006 12:08:11 -0200, Fabio Mascarenhas wrote: >> Hi, Terry, >> >> This: >> >>>> doc = word.Documents.Add() >>>> >> should be this: >> >> doc = word.Documents:Add() >> >> Method calls use ':'. Reading and writing properties use '.'. >> >> -- >> Fabio Mascarenhas >> >> On 1/31/06, Terry Bayne <tbayne@...> wrote: >> >>>> Good Morning. >>>> >>>> I've started using LuaCOM and I have a few questions. I am not >>>> a COM guru so please excuse my ignorance. >>>> when I try to create a new document - most of the examples on >>>> the web >>>> >> do >something like this: >> >>>> word = luacom.CreateObject("Word.Application") assert(word) >>>> word.visible = true -- Works good up to this point doc = >>>> word.Documents.Add() >>>> >>>> The last statement fails. I've tried passing parameters, even >>>> tried this: All this gets me is a type mismatch error. | |
RE: LuaCOM - more questionsby Ignacio Burgueño Feb 01, 2006; 01:16am :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Hi Terry. What version of LuaCOM are you using? Just tested your sample code using luaCom 1.2 and Office 2003 and it worked fine. > -----Original Message----- > From: lua-bounces@... > [mailto:lua-bounces@...] On Behalf Of Terry Bayne > Sent: Tuesday, January 31, 2006 1:15 PM > To: Lua list > Subject: Re: LuaCOM - more questions > > Fabio, > > Thanks for spotting that, but still getting a type mismatch error: > > LUA: Calling word.Documents:Add > Error executing lua code: [COM > error:(E:\Blackdog\kibble\trunk\luacom\src\library\tLuaCOM.cpp > ,403):Type mismatch.] > > Here is the lua code I am running: > > word = luacom.CreateObject("Word.Application") > MT = luacom.CreateObject("type.missing") > assert(word)word.visible = true > print("Calling word.Documents:Add") > doc = word.Documents:Add() > print("Back from Documents:Add()") > > Any ideas? > > Also I have tried passing MT to the Add() call like so: > > doc = word.Documents:Add(MT,MT,MT,MT) > > Thanks | |
RE: LuaCOM - more questionsby Terry Bayne Feb 01, 2006; 01:41am :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Ignacio, Hi, thank you for taking the time to look at this. I am using LUACom 1.3 with Office 2003 and LUA 5.0.2. Terry On Tue, 31 Jan 2006 15:12:24 -0300, Ignacio Burgueño wrote: >> Hi Terry. What version of LuaCOM are you using? Just tested your >> sample code using luaCom 1.2 and Office 2003 and it worked fine. >> >> >>>> -----Original Message----- >>>> From: lua-bounces@... >>>> [mailto:lua-bounces@...] On Behalf Of Terry >>>> Bayne Sent: Tuesday, January 31, 2006 1:15 PM To: Lua list >>>> Subject: Re: LuaCOM - more questions >>>> >>>> Fabio, >>>> >>>> Thanks for spotting that, but still getting a type mismatch >>>> error: >>>> >>>> LUA: Calling word.Documents:Add >>>> Error executing lua code: [COM >>>> error:(E:\Blackdog\kibble\trunk\luacom\src\library\tLuaCOM.cpp >>>> ,403):Type mismatch.] >>>> >>>> Here is the lua code I am running: >>>> >>>> word = luacom.CreateObject("Word.Application") >>>> MT = luacom.CreateObject("type.missing") >>>> assert(word)word.visible = true >>>> print("Calling word.Documents:Add") >>>> doc = word.Documents:Add() >>>> print("Back from Documents:Add()") >>>> >>>> Any ideas? >>>> >>>> Also I have tried passing MT to the Add() call like so: >>>> >>>> doc = word.Documents:Add(MT,MT,MT,MT) >>>> >>>> Thanks | |
RE: LuaCOM - more questionsby Ignacio Burgueño Feb 01, 2006; 05:04am :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message Well. I compiled a debug version of luacom 1.3 (as of 2005-02-28) and it does not work. Indeed, the code fails when calling the Add method from the Word.Document class Its signature is: HRESULT Add( [in, optional] VARIANT* Template, [in, optional] VARIANT* NewTemplate, [in, optional] VARIANT* DocumentType, [in, optional] VARIANT* Visible, [out, retval] Document** prop); I don't know if luacom 1.3 introduced a new approach to handle optional parameters, but I think that the problem lies in the function tLuaCOMTypeHandler::fillDispParams At line 943, there's this code: else if(!byref) // here we filter the optional out params (treated below) { // assumes that a parameter is expected but has not been found var.vt = VT_ERROR; var.scode = DISP_E_PARAMNOTFOUND; } if(!byref || var.vt == VT_ERROR) { VariantCopy(&r_rgvarg[i], &var); VariantClear(&var); } byref is true (it was set at line 911), and the parameter is [in] but it seems that that case isn't handled properly. It should pass a Variant with VT_ERROR and DISP_E_PARAMNOTFOUND. I'm not quite sure of how to fix this properly. Changing line 943 to this works fine: else if(byref) // here we filter the optional out params (treated below) But I didn't check if that breaks other calls. Regards, Ignacio Burgueño Desarrollo - Tecnolink S.A. ignacio@... Tel: +598 2 614-1003 www.inConcertCC.com > -----Original Message----- > From: lua-bounces@... > [mailto:lua-bounces@...] On Behalf Of Terry Bayne > Sent: Tuesday, January 31, 2006 2:45 PM > To: Lua list > Subject: RE: LuaCOM - more questions > > Ignacio, > > Hi, thank you for taking the time to look at this. I am > using LUACom 1.3 with Office 2003 and LUA 5.0.2. > > Terry > > On Tue, 31 Jan 2006 15:12:24 -0300, Ignacio Burgueño wrote: > >> Hi Terry. What version of LuaCOM are you using? Just tested your > >> sample code using luaCom 1.2 and Office 2003 and it worked fine. > >> > >> > >>>> -----Original Message----- > >>>> From: lua-bounces@... > >>>> [mailto:lua-bounces@...] On Behalf Of Terry > >>>> Bayne Sent: Tuesday, January 31, 2006 1:15 PM To: Lua list > >>>> Subject: Re: LuaCOM - more questions > >>>> > >>>> Fabio, > >>>> > >>>> Thanks for spotting that, but still getting a type mismatch > >>>> error: > >>>> > >>>> LUA: Calling word.Documents:Add > >>>> Error executing lua code: [COM > >>>> error:(E:\Blackdog\kibble\trunk\luacom\src\library\tLuaCOM.cpp > >>>> ,403):Type mismatch.] > >>>> > >>>> Here is the lua code I am running: > >>>> > >>>> word = luacom.CreateObject("Word.Application") > >>>> MT = luacom.CreateObject("type.missing") > >>>> assert(word)word.visible = true > >>>> print("Calling word.Documents:Add") > >>>> doc = word.Documents:Add() > >>>> print("Back from Documents:Add()") > >>>> > >>>> Any ideas? > >>>> > >>>> Also I have tried passing MT to the Add() call like so: > >>>> > >>>> doc = word.Documents:Add(MT,MT,MT,MT) > >>>> > >>>> Thanks > > > > | |
RE: LuaCOM - more questionsby Shaun-7 Feb 01, 2006; 05:23am :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message > I don't know if luacom 1.3 introduced a new approach to handle optional > parameters, but I think that the problem lies in the function > tLuaCOMTypeHandler::fillDispParams > At line 943, there's this code: I had exactly the same problem and implemented a fix exactly like you suggested. I sent an email to the maintainer, Fabio Mascarenhas, at the time, but don't think I ever heard anything back. Cheers, Shaun | |
RE: LuaCOM - more questionsby Terry Bayne Feb 01, 2006; 07:43am :: Rate this Message: - Use ratings to moderate (?) Reply | Reply to Author | View Threaded | Link to this Message That did seem to solve the problem! Thanks to both you and Shaun for your help! Terry On Tue, 31 Jan 2006 19:07:52 -0300, Ignacio Burgueño wrote: >> Well. I compiled a debug version of luacom 1.3 (as of 2005-02-28) >> and it does not work. >> Indeed, the code fails when calling the Add method from the >> Word.Document class Its signature is: >> >> HRESULT Add( >> [in, optional] VARIANT* Template, >> [in, optional] VARIANT* NewTemplate, >> [in, optional] VARIANT* DocumentType, >> [in, optional] VARIANT* Visible, >> [out, retval] Document** prop); >> >> I don't know if luacom 1.3 introduced a new approach to handle >> optional parameters, but I think that the problem lies in the >> function tLuaCOMTypeHandler::fillDispParams At line 943, there's >> this code: >> >> else if(!byref) // here we filter the optional out params (treated >> below) { >> // assumes that a parameter is expected but has not been found >> >> var.vt = VT_ERROR; >> var.scode = DISP_E_PARAMNOTFOUND; >> } >> >> if(!byref || var.vt == VT_ERROR) >> { >> VariantCopy(&r_rgvarg[i], &var); >> VariantClear(&var); >> } >> >> byref is true (it was set at line 911), and the parameter is [in] >> but it seems that that case isn't handled properly. It should pass >> a Variant with VT_ERROR and DISP_E_PARAMNOTFOUND. I'm not quite >> sure of how to fix this properly. Changing line 943 to this works >> fine: >> else if(byref) // here we filter the optional out params (treated >> below) But I didn't check if that breaks other calls. >> >> Regards, >> >> Ignacio Burgueño >> Desarrollo - Tecnolink S.A. >> ignacio@... >> >> Tel: +598 2 614-1003 >> www.inConcertCC.com >> >> >>>> -----Original Message----- >>>> From: lua-bounces@... >>>> [mailto:lua-bounces@...] On Behalf Of Terry >>>> Bayne Sent: Tuesday, January 31, 2006 2:45 PM To: Lua list >>>> Subject: RE: LuaCOM - more questions >>>> >>>> Ignacio, >>>> >>>> Hi, thank you for taking the time to look at this. I am using >>>> LUACom 1.3 with Office 2003 and LUA 5.0.2. >>>> >>>> Terry >>>> >>>> On Tue, 31 Jan 2006 15:12:24 -0300, Ignacio Burgueño wrote: >>>> >>>>>> Hi Terry. What version of LuaCOM are you using? Just tested >>>>>> your sample code using luaCom 1.2 and Office 2003 and it >>>>>> worked fine. >>>>>> >>>>>> >>>>>>>> -----Original Message----- >>>>>>>> From: lua-bounces@... >>>>>>>> [mailto:lua-bounces@...] On Behalf Of >>>>>>>> Terry Bayne Sent: Tuesday, January 31, 2006 1:15 PM To: >>>>>>>> Lua list Subject: Re: LuaCOM - more questions >>>>>>>> >>>>>>>> Fabio, >>>>>>>> >>>>>>>> Thanks for spotting that, but still getting a type >>>>>>>> mismatch error: >>>>>>>> >>>>>>>> LUA: Calling word.Documents:Add >>>>>>>> Error executing lua code: [COM >>>>>>>> error:(E:\Blackdog\kibble\trunk\luacom\src\library\tLuaCOM.cpp ,403): >>>>>>>> Type mismatch.] >>>>>>>> >>>>>>>> Here is the lua code I am running: >>>>>>>> >>>>>>>> word = luacom.CreateObject("Word.Application") >>>>>>>> MT = luacom.CreateObject("type.missing") >>>>>>>> assert(word)word.visible = true >>>>>>>> print("Calling word.Documents:Add") >>>>>>>> doc = word.Documents:Add() >>>>>>>> print("Back from Documents:Add()") >>>>>>>> >>>>>>>> Any ideas? >>>>>>>> >>>>>>>> Also I have tried passing MT to the Add() call like so: >>>>>>>> >>>>>>>> doc = word.Documents:Add(MT,MT,MT,MT) >>>>>>>> >>>>>>>> Thanks |