Category Archives: C
IN:C, 编程相关 Tags: x509 Comments:5X509证书的详细描述在rfc2459中。
简单的来说X509证书是这样的:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
— If present, version shall be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
— If present, version shall be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
— If present, version shall be v3
}
X509由三部分组成,分别是TBSCertificate,AlgorithmIdentifier ,signatureValue 。TBSCertificate包含了证书的详细信息,如证书编号,颁发者,发行者,过期日期等;AlgorithmIdentifier 是指证书自身使用数字签名算法标识,TBSCertificate中也有一个AlgorithmIdentifier,这个是证书可以用作的数字签名算法标识;signatureValue是指使用AlgorithmIdentifier 所指定的算法对整个TBSCertificate签名得到的数字签名。
可以使用openssl命令行工具生成X509证书,不过需要用openssl先生成一对RSA密钥对,如果只有公钥需要生产证书,就需要自己通过编程调用openssl函数来生成证书了。openssl自带的例子中有一个生成证书的例子,不过也是先生成一对RSA密钥对。
通过对openssl源代码的分析,可以X509_set_pubkey函数只是用到了RSA结构中的公钥,所以我们可以通过自己创建一个openssl的RSA结构,只设置RSA密钥对中的公钥,来完成证书的生成。
参考代码
该函数入口参数是一个证书的主题名,和128字节的公钥(1024位;RSA中的modulus INTEGER—-n),返回一个证书ID,和DER编码的证书,默认使用的publicExponent INTEGER, — e为65535。
参考:
RFC2459
PKCS#1
openssl
IN:C, Python, 编程相关 Tags: Python, sdcv Comments:3sdcv-0.4.2版本的代码有3480行,而图形界面的星际译王更是有N多的代码,俺也写了一个就十几行的Python代码,速度当然比不上sdcv,能差十倍,不过,请注意,sdcv查一个单词是0.01秒,我这个是0.1秒,我不觉得有人能感觉出来差别。
其实我的核心是C语言写的,之所以在速度上没有sdcv快是没有做那么些优化,俺只写了80多行,而且还有不少代码是用作Python封装的。我以前写文章说过sdcv代码写的很麻烦,用C语言可以很简洁的写出来,现在确实做到了,只是结合了Python。我觉得这种模式挺不错,影响速度的核心使用C语言去写,然后主逻辑框架使用Python写,不仅效率不会受影响,开发的速度也提高了不少。(我这个例子Python并没做什么)
static PyObject * lookup(PyObject *self, PyObject *args)
{
int fd;
char *file_prefix;
long file_size;
long wc;
char *word;
char *data;
const char *p;
long index_size;
int offset;
int size;
int flag = 0;
unsigned char *buf;
if (!PyArg_ParseTuple(args, "slls:lookup",
&file_prefix, &file_size, &wc, &word)) {
return NULL;
}
char file_name[256];
strcpy(file_name, file_prefix);
strcat(file_name, ".idx");
if ((fd = open(file_name, O_RDONLY)) < 0) {
printf("open failedn");
return NULL;
}
data = (char *)mmap( NULL, file_size, PROT_READ, MAP_SHARED, fd, 0);
p = data;
int i;
for (i=0;i<wc;i++) {
index_size = strlen(p) + 1 + 2*sizeof(int);
if (strcmp(word, p) == 0) {
flag = 1;
}
if (flag == 1) {
offset = ntohl(*(int *)(p + strlen(p) + 1));
size = ntohl(*(int *)(p + strlen(p) + 1 + sizeof(int)));
//printf("offset=%dnsize%dn",offset,size);
/*gzFile zfile;
zfile = gzopen("./dic/stardict-langdao-ec-gb-2.4.2/langdao-ec-gb.dict.dz", "rb");
gzseek(zfile, offset, SEEK_SET);
buf = (unsigned char *)malloc(*size+1);
memset(buf, ' ', size+1);
gzread(zfile, buf, size);
printf("%sn", buf);
*/
close(fd);
if ((fd = open("./dic/stardict-langdao-ec-gb-2.4.2/langdao-ec-gb.dict", O_RDONLY)) < 0) {
return NULL;
}
lseek(fd, offset, SEEK_SET);
buf = (unsigned char *)malloc(size+1);
memset(buf, ' ', size+1);
read(fd, buf, size);
//printf("%sn",buf);
close(fd);
return Py_BuildValue("s", buf);
}
p += index_size;
}
return Py_BuildValue("s","");
}
static struct PyMethodDef lookup_methods[] = {
{"lookup", lookup, 1, "lookup(file_prefix, file_size, wc, word)"},
{NULL, NULL}
};
void initlookup()
{
(void) Py_InitModule("lookup", lookup_methods);
}
使用C语言对Python进行扩展挺方便的,http://gashero.yeax.com/?p=38#id7这里有个不错的文档。
完了俺整理整理也放在google code上去。
上面的代码中dict文件需要是未gzip压缩过的,如果在压缩过的我使用被注释掉的那段代码在seek的时候速度很慢,又没办法用mmap,所以暂时就先只使用未压缩过的。
IN:C, 编程相关 Tags: C, libevent Comments:1libevent是一个异步事件处理软件函式库,以BSD许可证释出。
libevent提供了一组应用程序编程接口(API),让程式设计师可以设定某些事件发生时所执行的函式,也就是说,libevent可以用来取代网络服务器所使用的循环检查架构。
摘自维基百科
http://blog.gslin.info/2005/11/network-programming-using-libevent-i.html
这里介绍了libevent相关的网络编程背景,需要带套访问哦。
以下分析针对libevent-1.4.3-stable。
来看libevent自带的例子:
/*
* Compile with:
* cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
*/
static void
fifo_read(int fd, short event, void *arg)
{
char buf[255];
int len;
struct event *ev = arg;
/* Reschedule this event */
event_add(ev, NULL);
fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %pn",
fd, event, arg);
len = read(fd, buf, sizeof(buf) - 1);
if (len == -1) {
perror("read");
return;
} else if (len == 0) {
fprintf(stderr, "Connection closedn");
return;
}
buf[len] = '�';
fprintf(stdout, "Read: %sn", buf);
}
int
main (int argc, char **argv)
{
struct event evfifo;
struct stat st;
const char *fifo = "event.fifo";
int socket;
if (lstat (fifo, &st) == 0) {
if ((st.st_mode & S_IFMT) == S_IFREG) {
errno = EEXIST;
perror("lstat");
exit (1);
}
}
unlink (fifo);
if (mkfifo (fifo, 0600) == -1) {
perror("mkfifo");<code></code>
exit (1);
}
/* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
socket = open (fifo, O_RDWR | O_NONBLOCK, 0);
if (socket == -1) {
perror("open");
exit (1);
}
fprintf(stderr, "Write data to %sn", fifo);
/* Initalize the event library */
event_init();
/* Initalize one event */
event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
/* Add it to the active events, without a timeout */
event_add(&evfifo, NULL);
event_dispatch();
return (0);
}
我把原来代码中WIN平台相关的去掉了,看起来方便一些,这个例子创建了一个pipe,并且使用libevent来监听是否可读,读有数据可读时调用函数fifo_read。
libevent调用比较简单,首先event_init()对event库进行初始化,然后使用event_set()来对某个fd的操作进行监听,接着使用event_add()把这个event激活,这里可以指定超时的时间,最后一步event_dispatch(),开始进行循环。
event_init()里只是对外的一个接口,这个函数调用了event_base_new(),分配了一个event_base类型的空间,设置了一些全局变量,使用detect_monotonic来检测是否支持CLOCK_MONOTONIC类型的时钟,这里不太理解为什么要使用clock_gettime(CLOCK_MONOTONIC, &ts)来获得当前时间,这个与gettimeofday得到的精度是一样的,只是一个是标准的时间(UNIX元年算起),一个是开机时间算起,有什么差别吗?
CLOCK_MONOTONICI测试代码:
/* gcc -o ftime ftime.c*/
#include<stdio .h>
#include<time .h>
#include<sys /time.h>
int main(void)
{
struct timeval tp;
gettimeofday(&tp,NULL);
printf("sec=%ld\n",tp.tv_sec);
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC,&ts);
printf("sec=%ld\n",ts.tv_sec);
return 0;
}
结果:
[cocobear@cocobear libevent-1.4.3-stable]$ gcc ftime.c -lrt
[cocobear@cocobear libevent-1.4.3-stable]$ ./a.out
sec=1235372220
sec=4621
接下来就检测可使用的事件检测函数,这里与系统相关的调用被封装成了一个结构eventop:
struct eventop {
const char *name;
void *(*init)(struct event_base *);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
int (*dispatch)(struct event_base *, void *, struct timeval *);
void (*dealloc)(struct event_base *, void *);
/* set if we need to reinitialize the event base */
int need_reinit;
};
编译时libevent会通过
#ifdef HAVE_SELECT
&selectops,
#endif
来“动态”的确定eventops数组,在定义这个eventops数组时确定了使用这些事件驱动模型的顺序,如果你机子上有多种可用的模式,则可以通过修改改数组来自定义使用的模型。
在event_base_new()的最后调用了event_base_priority_init()初始化了消息的优先级队列。主要就是对activequeues变量进行空间分配。默认是分配了一个event_list给activequeues。
IN:C, 编程相关 Tags: C, libev Comments:0先给出libev的主页http://software.schmorp.de/pkg/libev.html,libev是一个高性能的事件驱动模型,与libevent类似,不过设计更为小巧,简洁。
libevent有成功的应用–memcached,libev是一个比较新的项目,代码比较少,所以这几天来研究下这个。
首先从CVS中下载最新的代码:
cvs -z3 -d :pserver:anonymous@cvs.schmorp.de/schmorpforge co libev
CVS代码中有autogen.sh文件,执行该文件会生成configure,我机子上出了点问题,需要首先运行
automake –add-missing
然后就是./configure && make && make install 了。
安装好后会有一个提示:
Libraries have been installed in:
/usr/local/lib
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR’
flag during linking and do at least one of the following:
– add LIBDIR to the `LD_LIBRARY_PATH’ environment variable
during execution
– add LIBDIR to the `LD_RUN_PATH’ environment variable
during linking
– use the `-Wl,–rpath -Wl,LIBDIR’ linker flag
– have your system administrator add LIBDIR to `/etc/ld.so.conf’
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
需要注意一下,因为默认这个库安装在了/usr/local/lib/里,所以运行程序时有可能会提示找不到libev.so这个动态库。我们需要在编译时加上-LLIBDIR参数,然后设置LD_RUN_PATH这个环境变量。
安装好为了测试libev,可以使用lighttz,其实我是从这里知道的libev,下载C文件,使用下面的命令来编译:
LD_RUN_PATH=/usr/local/lib/
export LD_RUN_PATH
gcc -LLIBDIR -o lighttz lighttz.c -lev
IN:C, 编程相关 Tags: sdcv Comments:3sdcv是stardict的命令行替代,打算用stardict的字典,所以看看如何从字典中取词,sdcv比较小巧,拿来看挺合适,不过在我机子上编译出现了点问题:
lib.cpp:516: error: no matching function for call to ‘min(long unsigned int, guint32&)’
解决办法:
-fread(wordentry_buf, std::min(sizeof(wordentry_buf), page_size), 1, idxfile);
+fread(wordentry_buf,std::min(sizeof(wordentry_buf),(size_t)page_size),1,idxfile);
——————————————–split—————————————
听说WordPress2.7在后台的UI上变化不小,今天试着升级上来,发现果然是完全改变了以前的UI,大量使用了JS,感觉还不错:-)
好久没有Opera了,因为又出现了无法输入的现象,只好去用了Firefox一段时间,今天换了下Ibus输入法,发现可以在Opera里面使用,赶快换回Opera,firefox的速度还是与Opera无法相比的。对了Ibus这个输入法也不错。
IN:C, Python, 编程相关 Tags: C, Python Comments:8在这里看到用Lua和Python写的使用筛选法求质数的代码,俺自己也写了写,Python版用到了上面链接中一位兄弟的tips
先来C语言版的:
#include <stdio .h>
#include <math .h>
#define NUM 2000000
int main(void)
{
int primes[NUM];
int i,j;
for (i=0;i<num ;i++) {
primes[i] = 1;
}
primes[0] = 0;
primes[1] = 0;
for (i=1;i<(long)sqrt(NUM)+1;i++) {
if (primes[i]) {
for (j=pow(i,2);j<NUM;j+=i) {
primes[j] = 0;
}
}
}
long sum = 0;
for (i=0;i<NUM;i++) {
if (primes[i]) sum+=i;
}
printf("%ld\n",sum);
return 0;
}
计算两百万以内质数和大约0.1秒左右:
[cocobear@cocobear wxpython]$ time ./a.out
142913828922
real 0m0.100s
user 0m0.088s
sys 0m0.012s
接着来可爱的Python版:
from math import sqrt
NUM = 2000000
prime_num = [i for i in xrange(NUM+1)]
for i in xrange(2,int(sqrt(NUM))+1):
if prime_num[i]:
start = i**2
step = i
prime_num[start::step] = ( (NUM - start)/step + 1)*[0]
print sum(prime_num)-1
执行时间1秒多点:
[cocobear@cocobear wxpython]$ time python prime.py
142913828922
real 0m1.204s
user 0m1.051s
sys 0m0.093s
Python不到10行的代码也有不错的效率:-)
以上测试平台为:
Fedora 9 AMD64 4600+ 4G
计算5的阶乘
reduce(lambda x,y:x*y,range(1,5+1))