libevent はこんなに便利

会社の受信メールサーバは IMAP4 と POP3、両方用意はされておりますが、
SMTP の認証には未だ POP Before SMTP が使われています。

これにはちょっと古めの PDA などでは SMTP 認証が使えないという理由もありますが、
実際は、サーバ類がすべて自作のアプリケーションゲートウェイを通して外部に公開されていて、SMTP のモジュールが認証に対応していないことが原因です・・・

でも、やはり IMAP 4 を使いたいということで、
IMAP Before SMTP に対応したゲートウェイをだいぶまえに作ったのですが、
どうも動きが不安定で社内から避難の声が多々聞こえてきていました。
社長なんかメールを書くときは telnet で pop3 サーバと会話して認証しているくらいで・・・

そこで以前 itojun さんに教えてもらった libevent を使って全面的に書き直してみました。
いやぁ、これがびっくりするくらい簡単に I/O を多重化できてとても便利!

どれくらい簡単かは下記のサンプルをみていただければわかるとおもいます。
これを、cc sample.c -levent -o sample とでもしてコンパイルして、実行します。
そうすると 2000番ポートで待ち受けて、受け取った文字列を表示するプログラムのできあがりです。
#もちろん行読み込みとか受信バッファの中に何があるとか何にも考えていないので、でたらめな表示になるかもしれませんが、本質ではないので触れていません :-p


/*
* sample.c
*/
#include
#include
#include
#include

static void
read_handler(int fd, short event, void *arg)
{
char buf[256];
struct event *ev=(struct event*)arg;

if(event&EV_READ){
if(read(fd, buf, sizeof(buf))<=0){
event_del(ev);
free(ev);
close(fd);
}
else{
printf("read=%s\n", buf);
}
}
}

static void
accept_handler(int fd, short event, void *arg)
{
struct sockaddr_in addr;
struct event *new_ev;
int new_fd;
socklen_t addrlen=sizeof(addr);

if(event&EV_READ){
new_fd=accept(fd,(struct sockaddr*)&addr,&addrlen);
new_ev=malloc(sizeof(struct event));
event_set(new_ev,new_fd,EV_READ|EV_PERSIST,read_handler,new_ev);
event_add(new_ev,NULL);
}
}

int
main(int argc, char *argv[])
{
struct event ev;
struct addrinfo hints, *res;
int fd;

memset(&hints,0,sizeof(hints));
hints.ai_socktype=SOCK_STREAM;
hints.ai_flags=AI_PASSIVE;
getaddrinfo(NULL,"2000",&hints,&res);
fd=socket(res->ai_family,res->ai_socktype,res->ai_protocol);
bind(fd,res->ai_addr,res->ai_addrlen);
listen(fd,SOMAXCONN);
freeaddrinfo(res);

event_init();
event_set(&ev,fd,EV_READ|EV_PERSIST,accept_handler,&ev);
event_add(&ev,NULL);

event_dispatch();
}